Skip to content
Snippets Groups Projects
Verified Commit 6f6d908f authored by Michiel Cottaar's avatar Michiel Cottaar
Browse files

Add `get_pulse` and `get_gradient`

parent e8baaa05
No related branches found
No related tags found
No related merge requests found
module Abstract module Abstract
import ...Variables: AbstractBlock, duration, effective_time, gradient_strength, amplitude, phase, VariableType import ...Variables: AbstractBlock, duration, effective_time, gradient_strength, amplitude, phase, VariableType, get_pulse, get_gradient
import ...Components.Readouts: readout_times import ...Components.Readouts: readout_times
import ...Components: BaseComponent, InstantPulse, InstantGradient, ReadoutComponent import ...Components: BaseComponent, InstantPulse, InstantGradient, ReadoutComponent, NoGradient, RFPulseComponent, GradientWaveform
""" """
Parent type for `BuildingBlock` or `BaseSequence`, i.e., any building block that contains other MRI components/blocks. Parent type for `BuildingBlock` or `BaseSequence`, i.e., any building block that contains other MRI components/blocks.
...@@ -120,6 +120,29 @@ Returns all the [`InstantGradient`](@ref) within the sequence with their timings ...@@ -120,6 +120,29 @@ Returns all the [`InstantGradient`](@ref) within the sequence with their timings
iter_instant_gradients(container::ContainerBlock) = iter(container, Val(:instantgradient)) iter_instant_gradients(container::ContainerBlock) = iter(container, Val(:instantgradient))
iter(component::Tuple{<:Number, <:InstantGradient}, ::Val{:instantgradient}) = [component] iter(component::Tuple{<:Number, <:InstantGradient}, ::Val{:instantgradient}) = [component]
"""
get_pulse(container, time)
Gets the pulse running at a particular `time` (in ms) during a sequence of building block.
If there is a RF pulse, this function will return a tuple with 2 elements:
1. The [`RFPulseComponent`](@ref) itself
2. The time since the start of the pulse
If there is no active RF pulse, `nothing` is returned.
"""
function get_pulse end
"""
get_gradient(container, time)
Gets the gradient running at a particular `time` (in ms) during a sequence of building block.
This function will return a tuple with 2 elements:
1. The [`GradientWaveform`](@ref) itself (which could be a [`NoGradient`](@ref) object).
2. The time since the start of the gradient
"""
function get_gradient end
""" """
readout_times(sequence) readout_times(sequence)
......
...@@ -4,7 +4,7 @@ Defines [`BaseSequence`](@ref) and [`Sequence`](@ref) ...@@ -4,7 +4,7 @@ Defines [`BaseSequence`](@ref) and [`Sequence`](@ref)
module BaseSequences module BaseSequences
import StaticArrays: SVector import StaticArrays: SVector
import JuMP: @constraint import JuMP: @constraint
import ...Variables: get_free_variable, repetition_time, VariableType, duration, variables, VariableNotAvailable, Variables, set_simple_constraints!, TR, make_generic, gradient_strength, amplitude, phase, gradient_strength3 import ...Variables: get_free_variable, repetition_time, VariableType, duration, variables, VariableNotAvailable, Variables, set_simple_constraints!, TR, make_generic, gradient_strength, amplitude, phase, gradient_strength3, get_gradient, get_pulse
import ...BuildSequences: global_model, global_scanner import ...BuildSequences: global_model, global_scanner
import ...Components: EventComponent, NoGradient import ...Components: EventComponent, NoGradient
import ...Scanners: Scanner, B0 import ...Scanners: Scanner, B0
...@@ -114,7 +114,7 @@ function edge_times(seq::BaseSequence; tol=1e-6) ...@@ -114,7 +114,7 @@ function edge_times(seq::BaseSequence; tol=1e-6)
return sort(unique_res) return sort(unique_res)
end end
for fn in (:gradient_strength, :amplitude, :phase, :gradient_strength3) for fn in (:gradient_strength, :amplitude, :phase, :gradient_strength3, :get_gradient, :get_pulse)
@eval function $fn(sequence::BaseSequence, time::AbstractFloat) @eval function $fn(sequence::BaseSequence, time::AbstractFloat)
(block_time, block) = sequence(time) (block_time, block) = sequence(time)
return $fn(block, block_time) return $fn(block, block_time)
......
...@@ -9,7 +9,7 @@ import ..Abstract: ContainerBlock, start_time, readout_times, edge_times, end_ti ...@@ -9,7 +9,7 @@ import ..Abstract: ContainerBlock, start_time, readout_times, edge_times, end_ti
import ...BuildSequences: global_model import ...BuildSequences: global_model
import ...Components: BaseComponent, GradientWaveform, EventComponent, NoGradient, ChangingGradient, ConstantGradient, split_gradient, RFPulseComponent, ReadoutComponent, InstantGradient import ...Components: BaseComponent, GradientWaveform, EventComponent, NoGradient, ChangingGradient, ConstantGradient, split_gradient, RFPulseComponent, ReadoutComponent, InstantGradient
import ...Variables: qval, bmat_gradient, effective_time, get_free_variable, qval3, slew_rate, gradient_strength, amplitude, phase import ...Variables: qval, bmat_gradient, effective_time, get_free_variable, qval3, slew_rate, gradient_strength, amplitude, phase
import ...Variables: VariableType, duration, make_generic, get_pulse, get_readout, scanner_constraints! import ...Variables: VariableType, duration, make_generic, get_pulse, get_readout, scanner_constraints!, get_gradient
""" """
Basic BuildingBlock, which can consist of a gradient waveforms with any number of RF pulses/readouts overlaid Basic BuildingBlock, which can consist of a gradient waveforms with any number of RF pulses/readouts overlaid
...@@ -221,24 +221,38 @@ function edge_times(bb::BaseBuildingBlock) ...@@ -221,24 +221,38 @@ function edge_times(bb::BaseBuildingBlock)
return sort(unique(res)) return sort(unique(res))
end end
function get_pulse(bb::BaseBuildingBlock, time::Number)
for (key, component) in events(bb)
if component isa RFPulseComponent && (start_time(bb, key) <= time <= end_time(bb, key))
return (component, time - start_time(bb, key))
end
end
return nothing
end
for (fn, default_value) in ((:amplitude, 0.), (:phase, NaN)) for (fn, default_value) in ((:amplitude, 0.), (:phase, NaN))
@eval function $fn(bb::BaseBuildingBlock, time::Number) @eval function $fn(bb::BaseBuildingBlock, time::Number)
for (key, block) in events(bb) pulse = get_pulse(bb, time)
if block isa RFPulseComponent && start_time(bb, key) <= time <= end_time(bb, key) if isnothing(pulse)
return $fn(block, time - start_time(bb, key)) return $default_value
end
end end
return $default_value return $fn(pulse[1], pulse[2])
end end
end end
function gradient_strength(bb::BaseBuildingBlock, time::Number)
function get_gradient(bb::BaseBuildingBlock, time::Number)
for (key, block) in waveform_sequence(bb) for (key, block) in waveform_sequence(bb)
if (start_time(bb, key) <= time <= end_time(bb, key)) || (time end_time(bb, key)) if (start_time(bb, key) <= time <= end_time(bb, key)) || (time end_time(bb, key))
return gradient_strength(block, time - start_time(bb, key)) return (block, time - start_time(bb, key))
end end
end end
error("$bb with duration $(duration(bb)) does not define a gradient strength at time $time.") error("$bb with duration $(duration(bb)) does not define a gradient at time $time.")
end
function gradient_strength(bb::BaseBuildingBlock, time::Number)
(grad, time) = get_gradient(bb, time)
return gradient_strength(grad, time)
end end
""" """
......
...@@ -2,7 +2,7 @@ using MRIBuilder ...@@ -2,7 +2,7 @@ using MRIBuilder
using Test using Test
@testset "MRIBuilder.jl" begin @testset "MRIBuilder.jl" begin
#include("test_sequences.jl") include("test_sequences.jl")
#include("test_IO.jl") include("test_IO.jl")
include("test_plot.jl") include("test_plot.jl")
end end
...@@ -88,6 +88,17 @@ ...@@ -88,6 +88,17 @@
@test length(readout_times(seq)) > 50 @test length(readout_times(seq)) > 50
@test 67 < TE(seq) < 68 @test 67 < TE(seq) < 68
@test 72 < TR(seq) < 73 @test 72 < TR(seq) < 73
(pulse, t_pulse) = get_pulse(seq, 1.)
@test 1. - t_pulse min_rise_time rtol=1e-4
@test flip_angle(pulse) 90.
@test iszero(phase(pulse))
@test isnothing(get_pulse(seq, 10.))
(pulse, t_pulse) = get_pulse(seq, 35.)
@test 1.1 < t_pulse < 1.2
@test flip_angle(pulse) 180.
@test iszero(phase(pulse))
end end
end end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment