Skip to content
Snippets Groups Projects
Unverified Commit c86d3118 authored by Michiel Cottaar's avatar Michiel Cottaar
Browse files

Fix tests

parent d26c9e97
No related branches found
No related tags found
1 merge request!2Define variables through new @defvar macro
......@@ -66,7 +66,7 @@ _mult(g1::AbstractVector, g2::AbstractVector) = g1 .* permutedims(g2)
end
function split_gradient(cgb::ConstantGradient, times::VariableType...)
durations = [times[1], [t[2] - t[1] for t in zip(times[1:end-1], times[2:end])]..., duration(cgb) - times[end]]
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
......
......@@ -57,8 +57,8 @@ end
@defvar gradient qvec(ig::InstantGradient3D) = ig.qvec
variables.duration.f(::InstantGradient) = 0.
variables.effective_time.f(::InstantGradient) = 0.
@defvar duration(::InstantGradient) = 0.
@defvar effective_time(::InstantGradient) = 0.
@defvar gradient bmat_gradient(::InstantGradient, qstart=nothing) = zero(SMatrix{3, 3, Float64, 3})
make_generic(ig::InstantGradient) = ig
......
......@@ -31,7 +31,7 @@ struct GenericPulse <: RFPulseComponent
@assert all(time .>= 0)
if isnothing(effective_time)
test_res = new(Float64.(time), Float64.(amplitude), Float64.(phase), 0.)
effective_time = time_halfway_flip(test_res)
effective_time = variables.time_halfway_flip(test_res)
end
return new(Float64.(time), Float64.(amplitude), Float64.(phase), Float64(effective_time))
end
......@@ -56,12 +56,12 @@ function GenericPulse(pulse::GenericPulse, t1::Number, t2::Number)
pnew = pulse.phase[use]
if !(t1 tnew[1])
pushfirst!(tnew, t1)
pushfirst!(anew, amplitude(pulse, t1))
pushfirst!(pnew, phase(pulse, t1))
pushfirst!(anew, variables.amplitude(pulse, t1))
pushfirst!(pnew, variables.phase(pulse, t1))
elseif !(t2 tnew[end])
push!(tnew, t2)
push!(anew, amplitude(pulse, t2))
push!(pnew, phase(pulse, t2))
push!(anew, variables.amplitude(pulse, t2))
push!(pnew, variables.phase(pulse, t2))
end
return GenericPulse(tnew .- t1, anew, pnew, pulse.effective_time - t1)
end
......
......@@ -99,7 +99,7 @@ end
end
@defvar begin
amplitude(pulse::SincPulse, time::Number) = variables.amplitude(pulse) * normalised_function(abs((time - variables.effective_time(pulse))) / variables.lobe_duration(pulse), N_left(pulse), N_right(pulse); apodise=pulse.apodise)
amplitude(pulse::SincPulse, time::Number) = variables.amplitude(pulse) * normalised_function(abs((time - variables.effective_time(pulse))) / variables.lobe_duration(pulse), variables.N_left(pulse), variables.N_right(pulse); apodise=pulse.apodise)
phase(pulse::SincPulse, time::Number) = variables.phase(pulse) + variables.frequency(pulse) * (time - variables.effective_time(pulse)) * 360.
frequency(pulse::SincPulse, time::Number) = variables.frequency(pulse)
end
......
......@@ -37,6 +37,7 @@ end_time(block::Tuple{<:VariableType, <:AbstractBlock}) = variables.duration(blo
effective_time(container::ContainerBlock, index, indices...) = start_time(container, index) + variables.effective_time(container[index], indices...)
effective_time(block::Tuple{<:VariableType, <:AbstractBlock}) = block[1] + variables.effective_time(block[2])
end
"""
effective_time(container, indices...)
......@@ -46,7 +47,7 @@ This will crash if the component does not have an [`effective_time`](@ref) (e.g.
Also see [`variables.duration`](@ref), [`start_time`](@ref), and [`end_time`](@ref)
"""
effective_time
variables.effective_time
"""
......@@ -147,8 +148,8 @@ function get_gradient end
Returns all the times that the sequence will readout.
"""
readout_times
variables.readout_times
iter(component::Tuple{<:Number, <:ReadoutComponent}, ::Val{:readout}) = [(time, nothing) for time in readout_times(component[2])]
iter(component::Tuple{<:Number, <:ReadoutComponent}, ::Val{:readout}) = [(time, nothing) for time in variables.readout_times(component[2])]
end
\ No newline at end of file
......@@ -232,7 +232,7 @@ Computes the area under the curve for the gradient waveform in [`BaseBuildingBlo
If `first_event` is set to something else than `nothing`, only the gradient waveform after this RF pulse/Readout will be considered.
Similarly, if `last_event` is set to something else than `nothing`, only the gradient waveform up to this RF pulse/Readout will be considered.
"""
qvec
variables.qvec
function edge_times(bb::BaseBuildingBlock)
res = Float64[]
......
......@@ -170,12 +170,12 @@ struct SliceSelect{N} <: BaseTrapezoid{N}
pulse :: RFPulseComponent
end
function SliceSelect(pulse::RFPulseComponent; orientation=nothing, rise_time=nothing, group=nothing, slew_rate=nothing, variables...)
function SliceSelect(pulse::RFPulseComponent; orientation=nothing, rise_time=nothing, group=nothing, slew_rate=nothing, vars...)
res = SliceSelect(
Trapezoid(; orientation=orientation, rise_time=rise_time, flat_time=duration(pulse), group=group, slew_rate=slew_rate),
Trapezoid(; orientation=orientation, rise_time=rise_time, flat_time=variables.duration(pulse), group=group, slew_rate=slew_rate),
pulse
)
set_simple_constraints!(res, variables)
set_simple_constraints!(res, vars)
return res
end
......@@ -225,7 +225,7 @@ function LineReadout(adc::ADC; ramp_overlap=nothing, orientation=nothing, group=
end
Base.keys(::LineReadout) = (Val(:rise), Val(:adc), Val(:flat), Val(:fall))
Base.getindex(lr::LineReadout, ::Val{:adc}) = ((1 - ramp_overlap(lr)) * rise_time(lr), lr.adc)
Base.getindex(lr::LineReadout, ::Val{:adc}) = ((1 - variables.ramp_overlap(lr)) * variables.rise_time(lr), lr.adc)
@defvar begin
ramp_overlap(lr::LineReadout) = lr.ramp_overlap
......
......@@ -27,7 +27,7 @@ The RF pulses cause mappings between these different states as described below.
- `:refocus`/`:invert`/180: Flips the sign of the spin state (i.e., +longitudinal <-> -longitudinal, +transverse <-> -transverse)
- `:excite`/90: Takes spin state one step along the following sequence +longitudinal -> +transverse -> -longitudinal -> -transverse -> +longitudinal
- `:neg_excite`/270/-90: Inverse step compared with `:excite`.
- `readout_index`: After encountering the number of pulses as defined in `pulse_effects`, continue the `PathWay` until the readout given by `index` is reached. If set to 0 the `PathWay` is terminated immediately after the last RF pulse.
- `readout_index`: After encountering the number of pulses as defined in `pulse_effects`, continue the `Pathway` until the readout given by `index` is reached. If set to 0 the `Pathway` is terminated immediately after the last RF pulse.
- `group`: which gradient grouping to consider for the `qvec` and `bmat`. If not set, all gradients will be considered (using their current alignment).
## Attributes
......@@ -169,7 +169,7 @@ variables.bval
"""
get_pathway(sequence)
Gets the main [`PathWay`](@ref) that spins are expected to experience in the sequence.
Gets the main [`Pathway`](@ref) that spins are expected to experience in the sequence.
Multiple pathways might be returned as an array or (named)tuple.
"""
......
......@@ -92,7 +92,7 @@ Main module containing all the MRIBuilder sequence variables.
All variables are available as members of this module, e.g.
`variables.echo_time` returns the echo time variable.
New variables can be defined using [`@defvar`](@ref).
New variables can be defined using `@defvar`.
Set constraints on variables by passing them on as keywords during the sequence generation,
e.g., `seq=SpinEcho(echo_time=70)`.
......@@ -360,9 +360,6 @@ Returns the gradient orientation.
function gradient_orientation end
@defvar function effective_time end
function (var::Variable)(block::AbstractBlock, args...; kwargs...)
if !applicable(var.f, block, args...) && !isnothing(var.getter)
apply_to = var.getter(block)
......
......@@ -24,7 +24,7 @@
end
# Single ADC event
@test length(readout_times(seq)) == 1024
@test length(variables.readout_times(seq)) == 1024
@test variables.readout_times(seq)[1] 0.22 + 5 + 0.02 + 0.5 * 0.3125
@test variables.readout_times(seq)[end] 0.22 + 5 + 0.02 + 1023.5 * 0.3125
......@@ -56,7 +56,7 @@
0.02 + # RF ringdown time (added by block duration)
29.730 # Delay until ADC start (to get start at ADC at TE=30)
)
@test length(readout_times(seq)) == 8192
@test length(variables.readout_times(seq)) == 8192
@test variables.readout_times(seq)[1] start_adc + 0.5 * 0.03125
@test variables.readout_times(seq)[end] start_adc + 8191.5 * 0.03125
end
......@@ -101,7 +101,7 @@
seq_json = read_sequence(io, format=:serialize)
@test variables.duration(seq_orig) == variables.duration(seq_json)
@test length(seq_orig) == length(seq_json)
@test all(duration.(seq_orig) .== duration.(seq_json))
@test all(variables.duration.(seq_orig) .== variables.duration.(seq_json))
@test iszero(length(iter_instant_gradients(seq_json)))
@test iszero(length(iter_instant_pulses(seq_json)))
@test all(variables.readout_times(seq_json) .== variables.readout_times(seq_orig))
......@@ -120,7 +120,7 @@
seq_json = read_sequence(io; format=:serialize)
@test variables.duration(seq_orig) == variables.duration(seq_json)
@test length(seq_orig) == length(seq_json)
@test all(duration.(seq_orig) .== duration.(seq_json))
@test all(variables.duration.(seq_orig) .== variables.duration.(seq_json))
@test length(iter_instant_gradients(seq_json)) == length(iter_instant_gradients(seq_json))
@test length(iter_instant_pulses(seq_json)) == length(iter_instant_pulses(seq_json))
@test all(variables.readout_times(seq_json) .== variables.readout_times(seq_orig))
......
......@@ -26,7 +26,7 @@
@testset "SincPulse" begin
sp = SincPulse(amplitude=1., frequency=2., phase=0., lobe_duration=10., Nzeros=(2, 1))
@test duration(sp) 30.
@test variables.duration(sp) 30.
@test variables.amplitude(sp, 20) 1.
@test variables.amplitude(sp, 0) 0. atol=1e-8
......
......@@ -27,7 +27,7 @@
seq = DiffusionSpinEcho(TE=:min, bval=1.)
@test length(seq) == 9
grad_duration = variables.TE(seq) / 2
@test all(isapprox.(duration.(seq), [0., 0., grad_duration, 0., 0., 0., grad_duration, 0., 0.], atol=1e-6))
@test all(isapprox.(variables.duration.(seq), [0., 0., grad_duration, 0., 0., 0., grad_duration, 0., 0.], atol=1e-6))
@test length([iter_instant_pulses(seq)...]) == 2
@test length([iter_instant_gradients(seq)...]) == 0.
@test variables.bval(seq) 1.
......@@ -38,24 +38,24 @@
@testset "Maximise b-value" begin
seq = DiffusionSpinEcho(TE=80., bval=:max)
@test length(seq) == 9
@test all(isapprox.(duration.(seq), [0., 0., 40., 0., 0., 0., 40., 0., 0.], atol=1e-4, rtol=1e-4))
@test all(isapprox.(variables.duration.(seq), [0., 0., 40., 0., 0., 0., 40., 0., 0.], atol=1e-4, rtol=1e-4))
@test length([iter_instant_pulses(seq)...]) == 2
@test length([iter_instant_gradients(seq)...]) == 0.
@test variables.TE(seq) 80.
@test variables.duration(seq) 80.
@test 4.8 < bval(seq) < 4.9
@test 4.8 < variables.bval(seq) < 4.9
@test variables.rise_time(seq[:gradient]) min_rise_time rtol=1e-4
@test all(isapprox.(edge_times(seq, tol=1e-3), [0., min_rise_time, 40. - min_rise_time, 40, 40 + min_rise_time, 80 - min_rise_time, 80.], atol=1e-4))
# can also maximise q-value
seq2 = DiffusionSpinEcho(TE=80., qval=:max)
@test all(isapprox.(duration.(seq), duration.(seq2), atol=1e-4, rtol=1e-4))
@test all(isapprox.(variables.duration.(seq), variables.duration.(seq2), atol=1e-4, rtol=1e-4))
@test variables.TE(seq) variables.TE(seq2) atol=1e-4 rtol=1e-4
@test variables.bval(seq) variables.bval(seq2) atol=1e-4 rtol=1e-4
end
@testset "Set diffusion time Δ" begin
seq = DiffusionSpinEcho(TE=80., Δ=70., qval=:max)
@test all(isapprox.(duration.(seq), [0., 0., 10., 30., 0., 30., 10., 0., 0.], atol=1e-4, rtol=1e-4))
@test all(isapprox.(variables.duration.(seq), [0., 0., 10., 30., 0., 30., 10., 0., 0.], atol=1e-4, rtol=1e-4))
@test variables.Δ(seq) 70.
@test variables.TE(seq) 80.
@test variables.duration(seq) 80.
......@@ -66,7 +66,7 @@
end
@testset "Set gradient duration" begin
seq = DiffusionSpinEcho(TE=80., gradient=(duration=10., ), bval=:max)
@test all(isapprox.(duration.(seq), [0., 0., 10., 30., 0., 30., 10., 0., 0.], atol=1e-4, rtol=1e-4))
@test all(isapprox.(variables.duration.(seq), [0., 0., 10., 30., 0., 30., 10., 0., 0.], atol=1e-4, rtol=1e-4))
@test variables.Δ(seq) 70. rtol=1e-4
@test variables.TE(seq) 80.
@test variables.duration(seq) 80.
......@@ -79,33 +79,33 @@
@testset "slice-select DW-SE" begin
seq = DiffusionSpinEcho(duration=:min, bval=2., slice_thickness=2.)
@test length(seq) == 9
@test duration(seq[1]) > 1.
@test variables.duration(seq[1]) > 1.
for index in 1:9
if index in [2, 4, 8, 9]
@test abs(duration(seq[index])) < 1e-6
@test abs(variables.duration(seq[index])) < 1e-6
else
@test abs(duration(seq[index])) > 1
@test abs(variables.duration(seq[index])) > 1
end
end
@test duration(seq[:gradient]) duration(seq[:gradient2])
@test variables.duration(seq[:gradient]) variables.duration(seq[:gradient2])
@test variables.bval(seq) 2.
@test length(readout_times(seq)) == 1
@test length(variables.readout_times(seq)) == 1
@test variables.readout_times(seq)[1] > variables.TE(seq)
end
@testset "voxel-wise DW-SE" begin
seq = DiffusionSpinEcho(duration=:min, bval=2., voxel_size=2., fov=(20, 20, 20))
@test length(seq) == 9
@test duration(seq[1]) > 1.
@test variables.duration(seq[1]) > 1.
for index in 1:9
if index in [2, 6, 8]
@test abs(duration(seq[index])) < 1e-6
@test abs(variables.duration(seq[index])) < 1e-6
else
@test abs(duration(seq[index])) > 1
@test abs(variables.duration(seq[index])) > 1
end
end
@test duration(seq[:gradient]) duration(seq[:gradient2])
@test variables.duration(seq[:gradient]) variables.duration(seq[:gradient2])
@test variables.bval(seq) 2.
@test length(readout_times(seq)) > 50
@test length(variables.readout_times(seq)) > 50
@test 67 < variables.TE(seq) < 68
@test 72 < variables.duration(seq) < 73
......
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