From 361d98e5711d8fcdf040af465389d1d564fec3fe Mon Sep 17 00:00:00 2001 From: Michiel Cottaar <michiel.cottaar@ndcn.ox.ac.uk> Date: Sun, 28 Jan 2024 13:43:33 +0000 Subject: [PATCH] Define effective_time --- src/building_blocks.jl | 23 ++++++++++++++++++++--- src/pulses/constant_pulses.jl | 3 ++- src/pulses/fixed_pulses.jl | 9 ++++++--- src/pulses/instant_pulses.jl | 5 +++-- src/pulses/pulses.jl | 1 + src/pulses/sinc_pulses.jl | 3 ++- src/readouts/instant_readouts.jl | 5 +++-- src/variables.jl | 2 ++ 8 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/building_blocks.jl b/src/building_blocks.jl index 51f7842..76912bd 100644 --- a/src/building_blocks.jl +++ b/src/building_blocks.jl @@ -2,7 +2,7 @@ module BuildingBlocks import JuMP: has_values, value, Model, @constraint, @objective, owner_model, objective_function, optimize!, AbstractJuMPScalar import Printf: @sprintf import ..Scanners: Scanner -import ..Variables: variables, start_time, duration, end_time, gradient_strength, slew_rate +import ..Variables: variables, start_time, duration, end_time, gradient_strength, slew_rate, effective_time """ Parent type for all individual components out of which a sequence can be built. @@ -18,6 +18,9 @@ abstract type BuildingBlock end Parent type for all RF pulses. RF pulses combined with gradients, should be childrent of [`ContainerBlock`](@ref) instead. + +Required methods: +- [`effective_time`](@ref)(pulse): Best approximation of time the RF pulse is applied. This is defined relative to the start of the pulse. """ abstract type RFPulseBlock <: BuildingBlock end @@ -54,6 +57,21 @@ The [`BuildingBlock`](@ref) is defined by one or more indices as defined below. start_time(bb::BuildingBlock) = 0. start_time(container::ContainerBlock, index1, index2, more_indices...) = start_time(container, index1) + start_time(container[index1], index2, more_indices) +""" + effective_time(pulse) + effective_time(readout) + effective_time(container, indices...) + +Returns the effective time of a pulse or readout. + +For a pulse, this means the timepoint at which one would place an [`InstantRFPulseBlock`](@ref) if one would want to have a similar effect. + +For a reaodut, this is the time the readout passes through the zero-point in k-space (or the minimum in k-space if it does not go through zero). + +The time is given with respect to the start of the pulse or readout, or to the start of a container if the pulse/readout is identified using indices. +""" +effective_time(bb::ContainerBlock, index, indices...) = start_time(bb, index) + effective_time(bb[index], indices...) + """ end_time(container, args...) @@ -61,8 +79,7 @@ Returns the end time of the specific [`BuildingBlock`](@ref) within the containe The [`BuildingBlock`](@ref) is defined by one or more indices as defined below. """ end_time(bb::BuildingBlock) = duration(bb::BuildingBlock) -end_time(container::ContainerBlock, index1) = start_time(container, index1) + duration(container[index1]) -end_time(container::ContainerBlock, index1, index2, more_indices...) = start_time(container, index1) + end_time(container[index1], index2, more_indices) +end_time(container::ContainerBlock, index1, indices...) = start_time(container, index1) + end_time(container[index1], indices...) """ diff --git a/src/pulses/constant_pulses.jl b/src/pulses/constant_pulses.jl index 6e5625c..8275ce6 100644 --- a/src/pulses/constant_pulses.jl +++ b/src/pulses/constant_pulses.jl @@ -1,7 +1,7 @@ module ConstantPulses import JuMP: VariableRef, @constraint, @variable, value, Model import ...BuildingBlocks: RFPulseBlock, set_simple_constraints!, fixed -import ...Variables: variables, get_free_variable, flip_angle, phase, amplitude, frequency, bandwidth, start_time, end_time, VariableType, duration +import ...Variables: variables, get_free_variable, flip_angle, phase, amplitude, frequency, bandwidth, start_time, end_time, VariableType, duration, effective_time import ...BuildSequences: @global_model_constructor import ..FixedPulses: FixedPulse @@ -43,6 +43,7 @@ phase(pulse::ConstantPulse) = pulse.phase frequency(pulse::ConstantPulse) = pulse.frequency flip_angle(pulse::ConstantPulse) = amplitude(pulse) * duration(pulse) * 360 bandwidth(pulse::ConstantPulse) = 3.79098854 / duration(pulse) +effective_time(pulse::ConstantPulse) = duration(pulse) / 2 variables(::Type{<:ConstantPulse}) = [amplitude, duration, phase, frequency, flip_angle, bandwidth] diff --git a/src/pulses/fixed_pulses.jl b/src/pulses/fixed_pulses.jl index d7dd240..49de3fe 100644 --- a/src/pulses/fixed_pulses.jl +++ b/src/pulses/fixed_pulses.jl @@ -1,7 +1,7 @@ module FixedPulses -import ...BuildingBlocks: RFPulseBlock, fixed -import ...Variables: variables, duration +import ...BuildingBlocks: RFPulseBlock, fixed, BuildingBlockPrinter +import ...Variables: variables, duration, amplitude, effective_time """ @@ -33,8 +33,11 @@ end variables(::Type{<:FixedPulse}) = [] duration(fp::FixedPulse) = maximum(fp.time) +amplitude(fp::FixedPulse) = maximum(abs.(fp.amplitude)) +effective_time(pulse::FixedPulse) = pulse.time[argmax(abs(pulse.amplitude))] + +Base.show(io::IO, fp::FixedPulse) = print(io, "FixedPulse for $(duration(fp)) ms (peak at $(effective_time(fp)) ms)") -Base.show(io::IO, fp::FixedPulse) = print(io, "FixedPulse for $(duration(fp)) ms") """ diff --git a/src/pulses/instant_pulses.jl b/src/pulses/instant_pulses.jl index 9390d5f..5230306 100644 --- a/src/pulses/instant_pulses.jl +++ b/src/pulses/instant_pulses.jl @@ -1,7 +1,7 @@ module InstantPulses import JuMP: @constraint, @variable, VariableRef, value, Model import ...BuildingBlocks: RFPulseBlock, fixed -import ...Variables: flip_angle, phase, start_time, variables, duration, get_free_variable, VariableType +import ...Variables: flip_angle, phase, start_time, variables, duration, get_free_variable, VariableType, effective_time import ...BuildSequences: @global_model_constructor import ..FixedPulses: FixedInstantPulse @@ -25,8 +25,9 @@ end flip_angle(instant::InstantRFPulseBlock) = instant.flip_angle phase(instant::InstantRFPulseBlock) = instant.phase -duration(instant::InstantRFPulseBlock) = 0. +duration(::InstantRFPulseBlock) = 0. variables(::Type{<:InstantRFPulseBlock}) = [flip_angle, phase] +effective_time(::InstantRFPulseBlock) = 0. function fixed(block::InstantRFPulseBlock) diff --git a/src/pulses/pulses.jl b/src/pulses/pulses.jl index ae19637..8eabf44 100644 --- a/src/pulses/pulses.jl +++ b/src/pulses/pulses.jl @@ -4,6 +4,7 @@ include("instant_pulses.jl") include("constant_pulses.jl") include("sinc_pulses.jl") +import ..Variables: effective_time import .FixedPulses: FixedPulse import .InstantPulses: InstantRFPulseBlock import .ConstantPulses: ConstantPulse diff --git a/src/pulses/sinc_pulses.jl b/src/pulses/sinc_pulses.jl index c771a48..90b7988 100644 --- a/src/pulses/sinc_pulses.jl +++ b/src/pulses/sinc_pulses.jl @@ -4,7 +4,7 @@ import JuMP: VariableRef, @constraint, @variable, value, Model import QuadGK: quadgk import Polynomials: fit, Polynomial import ...BuildingBlocks: RFPulseBlock, set_simple_constraints!, fixed -import ...Variables: flip_angle, phase, amplitude, frequency, bandwidth, VariableType, variables, get_free_variable, duration +import ...Variables: flip_angle, phase, amplitude, frequency, bandwidth, VariableType, variables, get_free_variable, duration, effective_time import ...BuildSequences: @global_model_constructor import ..FixedPulses: FixedPulse @@ -101,6 +101,7 @@ flip_angle(pulse::SincPulse) = (pulse.nlobe_integral(N_left(pulse)) + pulse.nlob lobe_duration(pulse::SincPulse) = pulse.lobe_duration bandwidth(pulse::SincPulse) = 1 / lobe_duration(pulse) variables(::Type{<:SincPulse}) = [amplitude, N_left, N_right, duration, phase, frequency, flip_angle, lobe_duration, bandwidth] +effective_time(pulse::SincPulse) = N_left(pulse) * lobe_duration(pulse) function fixed(block::SincPulse) normed_times = -value(N_left(block)):0.1:value(N_right(block)) + 1e-5 diff --git a/src/readouts/instant_readouts.jl b/src/readouts/instant_readouts.jl index d1ee57e..21e74a6 100644 --- a/src/readouts/instant_readouts.jl +++ b/src/readouts/instant_readouts.jl @@ -1,5 +1,5 @@ module InstantReadouts -import ...BuildingBlocks: BuildingBlock, to_block, fixed +import ...BuildingBlocks: BuildingBlock, to_block, fixed, effective_time import ...Variables: variables, duration """ @@ -14,6 +14,7 @@ end variables(::Type{<:InstantReadout}) = [] to_block(::Type{<:InstantReadout}) = InstantReadout() -duration(::InstantReadout) =0. +duration(::InstantReadout) = 0. fixed(i::InstantReadout) = i +effective_time(::InstantReadout) = 0. end \ No newline at end of file diff --git a/src/variables.jl b/src/variables.jl index 51cb70b..f47f85c 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -54,8 +54,10 @@ variables() = [values(symbol_to_func)...] area_under_curve(bb) = qval(bb) +# These functions are more fully defined in building_blocks.jl function start_time end function end_time end +function effective_time end const VariableType = Union{Number, AbstractJuMPScalar} -- GitLab