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

Allow SpoiltSliceSelect without SliceSelect part

parent d238716f
No related branches found
No related tags found
No related merge requests found
...@@ -4,7 +4,7 @@ import LinearAlgebra: norm ...@@ -4,7 +4,7 @@ import LinearAlgebra: norm
import StaticArrays: SVector import StaticArrays: SVector
import JuMP: @constraint, @objective, objective_function import JuMP: @constraint, @objective, objective_function
import ...BuildSequences: global_model, global_scanner import ...BuildSequences: global_model, global_scanner
import ...Variables: VariableType, duration, rise_time, flat_time, effective_time, qval, gradient_strength, slew_rate, inverse_slice_thickness, get_free_variable, get_pulse import ...Variables: VariableType, duration, rise_time, flat_time, effective_time, qval, gradient_strength, slew_rate, inverse_slice_thickness, get_free_variable, get_pulse, set_simple_constraints!
import ...Components: ChangingGradient, ConstantGradient, RFPulseComponent import ...Components: ChangingGradient, ConstantGradient, RFPulseComponent
import ..BaseBuildingBlocks: BaseBuildingBlock import ..BaseBuildingBlocks: BaseBuildingBlock
...@@ -35,26 +35,46 @@ struct SpoiltSliceSelect <: BaseBuildingBlock ...@@ -35,26 +35,46 @@ struct SpoiltSliceSelect <: BaseBuildingBlock
slew_rate :: Number slew_rate :: Number
end end
function SpoiltSliceSelect(pulse::RFPulseComponent; orientation=[0, 0, 1], group=nothing, spoiler_scale=nothing, kwargs...) function SpoiltSliceSelect(pulse::RFPulseComponent; orientation=[0, 0, 1], group=nothing, spoiler_scale=nothing, slice_thickness=nothing, kwargs...)
model = global_model() model = global_model()
res = SpoiltSliceSelect( res = nothing
orientation ./ norm(orientation), if isinf(slice_thickness)
get_free_variable(nothing; start=0.1), rise_time_var = get_free_variable(nothing)
get_free_variable(nothing; start=0.1), flat_time_var = get_free_variable(nothing)
get_free_variable(nothing; start=0.05), res = SpoiltSliceSelect(
pulse, orientation ./ norm(orientation),
get_free_variable(nothing; start=0.1), rise_time_var,
get_free_variable(nothing; start=0.1), flat_time_var,
group, 0.,
slew_rate(global_scanner()), pulse,
) flat_time_var,
for time_var in (res.rise_time1, res.flat_time1, res.diff_time, res.flat_time2, res.fall_time2) rise_time_var,
@constraint model time_var >= 0 group,
slew_rate(global_scanner()),
)
for time_var in (rise_time, flat_time)
@constraint model time_var >= 0
end
else
res = SpoiltSliceSelect(
orientation ./ norm(orientation),
get_free_variable(nothing; start=0.1),
get_free_variable(nothing; start=0.1),
get_free_variable(nothing; start=0.05),
pulse,
get_free_variable(nothing; start=0.1),
get_free_variable(nothing; start=0.1),
group,
slew_rate(global_scanner()),
)
for time_var in (res.rise_time1, res.flat_time1, res.diff_time, res.flat_time2, res.fall_time2)
@constraint model time_var >= 0
end
@constraint model res.diff_time <= res.rise_time1
@constraint model res.diff_time <= res.fall_time2
@constraint model qval(res, nothing, 1) == qval(res, 1, nothing)
end end
@constraint model res.diff_time <= res.rise_time1
@constraint model res.diff_time <= res.fall_time2
@constraint model qval(res, nothing, 1) == qval(res, 1, nothing)
if !isnothing(spoiler_scale) if !isnothing(spoiler_scale)
if spoiler_scale == :min # note that spoiler_scale is inverse of qval if spoiler_scale == :min # note that spoiler_scale is inverse of qval
@objective model Min objective_function(model) - qval(res, nothing, 1) @objective model Min objective_function(model) - qval(res, nothing, 1)
......
...@@ -96,8 +96,9 @@ For an [`InstantPulse`](@ref) (i.e., `shape=:instant`), only the `flip_angle`, ` ...@@ -96,8 +96,9 @@ For an [`InstantPulse`](@ref) (i.e., `shape=:instant`), only the `flip_angle`, `
- `spoiler`: set to the spatial scale on which the spins should be dephased in mm. For rotating spoilers, this does include the contribution from the slice select gradient as well. - `spoiler`: set to the spatial scale on which the spins should be dephased in mm. For rotating spoilers, this does include the contribution from the slice select gradient as well.
- `rotate_grad`: name of the parameter with which the slice selection and spoiler gradient will be rotated after sequence optimisation (default: `:FOV`). - `rotate_grad`: name of the parameter with which the slice selection and spoiler gradient will be rotated after sequence optimisation (default: `:FOV`).
- `scanner`: overrides the [`global_scanner`](@ref) for this part of the sequence. Recommended to set only if not part of a larger sequence. - `scanner`: overrides the [`global_scanner`](@ref) for this part of the sequence. Recommended to set only if not part of a larger sequence.
- `orientation`: vector with orientation of slice select gradient and pulses (defaults: z-direction).
""" """
function refocus_pulse(; flip_angle=180, phase=0., frequency=0., shape=:sinc, slice_thickness=Inf, Nzeros=3, group=nothing, rotate_grad=:FOV, bandwidth=nothing, duration=nothing, spoiler=Inf, scanner=nothing, optimise=false) function refocus_pulse(; flip_angle=180, phase=0., frequency=0., shape=:sinc, slice_thickness=Inf, Nzeros=3, group=nothing, bandwidth=nothing, duration=nothing, spoiler=Inf, scanner=nothing, optimise=false, orientation=[0, 0, 1])
build_sequence(scanner; optimise=optimise) do build_sequence(scanner; optimise=optimise) do
pulse = _get_pulse(shape, flip_angle, phase, frequency, Nzeros, group, bandwidth, duration) pulse = _get_pulse(shape, flip_angle, phase, frequency, Nzeros, group, bandwidth, duration)
if pulse isa InstantPulse && !isinf(slice_thickness) if pulse isa InstantPulse && !isinf(slice_thickness)
...@@ -107,18 +108,11 @@ function refocus_pulse(; flip_angle=180, phase=0., frequency=0., shape=:sinc, sl ...@@ -107,18 +108,11 @@ function refocus_pulse(; flip_angle=180, phase=0., frequency=0., shape=:sinc, sl
if isinf(slice_thickness) if isinf(slice_thickness)
return pulse return pulse
else else
return Trapezoid(pulse=pulse, duration=:min, slice_thickness=[Inf, Inf, slice_thickness], orientation=[0, 0, 1.], rotate=rotate_grad) return SliceSelect(pulse=pulse, duration=:min, slice_thickness=slice_thickness, orientation=orientation, group=:FOV)
end end
else else
orientation=isnothing(rotate_grad) ? [1, 1, 1] : [0, 0, 1] res = SpoiltSliceSelect(pulse; orientation=orientation, duration=:min, group=:FOV, slice_thickness=slice_thickness, spoiler_scale=spoiler)
if isinf(slice_thickness) return res
grad = Trapezoid(orientation=orientation, duration=:min, rotate=rotate_grad)
@constraint global_model() qvec(grad)[3] == 2π * 1e-3 / spoiler
return Sequence(grad, pulse, grad; TR=Inf)
else
res = SpoiltSliceSelect(pulse; orientation=orientation, duration=:min, rotate=rotate_grad, slice_thickness=slice_thickness, spoiler_scale=spoiler)
return res
end
end end
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