diff --git a/src/gradients/slice_selects.jl b/src/gradients/slice_selects.jl new file mode 100644 index 0000000000000000000000000000000000000000..e6f8165b3df2c39393d570ccea020ffc685e3ed3 --- /dev/null +++ b/src/gradients/slice_selects.jl @@ -0,0 +1,71 @@ +module SliceSelects +import JuMP: Model +import ...BuildingBlocks: RFPulseBlock, ContainerBlock, get_children_blocks +import ...Variables: VariableType, slice_thickness, get_free_variable, effective_time, start_time, qvec, bmat, qval, bval +import ...Variables: flip_angle, amplitude, phase, frequency, bandwidth, inverse_bandwidth, N_left, N_right +import ..ConstantGradientBlocks: ConstantGradientBlock + +struct AbstractSliceSelect{T<:VariableType} + model :: Model + time_before :: T + flat_before :: ConstantGradientBlock + pulse :: RFPulseBlock + time_after :: T + flat_after :: ConstantGradientBlock + flat_total :: ConstantGradientBlock +end + +""" +The fixed equivalent of [`SliceSelect`](@ref). +""" +const FixedSliceSelect = AbstractSliceSelect{Float64} + +""" + SliceSelect(gradient_strength, time_before_pulse, pulse, time_after_pulse, rotate, scale) + +Represents a slice-selective RF pulse. + +This will typically be embedded within a larger gradient waveform. +Do not create it directly. + +The fixed equivalent is [`FixedSliceSelect`](@ref). +""" +const SliceSelect = AbstractSliceSelect{VariableType} + +function AbstractSliceSelect{VariableType}(model::Model, gradient_strength::SVector{3, VariableType}, time_before_pulse, pulse::RFPulseBlock, time_after_pulse, rotate::Symbol, scale::Symbol) + time_before_pulse = get_free_variable(model, time_before_pulse), + time_after_pulse = get_free_variable(model, time_after_pulse), + return SliceSelect( + model, + time_before_pulse, + ConstantGradientBlock(gradient_strength, time_before_pulse + effective_time(pulse), rotate, scale), + pulse, + time_after_pulse, + ConstantGradientBlock(gradient_strength, duration(pulse) - effective_time(pulse) + time_after_pulse, rotate, scale), + ConstantGradientBlock(gradient_strength, duration(pulse) + time_before_pulse + time_after_pulse, rotate, scale), + ) +end + + +get_children_blocks(select::SliceSelect) = [(symb, getproperty(select, symb)) for symb in (:flat_before, :pulse, :flat_after)] +Base.get_index(select::SliceSelect, index::Symbol) = getproperty(select, index) + +start_time(select::SliceSelect, symbol::Symbol) = start_time(select, Val(symbol)) +start_time(select::SliceSelect, ::Val{:flat_before}) = 0. +start_time(select::SliceSelect, ::Val{:pulse}) = select.time_before_pulse +start_time(select::SliceSelect, ::Val{:flat_after}) = duration(select.flat_before) +start_time(select::SliceSelect, ::Val{:flat_total}) = 0. + +qvec(select::SliceSelect) = qvec(select.flat_total) +bmat(select::SliceSelect) = bmat(select.flat_total) +duration(select::SliceSelect) = duration(select.flat_total) +gradient_strength(select::SliceSelect) = gradient_strength(select.flat_total) +slice_thickness(select::SliceSelect) = bandwidth(select) ./ gradient_strength(select) + +for fn in (flip_angle, amplitude, phase, frequency, bandwidth, inverse_bandwidth, N_left, N_right) + @eval $fn(select::SliceSelect) = $fn(select.pulse) +end + +variables(::Type{<:SliceSelect}) = (duration, gradient_strength, slice_thickness, qvec, bmat, qval, bval, flip_angle, amplitude, phase, frequency, bandwidth, inverse_bandwidth, N_left, N_right) + +end \ No newline at end of file