From dc9e2780fee243ccdebb64b9f1649d26395f683b Mon Sep 17 00:00:00 2001 From: Michiel Cottaar <michiel.cottaar@ndcn.ox.ac.uk> Date: Mon, 12 Feb 2024 12:50:31 +0000 Subject: [PATCH] Define instant gradient component --- .../gradient_waveforms/instant_gradients.jl | 83 ------------------- src/components/instant_gradients.jl | 82 ++++++++++++++++++ 2 files changed, 82 insertions(+), 83 deletions(-) delete mode 100644 src/components/gradient_waveforms/instant_gradients.jl create mode 100644 src/components/instant_gradients.jl diff --git a/src/components/gradient_waveforms/instant_gradients.jl b/src/components/gradient_waveforms/instant_gradients.jl deleted file mode 100644 index 08026bd..0000000 --- a/src/components/gradient_waveforms/instant_gradients.jl +++ /dev/null @@ -1,83 +0,0 @@ -module InstantGradients -import StaticArrays: SVector -import JuMP: @constraint, @variable, AbstractJuMPScalar -import ...Variables: qvec, bmat_gradient, duration, variables, get_free_variable, VariableType -import ...BuildingBlocks: GradientBlock, fixed -import ...BuildSequences: global_model - -""" - InstantGradientBlock(; orientation=nothing, qval=nothing, qvec=nothing, rotate=nothing, scale=nothing) - -Defines an instantaneous gradient. - -## Parameters -- `orientation` sets the gradient orienation (ignored if `qvec` is set). Can be set to a vector for a fixed orientation. Otherwise the orientation will be aligned with the `rotate` (if set) or fully free (if `rotate` is nothing). Set to :flip to point in the inverse of the user-provided `rotate`. -- `rotate`: with which user-set parameter will this gradient be rotated (e.g., :bvec). Default is no rotation. -- `scale`: with which user-set parameter will this gradient be scaled (e.g., :bval). Default is no scaling. - -## Variables -- [`qvec`](@ref): Spatial scale and direction on which spins will be dephased due to this pulsed gradient in rad/um. -- [`qval`](@ref): Spatial scale on which spins will be dephased due to this pulsed gradient in rad/um. -""" -struct InstantGradientBlock <: GradientBlock - qvec :: SVector{3, VariableType} - rotate :: Union{Nothing, Symbol} - scale :: Union{Nothing, Symbol} -end - -function interpret_orientation(orientation, qval, qvec, will_rotate) - if !isnothing(qvec) - return (false, qvec) - end - if orientation == :flip - @assert will_rotate "setting `orientation=:flip` only makes sense if the `rotate` is set as well." - return (true, SVector{3}( - -get_free_variable(qval), - 0., - 0., - )) - end - if isnothing(orientation) - if !will_rotate - return (false, SVector{3}( - get_free_variable(nothing), - get_free_variable(nothing), - get_free_variable(nothing), - )) - else - return (true, SVector{3}( - get_free_variable(qval), - 0., - 0., - )) - end - else - qval = get_free_variable(qval) - return (true, (orientation ./ norm(orientation)) * qval) - end -end - -function InstantGradientBlock(; orientation=nothing, qval=nothing, qvec=nothing, rotate=nothing, scale=nothing) - model = global_model() - (used_qval, qvec) = interpret_orientation(orientation, qval, qvec, !isnothing(rotate)) - res = InstantGradientBlock( - qvec, - rotate, - scale - ) - if !used_qval && !isnothing(qval) - @constraint model qval_sqr(res) == qval^2 - end - if qval isa AbstractJuMPScalar - @constraint model qval >= 0 - end - return res -end - - -qvec(instant::InstantGradientBlock) = instant.qvec -bmat_gradient(::InstantGradientBlock, qstart=nothing) = zeros(3, 3) -duration(instant::InstantGradientBlock) = 0. - - -end \ No newline at end of file diff --git a/src/components/instant_gradients.jl b/src/components/instant_gradients.jl new file mode 100644 index 0000000..a0a726d --- /dev/null +++ b/src/components/instant_gradients.jl @@ -0,0 +1,82 @@ +module InstantGradients +import StaticArrays: SVector, SMatrix +import ...Variables: VariableType, duration, qvec, bmat_gradient, get_free_variable, set_simple_constraints, qval, effective_time +import ..AbstractTypes: EventComponent, GradientWaveform + +""" +Parent type for [`InstantGradient1D`](@ref) and [`InstantGradient3D`]. + +This is an [`EventComponent`](@ref) rather than part of the [`GradientWaveform`](@ref), +because it is more easily thought of as interrupting a finite gradient waveform rather than being part of it. +""" +abstract type InstantGradient <: EventComponent end + +""" + InstantGradient1D(; orientation=[1, 0, 0], group=nothing, variables...) + +Defines an instantaneous gradient with given fixed `orientation` (default: x-direction). + +To have a variable `orientation`, see [`InstantGradient3D`](@ref). + +## Parameters +- `orientation` sets the gradient orienation as a length-3 vector (default: x-direction). +- `group`: name of the group to which this gradient belongs (used for scaling and rotating). + +## Variables +- [`qval`](@ref): Spatial frequency on which spins will be dephased due to this pulsed gradient in rad/um. +- [`spoiler_scale`](@ref): Length-scale on which spins will be dephased by exactly 2Ï€ in mm. +""" +struct InstantGradient1D <: GradientBlock + qval :: VariableType + orientation :: SVector{3, Number} + group :: Union{Nothing, Symbol} +end + +function InstantGradient1D(; orientation=[1, 0, 0], group=nothing, qval=nothing, variables...) + res = InstantGradient1D(qval, orientation, group) + set_simple_constraints(res, variables) + return res +end + +qval(ig::InstantGradient1D) = ig.qval +qvec(ig::InstantGradient1D) = qval(ig) .* ig.orientation + + +""" + InstantGradient3D(; group=nothing, variables...) + +Defines an instantaneous gradient without a fixed orientation. + +To have a fixed `orientation`, see [`InstantGradient1D`](@ref). + +## Parameters +- `group`: name of the group to which this gradient belongs (used for scaling and rotating). + +## Variables +- [`qvec`](@ref): Vector with spatial frequency on which spins will be dephased due to this pulsed gradient in rad/um. +- [`qval`](@ref): Norm of spatial frequency on which spins will be dephased due to this pulsed gradient in rad/um. +- [`spoiler_scale`](@ref): Vector with length-scale on which spins will be dephased by exactly 2Ï€ in mm. +""" +struct InstantGradient3D <: GradientBlock + qvec :: SVector{3, VariableType} + group :: Union{Nothing, Symbol} +end + +function InstantGradient3D(; qvec=[nothing, nothing, nothing], group=nothing, variables...) + if isnothing(qvec) + qvec = [nothing, nothing, nothing] + end + res = InstantGradient3D(get_free_variable.(qvec), group) + set_simple_constraints(res, variables) + return res +end + +qvec(ig::InstantGradient3D) = ig.qvec + + +duration(::InstantGradient) = 0. +effective_time(::InstantGradient) = 0. +bmat_gradient(::InstantGradient, qstart=nothing) = zero(SMatrix{3, 3, Float64, 3}) + + +end \ No newline at end of file -- GitLab