From f93bebeb7056963af114ae8e0dc54b2014064d5e Mon Sep 17 00:00:00 2001 From: Michiel Cottaar <michiel.cottaar@ndcn.ox.ac.uk> Date: Sun, 28 Jan 2024 21:17:41 +0000 Subject: [PATCH] Switch to bmat_gradient --- src/gradients/changing_gradient_blocks.jl | 10 +++++----- src/gradients/constant_gradient_blocks.jl | 10 +++++----- src/gradients/instant_gradients.jl | 6 +++--- src/variables.jl | 19 ++++++++++++++++--- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/gradients/changing_gradient_blocks.jl b/src/gradients/changing_gradient_blocks.jl index b424871..a759eac 100644 --- a/src/gradients/changing_gradient_blocks.jl +++ b/src/gradients/changing_gradient_blocks.jl @@ -3,7 +3,7 @@ import StaticArrays: SVector import ...Variables: VariableType, variables import ...BuildingBlocks: GradientBlock import JuMP: @constraint, @variable, Model, owner_model -import ...Variables: qvec, bmat, gradient_strength, slew_rate, duration, variables, VariableType +import ...Variables: qvec, bmat_gradient, gradient_strength, slew_rate, duration, variables, VariableType import ...BuildingBlocks: GradientBlock, fixed, RFPulseBlock struct AbstractChangingGradientBlock{T<:VariableType} <: GradientBlock @@ -37,7 +37,7 @@ duration(cgb::AbstractChangingGradientBlock) = cgb.duration slew_rate(cgb::AbstractChangingGradientBlock) = (cgb.gradient_strength_end .- cgb.gradient_strength_start) ./ duration(cgb) qvec(cgb::AbstractChangingGradientBlock) = (cgb.gradient_strength_start .+ cgb.gradient_strength_end) .* (duration(cgb)/2) -function bmat(cgb::AbstractChangingGradientBlock, qstart) +function bmat_gradient(cgb::AbstractChangingGradientBlock, qstart) # grad = (g1 * (duration - t) + g2 * t) / duration # = g1 + (g2 - g1) * t / duration # q = qstart + g1 * t + (g2 - g1) * t^2 / (2 * duration) @@ -53,11 +53,11 @@ function bmat(cgb::AbstractChangingGradientBlock, qstart) duration(cgb)^2 .* qstart .* ( 2 .* cgb.gradient_strength_start' .+ cgb.gradient_strength_end') ./ 3 .+ - bmat(cgb) + bmat_gradient(cgb) ) end -function bmat(cgb::AbstractChangingGradientBlock) +function bmat_gradient(cgb::AbstractChangingGradientBlock) diff = cgb.gradient_strength_end .- cgb.gradient_strength_start return ( cgb.gradient_strength_start .* cgb.gradient_strength_start' ./ 3 .+ @@ -67,6 +67,6 @@ function bmat(cgb::AbstractChangingGradientBlock) end -variables(::Type{<:AbstractChangingGradientBlock}) = [duration, qvec, bmat, slew_rate] +variables(::Type{<:AbstractChangingGradientBlock}) = [duration, slew_rate] end diff --git a/src/gradients/constant_gradient_blocks.jl b/src/gradients/constant_gradient_blocks.jl index cbcae10..dce6fb3 100644 --- a/src/gradients/constant_gradient_blocks.jl +++ b/src/gradients/constant_gradient_blocks.jl @@ -3,7 +3,7 @@ import StaticArrays: SVector import ...Variables: VariableType, variables import ...BuildingBlocks: GradientBlock import JuMP: @constraint, @variable, Model, owner_model -import ...Variables: qvec, bmat, gradient_strength, slew_rate, duration, variables, VariableType +import ...Variables: qvec, bmat_gradient, gradient_strength, slew_rate, duration, variables, VariableType import ...BuildingBlocks: GradientBlock, fixed, RFPulseBlock struct AbstractConstantGradientBlock{T<:VariableType} <: GradientBlock @@ -37,11 +37,11 @@ gradient_strength(cgb::AbstractConstantGradientBlock) = cgb.gradient_strength slew_rate(::AbstractConstantGradientBlock) = zero(SVector{3, Float64}) qvec(cgb::AbstractConstantGradientBlock) = duration(cgb) .* gradient_strength(cgb) -function bmat(cgb::AbstractConstantGradientBlock) +function bmat_gradient(cgb::AbstractConstantGradientBlock) return (grad .* grad') .* duration(cgb)^3 ./3 end -function bmat(cgb::AbstractConstantGradientBlock, qstart) +function bmat_gradient(cgb::AbstractConstantGradientBlock, qstart) # \int dt (qstart + t * grad)^2 = # qstart^2 * duration + # qstart * grad * duration^2 + @@ -49,10 +49,10 @@ function bmat(cgb::AbstractConstantGradientBlock, qstart) return ( qstart .* qstart' .* duration(cgb) .+ qstart .* grad' .* duration(cgb)^2 .+ - bmat(cgb) + bmat_gradient(cgb) ) end -variables(::Type{<:AbstractConstantGradientBlock}) = [duration, gradient_strength, qvec, bmat] +variables(::Type{<:AbstractConstantGradientBlock}) = [duration, gradient_strength] end diff --git a/src/gradients/instant_gradients.jl b/src/gradients/instant_gradients.jl index 58c96bb..bb23766 100644 --- a/src/gradients/instant_gradients.jl +++ b/src/gradients/instant_gradients.jl @@ -1,6 +1,6 @@ module InstantGradients import JuMP: @constraint, @variable, Model, owner_model, AbstractJuMPScalar -import ...Variables: qvec, bmat, duration, variables, get_free_variable, VariableType +import ...Variables: qvec, bmat_gradient, duration, variables, get_free_variable, VariableType import ...BuildingBlocks: GradientBlock, fixed import ...BuildSequences: @global_model_constructor import ..FixedGradients: FixedInstantGradient @@ -70,9 +70,9 @@ end qvec(instant::InstantGradientBlock) = instant.qvec -bmat(instant::InstantGradientBlock, qstart=nothing) = zeros(3, 3) +bmat_gradient(instant::InstantGradientBlock, qstart=nothing) = zeros(3, 3) duration(instant::InstantGradientBlock) = 0. -variables(::Type{<:InstantGradientBlock}) = [qval] +variables(::Type{<:InstantGradientBlock}) = [qvec, qval] function fixed(block::InstantGradientBlock) return FixedInstantGradient(block.orientation, value(qval(block))) diff --git a/src/variables.jl b/src/variables.jl index 8630ade..e8d0180 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -19,8 +19,9 @@ all_variables_symbols = [ :slice_thickness => (:pulse, "Slice thickness of an RF pulse that is active during a gradient.") # gradients + :qvec => (:gradient, "The spatial range and orientation on which the displacements can be detected due to this gradient in 1/um (equivalent to [`area_under_curve_vec`](@ref))"), :qval => (:gradient, "The spatial range on which the displacements can be detected due to this gradient in 1/um (equivalent to [`area_under_curve`](@ref))"), - :area_under_curve => (:gradient, "Area under the curve of the gradient in 1/um (equivalent to [`qval`](@ref))."), + :qval_sqr => (:gradient, "Square of qval in 1/um^2. This can be more efficient to calculate and hence to contrain than `qval` (as it avoids computing a square root)."), :δ => (:gradient, "Effective duration of a gradient pulse ([`rise_time`](@ref) + [`flat_time`](@ref)) in ms."), :rise_time => (:gradient, "Time for gradient pulse to reach its maximum value in ms."), :flat_time => (:gradient, "Time of gradient pulse at maximum value in ms."), @@ -53,7 +54,11 @@ variables() = [values(symbol_to_func)...] # Some universal truths -area_under_curve(bb) = qval(bb) +qval(bb) = sqrt(qval_sqr(bb)) +function qval_sqr(bb) + vec = qvec(bb) + return vec[1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3] +end # These functions are more fully defined in building_blocks.jl @@ -93,6 +98,14 @@ function get_free_variable(model::Model, ::Val{:max}) return var end -function bval end +""" + bmat_gradient(gradient::GradientBlock, qstart=(0, 0, 0)) + +Computes the diffusion-weighting matrix due to a single gradient block. + +This should be defined for every `GradientBlock`, but not be called directly. +Instead, the `bmat` and `bval` should be constrained for specific `Pathways` +""" +function bmat_gradient end end \ No newline at end of file -- GitLab