Skip to content
Snippets Groups Projects
constant_gradient_blocks.jl 4 KiB
Newer Older
module ConstantGradientBlocks
import StaticArrays: SVector
import ....Variables: VariableType, get_free_variable, adjust_internal, variables, @defvar
import ...AbstractTypes: GradientWaveform
import ..ChangingGradientBlocks: split_gradient
    ConstantGradient(gradient_strength_vector, duration, group=nothing)
    ConstantGradient(gradient_strength_scalar, orientation, duration, group=nothing)
Underlying type for any flat part in a 3D (first constructor) or 3D (second constructor) gradient waveform.

Usually, you do not want to create this object directly, use a `BuildingBlock` instead.
"""
Michiel Cottaar's avatar
Michiel Cottaar committed
abstract type ConstantGradient{N} <: GradientWaveform{N} end
(::Type{ConstantGradient})(grad1::VariableType, orientation::AbstractVector, duration::VariableType, group=nothing) = ConstantGradient1D(grad1, orientation, duration, group)
(::Type{ConstantGradient})(grad1::AbstractVector, ::Nothing, duration::VariableType, group=nothing) = ConstantGradient3D(grad1, duration, group)
(::Type{ConstantGradient})(grad1::AbstractVector, duration::VariableType, group=nothing) = ConstantGradient3D(grad1, duration, group)
struct ConstantGradient1D <: ConstantGradient{1}
    gradient_strength :: VariableType
    orientation :: SVector{3, Float64}
    duration :: VariableType
    group :: Union{Symbol, Nothing}
Michiel Cottaar's avatar
Michiel Cottaar committed
struct ConstantGradient3D <: ConstantGradient{3}
    gradient_strength :: SVector{3, <:VariableType}
    duration :: VariableType
    group :: Union{Symbol, Nothing}

@defvar duration(cgb::ConstantGradient) = cgb.duration

@defvar gradient begin
Michiel Cottaar's avatar
Michiel Cottaar committed
    gradient_strength(cgb::ConstantGradient1D) = cgb.gradient_strength * cgb.orientation
    gradient_strength(cgb::ConstantGradient3D) = cgb.gradient_strength
    slew_rate(::ConstantGradient) = zero(SVector{3, Float64})
    qvec(cgb::ConstantGradient) = variables.duration(cgb) * variables.gradient_strength(cgb) * 2π
    gradient_strength(cgb::ConstantGradient, time::Number) = variables.gradient_strength(cgb)
_mult(g1::VariableType, g2::VariableType) = g1 * g2
_mult(g1::AbstractVector, g2::AbstractVector) = g1 .* permutedims(g2)

@defvar begin
    function bmat_gradient(cgb::ConstantGradient)
        grad = 2π .* variables.gradient_strength(cgb)
        return _mult(grad, grad) .* variables.duration(cgb)^3 ./3
    function bmat_gradient(cgb::ConstantGradient, qstart::AbstractVector)
        # \int dt (qstart + t * grad)^2 = 
        #   qstart^2 * duration +
        #   qstart * grad * duration^2 +
        #   grad * grad * duration^3 / 3 +
        grad = 2π .* variables.gradient_strength(cgb)
            _mult(qstart, qstart) .* variables.duration(cgb) .+
            _mult(qstart, grad) .* variables.duration(cgb)^2 .+
            variables.bmat_gradient(cgb)
end

function split_gradient(cgb::ConstantGradient, times::VariableType...)
Michiel Cottaar's avatar
Michiel Cottaar committed
    durations = [times[1], [t[2] - t[1] for t in zip(times[1:end-1], times[2:end])]..., variables.duration(cgb) - times[end]]
    if cgb isa ConstantGradient1D
        return [ConstantGradient1D(cgb.gradient_strength, cgb.orientation, d, cgb.group) for d in durations]
    else
        return [ConstantGradient3D(cgb.gradient_strength, d, cgb.group) for d in durations]
    end
Michiel Cottaar's avatar
Michiel Cottaar committed
function adjust_internal(cgb::ConstantGradient1D; orientation=nothing, scale=1., rotation=nothing)
    if !isnothing(orientation) && !isnothing(rotation)
        error("Cannot set both the gradient orientation and rotation.")
    end
    new_orientation = isnothing(orientation) ? (isnothing(rotation) ? cgb.orientation : rotation * cgb.orientation) : orientation
    return ConstantGradient1D(
        cgb.gradient_strength * scale,
        new_orientation,
        cgb.duration,
        cgb.group
    )
end

function adjust_internal(cgb::ConstantGradient3D; scale=1., rotation=nothing)
    return ConstantGradient3D(
        (
            isnothing(rotation) ? 
            (cgb.gradient_strength .* scale) : 
            (rotation * (cgb.gradient_strength .* scale))
        ),
        cgb.duration,
        cgb.group
    )
end