@@ -379,6 +379,12 @@ vector `∇J_a` containing the vectorized elements ``∂J_a/∂ϵ_{ln}``.
379379The function `J_a` must have the interface `J_a(pulsevals, tlist)`,
380380see, e.g., [`J_a_fluence`](@ref).
381381
382+ In `pulsevals`, the values ``ϵ_{nl}`` are vectorized with `n` (time interval
383+ index) varying faster than `l` (control index), i.e.,
384+ `pulsevals = [ϵ₁₁, ϵ₂₁, …, ϵ_{N_T,1}, ϵ₁₂, ϵ₂₂, …, ϵ_{N_T,2}, …]`,
385+ where ``N_T = `` `length(tlist) - 1`. The pulse values for each control are
386+ contiguous.
387+
382388The parameters `mode` and `automatic` are handled as in [`make_chi`](@ref),
383389where `mode` is one of `:any`, `:analytic`, `:automatic`, and `automatic` is
384390he loaded module of an automatic differentiation framework, where `:default`
@@ -924,16 +930,24 @@ J_a = J_a_fluence(pulsevals, tlist)
924930calculates
925931
926932```math
927- J_a = \s um_l \i nt_0^T |ϵ_l(t)|^2 dt = \l eft( \ s um_{nl} |ϵ_{nl}|^2 \r ight) dt
933+ J_a = \s um_l \i nt_0^T |ϵ_l(t)|^2 dt \a pprox \ s um_{nl} |ϵ_{nl}|^2 \, dt_n
928934```
929935
930- where ``ϵ_{nl}`` are the values in the (vectorized) `pulsevals`, `n` is the
931- index of the intervals of the time grid, and ``dt`` is the time step, taken
932- from the first time interval of `tlist` and assumed to be uniform.
936+ where ``ϵ_{nl}`` are the values in `pulsevals`, with `n`
937+ the index of the time interval and `l` the index of the control, and
938+ ``dt_n = `` `tlist[n+1] - tlist[n]` is the duration of interval `n`.
939+ The `pulsevals` are vectorized as ``[ϵ₁₁, ϵ₂₁, …, ϵ_{N_T,1}, ϵ₁₂, ϵ₂₂, …]``,
940+ where `N_T = length(tlist) - 1`. Supports non-uniform time grids.
941+
942+ # See also
943+
944+ * [`grad_J_a_fluence`](@ref) — analytic (automatic) gradient
933945"""
934946function J_a_fluence (pulsevals, tlist)
935- dt = tlist[begin + 1 ] - tlist[begin ]
936- return sum (abs2 .(pulsevals)) * dt
947+ N_T = length (tlist) - 1
948+ dt = reshape (diff (tlist), :, 1 ) # (N_T, 1) for column broadcasting
949+ pv = reshape (pulsevals, N_T, :) # (N_T, N_L), no copy
950+ return sum (abs2 .(pv) .* dt)
937951end
938952
939953
@@ -943,14 +957,16 @@ end
943957∇J_a = grad_J_a_fluence(pulsevals, tlist)
944958```
945959
946- returns the `∇J_a`, which contains the (vectorized) elements ``2 ϵ_{nl} dt ``,
947- where ``ϵ_{nl}`` are the (vectorized) elements of `pulsevals` and ``dt`` is the
948- time step, taken from the first time interval of `tlist` and assumed to be
949- uniform.
960+ returns `∇J_a`, which contains the (vectorized) elements ``2 ϵ_{nl} dt_n ``,
961+ where ``ϵ_{nl}`` are the (vectorized) elements of `pulsevals` and
962+ ``dt_n = `` `tlist[n+1] - tlist[n]` is the duration of interval `n`.
963+ Supports non- uniform time grids .
950964"""
951965function grad_J_a_fluence (pulsevals, tlist)
952- dt = tlist[begin + 1 ] - tlist[begin ]
953- return (2 * dt) * pulsevals
966+ N_T = length (tlist) - 1
967+ dt = reshape (diff (tlist), :, 1 ) # (N_T, 1) for column broadcasting
968+ pv = reshape (pulsevals, N_T, :) # (N_T, N_L), no copy
969+ return vec (2 .* dt .* pv)
954970end
955971
956972
0 commit comments