diff --git a/src/MRIBuilder.jl b/src/MRIBuilder.jl index 6d55ef6c5abc749a18f8deea5f1d7b3917c316f0..f49f5f46786e2dc0a2233875b89fd9002bd2d08d 100644 --- a/src/MRIBuilder.jl +++ b/src/MRIBuilder.jl @@ -28,8 +28,8 @@ export variables, make_generic, @defvar, get_pulse, get_readout, get_pathway, ge import .Components: InstantPulse, ConstantPulse, SincPulse, GenericPulse, InstantGradient, SingleReadout, ADC, CompositePulse, edge_times export InstantPulse, ConstantPulse, SincPulse, GenericPulse, InstantGradient, SingleReadout, ADC, CompositePulse, edge_times -import .Containers: ContainerBlock, start_time, end_time, waveform, waveform_sequence, events, BaseBuildingBlock, BuildingBlock, Wait, BaseSequence, nrepeat, Sequence, AlternativeBlocks, match_blocks!, get_index_single_TR, iter_blocks, iter_instant_gradients, iter_instant_pulses -export ContainerBlock, start_time, end_time, waveform, waveform_sequence, events, BaseBuildingBlock, BuildingBlock, Wait, BaseSequence, nrepeat, Sequence, AlternativeBlocks, match_blocks!, get_index_single_TR, iter_blocks, iter_instant_gradients, iter_instant_pulses +import .Containers: ContainerBlock, start_time, end_time, waveform, waveform_sequence, events, BaseBuildingBlock, BuildingBlock, Wait, BaseSequence, nrepeat, Sequence, AbstractAlternativeBlocks, get_alternatives_name, get_alternatives_options, AlternativeBlocks, match_blocks!, get_index_single_TR, iter_blocks, iter_instant_gradients, iter_instant_pulses +export ContainerBlock, start_time, end_time, waveform, waveform_sequence, events, BaseBuildingBlock, BuildingBlock, Wait, BaseSequence, nrepeat, Sequence, AbstractAlternativeBlocks, get_alternatives_name, get_alternatives_options, AlternativeBlocks, match_blocks!, get_index_single_TR, iter_blocks, iter_instant_gradients, iter_instant_pulses import .Pathways: Pathway export Pathway diff --git a/src/containers/alternatives.jl b/src/containers/alternatives.jl index 8847d5f3e8f911943a812fbca9d093c97a2bae63..791e3fb1d811200cf495bdd26614be9c99f21375 100644 --- a/src/containers/alternatives.jl +++ b/src/containers/alternatives.jl @@ -4,6 +4,17 @@ import ..Abstract: ContainerBlock import ...BuildSequences: fixed import ...Variables: @defvar, make_generic, apply_simple_constraint! +""" +Parent type for all blocks that can take different MR sequence components between multiple repetitions of the sequence. + +They can be extended into their individual components using `adjust(<name>=:all)`. + +Each subtype of [`AbstractAlternativeBlock`](@ref) needs to implement two methods: +- [`get_alternatives_name`](@ref): returns the `name` used to identify this block in `adjust` +- [`get_alternatives_options`](@ref): returns a dictionary mapping the name of the different options to a [`ContainerBlock`](@ref) with the actual sequence building block. +""" +abstract type AbstractAlternativeBlocks <: ContainerBlock end + """ AlternativeBlocks(name, blocks) @@ -11,19 +22,35 @@ Represents a part of the sequence where there are multiple possible alternatives Variables can be matched across these alternatives using [`match_blocks!`](@ref). -The `name` is a symbol that is used to identify this `AlternativeBlocks` in the broader sequence. +The `name` is a symbol that is used to identify this `AlternativeBlocks` in the broader sequence (as in `adjust`). """ -struct AlternativeBlocks <: ContainerBlock +struct AlternativeBlocks <: AbstractAlternativeBlocks name :: Symbol options :: Dict{Any, <:ContainerBlock} end AlternativeBlocks(name::Symbol, options_vector::AbstractVector) = AlternativeBlocks(name, Dict(index => value for (index, value) in enumerate(options_vector))) -Base.getindex(alt::AlternativeBlocks, index) = alt.options[index] -Base.length(alt::AlternativeBlocks) = length(alt.options) +""" + get_alternatives_name(alternative_block) + +Get the name with which any [`AbstractAlternativeBlocks`](@ref) will be identified in a call to `adjust`. +""" +get_alternatives_name(alt::AlternativeBlocks) = alt.name -@defvar duration(alt::AlternativeBlocks) = maximum(variables.duration.(values(alt.options))) +""" + get_alternatives_options(alternative_block) + +Get the options available for a [`AbstractAlternativeBlocks`](@ref). +""" +get_alternatives_options(alt::AlternativeBlocks) = alt.options + +Base.getindex(alt::AbstractAlternativeBlocks, index) = get_alternatives_options(alt)[index] +Base.length(alt::AbstractAlternativeBlocks) = length(get_alternatives_options(alt)) +Base.keys(alt::AbstractAlternativeBlocks) = keys(get_alternatives_options(alt)) +Base.values(alt::AbstractAlternativeBlocks) = values(get_alternatives_options(alt)) + +@defvar duration(alt::AbstractAlternativeBlocks) = maximum(variables.duration.(values(alt.options))) """ match_blocks!(alternatives, function) @@ -32,8 +59,11 @@ Matches the outcome of given `function` on each of the building blocks in [`Alte For example, `match_blocks!(alternatives, duration)` will ensure that all the alternative building blocks have the same duration. """ -function match_blocks!(alternatives::AlternativeBlocks, func) - options = [values(alternatives.options)...] +function match_blocks!(alternatives::AbstractAlternativeBlocks, func) + options = [values(get_alternatives_options(alternatives.options))...] + if length(options) <= 1 + return + end baseline = func(options[1]) for other_block in options[2:end] apply_simple_constraint!(func(other_block), baseline) @@ -41,7 +71,7 @@ function match_blocks!(alternatives::AlternativeBlocks, func) end fixed(alt::AlternativeBlocks) = AlternativeBlocks(alt.name, Dict(key=>fixed(value) for (key, value) in alt.options)) -make_generic(alt::AlternativeBlocks) = AlternativeBlocks(alt.name, Dict(key=>make_generic(value) for (key, value) in alt.options)) +make_generic(alt::AbstractAlternativeBlocks) = AlternativeBlocks(get_alternatives_name(alt), get_alternatives_options(alt)) end \ No newline at end of file diff --git a/src/containers/containers.jl b/src/containers/containers.jl index 96198e5d98ad698ee789af1dacbcc23a85f1555e..55c92a1679bc47674301ea34abbb5227e153f97f 100644 --- a/src/containers/containers.jl +++ b/src/containers/containers.jl @@ -7,6 +7,6 @@ include("alternatives.jl") import .Abstract: ContainerBlock, start_time, end_time, iter_blocks, iter_instant_gradients, iter_instant_pulses import .BuildingBlocks: BaseBuildingBlock, BuildingBlock, Wait, waveform, waveform_sequence, events, ndim_grad import .BaseSequences: BaseSequence, Sequence, nrepeat, get_index_single_TR -import .Alternatives: AlternativeBlocks, match_blocks! +import .Alternatives: AbstractAlternativeBlocks, get_alternatives_name, get_alternatives_options, AlternativeBlocks, match_blocks! end \ No newline at end of file