diff --git a/src/all_building_blocks/spoilt_slice_selects.jl b/src/all_building_blocks/spoilt_slice_selects.jl index 2210b0ad09b969c22f2bb0e7d4eb08febe972492..2c40aa0ae7ef6b8bdd9d10c2066b81da7dc85875 100644 --- a/src/all_building_blocks/spoilt_slice_selects.jl +++ b/src/all_building_blocks/spoilt_slice_selects.jl @@ -4,7 +4,7 @@ import LinearAlgebra: norm import StaticArrays: SVector import JuMP: @constraint, @objective, objective_function import ...BuildSequences: global_model, global_scanner -import ...Variables: VariableType, duration, rise_time, flat_time, effective_time, qvec, gradient_strength, slew_rate, inverse_slice_thickness, get_free_variable +import ...Variables: VariableType, duration, rise_time, flat_time, effective_time, qvec, gradient_strength, slew_rate, inverse_slice_thickness, get_free_variable, get_pulse import ...Components: ChangingGradient, ConstantGradient, RFPulseComponent import ..BaseBuildingBlocks: BaseBuildingBlock @@ -92,6 +92,7 @@ duration(spoilt::SpoiltSliceSelect) = sum(rise_time(spoilt)) + sum(flat_time(spo slew_rate(spoilt::SpoiltSliceSelect) = spoilt.slew_rate inverse_slice_thickness(spoilt::SpoiltSliceSelect) = spoilt.slew_rate * spoilt.diff_time * duration(spoilt.pulse) * 1e3 gradient_strength(spoilt::SpoiltSliceSelect) = slew_rate(spoilt) * max(spoilt.rise_time1, spoilt.fall_time2) +get_pulse(spoilt::SpoiltSliceSelect) = spoilt.pulse function all_gradient_strengths(spoilt::SpoiltSliceSelect) grad1 = spoilt.slew_rate * rise_time(spoilt)[1] grad2 = grad1 - spoilt.slew_rate * flat_time(spoilt)[1] diff --git a/src/all_building_blocks/trapezoids.jl b/src/all_building_blocks/trapezoids.jl index 21a1dff2330b69c46c6c635cce9ecc30947e4885..58d6aeacd97e6aa900d23cbbbaf1ac6f72178f31 100644 --- a/src/all_building_blocks/trapezoids.jl +++ b/src/all_building_blocks/trapezoids.jl @@ -7,7 +7,7 @@ import JuMP: @constraint import StaticArrays: SVector import LinearAlgebra: norm import ...Variables: qvec, rise_time, flat_time, slew_rate, gradient_strength, variables, duration, δ, get_free_variable, VariableType, inverse_bandwidth, effective_time, qval_square, duration, set_simple_constraints!, scanner_constraints!, inverse_slice_thickness -import ...Variables: Variables, all_variables_symbols, dwell_time, inverse_fov, inverse_voxel_size, fov, voxel_size +import ...Variables: Variables, all_variables_symbols, dwell_time, inverse_fov, inverse_voxel_size, fov, voxel_size, get_gradient, get_pulse, get_readout import ...BuildSequences: global_model import ...Components: ChangingGradient, ConstantGradient, RFPulseComponent, ADC import ..BaseBuildingBlocks: BaseBuildingBlock @@ -108,10 +108,6 @@ slew_rate(g::Trapezoid) = g.slew_rate δ(g::Trapezoid) = rise_time(g) + flat_time(g) duration(g::Trapezoid) = 2 * rise_time(g) + flat_time(g) -for func in (:rise_time, :flat_time, :gradient_strength, :slew_rate, :δ, :duration, :qvec) - @eval $func(bt::BaseTrapezoid) = $func(bt.trapezoid) -end - qvec(g::BaseTrapezoid, ::Nothing, ::Nothing) = δ(g) .* gradient_strength(g) .* 2π """ @@ -146,12 +142,8 @@ Base.getindex(pg::SliceSelect, ::Val{:pulse}) = pg.pulse inverse_slice_thickness(ss::SliceSelect) = 1e3 * gradient_strength(ss.trapezoid) .* inverse_bandwidth(ss.pulse) -for func in all_variables_symbols[:pulse] - if func in (:inverse_slice_thickness, :slice_thickness) - continue - end - Variables.$func(ss::SliceSelect) = Variables.$func(ss.pulse) -end +get_pulse(ss::SliceSelect) = ss.pulse +get_gradient(ss::SliceSelect) = ss.trapezoid """ LineReadout(adc; ramp_overlap=1., orientation=nothing, group=nothing, variables...) @@ -188,11 +180,7 @@ ramp_overlap(lr::LineReadout) = lr.ramp_overlap inverse_fov(lr::LineReadout) = @. 1e3 * dwell_time(lr.adc) * gradient_strength(lr.trapezoid) inverse_voxel_size(lr::LineReadout) = @. 1e3 * duration(lr.adc) * gradient_strength(lr.trapezoid) -for func in all_variables_symbols[:readout] - if func in (:inverse_fov, :slice_fov, :inverse_voxel_size, :slice_voxel_size, :ramp_overlap) - continue - end - Variables.$func(lr::LineReadout) = Variables.$func(lr.adc) -end +get_readout(lr::LineReadout) = rl.adc +get_gradient(lr::LineReadout) = rl.trapezoid end \ No newline at end of file diff --git a/src/variables.jl b/src/variables.jl index 1101fd02bbea9f70a887db5854dd368937f31ff2..7ce17ff4d5feb8ce44b607c4d21ab7b99ed2d769 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -8,6 +8,7 @@ In addition this defines: - [`VariableNotAvailable`](@ref): error raised if variable is not defined for specific [`AbstractBlock`](@ref). - [`set_simple_constraints`](@ref): call [`apply_simple_constraint`](@ref) for each keyword argument. - [`apply_simple_constraint`](@ref): set a simple equality constraint. +- [`get_pulse`](@ref)/[`get_gradient`](@ref)/[`get_readout`](@ref): Used to get the pulse/gradient/readout part of a building block """ module Variables import JuMP: @variable, Model, @objective, objective_function, value, AbstractJuMPScalar @@ -133,6 +134,33 @@ function get_free_variable(::Val{:max}) return var end +""" + get_pulse(building_block)] + +Get the pulse played out during the building block. + +Any `pulse` variables not explicitly defined for this building block will be passed on to the pulse. +""" +function get_pulse end + +""" + get_gradient(building_block)] + +Get the gradient played out during the building block. + +Any `gradient` variables not explicitly defined for this building block will be passed on to the gradient. +""" +function get_gradient end + +""" + get_readout(building_block)] + +Get the readout played out during the building block. + +Any `readout` variables not explicitly defined for this building block will be passed on to the readout. +""" +function get_gradient end + """ bmat_gradient(gradient::GradientBlock, qstart=(0, 0, 0)) @@ -165,29 +193,38 @@ function Base.showerror(io::IO, e::VariableNotAvailable) end -for variable_func in keys(variables) - if variable_func in [:qval_square, :qval] - continue - end - @eval function Variables.$variable_func(bb::BuildingBlock) - if Variables.$variable_func in keys(alternative_variables) - alt_var, forward, backward, _ = alternative_variables[Variables.$variable_func] +for (target_name, all_vars) in pairs(all_variables_symbols) + for variable_func in keys(all_vars) + if variable_func in [:qval_square, :qval] + continue + end + @eval function Variables.$variable_func(bb::BuildingBlock) try - value = alt_var(bb) - if value isa Number - return backward(value) - elseif value isa AbstractArray{<:Number} - return backward.(value) + if Variables.$variable_func in keys(alternative_variables) + alt_var, forward, backward, _ = alternative_variables[Variables.$variable_func] + try + value = alt_var(bb) + if value isa Number + return backward(value) + elseif value isa AbstractArray{<:Number} + return backward.(value) + end + catch e + if e isa VariableNotAvailable + throw(VariableNotAvailable(typeof(bb), Variables.$variable_func)) + end + rethrow() + end + throw(VariableNotAvailable(typeof(bb), Variables.$variable_func, alt_var)) end + throw(VariableNotAvailable(typeof(bb), Variables.$variable_func)) catch e - if e isa VariableNotAvailable - throw(VariableNotAvailable(typeof(bb), Variables.$variable_func)) + if e isa VariableNotAvailable && hasmethod(get_$(target_name), Tuple(typeof(bb))) && $(target_name) in (:pulse, :readout) + return Variables.$variable_func(get_$(target_name)(bb)) end rethrow() end - throw(VariableNotAvailable(typeof(bb), Variables.$variable_func, alt_var)) end - throw(VariableNotAvailable(typeof(bb), Variables.$variable_func)) end end