diff --git a/Project.toml b/Project.toml index e848c39..39119d0 100644 --- a/Project.toml +++ b/Project.toml @@ -38,7 +38,7 @@ MPIRecoDaggerExt = ["Dagger", "DaggerImageReconstruction"] MPIRecoKernelAbstractionsExt = ["Atomix", "KernelAbstractions", "GPUArrays"] [compat] -AbstractImageReconstruction = "0.5" +AbstractImageReconstruction = "0.6" Adapt = "3, 4" Atomix = "1" DSP = "0.6, 0.7, 0.8" diff --git a/docs/src/literate/howtos/custom.jl b/docs/src/literate/howtos/custom.jl index 191048f..d54c8ed 100644 --- a/docs/src/literate/howtos/custom.jl +++ b/docs/src/literate/howtos/custom.jl @@ -9,10 +9,10 @@ b = MPIFile(joinpath(datadir, "measurements", "20211226_203916_MultiPatch", "1.m # ## Custom Processing Steps # To implement a custom processing step, we need to add a new parameter struct, in our case we want to extend `AbstractWeightingParameters`. # As a toy-example, we will implement a weighting strategy in which frequencies are weighting with an alternating sequence of weights: -Base.@kwdef struct AlternatingWeightingParameters <: AbstractWeightingParameters +@parameter struct AlternatingWeightingParameters <: AbstractWeightingParameters alternatingWeights::Vector{Float64} end -# The `Base.@kwdef` macro generates a keyword-argment constructor with optional default values. Next, we can implement the actual processing function. +# The `@parameter` macro generates a keyword-argment constructor with optional default values. Next, we can implement the actual processing function. # Different algorithms can have different implementations of a given weighting strategy and we can specialise a function on the type of algorithm or an algorithm instance itself. # The former is helpful for pure functions, i.e. processing steps which solely depend on the given parameter and processing-arguments, not the state of the algorithm. diff --git a/docs/src/literate/howtos/extensions.jl b/docs/src/literate/howtos/extensions.jl index 46cf613..18056b1 100644 --- a/docs/src/literate/howtos/extensions.jl +++ b/docs/src/literate/howtos/extensions.jl @@ -10,7 +10,7 @@ module CustomWeighting using MPIReco.AbstractImageReconstruction export AlternatingWeightingParameters - Base.@kwdef struct AlternatingWeightingParameters <: AbstractWeightingParameters + @parameter struct AlternatingWeightingParameters <: AbstractWeightingParameters alternatingWeights::Vector{Float64} end diff --git a/docs/src/literate/howtos/solvers.jl b/docs/src/literate/howtos/solvers.jl index 2cd17b9..cd90331 100644 --- a/docs/src/literate/howtos/solvers.jl +++ b/docs/src/literate/howtos/solvers.jl @@ -72,7 +72,7 @@ hidedecorations!(fig.axis) fig # If our custom solver requires custom parameters, we could implement custom solver parameters in MPIReco: -Base.@kwdef struct OurSolverParameters <: MPIReco.AbstractSolverParameters{OurSolver} +@parameter struct OurSolverParameters <: MPIReco.AbstractSolverParameters{OurSolver} notification::String enforceReal::Bool=true enforcePositive::Bool=true diff --git a/ext/MPIRecoKernelAbstractionsExt/Weighting.jl b/ext/MPIRecoKernelAbstractionsExt/Weighting.jl index 6c0aa5b..2988144 100644 --- a/ext/MPIRecoKernelAbstractionsExt/Weighting.jl +++ b/ext/MPIRecoKernelAbstractionsExt/Weighting.jl @@ -1,4 +1,4 @@ -function AbstractImageReconstruction.process(algo::Type{<:AbstractMPIRecoAlgorithm}, params::ProcessResultCache{<:AbstractWeightingParameters}, freqs, S, meas, arrType::Type{<:AbstractGPUArray}) +function (params::ProcessResultCache{<:AbstractWeightingParameters})(algo::Type{<:AbstractMPIRecoAlgorithm}, freqs, S, meas, arrType::Type{<:AbstractGPUArray}) @warn "Caching of weight processing is disabled for GPU processing" - return process(algo, params.param, freqs, S, meas, arrType) + return params.param(algo, freqs, S, meas, arrType) end \ No newline at end of file diff --git a/src/AlgorithmInterface.jl b/src/AlgorithmInterface.jl index 3d20374..c651e11 100644 --- a/src/AlgorithmInterface.jl +++ b/src/AlgorithmInterface.jl @@ -23,7 +23,7 @@ abstract type AbstractMPIPreProcessingParameters{T<:AbstractMPIBackgroundCorrect export AbstractMPIPostProcessingParameters, NoPostProcessing abstract type AbstractMPIPostProcessingParameters <: AbstractMPIRecoParameters end struct NoPostProcessing <: AbstractMPIPostProcessingParameters end # TODO remove later -process(algo::AbstractMPIRecoAlgorithm, ::NoPostProcessing, data) = data +(::NoPostProcessing)(algo::AbstractMPIRecoAlgorithm, data) = data export AbstractMPIReconstructionParameters abstract type AbstractMPIReconstructionParameters <: AbstractMPIRecoParameters end @@ -42,6 +42,9 @@ struct MixedAlgorithm <: ReconstructionAlgorithmType end # TODO recoAlgorithmType # TODO undefined for certain "Algorithm" components #recoAlgorithmTypes(::Type{ConcreteRecoAlgorithm}) = SystemMatrixBasedAlgorithm() +export MPIRecoStyle +struct MPIRecoStyle <: CustomPlanStyle end + export addRecoPlanPath, getRecoPlanList const DEFAULT_PLANS_PATH = @path joinpath(@__DIR__, "..", "config") const recoPlanPaths = AbstractString[DEFAULT_PLANS_PATH] @@ -170,7 +173,7 @@ function loadRecoPlan(planfile::AbstractString, modules; kwargs...) end # Load plan from an io (could be file or iobuffer backed string) function loadRecoPlan(io, modules; kwargs...) - plan = loadPlan(io, modules) + plan = loadPlan(io, modules; field_style = MPIRecoStyle()) setKwargs!(plan; kwargs...) return plan end diff --git a/src/Algorithms/HandsFreeAlgorithms/HandsFreeLeastSquares.jl b/src/Algorithms/HandsFreeAlgorithms/HandsFreeLeastSquares.jl index f18d9c5..6e68fcf 100644 --- a/src/Algorithms/HandsFreeAlgorithms/HandsFreeLeastSquares.jl +++ b/src/Algorithms/HandsFreeAlgorithms/HandsFreeLeastSquares.jl @@ -1,5 +1,5 @@ export HandsFreeSolverParameters -Base.@kwdef struct HandsFreeSolverParameters <: AbstractSolverParameters{Kaczmarz} +@parameter struct HandsFreeSolverParameters <: AbstractSolverParameters{Kaczmarz} iterbounds::Tuple{Int64, Int64}=(1, 25) enforceReal::Bool=true enforcePositive::Bool=true @@ -11,7 +11,7 @@ Base.@kwdef struct HandsFreeSolverParameters <: AbstractSolverParameters{Kaczmar flattenIters::Bool=false end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::LeastSquaresParameters{Kaczmarz, O, SF, R, SL, W}, u::AbstractArray, snr::AbstractVector) where {O, SF, R, SL <: HandsFreeSolverParameters, W} +function (params::LeastSquaresParameters{Kaczmarz, O, SF, R, SL, W})(t::Type{<:AbstractMPIRecoAlgorithm}, u::AbstractArray, snr::AbstractVector) where {O, SF, R, SL <: HandsFreeSolverParameters, W} solverParams = params.solverParams N = size(params.S, 2) diff --git a/src/Algorithms/HandsFreeAlgorithms/HandsFreeSinglePatch.jl b/src/Algorithms/HandsFreeAlgorithms/HandsFreeSinglePatch.jl index 28bf3a5..29bd317 100644 --- a/src/Algorithms/HandsFreeAlgorithms/HandsFreeSinglePatch.jl +++ b/src/Algorithms/HandsFreeAlgorithms/HandsFreeSinglePatch.jl @@ -1,5 +1,5 @@ export SinglePatchHandsFreeReconstructionParameter -Base.@kwdef struct SinglePatchHandsFreeReconstructionParameter{L<:AbstractSystemMatrixLoadingParameter, +@parameter struct SinglePatchHandsFreeReconstructionParameter{L<:AbstractSystemMatrixLoadingParameter, arrT <: AbstractArray, SP<:HandsFreeSolverParameters, W<:AbstractWeightingParameters} <: AbstractSinglePatchReconstructionParameters # File sf::MPIFile @@ -12,16 +12,16 @@ Base.@kwdef struct SinglePatchHandsFreeReconstructionParameter{L<:AbstractSystem end function prepareSystemMatrix(reco::SinglePatchHandsFreeReconstructionParameter{L}) where {L<:AbstractSystemMatrixLoadingParameter} - freqs, sf, grid = process(AbstractMPIRecoAlgorithm, reco.sfLoad, reco.sf, Kaczmarz, reco.arrayType) + freqs, sf, grid = reco.sfLoad(AbstractMPIRecoAlgorithm, reco.sf, Kaczmarz, reco.arrayType) return freqs, sf, grid, reco.arrayType end function prepareWeights(reco::SinglePatchHandsFreeReconstructionParameter{L,arrT,SP,W}, freqs, sf) where {L, arrT, SP, W<:AbstractWeightingParameters} - return process(AbstractMPIRecoAlgorithm, reco.weightingParams, freqs, sf, nothing, reco.arrayType) + return reco.weightingParams(AbstractMPIRecoAlgorithm, reco.weightingParams, freqs, sf, nothing, reco.arrayType) end -function process(algo::SinglePatchReconstructionAlgorithm, params::SinglePatchHandsFreeReconstructionParameter, u) - weights = process(algo, params.weightingParams, u, WeightingType(params.weightingParams)) +function (params::SinglePatchHandsFreeReconstructionParameter)(algo::SinglePatchReconstructionAlgorithm, u) + weights = params.weightingParams(algo, u, WeightingType(params.weightingParams)) B = getLinearOperator(algo, params) @@ -29,7 +29,7 @@ function process(algo::SinglePatchReconstructionAlgorithm, params::SinglePatchHa snr = real(eltype(algo.S)).(vec(MPIFiles.getCalibSNR(algo.sf)[algo.freqs, 1])) - result = process(algo, solver, u, snr) + result = solver(algo, u, snr) return gridresult(result, algo.grid, algo.sf) end @@ -39,5 +39,5 @@ function getLinearOperator(algo::SinglePatchReconstructionAlgorithm, params::Sin end function getLinearOperator(algo::SinglePatchReconstructionAlgorithm, params::SinglePatchHandsFreeReconstructionParameter{<:SparseSystemMatrixLoadingParameter}) - return process(algo, params.sfLoad, eltype(algo.S), algo.arrayType, tuple(shape(algo.grid)...)) + return params.sfLoad(algo, eltype(algo.S), algo.arrayType, tuple(shape(algo.grid)...)) end \ No newline at end of file diff --git a/src/Algorithms/LowLevelAlgorithm.jl b/src/Algorithms/LowLevelAlgorithm.jl index d07c5e8..da9bb22 100644 --- a/src/Algorithms/LowLevelAlgorithm.jl +++ b/src/Algorithms/LowLevelAlgorithm.jl @@ -1,17 +1,5 @@ export LowLevelReconstructionAlgorithm -Base.@kwdef struct LowLevelReconstructionAlgorithm{P <: LeastSquaresParameters} <: AbstractMPIRecoAlgorithm - params::P - output::Channel{Any} - LowLevelReconstructionAlgorithm(params::P) where P = new{P}(params, Channel{Any}(Inf)) -end -recoAlgorithmTypes(::Type{LowLevelReconstructionAlgorithm}) = SystemMatrixBasedAlgorithm() -AbstractImageReconstruction.parameter(algo::LowLevelReconstructionAlgorithm) = algo.params -Base.lock(algo::LowLevelReconstructionAlgorithm) = lock(algo.output) -Base.unlock(algo::LowLevelReconstructionAlgorithm) = unlock(algo.output) -Base.isready(algo::LowLevelReconstructionAlgorithm) = isready(algo.output) -Base.wait(algo::LowLevelReconstructionAlgorithm) = wait(algo.output) -AbstractImageReconstruction.take!(algo::LowLevelReconstructionAlgorithm) = Base.take!(algo.output) - -function AbstractImageReconstruction.put!(algo::LowLevelReconstructionAlgorithm, u::AbstractArray) - put!(algo.output, process(algo, algo.params, u)) +@reconstruction struct LowLevelReconstructionAlgorithm{P <: LeastSquaresParameters} <: AbstractMPIRecoAlgorithm + @parameter params::P end +recoAlgorithmTypes(::Type{LowLevelReconstructionAlgorithm}) = SystemMatrixBasedAlgorithm() \ No newline at end of file diff --git a/src/Algorithms/MultiPatchAlgorithms/MultiPatchAlgorithm.jl b/src/Algorithms/MultiPatchAlgorithms/MultiPatchAlgorithm.jl index 214b237..d7c0334 100644 --- a/src/Algorithms/MultiPatchAlgorithms/MultiPatchAlgorithm.jl +++ b/src/Algorithms/MultiPatchAlgorithms/MultiPatchAlgorithm.jl @@ -1,5 +1,5 @@ export MultiPatchReconstructionAlgorithm, MultiPatchReconstructionParameter -Base.@kwdef struct MultiPatchReconstructionParameter{arrT <: AbstractArray,F<:AbstractFrequencyFilterParameter,O<:AbstractMultiPatchOperatorParameter, S<:AbstractSolverParameters, FF<:AbstractFocusFieldPositions, FFSF<:AbstractFocusFieldPositions, R <: AbstractRegularization, W<:AbstractWeightingParameters} <: AbstractMultiPatchReconstructionParameters +@parameter struct MultiPatchReconstructionParameter{arrT <: AbstractArray,F<:AbstractFrequencyFilterParameter,O<:AbstractMultiPatchOperatorParameter, S<:AbstractSolverParameters, FF<:AbstractFocusFieldPositions, FFSF<:AbstractFocusFieldPositions, R <: AbstractRegularization, W<:AbstractWeightingParameters} <: AbstractMultiPatchReconstructionParameters arrayType::Type{arrT} = Array # File sf::MultiMPIFile @@ -12,8 +12,8 @@ Base.@kwdef struct MultiPatchReconstructionParameter{arrT <: AbstractArray,F<:Ab weightingParams::Union{W, AbstractUtilityReconstructionParameters{W}} = NoWeightingParameters() end -Base.@kwdef mutable struct MultiPatchReconstructionAlgorithm{P, arrT <: AbstractArray, vecT <: AbstractArray} <: AbstractMultiPatchReconstructionAlgorithm where {P<:AbstractMultiPatchAlgorithmParameters} - params::P +@reconstruction constructor = false mutable struct MultiPatchReconstructionAlgorithm{P <: AbstractMultiPatchAlgorithmParameters, arrT <: AbstractArray, vecT <: AbstractArray} <: AbstractMultiPatchReconstructionAlgorithm + @parameter params::P # Could also do reconstruction progress meter here opParams::Union{AbstractMultiPatchOperatorParameter, AbstractUtilityReconstructionParameters{<:AbstractMultiPatchOperatorParameter},Nothing} = nothing sf::MultiMPIFile @@ -23,7 +23,6 @@ Base.@kwdef mutable struct MultiPatchReconstructionAlgorithm{P, arrT <: Abstract ffPos::Union{Nothing,AbstractArray} ffPosSF::Union{Nothing,AbstractArray} freqs::Vector{CartesianIndex{2}} - output::Channel{Any} end function MultiPatchReconstruction(params::MultiPatchParameters{<:AbstractMPIPreProcessingParameters,R,PT}) where {R<:AbstractMultiPatchReconstructionParameters,PT<:AbstractMPIPostProcessingParameters} @@ -31,7 +30,7 @@ function MultiPatchReconstruction(params::MultiPatchParameters{<:AbstractMPIPreP end function MultiPatchReconstructionAlgorithm(params::MultiPatchParameters{<:AbstractMPIPreProcessingParameters,<:MultiPatchReconstructionParameter,<:AbstractMPIPostProcessingParameters}) reco = params.reco - freqs = process(MultiPatchReconstructionAlgorithm, reco.freqFilter, reco.sf) + freqs = reco.freqFilter(MultiPatchReconstructionAlgorithm, reco.sf) # Prepare operator construction ffPos_ = positions(reco.ffPos) @@ -41,24 +40,14 @@ function MultiPatchReconstructionAlgorithm(params::MultiPatchParameters{<:Abstra ffPosSF = [vec(ffPos(SF))[l] for l=1:L, SF in reco.sf] end - return MultiPatchReconstructionAlgorithm{typeof(params), reco.arrayType, typeof(reco.arrayType{Float32}(undef, 0))}(params, reco.opParams, reco.sf, nothing, reco.arrayType, nothing, ffPos_, ffPosSF, freqs, Channel{Any}(Inf)) + return MultiPatchReconstructionAlgorithm{typeof(params), reco.arrayType, typeof(reco.arrayType{Float32}(undef, 0))}(params, reco.opParams, reco.sf, nothing, reco.arrayType, nothing, ffPos_, ffPosSF, freqs, @reconstruction_internals MultiPatchReconstructionAlgorithm) end recoAlgorithmTypes(::Type{MultiPatchReconstruction}) = SystemMatrixBasedAlgorithm() -AbstractImageReconstruction.parameter(algo::MultiPatchReconstructionAlgorithm) = algo.origParam -Base.lock(algo::MultiPatchReconstructionAlgorithm) = lock(algo.output) -Base.unlock(algo::MultiPatchReconstructionAlgorithm) = unlock(algo.output) -Base.isready(algo::MultiPatchReconstructionAlgorithm) = isready(algo.output) -Base.wait(algo::MultiPatchReconstructionAlgorithm) = wait(algo.output) -AbstractImageReconstruction.take!(algo::MultiPatchReconstructionAlgorithm) = Base.take!(algo.output) - -function AbstractImageReconstruction.put!(algo::MultiPatchReconstructionAlgorithm, data::MPIFile) - lock(algo) do - #consistenceCheck(algo.sf, data) - - algo.ffOp, algo.weights = process(algo, algo.opParams, data, algo.freqs, algo.params.reco.weightingParams) +function (params::MultiPatchParameters)(algo::MultiPatchReconstructionAlgorithm, data::MPIFile) + algo.ffOp, algo.weights = algo.opParams(algo, data, algo.freqs, algo.params.reco.weightingParams) - result = process(algo, algo.params, data, algo.freqs) + result = params(algo, data, algo.freqs) # Create Image (maybe image parameter as post params?) # TODO make more generic to apply to other pre/reco params as well (pre.numAverage main issue atm) @@ -67,12 +56,10 @@ function AbstractImageReconstruction.put!(algo::MultiPatchReconstructionAlgorith dt = acqNumAverages(data) * dfCycle(data) * numAverages(algo.params.pre) * 1u"s" im = makeAxisArray(result, pixspacing, offset, dt) result = ImageMeta(im, generateHeaderDict(algo.sf, data)) - - Base.put!(algo.output, result) - end + return result end -function process(algo::MultiPatchReconstructionAlgorithm, params::Union{OP, ProcessResultCache{OP}}, f::MPIFile, frequencies::Vector{CartesianIndex{2}}, weightingParams) where OP <: AbstractMultiPatchOperatorParameter +function (params::Union{OP, ProcessResultCache{OP}})(algo::MultiPatchReconstructionAlgorithm, f::MPIFile, frequencies::Vector{CartesianIndex{2}}, weightingParams) where OP <: AbstractMultiPatchOperatorParameter ffPos_ = ffPos(f) periodsSortedbyFFPos = unflattenOffsetFieldShift(ffPos_) idxFirstPeriod = getindex.(periodsSortedbyFFPos,1) @@ -83,22 +70,22 @@ function process(algo::MultiPatchReconstructionAlgorithm, params::Union{OP, Proc ffPos_[:] = algo.ffPos end - result = process(typeof(algo), params, algo.sf, frequencies, gradient, ffPos_, algo.ffPosSF) + result = params(typeof(algo), algo.sf, frequencies, gradient, ffPos_, algo.ffPosSF) # Kinda of hacky. MultiPatch parameters don't map nicely to the SinglePatch inspired pre, reco, post structure # Have to create weights before ffop is (potentially) moved to GPU, as GPU arrays don't have efficient hash implementations # Which makes this process expensive to cache - weights = process(typeof(algo), weightingParams, frequencies, result, nothing, algo.arrayType) - resultXPU = process(typeof(algo), params, result, algo.arrayType) + weights = weightingParams(typeof(algo), frequencies, result, nothing, algo.arrayType) + resultXPU = params(typeof(algo), result, algo.arrayType) return resultXPU, weights end -function process(algo::MultiPatchReconstructionAlgorithm, params::Union{A, ProcessResultCache{<:A}}, f::MPIFile, args...) where A <: AbstractMPIPreProcessingParameters - result = process(typeof(algo), params, f, args...) +function (params::Union{A, ProcessResultCache{<:A}})(algo::MultiPatchReconstructionAlgorithm, f::MPIFile, args...) where A <: AbstractMPIPreProcessingParameters + result = params(typeof(algo), f, args...) result = adapt(algo.arrayType, result) return result end -function process(t::Type{<:MultiPatchReconstructionAlgorithm}, params::CommonPreProcessingParameters{NoBackgroundCorrectionParameters}, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) +function (params::CommonPreProcessingParameters{NoBackgroundCorrectionParameters})(t::Type{<:MultiPatchReconstructionAlgorithm}, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) kwargs = toKwargs(params, default = Dict{Symbol, Any}(:frames => params.neglectBGFrames ? (1:acqNumFGFrames(f)) : (1:acqNumFrames(f))), ignore = [:neglectBGFrames, :bgCorrection]) result = getMeasurementsFD(f, bgCorrection = false; kwargs..., frequencies = frequencies) periodsSortedbyFFPos = unflattenOffsetFieldShift(ffPos(f)) @@ -109,18 +96,18 @@ function process(t::Type{<:MultiPatchReconstructionAlgorithm}, params::CommonPre return uTotal end -function process(t::Type{<:MultiPatchReconstructionAlgorithm}, params::CommonPreProcessingParameters{SimpleExternalBackgroundCorrectionParameters}, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) +function (params::CommonPreProcessingParameters{SimpleExternalBackgroundCorrectionParameters})(t::Type{<:MultiPatchReconstructionAlgorithm}, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) # Foreground, ignore BGCorrection to reuse preprocessing fgParams = CommonPreProcessingParameters(;toKwargs(params)..., bgParams = NoBackgroundCorrectionParameters()) - result = process(t, fgParams, f, frequencies) + result = fgParams(t, f, frequencies) # Background kwargs = toKwargs(params, ignore = [:neglectBGFrames, :bgCorrection], default = Dict{Symbol, Any}(:frames => params.neglectBGFrames ? (1:acqNumFGFrames(f)) : (1:acqNumFrames(f)))) bgParams = fromKwargs(ExternalPreProcessedBackgroundCorrectionParameters; kwargs..., bgParams = params.bgParams) - return process(t, bgParams, result, frequencies) + return bgParams(t, result, frequencies) end -function process(::Type{<:MultiPatchReconstructionAlgorithm}, params::ExternalPreProcessedBackgroundCorrectionParameters{SimpleExternalBackgroundCorrectionParameters}, data::Array, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) +function (params::ExternalPreProcessedBackgroundCorrectionParameters{SimpleExternalBackgroundCorrectionParameters})(::Type{<:MultiPatchReconstructionAlgorithm}, data::Array, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) kwargs = toKwargs(params, overwrite = Dict{Symbol, Any}(:frames => params.bgParams.bgFrames), ignore = [:bgParams]) # TODO migrate with hardcoded params as in old code or reuse given preprocessing options? empty = getMeasurementsFD(params.bgParams.emptyMeas, false; bgCorrection = false, numAverages=1, kwargs..., frequencies = frequencies) @@ -132,20 +119,20 @@ function process(::Type{<:MultiPatchReconstructionAlgorithm}, params::ExternalPr return data end -function process(algo::MultiPatchReconstructionAlgorithm, params::MultiPatchReconstructionParameter, u::AbstractArray) - weights = process(algo, params.weightingParams, u, WeightingType(params.weightingParams)) +function (params::MultiPatchReconstructionParameter)(algo::MultiPatchReconstructionAlgorithm, u::AbstractArray) + weights = params.weightingParams(algo, u, WeightingType(params.weightingParams)) solver = LeastSquaresParameters(S = algo.ffOp, reg = params.reg, solverParams = params.solverParams, weights = weights) - result = process(algo, solver, u) + result = solver(algo, u) return gridresult(result, algo.ffOp.grid, algo.sf) end -function process(algo::MultiPatchReconstructionAlgorithm, params::Union{W, ProcessResultCache{W}}, u, ::MeasurementBasedWeighting) where W<:AbstractWeightingParameters - return process(typeof(algo), params, algo.freqs, algo.ffOp, u, algo.arrayType) +function (params::Union{W, ProcessResultCache{W}})(algo::MultiPatchReconstructionAlgorithm, u, ::MeasurementBasedWeighting) where W<:AbstractWeightingParameters + return params(typeof(algo), algo.freqs, algo.ffOp, u, algo.arrayType) end -function process(algo::MultiPatchReconstructionAlgorithm, params::Union{W, ProcessResultCache{W}}, u, ::SystemMatrixBasedWeighting) where W<:AbstractWeightingParameters +function (params::Union{W, ProcessResultCache{W}})(algo::MultiPatchReconstructionAlgorithm, u, ::SystemMatrixBasedWeighting) where W<:AbstractWeightingParameters return algo.weights end \ No newline at end of file diff --git a/src/Algorithms/MultiPatchAlgorithms/MultiPatchAlgorithms.jl b/src/Algorithms/MultiPatchAlgorithms/MultiPatchAlgorithms.jl index bca621e..ea3491e 100644 --- a/src/Algorithms/MultiPatchAlgorithms/MultiPatchAlgorithms.jl +++ b/src/Algorithms/MultiPatchAlgorithms/MultiPatchAlgorithms.jl @@ -8,25 +8,19 @@ export AbstractFocusFieldPositions, DefaultFocusFieldPositions, CustomFocusField abstract type AbstractFocusFieldPositions <: AbstractMPIRecoParameters end struct DefaultFocusFieldPositions <: AbstractFocusFieldPositions end positions(ffPos::DefaultFocusFieldPositions) = nothing -Base.@kwdef struct CustomFocusFieldPositions{T<:AbstractArray} <: AbstractFocusFieldPositions +@parameter struct CustomFocusFieldPositions{T<:AbstractArray} <: AbstractFocusFieldPositions positions::T end positions(ffPos::CustomFocusFieldPositions) = ffPos.positions -Base.@kwdef mutable struct MultiPatchParameters{PR<:AbstractMPIPreProcessingParameters, +@chain mutable struct MultiPatchParameters{PR<:AbstractMPIPreProcessingParameters, R<:AbstractMultiPatchReconstructionParameters, PT<:AbstractMPIPostProcessingParameters} <: AbstractMultiPatchAlgorithmParameters pre::Union{PR, AbstractUtilityReconstructionParameters{PR}} reco::R post::PT = NoPostProcessing() end -function process(algo::T, params::MultiPatchParameters, data::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) where {T<:AbstractMultiPatchReconstructionAlgorithm} - result = process(algo, params.pre, data, frequencies) - result = process(algo, params.reco, result) - result = process(algo, params.post, result) - return result -end -function process(algo::T, params::MultiPatchParameters, data::AbstractArray, args...) where {T<:AbstractMultiPatchReconstructionAlgorithm} +function (params::MultiPatchParameters)(algo::T, data::AbstractArray, args...) where {T<:AbstractMultiPatchReconstructionAlgorithm} throw(ArgumentError("MultiPatchAlgorithms are not defined for the given arguments, expected <: MPIFile, found $(typeof(data))")) end diff --git a/src/Algorithms/MultiPatchAlgorithms/MultiPatchPeriodicMotion.jl b/src/Algorithms/MultiPatchAlgorithms/MultiPatchPeriodicMotion.jl index da3964b..9b06732 100644 --- a/src/Algorithms/MultiPatchAlgorithms/MultiPatchPeriodicMotion.jl +++ b/src/Algorithms/MultiPatchAlgorithms/MultiPatchPeriodicMotion.jl @@ -1,5 +1,5 @@ export PeriodicMotionPreProcessing, PeriodicMotionReconstructionParameter -Base.@kwdef struct PeriodicMotionPreProcessing{BG<:AbstractMPIBackgroundCorrectionParameters, W <: AbstractWeightingParameters} <: AbstractMPIPreProcessingParameters{BG} +@parameter struct PeriodicMotionPreProcessing{BG<:AbstractMPIBackgroundCorrectionParameters, W <: AbstractWeightingParameters} <: AbstractMPIPreProcessingParameters{BG} # Periodic Motion frames::Union{Nothing, UnitRange{Int64}, Vector{Int64}} = nothing alpha::Float64 = 3.0 @@ -13,7 +13,7 @@ Base.@kwdef struct PeriodicMotionPreProcessing{BG<:AbstractMPIBackgroundCorrecti weightingParams::Union{W, AbstractUtilityReconstructionParameters{W}} = NoWeightingParameters() end -Base.@kwdef struct PeriodicMotionReconstructionParameter{F<:AbstractFrequencyFilterParameter, S<:AbstractSolverParameters, R <: AbstractRegularization, arrT <: AbstractArray} <: AbstractMultiPatchReconstructionParameters +@parameter struct PeriodicMotionReconstructionParameter{F<:AbstractFrequencyFilterParameter, S<:AbstractSolverParameters, R <: AbstractRegularization, arrT <: AbstractArray} <: AbstractMultiPatchReconstructionParameters sf::MultiMPIFile freqFilter::F solverParams::S @@ -23,35 +23,31 @@ end function MultiPatchReconstructionAlgorithm(params::MultiPatchParameters{<:PeriodicMotionPreProcessing,<:PeriodicMotionReconstructionParameter,<:AbstractMPIPostProcessingParameters}) reco = params.reco - freqs = process(MultiPatchReconstructionAlgorithm, reco.freqFilter, reco.sf) + freqs = reco.freqFilter(MultiPatchReconstructionAlgorithm, reco.sf) return MultiPatchReconstructionAlgorithm{typeof(params), reco.arrayType, typeof(reco.arrayType{Float32}(undef, 0))}(params, nothing, reco.sf, nothing, reco.arrayType, nothing, nothing, nothing, freqs, Channel{Any}(Inf)) end -function AbstractImageReconstruction.put!(algo::MultiPatchReconstructionAlgorithm{MultiPatchParameters{PT, R, T}}, data::MPIFile) where {R, T, PT <: PeriodicMotionPreProcessing} - lock(algo) do - result = process(algo, algo.params, data, algo.freqs) - - # Create Image (maybe image parameter as post params?) - # TODO make more generic to apply to other pre/reco params as well (pre.numAverage main issue atm) - pixspacing = (voxelSize(algo.sf) ./ sfGradient(data,3) .* sfGradient(algo.sf,3)) * 1000u"mm" - offset = (fieldOfViewCenter(algo.ffOp.grid) .- 0.5.*fieldOfView(algo.ffOp.grid) .+ 0.5.*spacing(algo.ffOp.grid)) * 1000u"mm" - dt = acqNumAverages(data) * dfCycle(data) * 1 * 1u"s" # Motion has no averages - im = makeAxisArray(result, pixspacing, offset, dt) - result = ImageMeta(im, generateHeaderDict(algo.sf, data)) - - Base.put!(algo.output, result) - end +function (params::MultiPatchParameters{PT, R, T})(algo::MultiPatchReconstructionAlgorithm{P}, data::MPIFile) where {R, T, PT <: PeriodicMotionPreProcessing, P <: MultiPatchOperator{PT, R, T}} + result = params(algo, data, algo.freqs) + + # Create Image (maybe image parameter as post params?) + # TODO make more generic to apply to other pre/reco params as well (pre.numAverage main issue atm) + pixspacing = (voxelSize(algo.sf) ./ sfGradient(data,3) .* sfGradient(algo.sf,3)) * 1000u"mm" + offset = (fieldOfViewCenter(algo.ffOp.grid) .- 0.5.*fieldOfView(algo.ffOp.grid) .+ 0.5.*spacing(algo.ffOp.grid)) * 1000u"mm" + dt = acqNumAverages(data) * dfCycle(data) * 1 * 1u"s" # Motion has no averages + im = makeAxisArray(result, pixspacing, offset, dt) + result = ImageMeta(im, generateHeaderDict(algo.sf, data)) end -function process(algo::MultiPatchReconstructionAlgorithm, params::Union{OP, ProcessResultCache{OP}}, +function (params::Union{OP, ProcessResultCache{OP}})(algo::MultiPatchReconstructionAlgorithm, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) where OP <: PeriodicMotionPreProcessing - uReco, ffOp, weights = process(typeof(algo), params, f, algo.sf, frequencies) + uReco, ffOp, weights = params(typeof(algo), f, algo.sf, frequencies) algo.ffOp = adapt(algo.arrayType, ffOp) algo.weights = adapt(algo.arrayType, weights) return adapt(algo.arrayType, uReco) end -function process(algoT::Type{<:MultiPatchReconstructionAlgorithm}, params::PeriodicMotionPreProcessing{NoBackgroundCorrectionParameters}, +function (params::PeriodicMotionPreProcessing{NoBackgroundCorrectionParameters})(algoT::Type{<:MultiPatchReconstructionAlgorithm}, f::MPIFile, sf::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) @info "Loading Multi Patch motion operator" ffPos_ = ffPos(f) @@ -76,24 +72,24 @@ function process(algoT::Type{<:MultiPatchReconstructionAlgorithm}, params::Perio FFPos=ffPos_[:,resortedInd[:,1]], mapping=mapping, FFPosSF=ffPos_[:,resortedInd[:,1]], bgCorrection = false, tfCorrection = params.tfCorrection) - weights = process(algoT, params.weightingParams, frequencies, ffOp, nothing, Array) + weights = params.weightingParams(algoT, frequencies, ffOp, nothing, Array) return uReco, ffOp, weights end -function process(algoT::Type{<:MultiPatchReconstructionAlgorithm}, - params::PeriodicMotionPreProcessing{SimpleExternalBackgroundCorrectionParameters}, f::MPIFile, sf::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) +function (params::PeriodicMotionPreProcessing{SimpleExternalBackgroundCorrectionParameters})(algoT::Type{<:MultiPatchReconstructionAlgorithm}, f::MPIFile, + sf::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) # Foreground fgParams = fromKwargs(PeriodicMotionPreProcessing; toKwargs(params)..., bgParams = NoBackgroundCorrectionParameters()) - result, ffOp, weights = process(algoT, fgParams, f, sf, frequencies) + result, ffOp, weights = fgParams(algoT, f, sf, frequencies) # Background bgParams = fromKwargs(ExternalPreProcessedBackgroundCorrectionParameters; toKwargs(params)..., bgParams = params.bgParams, spectralLeakageCorrection=true) - return process(algoT, bgParams, result, frequencies), ffOp, weights + return bgParams(algoT, result, frequencies), ffOp, weights end -function process(algo::MultiPatchReconstructionAlgorithm, params::PeriodicMotionReconstructionParameter, u::Array) +function (params::PeriodicMotionReconstructionParameter)(algo::MultiPatchReconstructionAlgorithm, u::Array) solver = LeastSquaresParameters(S = algo.ffOp, reg = params.reg, solverParams = params.solverParams, weights = algo.weights) - result = process(algo, solver, u) + result = solver(algo, u) return gridresult(result, algo.ffOp.grid, algo.sf) end \ No newline at end of file diff --git a/src/Algorithms/SinglePatchAlgorithms/SinglePatchAlgorithm.jl b/src/Algorithms/SinglePatchAlgorithms/SinglePatchAlgorithm.jl index 5668607..ae4ea22 100644 --- a/src/Algorithms/SinglePatchAlgorithms/SinglePatchAlgorithm.jl +++ b/src/Algorithms/SinglePatchAlgorithms/SinglePatchAlgorithm.jl @@ -1,4 +1,4 @@ -Base.@kwdef struct SinglePatchReconstructionParameter{L<:AbstractSystemMatrixLoadingParameter, SL<:AbstractLinearSolver, +@parameter struct SinglePatchReconstructionParameter{L<:AbstractSystemMatrixLoadingParameter, SL<:AbstractLinearSolver, arrT <: AbstractArray, SP<:AbstractSolverParameters{SL}, R<:AbstractRegularization, W<:AbstractWeightingParameters} <: AbstractSinglePatchReconstructionParameters # File sf::MPIFile @@ -10,8 +10,8 @@ Base.@kwdef struct SinglePatchReconstructionParameter{L<:AbstractSystemMatrixLoa weightingParams::Union{W, AbstractUtilityReconstructionParameters{W}} = NoWeightingParameters() end -Base.@kwdef mutable struct SinglePatchReconstructionAlgorithm{P, SM, arrT <: AbstractArray, vecT <: arrT} <: AbstractSinglePatchReconstructionAlgorithm where {P<:AbstractSinglePatchAlgorithmParameters} - params::P +@reconstruction constructor = false mutable struct SinglePatchReconstructionAlgorithm{P <: AbstractSinglePatchAlgorithmParameters, SM, arrT <: AbstractArray, vecT <: arrT} <: AbstractSinglePatchReconstructionAlgorithm + @parameter params::P # Could also do reconstruction progress meter here sf::Union{MPIFile, Vector{MPIFile}} S::SM @@ -19,7 +19,6 @@ Base.@kwdef mutable struct SinglePatchReconstructionAlgorithm{P, SM, arrT <: Abs arrayType::Type{arrT} grid::RegularGridPositions freqs::Vector{CartesianIndex{2}} - output::Channel{Any} end function SinglePatchReconstruction(params::SinglePatchParameters{<:AbstractMPIPreProcessingParameters, R, PT}) where {R<:AbstractSinglePatchReconstructionParameters, PT <:AbstractMPIPostProcessingParameters} @@ -28,28 +27,25 @@ end function SinglePatchReconstructionAlgorithm(params::SinglePatchParameters{<:AbstractMPIPreProcessingParameters, R, PT}) where {R<:AbstractSinglePatchReconstructionParameters, PT <:AbstractMPIPostProcessingParameters} freqs, S, grid, arrayType = prepareSystemMatrix(params.reco) weights = prepareWeights(params.reco, freqs, S) - return SinglePatchReconstructionAlgorithm{typeof(params), typeof(S), arrayType, typeof(arrayType{real(eltype(S))}(undef, 0))}(params, params.reco.sf, S, weights, arrayType, grid, freqs, Channel{Any}(Inf)) + return SinglePatchReconstructionAlgorithm{typeof(params), typeof(S), arrayType, typeof(arrayType{real(eltype(S))}(undef, 0))}(params, params.reco.sf, S, weights, arrayType, grid, freqs, @reconstruction_internals SinglePatchReconstructionAlgorithm) end recoAlgorithmTypes(::Type{SinglePatchReconstruction}) = SystemMatrixBasedAlgorithm() -AbstractImageReconstruction.parameter(algo::SinglePatchReconstructionAlgorithm) = algo.params function prepareSystemMatrix(reco::SinglePatchReconstructionParameter{L,S}) where {L<:AbstractSystemMatrixLoadingParameter, S<:AbstractLinearSolver} - freqs, sf, grid = process(AbstractMPIRecoAlgorithm, reco.sfLoad, reco.sf, S, reco.arrayType) + freqs, sf, grid = reco.sfLoad(AbstractMPIRecoAlgorithm, reco.sf, S, reco.arrayType) return freqs, sf, grid, reco.arrayType end function prepareWeights(reco::SinglePatchReconstructionParameter{L,S,arrT,SP,R,W}, freqs, sf) where {L, S, arrT, SP, R, W<:AbstractWeightingParameters} - return process(AbstractMPIRecoAlgorithm, reco.weightingParams, freqs, sf, nothing, reco.arrayType) + return reco.weightingParams(AbstractMPIRecoAlgorithm, freqs, sf, nothing, reco.arrayType) end -Base.lock(algo::SinglePatchReconstructionAlgorithm) = lock(algo.output) -Base.unlock(algo::SinglePatchReconstructionAlgorithm) = unlock(algo.output) -Base.isready(algo::SinglePatchReconstructionAlgorithm) = isready(algo.output) -Base.wait(algo::SinglePatchReconstructionAlgorithm) = wait(algo.output) -AbstractImageReconstruction.take!(algo::SinglePatchReconstructionAlgorithm) = Base.take!(algo.output) +function (params::SinglePatchParameters)(algo::SinglePatchReconstructionAlgorithm, data::MPIFile) + return params(algo, data, algo.freqs) +end -function process(algo::SinglePatchReconstructionAlgorithm, params::Union{A, ProcessResultCache{<:A}}, f::MPIFile, args...) where A <: AbstractMPIPreProcessingParameters - result = process(typeof(algo), params, f, args...) +function (params::Union{A, ProcessResultCache{<:A}})(algo::SinglePatchReconstructionAlgorithm, f::MPIFile, args...) where A <: AbstractMPIPreProcessingParameters + result = params(typeof(algo), f, args...) if eltype(algo.S) != eltype(result) @warn "System matrix and measurement have different element data type. Mapping measurment data to system matrix element type." result = map(eltype(algo.S),result) @@ -59,24 +55,24 @@ function process(algo::SinglePatchReconstructionAlgorithm, params::Union{A, Proc end -function process(algo::SinglePatchReconstructionAlgorithm, params::SinglePatchReconstructionParameter, u) - weights = process(algo, params.weightingParams, u, WeightingType(params.weightingParams)) +function (params::SinglePatchReconstructionParameter)(algo::SinglePatchReconstructionAlgorithm, u) + weights = params.weightingParams(algo, u, WeightingType(params.weightingParams)) B = getLinearOperator(algo, params) solver = LeastSquaresParameters(op = B, S = algo.S, reg = params.reg, solverParams = params.solverParams, weights = weights) - result = process(algo, solver, u) + result = solver(algo, u) return gridresult(result, algo.grid, algo.sf) end -function process(algo::SinglePatchReconstructionAlgorithm, params::Union{W, ProcessResultCache{W}}, u, ::MeasurementBasedWeighting) where W<:AbstractWeightingParameters - return process(typeof(algo), params, algo.freqs, algo.S, u, algo.arrayType) +function (params::Union{W, ProcessResultCache{W}})(algo::SinglePatchReconstructionAlgorithm, u, ::MeasurementBasedWeighting) where W<:AbstractWeightingParameters + return params(typeof(algo), algo.freqs, algo.S, u, algo.arrayType) end -function process(algo::SinglePatchReconstructionAlgorithm, params::Union{W, ProcessResultCache{W}}, u, ::SystemMatrixBasedWeighting) where W<:AbstractWeightingParameters +function (params::Union{W, ProcessResultCache{W}})(algo::SinglePatchReconstructionAlgorithm, u, ::SystemMatrixBasedWeighting) where W<:AbstractWeightingParameters return algo.weights end @@ -85,5 +81,5 @@ function getLinearOperator(algo::SinglePatchReconstructionAlgorithm, params::Sin end function getLinearOperator(algo::SinglePatchReconstructionAlgorithm, params::SinglePatchReconstructionParameter{<:SparseSystemMatrixLoadingParameter}) - return process(algo, params.sfLoad, algo.sf, eltype(algo.S), algo.arrayType, tuple(shape(algo.grid)...)) + return params.sfLoad(algo, algo.sf, eltype(algo.S), algo.arrayType, tuple(shape(algo.grid)...)) end \ No newline at end of file diff --git a/src/Algorithms/SinglePatchAlgorithms/SinglePatchAlgorithms.jl b/src/Algorithms/SinglePatchAlgorithms/SinglePatchAlgorithms.jl index 3928b44..af15976 100644 --- a/src/Algorithms/SinglePatchAlgorithms/SinglePatchAlgorithms.jl +++ b/src/Algorithms/SinglePatchAlgorithms/SinglePatchAlgorithms.jl @@ -4,35 +4,24 @@ abstract type AbstractSinglePatchReconstructionAlgorithm <: AbstractMPIRecoAlgor abstract type AbstractSinglePatchReconstructionParameters <: AbstractMPIReconstructionParameters end abstract type AbstractSinglePatchAlgorithmParameters <: AbstractMPIRecoParameters end -Base.@kwdef mutable struct SinglePatchParameters{PR<:AbstractMPIPreProcessingParameters, +@parameter mutable struct SinglePatchParameters{PR<:AbstractMPIPreProcessingParameters, R<:AbstractSinglePatchReconstructionParameters, PT<:AbstractMPIPostProcessingParameters} <: AbstractSinglePatchAlgorithmParameters pre::Union{PR, AbstractUtilityReconstructionParameters{PR}} reco::R post::PT = NoPostProcessing() end -function process(algo::T, params::SinglePatchParameters, data::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) where {T<:AbstractSinglePatchReconstructionAlgorithm} - result = process(algo, params.pre, data, frequencies) - result = process(algo, params.reco, result) - result = process(algo, params.post, result) +function (params::SinglePatchParameters)(algo::T, data::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) where {T<:AbstractSinglePatchReconstructionAlgorithm} + result = params.pre(algo, data, frequencies) + result = params.reco(algo, result) + result = params.post(algo, result) + result = finalizeResult(algo, result, data) return result end -function process(algo::T, params::SinglePatchParameters, data::AbstractArray, args...) where {T<:AbstractSinglePatchReconstructionAlgorithm} +function (params::SinglePatchParameters)(algo::T, data::AbstractArray, args...) where {T<:AbstractSinglePatchReconstructionAlgorithm} throw(ArgumentError("SinglePatchAlgorithms are not defined for the given arguments, expected <: MPIFile, found $(typeof(data))")) end -function AbstractImageReconstruction.put!(algo::AbstractSinglePatchReconstructionAlgorithm, data) - lock(algo) do - #consistenceCheck(algo.sf, data) - - result = process(algo, algo.params, data, algo.freqs) - - result = finalizeResult(algo, result, data) - - Base.put!(algo.output, result) - end -end - function finalizeResult(algo::AbstractSinglePatchReconstructionAlgorithm, result, data::MPIFile) pixspacing, offset = calcSpacingAndOffset(algo.sf, data, algo.grid) dt = acqNumAverages(data)*dfCycle(data)*numAverages(algo.params.pre)*1u"s" @@ -54,14 +43,14 @@ include("SinglePatchBGEstimationAlgorithm.jl") consistenceCheck(sf::MPIFile, threaded::MultiThreadedInput) = consistenceCheck(sf, threaded.inputs[1]) finalizeResult(algo::AbstractSinglePatchReconstructionAlgorithm, result, threadedInput::MultiThreadedInput) = finalizeResult(algo, result, threadedInput.inputs[1]) -function process(algo::T, params::SinglePatchParameters, threadedInput::MultiThreadedInput, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) where {T<:AbstractSinglePatchReconstructionAlgorithm} - result = process(algo, params.pre, threadedInput, frequencies) - result = process(algo, params.reco, MultiThreadedInput(threadedInput.scheduler, (result,))) - result = process(algo, params.post, MultiThreadedInput(threadedInput.scheduler, (result,))) +function (params::SinglePatchParameters)(algo::T, threadedInput::MultiThreadedInput, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) where {T<:AbstractSinglePatchReconstructionAlgorithm} + result = params.pre(algo, threadedInput, frequencies) + result = params.reco(algo, MultiThreadedInput(threadedInput.scheduler, (result,))) + result = params.post(algo, MultiThreadedInput(threadedInput.scheduler, (result,))) return result end -function process(algo::T, params::P, threadInput::MultiThreadedInput, frequencies::Vector{CartesianIndex{2}}) where {T<:Union{SinglePatchReconstructionAlgorithm, SinglePatchBGEstimationAlgorithm}, P <: AbstractMPIPreProcessingParameters} +function (params::P)(algo::T, threadInput::MultiThreadedInput, frequencies::Vector{CartesianIndex{2}}) where {T<:Union{SinglePatchReconstructionAlgorithm, SinglePatchBGEstimationAlgorithm}, P <: AbstractMPIPreProcessingParameters} scheduler = threadInput.scheduler data = threadInput.inputs @@ -96,7 +85,7 @@ function process(algo::T, params::P, threadInput::MultiThreadedInput, frequencie return result end -function process(algo::T, params::LeastSquaresParameters, threadInput::MultiThreadedInput) where {T<:Union{SinglePatchReconstructionAlgorithm, SinglePatchBGEstimationAlgorithm}} +function (params::LeastSquaresParameters)(algo::T, threadInput::MultiThreadedInput) where {T<:Union{SinglePatchReconstructionAlgorithm, SinglePatchBGEstimationAlgorithm}} scheduler = threadInput.scheduler data = threadInput.inputs u = threadInput.inputs[1] @@ -123,5 +112,5 @@ function process(algo::T, params::LeastSquaresParameters, threadInput::MultiThre return result end -process(algo::T, params::NoPostProcessing, threadInput::MultiThreadedInput) where {T<:Union{SinglePatchReconstructionAlgorithm, SinglePatchBGEstimationAlgorithm}} = process(algo, params, threadInput.inputs...) +(params::NoPostProcessing)(algo::T, threadInput::MultiThreadedInput) where {T<:Union{SinglePatchReconstructionAlgorithm, SinglePatchBGEstimationAlgorithm}} = params(algo, threadInput.inputs...) =# \ No newline at end of file diff --git a/src/Algorithms/SinglePatchAlgorithms/SinglePatchBGEstimationAlgorithm.jl b/src/Algorithms/SinglePatchAlgorithms/SinglePatchBGEstimationAlgorithm.jl index a2040e5..bb1bcc6 100644 --- a/src/Algorithms/SinglePatchAlgorithms/SinglePatchBGEstimationAlgorithm.jl +++ b/src/Algorithms/SinglePatchAlgorithms/SinglePatchBGEstimationAlgorithm.jl @@ -1,5 +1,5 @@ export SinglePatchBGEstimationAlgorithm, SinglePatchBGEstimationReconstructionParameter -Base.@kwdef struct SinglePatchBGEstimationReconstructionParameter{L<:DenseSystemMatixLoadingParameter, +@parameter struct SinglePatchBGEstimationReconstructionParameter{L<:DenseSystemMatixLoadingParameter, SP<:AbstractSolverParameters, arrT <: AbstractArray} <: AbstractSinglePatchReconstructionParameters # File sf::MPIFile @@ -13,8 +13,8 @@ Base.@kwdef struct SinglePatchBGEstimationReconstructionParameter{L<:DenseSystem bgDict::BGDictParameter end -Base.@kwdef mutable struct SinglePatchBGEstimationAlgorithm{P, arrT <: AbstractArray} <: AbstractSinglePatchReconstructionAlgorithm where {P<:AbstractSinglePatchAlgorithmParameters} - params::P +@reconstruction constructor = false mutable struct SinglePatchBGEstimationAlgorithm{P <: AbstractSinglePatchAlgorithmParameters, arrT <: AbstractArray} <: AbstractSinglePatchReconstructionAlgorithm + @parameter params::P # Could also do reconstruction progress meter here sf::Union{MPIFile,Vector{MPIFile}} S::AbstractArray @@ -23,7 +23,6 @@ Base.@kwdef mutable struct SinglePatchBGEstimationAlgorithm{P, arrT <: AbstractA bgDict::AbstractArray grid::RegularGridPositions freqs::Vector{CartesianIndex{2}} - output::Channel{Any} end function SinglePatchReconstruction(params::SinglePatchParameters{<:AbstractMPIPreProcessingParameters,<:SinglePatchBGEstimationReconstructionParameter,PT}) where {PT<:AbstractMPIPostProcessingParameters} @@ -31,24 +30,17 @@ function SinglePatchReconstruction(params::SinglePatchParameters{<:AbstractMPIPr end function SinglePatchBGEstimationAlgorithm(params::SinglePatchParameters{<:AbstractMPIPreProcessingParameters,R,PT}) where {R<:SinglePatchBGEstimationReconstructionParameter,PT<:AbstractMPIPostProcessingParameters} freqs, S, grid, arrayType = prepareSystemMatrix(params.reco) - return SinglePatchBGEstimationAlgorithm(params, params.reco.sf, S, nothing, arrayType, process(SinglePatchBGEstimationAlgorithm, freqs, params.reco.bgDict), grid, freqs, Channel{Any}(Inf)) + return SinglePatchBGEstimationAlgorithm(params, params.reco.sf, S, nothing, arrayType, params.reco.bgDict(SinglePatchBGEstimationAlgorithm, freqs), grid, freqs, @reconstruction_internals SinglePatchBGEstimationAlgorithm) end recoAlgorithmTypes(::Type{SinglePatchBGEstimationAlgorithm}) = SystemMatrixBasedAlgorithm() -AbstractImageReconstruction.parameter(algo::SinglePatchBGEstimationAlgorithm) = algo.origParam function prepareSystemMatrix(reco::SinglePatchBGEstimationReconstructionParameter{L}) where {L<:AbstractSystemMatrixLoadingParameter} - freqs, sf, grid = process(AbstractMPIRecoAlgorithm, reco.sfLoad, reco.sf, Kaczmarz, reco.arrayType) + freqs, sf, grid = reco.sfLoad(AbstractMPIRecoAlgorithm, reco.sf, Kaczmarz, reco.arrayType) return freqs, sf, grid, reco.arrayType end -Base.lock(algo::SinglePatchBGEstimationAlgorithm) = lock(algo.output) -Base.unlock(algo::SinglePatchBGEstimationAlgorithm) = unlock(algo.output) -Base.isready(algo::SinglePatchBGEstimationAlgorithm) = isready(algo.output) -Base.wait(algo::SinglePatchBGEstimationAlgorithm) = wait(algo.output) -AbstractImageReconstruction.take!(algo::SinglePatchBGEstimationAlgorithm) = Base.take!(algo.output) - -function process(algo::SinglePatchBGEstimationAlgorithm, params::AbstractMPIPreProcessingParameters, f::MPIFile) - result = process(typeof(algo), params, f) +function (params::AbstractMPIPreProcessingParameters)(algo::SinglePatchBGEstimationAlgorithm, f::MPIFile) + result = params(typeof(algo), f) if eltype(algo.S) != eltype(result) @warn "System matrix and measurement have different element data type. Mapping measurment data to system matrix element type." result = map(eltype(algo.S), result) @@ -58,7 +50,7 @@ function process(algo::SinglePatchBGEstimationAlgorithm, params::AbstractMPIPreP end -function process(algo::SinglePatchBGEstimationAlgorithm, params::SinglePatchBGEstimationReconstructionParameter, u) +function (params::SinglePatchBGEstimationReconstructionParameter)(algo::SinglePatchBGEstimationAlgorithm, u) weights = nothing # getWeights(...) # Prepare Regularization @@ -77,7 +69,7 @@ function process(algo::SinglePatchBGEstimationAlgorithm, params::SinglePatchBGEs solver = LeastSquaresParameters(solver = Kaczmarz, S = G, reg = [reg], solverParams = solverParams) - temp = process(algo, solver, u) + temp = solver(algo, u) result = zeros(eltype(temp), N, size(temp, 2)) diff --git a/src/Algorithms/SinglePatchAlgorithms/SinglePatchTemporalRegularizationAlgorithm.jl b/src/Algorithms/SinglePatchAlgorithms/SinglePatchTemporalRegularizationAlgorithm.jl index 9d9f1db..fd92ef6 100644 --- a/src/Algorithms/SinglePatchAlgorithms/SinglePatchTemporalRegularizationAlgorithm.jl +++ b/src/Algorithms/SinglePatchAlgorithms/SinglePatchTemporalRegularizationAlgorithm.jl @@ -1,5 +1,5 @@ export SinglePatchTemporalRegularizationAlgorithm, SinglePatchTemporalRegularizationReconstructionParameter -Base.@kwdef struct SinglePatchTemporalRegularizationReconstructionParameter{L<:DenseSystemMatixLoadingParameter, +@parameter struct SinglePatchTemporalRegularizationReconstructionParameter{L<:DenseSystemMatixLoadingParameter, SP<:AbstractSolverParameters, arrT <: AbstractArray} <: AbstractSinglePatchReconstructionParameters # File sf::MPIFile @@ -15,8 +15,8 @@ Base.@kwdef struct SinglePatchTemporalRegularizationReconstructionParameter{L<:D bgDict::BGDictParameter end -Base.@kwdef mutable struct SinglePatchTemporalRegularizationAlgorithm{P, arrT <: AbstractArray} <: AbstractSinglePatchReconstructionAlgorithm where {P<:AbstractSinglePatchAlgorithmParameters} - params::P +@reconstruction constructor = false mutable struct SinglePatchTemporalRegularizationAlgorithm{P <: AbstractSinglePatchAlgorithmParameters, arrT <: AbstractArray} <: AbstractSinglePatchReconstructionAlgorithm + @parameter params::P sf::Union{MPIFile,Vector{MPIFile}} S::AbstractArray arrayType::Type{arrT} @@ -25,7 +25,6 @@ Base.@kwdef mutable struct SinglePatchTemporalRegularizationAlgorithm{P, arrT <: idxFG::Union{Nothing, UnitRange{Int64}, Vector{Int64}} = nothing grid::RegularGridPositions freqs::Vector{CartesianIndex{2}} - output::Channel{Any} end function SinglePatchReconstruction(params::SinglePatchParameters{<:AbstractMPIPreProcessingParameters,<:SinglePatchTemporalRegularizationReconstructionParameter,PT}) where {PT<:AbstractMPIPostProcessingParameters} @@ -33,25 +32,18 @@ function SinglePatchReconstruction(params::SinglePatchParameters{<:AbstractMPIPr end function SinglePatchTemporalRegularizationAlgorithm(params::SinglePatchParameters{<:AbstractMPIPreProcessingParameters,R,PT}) where {R<:SinglePatchTemporalRegularizationReconstructionParameter,PT<:AbstractMPIPostProcessingParameters} freqs, S, grid, arrayType = prepareSystemMatrix(params.reco) - return SinglePatchTemporalRegularizationAlgorithm(params, params.reco.sf, S, arrayType, process(SinglePatchTemporalRegularizationAlgorithm, params.reco.bgDict, freqs) - ,params.reco.idxFG, params.reco.idxBG, grid, freqs, Channel{Any}(Inf)) + return SinglePatchTemporalRegularizationAlgorithm(params, params.reco.sf, S, arrayType, params.reco.bgDict(SinglePatchTemporalRegularizationAlgorithm, freqs) + ,params.reco.idxFG, params.reco.idxBG, grid, freqs, @reconstruction_internals SinglePatchTemporalRegularizationAlgorithm) end recoAlgorithmTypes(::Type{SinglePatchTemporalRegularizationAlgorithm}) = SystemMatrixBasedAlgorithm() -AbstractImageReconstruction.parameter(algo::SinglePatchTemporalRegularizationAlgorithm) = algo.origParam function prepareSystemMatrix(reco::SinglePatchTemporalRegularizationReconstructionParameter{L}) where {L<:AbstractSystemMatrixLoadingParameter} - freqs, sf, grid = process(AbstractMPIRecoAlgorithm, reco.sfLoad, reco.sf, Kaczmarz, reco.arrayType) + freqs, sf, grid = reco.sfLoad(AbstractMPIRecoAlgorithm, reco.sf, Kaczmarz, reco.arrayType) return freqs, sf, grid, reco.arrayType end -Base.lock(algo::SinglePatchTemporalRegularizationAlgorithm) = lock(algo.output) -Base.unlock(algo::SinglePatchTemporalRegularizationAlgorithm) = unlock(algo.output) -Base.isready(algo::SinglePatchTemporalRegularizationAlgorithm) = isready(algo.output) -Base.wait(algo::SinglePatchTemporalRegularizationAlgorithm) = wait(algo.output) -AbstractImageReconstruction.take!(algo::SinglePatchTemporalRegularizationAlgorithm) = Base.take!(algo.output) - -function process(algo::SinglePatchTemporalRegularizationAlgorithm, params::AbstractMPIPreProcessingParameters, f::MPIFile) - result = process(typeof(algo), f, params) +function (params::AbstractMPIPreProcessingParameters)(algo::SinglePatchTemporalRegularizationAlgorithm, f::MPIFile) + result = params(typeof(algo), f) if eltype(algo.S) != eltype(result) @warn "System matrix and measurement have different element data type. Mapping measurment data to system matrix element type." result = map(eltype(algo.S), result) @@ -61,7 +53,7 @@ function process(algo::SinglePatchTemporalRegularizationAlgorithm, params::Abstr end -function process(algo::SinglePatchTemporalRegularizationAlgorithm, params::SinglePatchTemporalRegularizationReconstructionParameter, u::Array) +function (params::SinglePatchTemporalRegularizationReconstructionParameter)(algo::SinglePatchTemporalRegularizationAlgorithm, u::Array) weights = nothing # getWeights(...) L = size(u)[end] @@ -87,7 +79,7 @@ function process(algo::SinglePatchTemporalRegularizationAlgorithm, params::Singl solver = LeastSquaresParameters(solver = Kaczmarz, S = op, reg = [reg], solverParams = solverParams) - temp = process(algo, solver, u) + temp = solver(algo, u) temp = real.( reshape(temp[1:(NSub*J),:],NSub,J) ./ sqrt(λ) ) cInterp = similar(temp, size(c,1), op.L) diff --git a/src/Algorithms/SinglePatchAlgorithms/SinglePatchTwoStepReconstructionAlgorithm.jl b/src/Algorithms/SinglePatchAlgorithms/SinglePatchTwoStepReconstructionAlgorithm.jl index 70257ff..a9e16e1 100644 --- a/src/Algorithms/SinglePatchAlgorithms/SinglePatchTwoStepReconstructionAlgorithm.jl +++ b/src/Algorithms/SinglePatchAlgorithms/SinglePatchTwoStepReconstructionAlgorithm.jl @@ -1,5 +1,5 @@ export SinglePatchTwoStepReconstructionParameters, SinglePatchTwoStepReconstructionAlgorithm -Base.@kwdef struct SinglePatchTwoStepReconstructionParameters{L_H<:AbstractSystemMatrixLoadingParameter, L_L<:AbstractSystemMatrixLoadingParameter, S<:AbstractLinearSolver, SP_H<:AbstractSolverParameters, SP_L<:AbstractSolverParameters, R_H<:AbstractRegularization, R_L<:AbstractRegularization} <: AbstractSinglePatchReconstructionParameters +@parameter struct SinglePatchTwoStepReconstructionParameters{L_H<:AbstractSystemMatrixLoadingParameter, L_L<:AbstractSystemMatrixLoadingParameter, S<:AbstractLinearSolver, SP_H<:AbstractSolverParameters, SP_L<:AbstractSolverParameters, R_H<:AbstractRegularization, R_L<:AbstractRegularization} <: AbstractSinglePatchReconstructionParameters # Threshhold Γ::Float64 # File @@ -13,16 +13,15 @@ Base.@kwdef struct SinglePatchTwoStepReconstructionParameters{L_H<:AbstractSyste reg_high::Vector{R_H} = AbstractRegularization[] reg_low::Vector{R_L} = AbstractRegularization[] end -Base.@kwdef mutable struct SinglePatchTwoStepReconstructionAlgorithm{P} <: AbstractSinglePatchReconstructionAlgorithm where {P<:AbstractSinglePatchAlgorithmParameters} - params::P +@reconstruction constructor = false mutable struct SinglePatchTwoStepReconstructionAlgorithm{P<:AbstractSinglePatchAlgorithmParameters} <: AbstractSinglePatchReconstructionAlgorithm + @parameter params::P # Could also do reconstruction progress meter here algoHigh::SinglePatchReconstructionAlgorithm algoLow::SinglePatchReconstructionAlgorithm - output::Channel{Any} end # Bit hacky: Create transparent parameter to give to inner algorithm -Base.@kwdef mutable struct TwoStepSubstractionPreProcessingParameter{B, PR<:AbstractMPIPreProcessingParameters{B}} <: AbstractMPIPreProcessingParameters{B} +@parameter mutable struct TwoStepSubstractionPreProcessingParameter{B, PR<:AbstractMPIPreProcessingParameters{B}} <: AbstractMPIPreProcessingParameters{B} pre::PR proj::Array{ComplexF32} = zeros(ComplexF32, 0, 0) end @@ -51,14 +50,14 @@ function AbstractImageReconstruction.fromKwargs(type::Type{TwoStepSubstractionPr return type(;pre = inner, proj = proj) end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::TwoStepSubstractionPreProcessingParameter, args...) - meas = process(t, params.pre, args...) +function (params::TwoStepSubstractionPreProcessingParameter)(t::Type{<:AbstractMPIRecoAlgorithm}, args...) + meas = params.pre(t, args...) return meas .- params.proj end # Specify multi threaded variant, s.t. substraction happens on collected results -#function process(algo::T, params::TwoStepSubstractionPreProcessingParameter, threadedInput::MultiThreadedInput, frequencies::Vector{CartesianIndex{2}}) where T <: SinglePatchReconstructionAlgorithm -# meas = process(algo, params.pre, threadedInput, frequencies) +#function (params::TwoStepSubstractionPreProcessingParameter)(algo::T, threadedInput::MultiThreadedInput, frequencies::Vector{CartesianIndex{2}}) where T <: SinglePatchReconstructionAlgorithm +# meas = params.pre(algo, threadedInput, frequencies) # return meas .- params.proj #end @@ -74,40 +73,31 @@ function SinglePatchTwoStepReconstructionAlgorithm(params::SinglePatchParameters # Then construct "custom" SinglePatchAlgorithm paramsLow = SinglePatchParameters(TwoStepSubstractionPreProcessingParameter(;pre = algoLow.params.pre), algoLow.params.reco, algoLow.params.post) algoLow = SinglePatchReconstructionAlgorithm(paramsLow, params.reco.sf, algoLow.S, algoLow.grid, algoLow.freqs, algoLow.output) - return SinglePatchTwoStepReconstructionAlgorithm(params, algoHigh, algoLow, Channel{Any}(Inf)) + return SinglePatchTwoStepReconstructionAlgorithm(params, algoHigh, algoLow, @reconstruction_internals SinglePatchTwoStepReconstructionAlgorithm) end -AbstractImageReconstruction.parameter(algo::SinglePatchTwoStepReconstructionAlgorithm) = algo.params -AbstractImageReconstruction.take!(algo::SinglePatchTwoStepReconstructionAlgorithm) = Base.take!(algo.output) -function Base.put!(algo::SinglePatchTwoStepReconstructionAlgorithm, data) - lock(algo.output) do - # First reco - cPre = reconstruct(algo.algoHigh, data) - # Thresholding - thresh = maximum(abs.(cPre))*algo.params.reco.Γ - cThresh = map(x-> abs(x) < thresh ? 0.0 : x, cPre.data) +function (params::AbstractSinglePatchAlgorithmParameters)(algo::SinglePatchTwoStepReconstructionAlgorithm, data) + # First reco + cPre = reconstruct(algo.algoHigh, data) - # Projection into raw data space - uProj = zeros(ComplexF32, size(algo.algoLow.S, 1), 1, size(cThresh)[end]) - cMapped = map(ComplexF32, cThresh) - for frame = 1:size(uProj, 3) - uProj[:, 1, frame] = algo.algoLow.S*vec(cMapped[1, :, :, :, frame]) - end - - # Prepare subtraction - algo.algoLow.params.pre.proj = uProj + # Thresholding + thresh = maximum(abs.(cPre))*algo.params.reco.Γ + cThresh = map(x-> abs(x) < thresh ? 0.0 : x, cPre.data) + + # Projection into raw data space + uProj = zeros(ComplexF32, size(algo.algoLow.S, 1), 1, size(cThresh)[end]) + cMapped = map(ComplexF32, cThresh) + for frame = 1:size(uProj, 3) + uProj[:, 1, frame] = algo.algoLow.S*vec(cMapped[1, :, :, :, frame]) + end - # Second reconstruction - cPost = reconstruct(algo.algoLow, data) + # Prepare subtraction + algo.algoLow.params.pre.proj = uProj - # Addition - result = AxisArray(cPost.data + cThresh, cPost.data.axes) - result = ImageMeta(result, properties(cPost)) + # Second reconstruction + cPost = reconstruct(algo.algoLow, data) - Base.put!(algo.output, result) - end -end -Base.lock(algo::SinglePatchTwoStepReconstructionAlgorithm) = lock(algo.output) -Base.unlock(algo::SinglePatchTwoStepReconstructionAlgorithm) = unlock(algo.output) -Base.isready(algo::SinglePatchTwoStepReconstructionAlgorithm) = isready(algo.output) -Base.wait(algo::SinglePatchTwoStepReconstructionAlgorithm) = wait(algo.output) \ No newline at end of file + # Addition + result = AxisArray(cPost.data + cThresh, cPost.data.axes) + result = ImageMeta(result, properties(cPost)) +end \ No newline at end of file diff --git a/src/Background.jl b/src/Background.jl index bb72df9..8318f5c 100644 --- a/src/Background.jl +++ b/src/Background.jl @@ -4,14 +4,14 @@ export NoBackgroundCorrectionParameters struct NoBackgroundCorrectionParameters <: AbstractMPIBackgroundCorrectionParameters end export InternalBackgroundCorrectionParameters -Base.@kwdef struct InternalBackgroundCorrectionParameters <: AbstractMPIBackgroundCorrectionParameters +@parameter struct InternalBackgroundCorrectionParameters <: AbstractMPIBackgroundCorrectionParameters interpolateBG::Bool = false end export ExternalBackgroundCorrection abstract type ExternalBackgroundCorrection <: AbstractMPIBackgroundCorrectionParameters end -Base.@kwdef struct ExternalPreProcessedBackgroundCorrectionParameters{T} <: AbstractMPIBackgroundCorrectionParameters where {T<:ExternalBackgroundCorrection} +@parameter struct ExternalPreProcessedBackgroundCorrectionParameters{T} <: AbstractMPIBackgroundCorrectionParameters where {T<:ExternalBackgroundCorrection} numPeriodAverages::Int64 = 1 numPeriodGrouping::Int64 = 1 spectralLeakageCorrection::Bool = false @@ -22,16 +22,16 @@ end # TODO Shorter struct names? export SimpleExternalBackgroundCorrectionParameters -Base.@kwdef struct SimpleExternalBackgroundCorrectionParameters <: ExternalBackgroundCorrection +@parameter struct SimpleExternalBackgroundCorrectionParameters <: ExternalBackgroundCorrection emptyMeas::MPIFile bgFrames::Union{Vector{Int64}, UnitRange{Int64}} = [1] end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::SimpleExternalBackgroundCorrectionParameters, data::Array) +function (params::SimpleExternalBackgroundCorrectionParameters)(::Type{<:AbstractMPIRecoAlgorithm}, data::Array) kwargs = toKwargs(params, overwrite = Dict{Symbol, Any}(:frames => params.bgFrames)) empty = getMeasurementsFD(params.emptyMeas, false; bgCorrection = false, numAverages=length(bgFrames), kwargs...) return data .-empty end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::ExternalPreProcessedBackgroundCorrectionParameters{SimpleExternalBackgroundCorrectionParameters}, data::Array, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) +function (params::ExternalPreProcessedBackgroundCorrectionParameters{SimpleExternalBackgroundCorrectionParameters})(::Type{<:AbstractMPIRecoAlgorithm}, data::Array, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) kwargs = toKwargs(params, default = Dict{Symbol, Any}(:tfCorrection => rxHasTransferFunction(params.bgParams.emptyMeas)), overwrite = Dict{Symbol, Any}(:frames => params.bgParams.bgFrames), ignore = [:bgParams]) empty = getMeasurementsFD(params.bgParams.emptyMeas, false; bgCorrection = false, numAverages=length(params.bgParams.bgFrames), kwargs..., frequencies = frequencies) @@ -39,12 +39,12 @@ function process(::Type{<:AbstractMPIRecoAlgorithm}, params::ExternalPreProcesse end export LinearInterpolatedExternalBackgroundCorrectionParameters -Base.@kwdef struct LinearInterpolatedExternalBackgroundCorrectionParameters <: AbstractMPIBackgroundCorrectionParameters +@parameter struct LinearInterpolatedExternalBackgroundCorrectionParameters <: AbstractMPIBackgroundCorrectionParameters emptyMeas::MPIFile bgFrames::UnitRange{Int64} = 1:1 bgFramesPost::UnitRange{Int64} = 1:1 end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::LinearInterpolatedExternalBackgroundCorrectionParameters, data::Array) +function (params::LinearInterpolatedExternalBackgroundCorrectionParameters)(::Type{<:AbstractMPIRecoAlgorithm}, data::Array) kwargs = toKwargs(params) kwargs[:frames] = params.bgFrames empty = getMeasurementsFD(bgParams.emptyMeas, false; bgCorrection = false, numAverages=length(params.bgFrames), kwargs...) @@ -56,7 +56,7 @@ function process(::Type{<:AbstractMPIRecoAlgorithm}, params::LinearInterpolatedE end return result end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::ExternalPreProcessedBackgroundCorrectionParameters{LinearInterpolatedExternalBackgroundCorrectionParameters}, data::Array, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) +function (params::ExternalPreProcessedBackgroundCorrectionParameters{LinearInterpolatedExternalBackgroundCorrectionParameters})(::Type{<:AbstractMPIRecoAlgorithm}, data::Array, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) bgParams = params.bgParams kwargs = toKwargs(params, default = Dict{Symbol, Any}(:tfCorrection => rxHasTransferFunction(bgParams.emptyMeas)), ignore = [:bgParams]) kwargs[:frames] = bgParams.bgFrames @@ -73,22 +73,22 @@ end export AbstractBGDictLoader abstract type AbstractBGDictLoader <: AbstractMPIRecoParameters end export MeasurementBGDictLoader -Base.@kwdef struct MeasurementBGDictLoader{T} <: AbstractBGDictLoader where {T<:MPIFile} +@parameter struct MeasurementBGDictLoader{T} <: AbstractBGDictLoader where {T<:MPIFile} file::T bgFrames::Union{UnitRange{Int64}, Vector{Int64}} = measBGFrameIdx(file) numPeriodGrouping::Int64 = acqNumPeriodsPerFrame(file) numPeriodAverages::Int64 = 1 bgAverages::Int64 = 1 end -function process(algoT::Type{<:AbstractMPIRecoAlgorithm}, params::MeasurementBGDictLoader, freqs::Vector{CartesianIndex{2}}) +function (params::MeasurementBGDictLoader)(algoT::Type{<:AbstractMPIRecoAlgorithm}, freqs::Vector{CartesianIndex{2}}) uEmpty = getMeasurementsFD(params.file, false, frequencies=freqs, frames=params.bgFrames, numAverages=params.bgAverages, spectralLeakageCorrection=false, bgCorrection=false, numPeriodGrouping = params.numPeriodGrouping, numPeriodAverages = params.numPeriodAverages) return transpose(reshape(uEmpty, :, div(length(params.bgFrames),params.bgAverages))) end export SystemMatrixBGDictLoader -Base.@kwdef struct SystemMatrixBGDictLoader{T} <: AbstractBGDictLoader where {T<:MPIFile} +@parameter struct SystemMatrixBGDictLoader{T} <: AbstractBGDictLoader where {T<:MPIFile} file::T end -function process(algoT::Type{<:AbstractMPIRecoAlgorithm}, params::SystemMatrixBGDictLoader, freqs::Vector{CartesianIndex{2}}) +function (params::SystemMatrixBGDictLoader)(algoT::Type{<:AbstractMPIRecoAlgorithm}, freqs::Vector{CartesianIndex{2}}) idxBGFrames = measBGFrameIdx(params.file) D = measData(params.file, idxBGFrames) D_ = reshape(D, size(D,1), size(D,2), size(D,3), size(D,4)) @@ -115,23 +115,23 @@ function getBackgroundDictionaryComplete(fSF::MPIFile, f::MPIFile, frequencies, end export BGDictParameter -Base.@kwdef struct BGDictParameter <: AbstractMPIRecoParameters +@parameter struct BGDictParameter <: AbstractMPIRecoParameters loader::Vector{AbstractBGDictLoader} dictSize::Int64 = 2 end -function process(algoT::Type{<:AbstractMPIRecoAlgorithm}, params::BGDictParameter, freqs) - U,S,V = process(algoT, freqs, params.loader) +function (params::BGDictParameter)(algoT::Type{<:AbstractMPIRecoAlgorithm}, freqs) + U,S,V = params.loader(algoT, freqs) for l=1:params.dictSize U[:,l] *= (S[l] / S[1])^(1/2) end return U[:,1:params.dictSize] end -function process(algoT::Type{<:AbstractMPIRecoAlgorithm}, loader::Vector{T}, freqs) where {T<:AbstractBGDictLoader} +function (loader::Vector{T})(algoT::Type{<:AbstractMPIRecoAlgorithm}, freqs) where {T<:AbstractBGDictLoader} tempBGs = [] for load in loader - push!(tempBGs, process(algoT, freqs, load)) + push!(tempBGs, load(algoT, freqs)) end return svd(transpose(cat(tempBGs..., dims=1))) end diff --git a/src/LeastSquares.jl b/src/LeastSquares.jl index 5f8b64b..d8e5b96 100644 --- a/src/LeastSquares.jl +++ b/src/LeastSquares.jl @@ -3,7 +3,7 @@ export LeastSquaresParameters abstract type AbstractSolverParameters{AbstractLinearSolver} <: AbstractMPIRecoParameters end export LeastSquaresParameters -Base.@kwdef struct LeastSquaresParameters{L<:AbstractLinearSolver, O, M, R<:AbstractRegularization, P<:AbstractSolverParameters{L}, W} <: AbstractMPIRecoParameters +@parameter struct LeastSquaresParameters{L<:AbstractLinearSolver, O, M, R<:AbstractRegularization, P<:AbstractSolverParameters{L}, W} <: AbstractMPIRecoParameters op::O = nothing S::M reg::Vector{R} @@ -14,19 +14,19 @@ end # TODO place weights and more export SimpleSolverParameters -Base.@kwdef struct SimpleSolverParameters <: AbstractSolverParameters{Kaczmarz} +@parameter struct SimpleSolverParameters <: AbstractSolverParameters{Kaczmarz} iterations::Int64=10 enforceReal::Bool=true enforcePositive::Bool=true normalizeReg::AbstractRegularizationNormalization = SystemMatrixBasedNormalization() end export ConstraintMaskedSolverParameters -Base.@kwdef struct ConstraintMaskedSolverParameters{S, P<:AbstractSolverParameters{S}} <: AbstractSolverParameters{S} +@parameter struct ConstraintMaskedSolverParameters{S, P<:AbstractSolverParameters{S}} <: AbstractSolverParameters{S} constraintMask::Vector{Bool} params::P end export ElaborateSolverParameters -Base.@kwdef mutable struct ElaborateSolverParameters{SL} <: AbstractSolverParameters{SL} +@parameter mutable struct ElaborateSolverParameters{SL} <: AbstractSolverParameters{SL} solver::Type{SL} = Kaczmarz iterations::Int64 = 10 enforceReal::Bool = true @@ -56,7 +56,7 @@ Base.propertynames(params::RecoPlan{ElaborateSolverParameters}) = union([:solver getSolverKwargs(::Type{SL}) where SL <: AbstractLinearSolver = intersect(union(Base.kwarg_decl.(methods(SL))...), fieldnames(ElaborateSolverParameters)) -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::LeastSquaresParameters{SL}, u::AbstractArray) where SL +function (params::LeastSquaresParameters{SL})(t::Type{<:AbstractMPIRecoAlgorithm}, u::AbstractArray) where SL N = size(params.S, 2) M = div(length(params.S), N) @@ -129,7 +129,7 @@ function prepareRegularization(reg::Vector{R}, regLS::LeastSquaresParameters) wh return result, callbacks, args end #= -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::LeastSquaresParameters, threadInput::MultiThreadedInput) +function (params::LeastSquaresParameters)(t::Type{<:AbstractMPIRecoAlgorithm}, threadInput::MultiThreadedInput) scheduler = threadInput.scheduler data = threadInput.inputs diff --git a/src/MPIReco.jl b/src/MPIReco.jl index aea6cc6..282e003 100644 --- a/src/MPIReco.jl +++ b/src/MPIReco.jl @@ -7,6 +7,7 @@ module MPIReco const shape = MPIFiles.shape @reexport using AbstractImageReconstruction using AbstractImageReconstruction.AbstractTrees + using AbstractImageReconstruction.StructUtils using LRUCache using Adapt @reexport using DSP diff --git a/src/MultiPatch.jl b/src/MultiPatch.jl index 5992754..733bb0c 100644 --- a/src/MultiPatch.jl +++ b/src/MultiPatch.jl @@ -181,11 +181,11 @@ function MultiPatchOperatorHighLevel(bSF::MultiMPIFile, bMeas, freq, bgCorrectio return FFOp end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::AbstractMultiPatchOperatorParameter, bSF::MultiMPIFile, freq, gradient, FFPos, FFPosSF) +function (params::AbstractMultiPatchOperatorParameter)(::Type{<:AbstractMPIRecoAlgorithm}, bSF::MultiMPIFile, freq, gradient, FFPos, FFPosSF) @info "Loading Multi Patch operator" return MultiPatchOperator(bSF, freq; toKwargs(params)..., FFPos = FFPos, FFPosSF = FFPosSF, gradient = gradient) end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::AbstractMultiPatchOperatorParameter, op::AbstractMultiPatchOperator, arrayType::Type{<:AbstractArray}) +function (params::AbstractMultiPatchOperatorParameter)(::Type{<:AbstractMPIRecoAlgorithm}, op::AbstractMultiPatchOperator, arrayType::Type{<:AbstractArray}) return adapt(arrayType, op) end @@ -229,7 +229,7 @@ Thus, the mapping is automatically set to $mapping." end export ExplicitMultiPatchParameter -Base.@kwdef struct ExplicitMultiPatchParameter <: AbstractMultiPatchOperatorParameter +@parameter struct ExplicitMultiPatchParameter <: AbstractMultiPatchOperatorParameter bgCorrection::Bool = false tfCorrection::Bool = true SFGridCenter::AbstractArray = zeros(0,0) @@ -354,7 +354,7 @@ function MultiPatchOperatorExpliciteMapping(SFs::MultiMPIFile, freq; bgCorrectio end export RegularMultiPatchOperatorParameter -Base.@kwdef struct RegularMultiPatchOperatorParameter <: AbstractMultiPatchOperatorParameter +@parameter struct RegularMultiPatchOperatorParameter <: AbstractMultiPatchOperatorParameter bgCorrection::Bool = false denoiseWeight::Float64=0.0 roundPatches::Bool = false diff --git a/src/PreProcessing/CommonPreProcessing.jl b/src/PreProcessing/CommonPreProcessing.jl index 58633b3..a6612f3 100644 --- a/src/PreProcessing/CommonPreProcessing.jl +++ b/src/PreProcessing/CommonPreProcessing.jl @@ -5,7 +5,7 @@ export CommonPreProcessingParameters """ Parameters for retrieving MPI measurement data in frequency domain """ -Base.@kwdef struct CommonPreProcessingParameters{T<:AbstractMPIBackgroundCorrectionParameters} <: AbstractMPIPreProcessingParameters{T} +@parameter struct CommonPreProcessingParameters{T<:AbstractMPIBackgroundCorrectionParameters} <: AbstractMPIPreProcessingParameters{T} "Type of background correction" bgParams::T = NoBackgroundCorrectionParameters() "Frames to be retrieved from the data" @@ -26,24 +26,24 @@ Base.@kwdef struct CommonPreProcessingParameters{T<:AbstractMPIBackgroundCorrect loadasreal::Bool = false end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::CommonPreProcessingParameters{NoBackgroundCorrectionParameters}, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) +function (params::CommonPreProcessingParameters{NoBackgroundCorrectionParameters})(t::Type{<:AbstractMPIRecoAlgorithm}, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) kwargs = toKwargs(params, default = Dict{Symbol, Any}(:tfCorrection => rxHasTransferFunction(f), :frames => params.neglectBGFrames ? (1:acqNumFGFrames(f)) : (1:acqNumFrames(f))), ignore = [:neglectBGFrames, :bgParams]) result = getMeasurementsFD(f; bgCorrection = false, kwargs..., frequencies = frequencies) return result end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::CommonPreProcessingParameters{InternalBackgroundCorrectionParameters}, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) +function (params::CommonPreProcessingParameters{InternalBackgroundCorrectionParameters})(t::Type{<:AbstractMPIRecoAlgorithm}, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) kwargs = toKwargs(params, default = Dict{Symbol, Any}(:tfCorrection => rxHasTransferFunction(f), :frames => params.neglectBGFrames ? (1:acqNumFGFrames(f)) : (1:acqNumFrames(f))), ignore = [:neglectBGFrames, :bgParams]) result = getMeasurementsFD(f; bgCorrection = true, interpolateBG = params.bgParams.interpolateBG, kwargs..., frequencies = frequencies) return result end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::CommonPreProcessingParameters{<:ExternalBackgroundCorrection}, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) +function (params::CommonPreProcessingParameters{<:ExternalBackgroundCorrection})(t::Type{<:AbstractMPIRecoAlgorithm}, f::MPIFile, frequencies::Union{Vector{CartesianIndex{2}}, Nothing} = nothing) kwargs = toKwargs(params, default = Dict{Symbol, Any}(:tfCorrection => rxHasTransferFunction(f), :frames => params.neglectBGFrames ? (1:acqNumFGFrames(f)) : (1:acqNumFrames(f))), ignore = [:neglectBGFrames, :bgParams]) result = getMeasurementsFD(f; bgCorrection = false, kwargs..., frequencies = frequencies) bgParams = fromKwargs(ExternalPreProcessedBackgroundCorrectionParameters; kwargs..., bgParams = params.bgParams, frequencies = frequencies) - return process(t, bgParams, result, frequencies) + return bgParams(t, result, frequencies) end numAverages(params::CommonPreProcessingParameters) = params.numAverages diff --git a/src/PreProcessing/FrequencyFilterParameter.jl b/src/PreProcessing/FrequencyFilterParameter.jl index e33ca50..819f985 100644 --- a/src/PreProcessing/FrequencyFilterParameter.jl +++ b/src/PreProcessing/FrequencyFilterParameter.jl @@ -5,7 +5,7 @@ export NoFrequencyFilterParameter # TODO This requires numPeriodAverages and numPeriodGrouping and should use a freq. loading function from MPIFiles struct NoFrequencyFilterParameter <: AbstractFrequencyFilterParameter end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::NoFrequencyFilterParameter, file::MPIFile) +function (params::NoFrequencyFilterParameter)(::Type{<:AbstractMPIRecoAlgorithm}, file::MPIFile) return collect(vec(CartesianIndices((rxNumFrequencies(file), rxNumChannels(file))))) end @@ -23,18 +23,18 @@ struct DirectSelectionFrequencyFilterParameters{T <: Union{Integer, CartesianInd new{el, v}(freqIndices) end end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::DirectSelectionFrequencyFilterParameters{T}, file::MPIFile) where T <: Integer +function (params::DirectSelectionFrequencyFilterParameters)(::Type{<:AbstractMPIRecoAlgorithm}, file::MPIFile) where T <: Integer nFreq = params.freqIndices nReceivers = rxNumChannels(file) return vec([CartesianIndex{2}(i, j) for i in nFreq, j in nReceivers]) end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::DirectSelectionFrequencyFilterParameters{T}, file::MPIFile) where T <: CartesianIndex{2} +function (params::DirectSelectionFrequencyFilterParameters{T})(::Type{<:AbstractMPIRecoAlgorithm}, file::MPIFile) where T <: CartesianIndex{2} return params.freqIndices end # Could possible also be nested export SNRThresholdFrequencyFilterParameter -Base.@kwdef struct SNRThresholdFrequencyFilterParameter <: AbstractFrequencyFilterParameter +@parameter struct SNRThresholdFrequencyFilterParameter <: AbstractFrequencyFilterParameter minFreq::Float64 = 0.0 maxFreq::Union{Float64, Nothing} = nothing recChannels::Union{Vector{Int64}, UnitRange{Int64}, Nothing} = nothing @@ -62,7 +62,7 @@ defaultParameterRecChannels(new::Missing) = missing # return SNRThresholdFrequencyFilterParameter(;maxFreq = maxFreq, recChannels = recChannels) #end export FreqNumThresholdFrequencyFilterParameter -Base.@kwdef struct FreqNumThresholdFrequencyFilterParameter <: AbstractFrequencyFilterParameter +@parameter struct FreqNumThresholdFrequencyFilterParameter <: AbstractFrequencyFilterParameter minFreq::Float64 = 0.0 maxFreq::Union{Float64, Nothing} = nothing recChannels::Union{UnitRange{Int64}, Nothing} = nothing @@ -74,22 +74,22 @@ Base.@kwdef struct FreqNumThresholdFrequencyFilterParameter <: AbstractFrequency numSidebandFreqs::Int64 = -1 end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::AbstractFrequencyFilterParameter, file::MPIFile) +function (params::AbstractFrequencyFilterParameter)(::Type{<:AbstractMPIRecoAlgorithm}, file::MPIFile) kwargs = toKwargs(params, default = Dict{Symbol, Any}(:maxFreq => rxBandwidth(file), :recChannels => 1:rxNumChannels(file))) filterFrequencies(file; kwargs...) end export CompositeFrequencyFilterParameters -Base.@kwdef struct CompositeFrequencyFilterParameters <: AbstractFrequencyFilterParameter +@parameter struct CompositeFrequencyFilterParameters <: AbstractFrequencyFilterParameter filters::Vector{AbstractFrequencyFilterParameter} end -function process(algoT::Type{<:AbstractMPIRecoAlgorithm}, params::CompositeFrequencyFilterParameters, file::MPIFile) - return reduce(intersect, filter(!isnothing, map(p -> process(algoT, p, file), params.filters))) +function (params::CompositeFrequencyFilterParameters)(algoT::Type{<:AbstractMPIRecoAlgorithm}, file::MPIFile) + return reduce(intersect, filter(!isnothing, map(p -> p(algoT, file), params.filters))) end #= export NoiseLevelFrequencyFilterParameter -Base.@kwdef struct NoiseLevelFrequencyFilterParameter <: AbstractFrequencyFilterParameter +@parameter struct NoiseLevelFrequencyFilterParameter <: AbstractFrequencyFilterParameter noiseMeas::MPIFile levelFactor::Float64 noiseFrames::Union{Vector{Int64}, UnitRange{Int64}} = measBGFrameIdx(noiseMeas) @@ -101,7 +101,7 @@ Base.@kwdef struct NoiseLevelFrequencyFilterParameter <: AbstractFrequencyFilter maxMixingOrder::Int64 = -1 numSidebandFreqs::Int64 = -1 end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::NoiseLevelFrequencyFilterParameter, file::MPIFile) +function (params::NoiseLevelFrequencyFilterParameter)(::Type{<:AbstractMPIRecoAlgorithm}, file::MPIFile) noiseLevel = getNoiseLevel(params.noiseMeas, params.frames, params.recChannels) kwargs = toKwargs(params, ignore = [:noiseMeas, :frames], default = Dict{Symbol, Any}(:maxFreq => rxBandwidth(file), :recChannels => 1:rxNumChannels(file))) return filterFrequencies(file; kwargs..., SNRThresh = params.levelFactor * noiseLevel) diff --git a/src/Serialisation.jl b/src/Serialisation.jl index 8b59590..4ad5171 100644 --- a/src/Serialisation.jl +++ b/src/Serialisation.jl @@ -1,32 +1,109 @@ -AbstractImageReconstruction.toDictValue(file::MPIFile) = AbstractImageReconstruction.toDict(file) -AbstractImageReconstruction.toDictValue!(dict, file::Union{MultiMPIFile, MultiContrastFile}) = dict[AbstractImageReconstruction.VALUE_TAG] = filepath.(file) -AbstractImageReconstruction.toDictValue!(dict, file::MPIFile) = dict[AbstractImageReconstruction.VALUE_TAG] = filepath(file) -AbstractImageReconstruction.toDictValue(norm::AbstractRegularizationNormalization) = AbstractImageReconstruction.toDict(norm) +function StructUtils.lower(::MPIRecoStyle, file::MPIFile) + return filepath(file) +end +function StructUtils.lift(::MPIRecoStyle, ::Type{T}, source::String) where {T<:MPIFile} + return MPIFile(source), source +end +function StructUtils.lower(::MPIRecoStyle, file::MultiMPIFile) + return filepath.(file) +end +function StructUtils.lift(::MPIRecoStyle, ::Type{MultiMPIFile}, source::Vector) + files = MPIFile.(source) + return MultiMPIFile(files), source +end +function StructUtils.lower(::MPIRecoStyle, file::MultiContrastFile) + return filepath.(file) +end +function StructUtils.lift(::MPIRecoStyle, ::Type{MultiContrastFile}, source::Vector) + files = MPIFile.(source) + return MultiContrastFile(files), source +end + + +function StructUtils.lower(::MPIRecoStyle, range::UnitRange) + return Dict{String, Any}( + "start" => range.start, + "stop" => range.stop + ) +end +function StructUtils.lift(::MPIRecoStyle, ::Type{T}, dict::Dict) where {T<:UnitRange} + start = dict["start"] + stop = dict["stop"] + return UnitRange(start, stop), dict +end + +function StructUtils.lower(::MPIRecoStyle, reg::T) where {T<:AbstractRegularization} + dict = Dict{String, Any}( + MODULE_TAG => string(parentmodule(T)), + TYPE_TAG => string(nameof(T)), + "λ" => reg.λ + ) + + # Add all other fields except λ + for field in fieldnames(T) + if field != :λ + value = getfield(reg, field) + # Skip empty sparse trafos or other empty collections + if !(value isa AbstractArray && isempty(value)) + dict[string(field)] = StructUtils.lower(FIELD_STYLE[], value) + end + end + end + + return dict +end + +function StructUtils.lift(::MPIRecoStyle, ::Type{T}, dict::Dict{String, Any}) where {T<:AbstractRegularization} + λ = dict["λ"] + + # Collect kwargs from all keys except λ and metadata + filteredKeys = filter(x -> !(isequal("λ", x) || startswith(x, "_")), keys(dict)) + kwargs = Dict(Symbol(x) => dict[x] for x in filteredKeys) + + # Remove empty sparseTrafo if present + if haskey(kwargs, :sparseTrafo) && isempty(kwargs[:sparseTrafo]) + pop!(kwargs, :sparseTrafo) + end + + return T(λ; kwargs...), dict +end +function StructUtils.lift(style::MPIRecoStyle, ::Type{Vector{T}}, source::Vector) where {T<:AbstractRegularization} + result = Any[] + + for val in source + if val isa Dict && haskey(val, MODULE_TAG) && haskey(val, TYPE_TAG) + # Has type metadata - get concrete type + modDict = MODULE_DICT[] + if isnothing(modDict) + error("Cannot lift regularization without MODULE_DICT context") + end + + mod_name = val[MODULE_TAG] + type_name = val[TYPE_TAG] + concrete_type = modDict[mod_name, type_name] + + if !isnothing(concrete_type) + lifted, _ = StructUtils.lift(style, concrete_type, val) + push!(result, lifted) + else + error("Cannot find type $type_name in module $mod_name") + end + else + error("Regularization entry missing type metadata: $val") + end + end + + # Narrow vector to concrete type if possible + return identity.(result), source +end + +function StructUtils.lower(::MPIRecoStyle, norm::T) where {T<:AbstractRegularizationNormalization} + return Dict{String, Any}( + MODULE_TAG => string(parentmodule(T)), + TYPE_TAG => string(nameof(T)) + ) +end -function AbstractImageReconstruction.fromTOML(::Type{T}, dict::Dict{String, Any}) where {T<: UnitRange} - start = dict["start"] - stop = dict["stop"] - return UnitRange(start, stop) -end -AbstractImageReconstruction.fromTOML(t::Type{<:MPIFile}, x::Dict) = AbstractImageReconstruction.fromTOML(t, x[AbstractImageReconstruction.VALUE_TAG]) -AbstractImageReconstruction.fromTOML(::Type{<:MPIFile}, x::AbstractString) = MPIFile(x) -AbstractImageReconstruction.fromTOML(::Type{<:MultiMPIFile}, x::Vector) = MultiMPIFile(MPIFile.(x)) -function AbstractImageReconstruction.loadPlanValue(::Type{Vector{T} where T <: AbstractRegularization}, value::Vector, modDict) - result = Any[] - for val in value - type = modDict[val[AbstractImageReconstruction.MODULE_TAG]][val[AbstractImageReconstruction.TYPE_TAG]] - push!(result, AbstractImageReconstruction.fromTOML(type, val)) - end - # Narrow vector - return identity.(result) -end -function AbstractImageReconstruction.fromTOML(::Type{T}, dict::Dict{String, Any}) where {T<: AbstractRegularization} - λ = dict["λ"] - filteredKeys = filter(x-> !(isequal("λ",x) || startswith(x, ".")), keys(dict)) - kwargs = Dict(Symbol(x) => dict[x] for x in filteredKeys) - if haskey(kwargs, :sparseTrafo) && isempty(kwargs[:sparseTrafo]) - pop!(kwargs, :sparseTrafo) - end - return T(λ; kwargs...) -end -AbstractImageReconstruction.fromTOML(t::Type{T}, dict) where {T<:AbstractRegularizationNormalization} = T() \ No newline at end of file +function StructUtils.lift(::MPIRecoStyle, ::Type{T}, dict::Dict) where {T<:AbstractRegularizationNormalization} + return T(), dict +end \ No newline at end of file diff --git a/src/SystemMatrix/SystemMatrix.jl b/src/SystemMatrix/SystemMatrix.jl index de04362..4636a5b 100644 --- a/src/SystemMatrix/SystemMatrix.jl +++ b/src/SystemMatrix/SystemMatrix.jl @@ -17,7 +17,7 @@ export NoGridding struct NoGridding <: AbstractSystemMatrixGriddingParameter end export SystemMatrixGriddingParameter -Base.@kwdef struct SystemMatrixGriddingParameter <: AbstractSystemMatrixGriddingParameter +@parameter struct SystemMatrixGriddingParameter <: AbstractSystemMatrixGriddingParameter gridsize::Vector{Int64} = [1, 1, 1] fov::Vector{Float64} = [0.0, 0.0, 0.0] center::Vector{Float64} = [0.0,0.0,0.0] @@ -54,26 +54,26 @@ export AbstractSystemMatrixLoadingParameter abstract type AbstractSystemMatrixLoadingParameter <: AbstractSystemMatrixParameter end export DenseSystemMatixLoadingParameter -Base.@kwdef struct DenseSystemMatixLoadingParameter{F<:AbstractFrequencyFilterParameter, G<:AbstractSystemMatrixGriddingParameter} <: AbstractSystemMatrixLoadingParameter +@parameter struct DenseSystemMatixLoadingParameter{F<:AbstractFrequencyFilterParameter, G<:AbstractSystemMatrixGriddingParameter} <: AbstractSystemMatrixLoadingParameter freqFilter::F gridding::G bgCorrection::Bool = false tfCorrection::Union{Bool, Nothing} = nothing loadasreal::Bool = false end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::DenseSystemMatixLoadingParameter, sf::MPIFile) +function (params::DenseSystemMatixLoadingParameter)(t::Type{<:AbstractMPIRecoAlgorithm}, sf::MPIFile) # Construct freqFilter - frequencies = process(t, params.freqFilter, sf) - return frequencies, process(t, params, sf, frequencies)... + frequencies = params.freqFilter(t, sf) + return frequencies, params(t, sf, frequencies)... end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::DenseSystemMatixLoadingParameter, sf::MPIFile, frequencies::Vector{CartesianIndex{2}}) +function (params::DenseSystemMatixLoadingParameter)(t::Type{<:AbstractMPIRecoAlgorithm}, sf::MPIFile, frequencies::Vector{CartesianIndex{2}}) S, grid = getSF(sf, frequencies, nothing; toKwargs(params, default = Dict{Symbol, Any}(:tfCorrection => rxHasTransferFunction(sf)))...) @info "Loading SM" return S, grid end export SparseSystemMatrixLoadingParameter -Base.@kwdef struct SparseSystemMatrixLoadingParameter{F<:AbstractFrequencyFilterParameter} <: AbstractSystemMatrixLoadingParameter +@parameter struct SparseSystemMatrixLoadingParameter{F<:AbstractFrequencyFilterParameter} <: AbstractSystemMatrixLoadingParameter freqFilter::F sparseTrafo::String thresh::Union{Float64, Vector{Float64}} = 0.0 @@ -83,19 +83,19 @@ Base.@kwdef struct SparseSystemMatrixLoadingParameter{F<:AbstractFrequencyFilter loadasreal::Bool=false useDFFoV::Bool = false end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::SparseSystemMatrixLoadingParameter, sf::MPIFile) +function (params::SparseSystemMatrixLoadingParameter)(t::Type{<:AbstractMPIRecoAlgorithm}, sf::MPIFile) # Construct freqFilter - frequencies = process(t, params.freqFilter, sf) - return frequencies, process(t, params, sf, frequencies)... + frequencies = params.freqFilter(t, sf) + return frequencies, params(t, sf, frequencies)... end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::SparseSystemMatrixLoadingParameter, sf::MPIFile, frequencies::Vector{CartesianIndex{2}}) +function (params::SparseSystemMatrixLoadingParameter)(t::Type{<:AbstractMPIRecoAlgorithm}, sf::MPIFile, frequencies::Vector{CartesianIndex{2}}) S, grid = getSF(sf, frequencies, params.sparseTrafo; toKwargs(params, default = Dict{Symbol, Any}(:tfCorrection => rxHasTransferFunction(sf)))...) return S, grid end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::SparseSystemMatrixLoadingParameter, sf::MPIFile, elType::Type{<:Number}, arrayType, shape::NTuple{N, Int64}) where N +function (params::SparseSystemMatrixLoadingParameter)(t::Type{<:AbstractMPIRecoAlgorithm}, sf::MPIFile, elType::Type{<:Number}, arrayType, shape::NTuple{N, Int64}) where N return createLinearOperator(params.sparseTrafo, elType; shape, S = typeof(arrayType{elType}(undef, 0))) end -function process(t::Type{<:AbstractMPIRecoAlgorithm}, params::SparseSystemMatrixLoadingParameter, sf::MultiContrastFile, elType::Type{<:Number}, arrayType, shape::NTuple{N, Int64}) where N +function (params::SparseSystemMatrixLoadingParameter)(t::Type{<:AbstractMPIRecoAlgorithm}, sf::MultiContrastFile, elType::Type{<:Number}, arrayType, shape::NTuple{N, Int64}) where N ops = [createLinearOperator(params.sparseTrafo, elType; shape, S = typeof(arrayType{elType}(undef, 0))) for i = 1:length(sf)] return DiagOp(ops) end @@ -139,18 +139,18 @@ end # In this instance we want to dispatch before the cache and call individual steps processing steps which in turn can use the cache. This is only effective if the cache size is >= number of sub-processes # Alternative solutions require us to nest our parameters with caches in between -function AbstractImageReconstruction.process(type::Type{<:AbstractMPIRecoAlgorithm}, params::Union{L, ProcessResultCache{L}}, sf::MPIFile, solverT, arrayType = Array) where L <: AbstractSystemMatrixLoadingParameter +function (params::Union{L, ProcessResultCache{L}})(type::Type{<:AbstractMPIRecoAlgorithm}, sf::MPIFile, solverT, arrayType = Array) where L <: AbstractSystemMatrixLoadingParameter # Each process step can access the cache - freqs, sf, grid = process(type, params, sf) - sf, grid = process(type, params, sf, solverT, grid) - sf = process(type, params, sf, arrayType) + freqs, sf, grid = params(type, sf) + sf, grid = params(type, sf, solverT, grid) + sf = params(type, sf, arrayType) return freqs, sf, grid end -function AbstractImageReconstruction.process(type::Type{<:AbstractMPIRecoAlgorithm}, params::L, sf::AbstractArray, solverT::Type{<:AbstractLinearSolver}, grid) where L <: AbstractSystemMatrixLoadingParameter +function (params::AbstractSystemMatrixLoadingParameter)(type::Type{<:AbstractMPIRecoAlgorithm}, sf::AbstractArray, solverT::Type{<:AbstractLinearSolver}, grid) @info "Preparing SF" return prepareSF(solverT, sf, grid) end -function AbstractImageReconstruction.process(type::Type{<:AbstractMPIRecoAlgorithm}, params::L, sf::AbstractArray, arrayType::Type{<:AbstractArray}) where L <: AbstractSystemMatrixLoadingParameter +function (params::AbstractSystemMatrixLoadingParameter)(type::Type{<:AbstractMPIRecoAlgorithm}, sf::AbstractArray, arrayType::Type{<:AbstractArray}) @info "Adapting SF" return adaptSF(arrayType, sf) end diff --git a/src/Weighting.jl b/src/Weighting.jl index 3c40775..8778a8f 100644 --- a/src/Weighting.jl +++ b/src/Weighting.jl @@ -2,8 +2,8 @@ export getWeights, WeightingType, setFreqToZero export AbstractWeightingParameters abstract type AbstractWeightingParameters <: AbstractMPIRecoParameters end -function process(type::Type{<:AbstractMPIRecoAlgorithm}, params::AbstractWeightingParameters, freqs, op = nothing, u = nothing, arrayType = Array) - result = process(type, params, freqs, op, u) +function (params::AbstractWeightingParameters)(type::Type{<:AbstractMPIRecoAlgorithm}, freqs, op = nothing, u = nothing, arrayType = Array) + result = params(type, freqs, op, u) if !isnothing(result) result = map(real(eltype(algo.S)), result) end @@ -19,20 +19,20 @@ WeightingType(cache::ProcessResultCache) = WeightingType(cache.param) export NoWeightingParameters struct NoWeightingParameters <: AbstractWeightingParameters end -process(::Type{<:AbstractMPIRecoAlgorithm}, params::NoWeightingParameters, args...) = nothing +(params::NoWeightingParameters)(::Type{<:AbstractMPIRecoAlgorithm}, args...) = nothing export ChannelWeightingParameters -Base.@kwdef struct ChannelWeightingParameters <: AbstractWeightingParameters +@parameter struct ChannelWeightingParameters <: AbstractWeightingParameters channelWeights::Vector{Float64} = [1.0, 1.0, 1.0] end -process(::Type{<:AbstractMPIRecoAlgorithm}, params::ChannelWeightingParameters, freqs::Vector{CartesianIndex{2}}, args...) = map(x-> params.channelWeights[x[2]], freqs) +(params::ChannelWeightingParameters)(::Type{<:AbstractMPIRecoAlgorithm}, freqs::Vector{CartesianIndex{2}}, args...) = map(x-> params.channelWeights[x[2]], freqs) export WhiteningWeightingParameters -Base.@kwdef struct WhiteningWeightingParameters <: AbstractWeightingParameters +@parameter struct WhiteningWeightingParameters <: AbstractWeightingParameters whiteningMeas::MPIFile tfCorrection::Union{Bool, Nothing} = nothing end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::WhiteningWeightingParameters, freqs::Vector{CartesianIndex{2}}, args...) +function (params::WhiteningWeightingParameters)(::Type{<:AbstractMPIRecoAlgorithm}, freqs::Vector{CartesianIndex{2}}, args...) u_bg = getMeasurementsFD(params.whiteningMeas, false, tfCorrection = isnothing(params.tfCorrection) ? rxHasTransferFunction(params.whiteningMeas) : params.tfCorrection, frequencies=freqs, frames=measBGFrameIdx(params.whiteningMeas), bgCorrection = false) bg_std = std(u_bg, dims=3) @@ -41,10 +41,10 @@ function process(::Type{<:AbstractMPIRecoAlgorithm}, params::WhiteningWeightingP end export RowNormWeightingParameters -Base.@kwdef struct RowNormWeightingParameters <: AbstractWeightingParameters +@parameter struct RowNormWeightingParameters <: AbstractWeightingParameters # NOP end -function process(::Type{<:AbstractMPIRecoAlgorithm}, params::RowNormWeightingParameters, freqs, op, args...) +function (params::RowNormWeightingParameters)(::Type{<:AbstractMPIRecoAlgorithm}, freqs, op, args...) weights = map(r -> 1/sqrt(rownorm²(op, r)), 1:size(op, 1)) return weights end @@ -62,8 +62,8 @@ struct CompositeWeightingParameters{C} <: AbstractWeightingParameters where {C < return new{eltype(weightingParameters)}(weightingParameters) end end -function process(algoT::Type{<:AbstractMPIRecoAlgorithm}, params::CompositeWeightingParameters, args...) - weights = map(p -> process(algoT, p, args...), params.weightingParameters) +function (params::CompositeWeightingParameters)(algoT::Type{<:AbstractMPIRecoAlgorithm}, args...) + weights = map(p -> p(algoT, args...), params.weightingParameters) return reduce(.*, weights) end #= diff --git a/test/LowLevel.jl b/test/LowLevel.jl index b62572a..e0e913c 100644 --- a/test/LowLevel.jl +++ b/test/LowLevel.jl @@ -19,7 +19,7 @@ cHigh = reconstruct(high, b) S = high.S - u = process(high, high.params.pre, b, high.freqs) + u = high.params.pre(high, b, high.freqs) cLow = reconstruct("LowLevel", u; S = S, iterations = params[:iterations], reg = params[:reg], solver = params[:solver]) cLow = reshape(cLow, size(cHigh)) @@ -31,7 +31,7 @@ cHigh = reconstruct(high, b) S = high.S - u = process(high, high.params.pre, b, high.freqs) + u = high.params.pre(high, b, high.freqs) weights = high.weights cLow = reconstruct("LowLevel", u; S = S, iterations = params[:iterations], reg = params[:reg], solver = params[:solver], weights = weights) @@ -61,7 +61,7 @@ cHigh = reconstruct(high, b) S = high.S - u = process(high, high.params.pre, b, high.freqs) + u = high.params.pre(high, b, high.freqs) op = MPIReco.getLinearOperator(high, high.params.reco) cLow = reconstruct("LowLevel", u; S = S, op = op, iterations = params[:iterations], reg = params[:reg], solver = params[:solver]) @@ -74,7 +74,7 @@ cHigh = reconstruct(high, b) S = high.S - u = process(high, high.params.pre, b, high.freqs) + u = high.params.pre(high, b, high.freqs) op = MPIReco.getLinearOperator(high, high.params.reco) weights = high.weights cLow = reconstruct("LowLevel", u; S = S, op = op, iterations = params[:iterations], reg = params[:reg], solver = params[:solver], weights = weights) @@ -104,7 +104,7 @@ cHigh = reconstruct(high, b) S = copy(high.ffOp) - u = process(high, high.params.pre, b, high.freqs) + u = high.params.pre(high, b, high.freqs) cLow = reconstruct("LowLevel", u; S = S, iterations = params[:iterations], reg = params[:reg], solver = params[:solver]) cLow = reshape(cLow, size(cHigh)) @@ -116,7 +116,7 @@ cHigh = reconstruct(high, b) S = copy(high.ffOp) - u = process(high, high.params.pre, b, high.freqs) + u = high.params.pre(high, b, high.freqs) weights = high.weights cLow = reconstruct("LowLevel", u; S = S, iterations = params[:iterations], reg = params[:reg], solver = params[:solver], weights = weights)