Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More statistics functions #115

Merged
merged 50 commits into from
Apr 15, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
3ec58b3
function to save z, dz
chrisbrahms Mar 25, 2020
c8810d0
t and ω energyfunctions
chrisbrahms Mar 25, 2020
948dbb0
testing t and ω energy-functions
chrisbrahms Mar 26, 2020
59bf810
Merge branch 'master' into stats
chrisbrahms Mar 26, 2020
5ef705d
t and ω energy function for modes
chrisbrahms Mar 26, 2020
13c1229
energy stat
chrisbrahms Mar 26, 2020
395a2a7
test script
chrisbrahms Mar 27, 2020
cea4a67
Merge branch 'master' into stats
chrisbrahms Apr 1, 2020
92e6dd8
energy functions
chrisbrahms Apr 1, 2020
577d714
change MemoryOutput call signature
chrisbrahms Apr 1, 2020
202a00a
improve hilbert transform, add plan_hilbert
chrisbrahms Apr 1, 2020
d764aa3
load/save FFTW wisdom
chrisbrahms Apr 2, 2020
35aef02
some more stats
chrisbrahms Apr 2, 2020
e50c732
docstrings
chrisbrahms Apr 2, 2020
f699edf
Merge branch 'master' into stats
chrisbrahms Apr 2, 2020
2cde7cb
switch back to separate transforms
chrisbrahms Apr 2, 2020
1732406
docstring, clutter
chrisbrahms Apr 2, 2020
4c5437e
FWHM, energy in window
chrisbrahms Apr 2, 2020
d78efe5
switch to window for energy_λ to fix envelope
chrisbrahms Apr 2, 2020
72f090c
rename energy functions
chrisbrahms Apr 2, 2020
ffebd5c
make ADK function type-stable
chrisbrahms Apr 2, 2020
ace7626
fix electron density, typo
chrisbrahms Apr 2, 2020
6eb07f0
add FWHM with linear interpolation
chrisbrahms Apr 2, 2020
19f6d41
docstrings
chrisbrahms Apr 2, 2020
7ed5fca
docstrings
chrisbrahms Apr 2, 2020
1330b9d
typo
chrisbrahms Apr 2, 2020
c947685
Merge branch 'master' into stats
chrisbrahms Apr 3, 2020
5c1ea66
Merge branch 'master' into stats
chrisbrahms Apr 7, 2020
70d2e16
improve FWHM
chrisbrahms Apr 8, 2020
d9c1010
compact printing
chrisbrahms Apr 8, 2020
4ef1141
save simulation type
chrisbrahms Apr 8, 2020
8c8f742
Merge branch 'master' into stats
chrisbrahms Apr 8, 2020
d26aa68
electron density for multimode
chrisbrahms Apr 8, 2020
ddf9e37
radial FWHM statistic
chrisbrahms Apr 8, 2020
546962a
docstrings, combine functions
chrisbrahms Apr 8, 2020
8ce0161
Merge branch 'master-saved' into stats
chrisbrahms Apr 9, 2020
e4c1ba2
Merge branch 'master' into stats
chrisbrahms Apr 14, 2020
572e780
switch to BSpline in FWHM with spline method
chrisbrahms Apr 14, 2020
3672faf
save transform as string
chrisbrahms Apr 14, 2020
aad6ce8
tests pass
chrisbrahms Apr 14, 2020
9762587
string representation for modes in output
chrisbrahms Apr 14, 2020
ae64861
fix npol
chrisbrahms Apr 14, 2020
499f70a
more roots for BSpline FWHM
chrisbrahms Apr 14, 2020
eb2385c
peak intensity
chrisbrahms Apr 14, 2020
e43eb45
docstring
chrisbrahms Apr 14, 2020
59119b8
add modal stats tests
chrisbrahms Apr 14, 2020
2baafb1
mode-averaged peak intensity
chrisbrahms Apr 14, 2020
f6a67e5
docstring
chrisbrahms Apr 14, 2020
41cd416
correct docstring for TransFree
chrisbrahms Apr 15, 2020
c1b5d8b
add dumps of linop and transform to output
chrisbrahms Apr 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions src/Luna.jl
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ function setup(grid::Grid.RealGrid, xygrid::Grid.FreeGrid,
end
xo = Array{Float64}(undef, length(grid.to), length(y), length(x))
FTo = FFTW.plan_rfft(xo, (1, 2, 3), flags=settings["fftw_flag"])
transform = NonlinearRHS.TransFree(grid, FTo, length(y), length(x),
transform = NonlinearRHS.TransFree(grid, xygrid, FTo,
responses, densityfun, normfun)
inv(FT) # create inverse FT plans now, so wisdom is saved
inv(FTo)
Expand All @@ -226,7 +226,7 @@ function setup(grid::Grid.EnvGrid, xygrid::Grid.FreeGrid,
end
xo = Array{ComplexF64}(undef, length(grid.to), length(y), length(x))
FTo = FFTW.plan_fft(xo, (1, 2, 3), flags=settings["fftw_flag"])
transform = NonlinearRHS.TransFree(grid, FTo, length(y), length(x),
transform = NonlinearRHS.TransFree(grid, xygrid, FTo,
responses, densityfun, normfun)
inv(FT) # create inverse FT plans now, so wisdom is saved
inv(FTo)
Expand Down Expand Up @@ -274,10 +274,6 @@ function shotnoise!(Eω, grid::Grid.EnvGrid; seed=nothing)
@. Eω += FFTamp * exp(1im*φ)
end

transtype(t::NonlinearRHS.TransModeAvg) = "mode average"
transtype(t::NonlinearRHS.TransModal) = "multimode"
transtype(t) = "unknown"

linoptype(l::AbstractArray) = "constant"
linoptype(l) = "variable"

Expand All @@ -286,14 +282,13 @@ gridtype(g::Grid.EnvGrid) = "envelope"
gridtype(g) = "unknown"

simtype(g, t, l) = Dict("field" => gridtype(g),
"transform" => transtype(t),
"transform" => string(t),
"linop" => linoptype(l))

function run(Eω, grid,
linop, transform, FT, output;
min_dz=0, max_dz=Inf, init_dz=1e-4,
rtol=1e-6, atol=1e-10, safety=0.9, norm=RK45.weaknorm,
stats=true,
status_period=1)


Expand Down
65 changes: 35 additions & 30 deletions src/Maths.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,37 +90,42 @@ function fwhm(x, y; method=:linear, baseline=false, minmax=:min)
end
maxidx = argmax(y)
xmax = x[maxidx]
left, right = try
if minmax == :min
lefti = findlast((x .< xmax) .& (y .< val))
righti = findfirst((x .> xmax) .& (y .< val))
(method == :nearest) && return abs(x[lefti] - x[righti])
left = linterpx(x[lefti], x[lefti+1], y[lefti], y[lefti+1], val)
right = linterpx(x[righti-1], x[righti], y[righti-1], y[righti], val)
else
lefti = findfirst((x .< xmax) .& (y .> val))
righti = findlast((x .> xmax) .& (y .> val))
(method == :nearest) && return abs(x[lefti] - x[righti])
left = linterpx(x[lefti-1], x[lefti], y[lefti-1], y[lefti], val)
right = linterpx(x[righti], x[righti+1], y[righti], y[righti+1], val)
if method in (:nearest, :linear)
try
if minmax == :min
lefti = findlast((x .< xmax) .& (y .< val))
righti = findfirst((x .> xmax) .& (y .< val))
(method == :nearest) && return abs(x[lefti] - x[righti])
left = linterpx(x[lefti], x[lefti+1], y[lefti], y[lefti+1], val)
right = linterpx(x[righti-1], x[righti], y[righti-1], y[righti], val)
else
lefti = findfirst((x .< xmax) .& (y .> val))
righti = findlast((x .> xmax) .& (y .> val))
(method == :nearest) && return abs(x[lefti] - x[righti])
left = linterpx(x[lefti-1], x[lefti], y[lefti-1], y[lefti], val)
right = linterpx(x[righti], x[righti+1], y[righti], y[righti+1], val)
end
return abs(right - left)
catch
return NaN
end
(method == :linear) && return abs(right - left)
left, right
catch
return NaN
end
#spline method
minmax == :max && error("Spline method only supports min FWHM")
try
spl = CSpline(x, y)
lb = xmax - 2*(xmax-left)
ub = xmax + 2*(right-xmax)
f(x) = spl(x) - val
lfine = fzero(f, lb, xmax)
rfine = fzero(f, xmax, ub)
return abs(rfine - lfine)
catch
return NaN
elseif method == :spline
#spline method
try
spl = BSpline(x, y .- val)
r = roots(spl)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For horrible functions the number of roots could be very high, we probably need to increase the argument to the Dierckx roots function. See here:
https://github.com/kbarbary/Dierckx.jl/blob/master/src/Dierckx.jl#L378

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any feeling for how many might be enough?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well for a "noise burst" it could be thousands. That might come with a performance hit though. To be clear, passing a high maxn to Dierckx doesn't cost anything if there are not many roots. But if there are thousands then it will find all of them.

This isn't just academic, when looking for pulse convergence in say modelocking (or a FOPO!), a key metric is if the min and max FWHM match. We could be doing a lot of that quite soon. I suppose in that case we'd specify a different method here, and only use the spline for more precise requirements.

It might be worth adding a "noise burst" test though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this pulse:
image
it finds around 600 roots, FWHM max still works, and it still only takes 1.5 ms with 2^14 points

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

funnily, the warning in Dierckx.jl when more roots than maxn were found is now an exception, because warn no longer exists. Medium to long term it would be good to no longer depend on that package.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but Dierckx (the fortran part) is by far the highest quality and most tested spline package I've found so far. And the wrapper code is rather minimal, so we can help maintain it. If I had sufficient free time I'd translate it, but alas I can;t see that happening very soon.

rleft = r[r .< xmax]
rright = r[r .> xmax]
if minmax == :min
return abs(minimum(rright) - maximum(rleft))
else
return abs(maximum(rright) - minimum(rleft))
end
catch
return NaN
end
else
error("Unknown FWHM method $method")
end
end

Expand Down
38 changes: 32 additions & 6 deletions src/NonlinearRHS.jl
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,13 @@ end

function show(io::IO, t::TransModal)
grid = "grid type: $(typeof(t.grid))"
nmodes = "no. of modes: $(t.nmodes)"
nmodes = "no. of modes: $(t.ts.nmodes)"
p = t.ts.indices == 1:2 ? "x,y" : t.ts.indices == 1 ? "x" : "y"
pol = "polarisation: $p"
samples = "time grid size: $(length(t.grid.t)) / $(length(t.grid.to))"
resp = "responses: "*join([string(typeof(ri)) for ri in t.resp], "\n ")
full = "full: $(t.full)"
out = join(["TransModal", nmodes, grid, samples, full, resp], "\n ")
out = join(["TransModal", nmodes, pol, grid, samples, full, resp], "\n ")
print(io, out)
end

Expand Down Expand Up @@ -293,7 +295,7 @@ function show(io::IO, t::TransModeAvg)
grid = "grid type: $(typeof(t.grid))"
samples = "time grid size: $(length(t.grid.t)) / $(length(t.grid.to))"
resp = "responses: "*join([string(typeof(ri)) for ri in t.resp], "\n ")
out = join(["TransModal", grid, samples, resp], "\n ")
out = join(["TransModeAvg", grid, samples, resp], "\n ")
print(io, out)
end

Expand Down Expand Up @@ -371,6 +373,16 @@ struct TransRadial{TT, HTT, FTT, nT, rT, gT, dT, iT}
idcs::iT # CartesianIndices for Et_to_Pt! to iterate over
end

function show(io::IO, t::TransRadial)
grid = "grid type: $(typeof(t.grid))"
samples = "time grid size: $(length(t.grid.t)) / $(length(t.grid.to))"
resp = "responses: "*join([string(typeof(ri)) for ri in t.resp], "\n ")
nr = "radial points: $(t.QDHT.N)"
R = "aperture: $(t.QDHT.R)"
out = join(["TransRadial", grid, samples, nr, R, resp], "\n ")
print(io, out)
end

function TransRadial(TT, grid, HT, FT, responses, densityfun, normfun)
Eωo = zeros(ComplexF64, (length(grid.ωo), HT.N))
Eto = zeros(TT, (length(grid.to), HT.N))
Expand Down Expand Up @@ -504,11 +516,12 @@ end

Transform E(ω) -> Pₙₗ(ω) for full 3D free-space propagation
"""
mutable struct TransFree{TT, FTT, nT, rT, gT, dT, iT}
mutable struct TransFree{TT, FTT, nT, rT, gT, xygT, dT, iT}
FT::FTT # 3D Fourier transform (space to k-space and time to frequency)
normfun::nT # Function which returns normalisation factor
resp::rT # nonlinear responses (tuple of callables)
grid::gT # time grid
xygrid::xygT
densityfun::dT # callable which returns density
Pto::Array{TT, 3} # buffer for oversampled time-domain NL polarisation
Eto::Array{TT, 3} # buffer for oversampled time-domain field
Expand All @@ -518,13 +531,26 @@ mutable struct TransFree{TT, FTT, nT, rT, gT, dT, iT}
idcs::iT # iterating over these slices Eto/Pto into Vectors, one at each position
end

function TransFree(TT, scale, grid, FT, Ny, Nx, responses, densityfun, normfun)
function show(io::IO, t::TransFree)
grid = "grid type: $(typeof(t.grid))"
samples = "time grid size: $(length(t.grid.t)) / $(length(t.grid.to))"
resp = "responses: "*join([string(typeof(ri)) for ri in t.resp], "\n ")
y = "y grid: $(minimum(t.xygrid.y)) to $(maximum(t.xygrid.y)), N=$(length(t.xygrid.y))"
x = "x grid: $(minimum(t.xygrid.x)) to $(maximum(t.xygrid.x)), N=$(length(t.xygrid.x))"
out = join(["TransFree", grid, samples, y, x, resp], "\n ")
print(io, out)
end

function TransFree(TT, scale, grid, xygrid, FT, responses, densityfun, normfun)
Ny = length(xygrid.y)
Nx = length(xygrid.x)
Eωo = zeros(ComplexF64, (length(grid.ωo), Ny, Nx))
Eto = zeros(TT, (length(grid.to), Ny, Nx))
Pto = similar(Eto)
Pωo = similar(Eωo)
idcs = CartesianIndices((Ny, Nx))
TransFree(FT, normfun, responses, grid, densityfun, Pto, Eto, Eωo, Pωo, scale, idcs)
TransFree(FT, normfun, responses, grid, xygrid, densityfun,
Pto, Eto, Eωo, Pωo, scale, idcs)
end

"""
Expand Down
14 changes: 13 additions & 1 deletion src/Stats.jl
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ function electrondensity(grid::Grid.RealGrid, ionrate!, dfun,
end
tospace = Modes.ToSpace(modes, components=components)
frac = similar(to)
npol = components == :xy ? 2 : 1
npol = tospace.npol
Et0 = zeros(ComplexF64, (length(to), npol))
function addstat!(d, Eω, Et, z, dz)
# note: oversampling returns its arguments without any work done if factor==1
Expand All @@ -194,6 +194,18 @@ function density(dfun)
end
end

function core_radius(a::Number)
function addstat!(d, Eω, Et, z, dz)
d["core_radius"] = a
end
end

function core_radius(afun)
function addstat!(d, Eω, Et, z, dz)
d["core_radius"] = afun(z)
end
end

function zdz!(d, Eω, Et, z, dz)
d["z"] = z
d["dz"] = dz
Expand Down
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ end
end

@testset "ODE Solver" begin
@info("================= test_rect_rk45.jl")
@info("================= test_rk45.jl")
include(joinpath(testdir, "test_rk45.jl"))
end

Expand Down
5 changes: 3 additions & 2 deletions test/test_freespace.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ function gausspulse(t)
return prop(Et, -0.3)
end

dens0 = PhysData.density(gas, pres)
densityfun(z) = dens0
densityfun = let dens0=PhysData.density(gas, pres)
z -> dens0
end

ionpot = PhysData.ionisation_potential(gas)
ionrate = Ionisation.ionrate_fun!_PPTcached(gas, λ0)
Expand Down
5 changes: 3 additions & 2 deletions test/test_freespace_fourier.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ function gausspulse(t)
Et = @. sqrt(It)*cos(ω0*t)
end

dens0 = PhysData.density(gas, pres)
densityfun(z) = dens0
densityfun = let dens0=PhysData.density(gas, pres)
z -> dens0
end

ionpot = PhysData.ionisation_potential(gas)
ionrate = Ionisation.ionrate_fun!_ADK(ionpot)
Expand Down
Loading