Callbacks
RegularizedLeastSquares provides a callback mechanism that allows you to access and monitor the state of the optimization process. These callbacks are invoked at the start of each iteration and have the form f(solver, iteration). Via the solver, you can access any internal property of the solver state.
MPIReco exposes this interface for compatible algorithms. You can use do-syntax to pass a callback of the form f(solver, frame, iteration) to the reconstruction:
c = reconstruct("SinglePatch", b; parameters...) do solver, frame, iteration
tmp = sum(solversolution(solver))
@info "Sum of concentration at frame $frame and iteration $iteration is $tmp"
end
Float32 ImageMeta with:
data: 5-dimensional AxisArray{Float32,5,...} with axes:
:color, 1:1
:x, (-27.375:1.25:11.375) mm
:y, (-11.375:1.25:27.375) mm
:z, (0.0:1.0:0.0) mm
:time, (0.0:6.5280000000000005:0.0) s
And data, a 1×32×32×1×1 Array{Float32, 5}
properties:
tracerName: ["Resovist"]
version: 2.0.1
experimentDescription: Ph5DotsDF10Overlap0LL (E99)
scannerOperator: nmrsu
rxNumSamplingPoints: 1632
acqOffsetField: [-0.01; 0.01; -0.0;;;]
dfStrength: [0.01 0.01 0.0;;;]
scannerTopology: FFP
rxDataConversionFactor: [0.0001 0.0001 0.0001; 0.0 0.0 0.0]
experimentNumber: 99
dfDivider: [102; 96; 99;;]
tracerBatch: ["0"]
acqStartTime: 2014-11-27T14:40:01.280
tracerInjectionTime: [DateTime("2014-11-27T14:40:01.280")]
dfWaveform: ["sine";;]
dim: 2
uuid: 8eadd786-d630-4f53-ae91-c8f90721bbdc
dfBaseFrequency: 2.5e6
dfCycle: 0.0006528
experimentName: Ph5DotsDF10Overlap0LL (E99)
studyUuid: 12246d79-646a-41b8-a278-5274fc9ae7c5
tracerVolume: [0.0]
studyDescription: n.a.
experimentSubject: FocusField
experimentUuid: 787b3b7b-734a-4872-8bad-a38a64478cca
acqNumFrames: 1
tracerConcentration: [0.5]
dfNumChannels: 3
dfPhase: [1.5708 1.5708 1.5708;;;]
scannerManufacturer: Bruker/Philips
studyTime: 2014-11-13T16:20:01.217
scannerFacility: Universitätsklinikum Hamburg Eppendorf
studyName: FocusField
scannerName: Preclinical MPI System
tracerSolute: ["Fe"]
size: [32, 32, 1]
time: 2021-12-26T19:52:45.666
experimentIsSimulation: false
datatype: MPI
acqNumPeriodsPerFrame: 1
experimentIsCalibration: false
studyNumber: 1
rxBandwidth: 1.25e6
tracerVendor: ["n.a."]
rxUnit: a.u.
acqNumAverages: 10000
rxNumChannels: 3
acqGradient: [-1.25 0.0 0.0; 0.0 -1.25 0.0; 0.0 0.0 2.5;;;;]
MPIReco also provides built-in callbacks that can store the solution in each iteration or compare the current solution with a reference:
cb = StoreSolutionPerFrameCallback()
reconstruct(cb, "SinglePatch", b; parameters...);
cb.solutions[1]
4-element Vector{Vector{Float32}}:
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
[0.0, 0.00020932728, 0.0, 2.7252778f-5, 0.00021386408, 0.0, 0.0, 0.0, 0.0, 0.00050126185 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
You can also combine multiple callbacks:
cb1 = StoreSolutionPerFrameCallback()
ref = reshape(c[1, :, :, :, 1].data.data, :, 1)
cb2 = CompareSolutionPerFrameCallback(ref)
reconstruct("SinglePatch", b; parameters...) do solver, frame, iteration
cb1(solver, frame, iteration)
cb2(solver, frame, iteration)
end
cb2.results[1]
4-element Vector{Float64}:
0.09727259689947518
0.019788756997517483
0.0063009444256531865
2.3881879308376115e-8
Note that callbacks are used directly in the solver and thus reflect its value domain. This means that in sparse reconstruction, the current solution approximation is not in the image domain. Likewise, the solution might still be a complex number.
Both variants shown above get passed as a callbacks keyword argument to the algorithm. When using the callback directly like this, the interface changes from f(solver, frame, iteration) to f(solver, iteration). And you have to manually differentiate between frames by watching for the start of a new reconstruction:
frame = 0
function my_callback(solver, iteration)
if iteration == 0
global frame += 1
end
@info "Frame $frame, Iteration $iteration"
end
reconstruct("SinglePatch", b; parameters..., callbacks = my_callback);
[ Info: Loading SM
[ Info: Preparing SF
[ Info: Adapting SF
[ Info: Frame 1, Iteration 0
[ Info: Frame 1, Iteration 1
[ Info: Frame 1, Iteration 2
[ Info: Frame 1, Iteration 3
This page was generated using Literate.jl.