diff --git a/src/build_sequences.jl b/src/build_sequences.jl index 5600724d53a6a9426678e9f74f34e9fc30c5c957..461e3516298badaae4b48502300ca94af4814a94 100644 --- a/src/build_sequences.jl +++ b/src/build_sequences.jl @@ -1,5 +1,5 @@ module BuildSequences -import JuMP: Model, optimizer_with_attributes, optimize! +import JuMP: Model, optimizer_with_attributes, optimize!, AbstractJuMPScalar, value import Ipopt import Juniper import ..Scanners: Scanner @@ -44,7 +44,7 @@ function build_sequence(f::Function, scanner::Scanner, model::Model) try sequence = f(model) optimize!(model) - return sequence + return fixed(sequence) finally GLOBAL_MODEL[] = prev_model GLOBAL_SCANNER[] = prev_scanner @@ -74,4 +74,17 @@ function global_scanner() end +""" + fixed(building_block) + +Returns an equiavalent [`BuildingBlock`](@ref) with all free variables replaced by numbers. +This will only work after calling [`optimize!`](@ref)([`global_model`](@ref)()). +It is used internally by [`build_sequence`](@ref). +""" +fixed(some_value) = some_value +fixed(jump_variable::AbstractJuMPScalar) = value(jump_variable) +fixed(jump_variable::AbstractArray) = fixed.(jump_variable) + + + end \ No newline at end of file diff --git a/src/building_blocks.jl b/src/building_blocks.jl index a2cab1dfb5f51c9af81fa28ec461d03536f3e2cb..4d9d459aa6a6956a7429a87a8aead766b49133e4 100644 --- a/src/building_blocks.jl +++ b/src/building_blocks.jl @@ -2,7 +2,7 @@ module BuildingBlocks import JuMP: value, Model, @constraint, @objective, objective_function, AbstractJuMPScalar import Printf: @sprintf import ..Variables: variables, start_time, duration, end_time, gradient_strength, slew_rate, effective_time, VariableType, qval_square -import ..BuildSequences: global_model, global_scanner +import ..BuildSequences: global_model, global_scanner, fixed import ..Scanners: Scanner """ @@ -10,7 +10,6 @@ Parent type for all individual components out of which a sequence can be built. Required methods: - [`duration`](@ref)(block, parameters): Return block duration in ms. -- [`fixed`](block): Return the equivalent fixed BuildingBlock (i.e., `FixedBlock`, `FixedPulse`, `FixedGradient`, `FixedInstantPulse`, `FixedInstantGradient`, or `InstantReadout`). These all have in common that they have no free variables and explicitly set any gradient and RF pulse profiles. - [`variables`](@ref): A list of all functions that are used to compute variables of the building block. Any of these can be used in constraints or objective functions. """ abstract type BuildingBlock end @@ -101,17 +100,6 @@ Function used internally to convert a wide variety of objects into [`BuildingBlo to_block(bb::BuildingBlock) = bb -""" - fixed(block::BuildingBlock) - -Return the fixed equivalent of the `BuildingBlock` - -Possible return types are `FixedSequence`, `FixedBlock`, `FixedPulse`, `FixedGradient`, `FixedInstantPulse`, `FixedInstantGradient`, or `InstantReadout`. -These all have in common that they have no free variables and explicitly set any gradient and RF pulse profiles. -""" -function fixed end - - """ variables(building_block) @@ -251,7 +239,7 @@ apply_simple_constraint!(variable, ::Nothing) = nothing apply_simple_constraint!(variable, value::Symbol) = apply_simple_constraint!(variable, Val(value)) apply_simple_constraint!(variable, ::Val{:min}) = @objective global_model() Min objective_function(global_model()) + variable apply_simple_constraint!(variable, ::Val{:max}) = @objective global_model() Min objective_function(global_model()) - variable -apply_simple_constraint!(variable, value::VariableType) = @constraint model variable == value +apply_simple_constraint!(variable, value::VariableType) = @constraint global_model() variable == value apply_simple_constraint!(variable::AbstractVector, value::AbstractVector) = [apply_simple_constraint!(v1, v2) for (v1, v2) in zip(variable, value)] @@ -318,4 +306,13 @@ function scanner_constraints!(building_block::BuildingBlock, scanner::Scanner, f end end + +function fixed(bb::BuildingBlock) + arguments = [] + for name in propertynames(bb) + push!(arguments, fixed(getproperty(bb, name))) + end + return typeof(bb)(arguments...) +end + end \ No newline at end of file diff --git a/src/gradients/changing_gradient_blocks.jl b/src/gradients/changing_gradient_blocks.jl index cf2fd572d1fae097ff6cd8673e62983d98579afc..5ecba8af0fc893a0478998a3424548776fa17199 100644 --- a/src/gradients/changing_gradient_blocks.jl +++ b/src/gradients/changing_gradient_blocks.jl @@ -3,7 +3,7 @@ import StaticArrays: SVector import ...Variables: VariableType, variables, get_free_variable import ...BuildingBlocks: GradientBlock import ...Variables: qvec, bmat_gradient, gradient_strength, slew_rate, duration, variables, VariableType -import ...BuildingBlocks: GradientBlock, fixed, RFPulseBlock +import ...BuildingBlocks: GradientBlock, RFPulseBlock """ ChangingGradientBlock(grad1, slew_rate, duration, rotate, scale) diff --git a/src/gradients/constant_gradient_blocks.jl b/src/gradients/constant_gradient_blocks.jl index 61e32f0ac0b8f3fc52207a43c30224e82a45ae74..858081c209c957cd900404ec4ff71b71c8211500 100644 --- a/src/gradients/constant_gradient_blocks.jl +++ b/src/gradients/constant_gradient_blocks.jl @@ -3,7 +3,7 @@ import StaticArrays: SVector import ...Variables: VariableType, variables import ...BuildingBlocks: GradientBlock import ...Variables: qvec, bmat_gradient, gradient_strength, slew_rate, duration, variables, VariableType -import ...BuildingBlocks: GradientBlock, fixed, RFPulseBlock +import ...BuildingBlocks: GradientBlock, RFPulseBlock import ..ChangingGradientBlocks: split_gradient """ diff --git a/src/overlapping/spoilt_slice_selects.jl b/src/overlapping/spoilt_slice_selects.jl index e21862595a040d65f85f1702400b2988e957e7da..2b0a684e6a24fe8fe2ab6cec2a888ab708cd27d6 100644 --- a/src/overlapping/spoilt_slice_selects.jl +++ b/src/overlapping/spoilt_slice_selects.jl @@ -66,7 +66,7 @@ function SpoiltSliceSelect(pulse; orientation=[0, 0, 1], rotate=nothing, spoiler @constraint model (qvec(res, nothing, 1)[dim] ./ res.orientation[dim]) >= 2π * 1e-3 / spoiler_scale end end - set_simple_constraints!(model, res, kwargs) + set_simple_constraints!(res, kwargs) max_time = gradient_strength(global_scanner()) / res.slew_rate @constraint model rise_time(res)[1] <= max_time diff --git a/src/overlapping/trapezoid_gradients.jl b/src/overlapping/trapezoid_gradients.jl index 11b5d863714bf8e151415c6db0e193b0be2e9acc..0665ca6c054ac82af35718f8937a62a71c7eca72 100644 --- a/src/overlapping/trapezoid_gradients.jl +++ b/src/overlapping/trapezoid_gradients.jl @@ -7,7 +7,7 @@ import JuMP: @constraint, @variable, VariableRef, value import StaticArrays: SVector import LinearAlgebra: norm import ...Variables: qvec, rise_time, flat_time, slew_rate, gradient_strength, variables, duration, δ, get_free_variable, VariableType, inverse_slice_thickness, inverse_bandwidth, effective_time -import ...BuildingBlocks: duration, set_simple_constraints!, fixed, RFPulseBlock, scanner_constraints! +import ...BuildingBlocks: duration, set_simple_constraints!, RFPulseBlock, scanner_constraints! import ...BuildSequences: global_model import ...Gradients: ChangingGradientBlock, ConstantGradientBlock import ..Abstract: interruptions, waveform, AbstractOverlapping diff --git a/src/pulses/constant_pulses.jl b/src/pulses/constant_pulses.jl index cf069cb2390fd920020dd33dae5ce4035906c661..07ac767fd93232af03324366196f5d75c823c9af 100644 --- a/src/pulses/constant_pulses.jl +++ b/src/pulses/constant_pulses.jl @@ -1,9 +1,8 @@ module ConstantPulses import JuMP: VariableRef, @constraint, @variable, value -import ...BuildingBlocks: RFPulseBlock, set_simple_constraints!, fixed +import ...BuildingBlocks: RFPulseBlock, set_simple_constraints! import ...Variables: variables, get_free_variable, flip_angle, phase, amplitude, frequency, start_time, end_time, VariableType, duration, effective_time, inverse_bandwidth import ...BuildSequences: global_model -import ..FixedPulses: FixedPulse """ ConstantPulse(; variables...) diff --git a/src/pulses/instant_pulses.jl b/src/pulses/instant_pulses.jl index 4dafb7dfb1921eccf1999326a8ec808b391f7065..bb8e19527911a400ff54505c8bd4e6240b18c4a2 100644 --- a/src/pulses/instant_pulses.jl +++ b/src/pulses/instant_pulses.jl @@ -1,6 +1,6 @@ module InstantPulses import JuMP: @constraint, @variable, VariableRef, value -import ...BuildingBlocks: RFPulseBlock, fixed +import ...BuildingBlocks: RFPulseBlock import ...Variables: flip_angle, phase, start_time, variables, duration, get_free_variable, VariableType, effective_time, inverse_bandwidth import ...BuildSequences: global_model import ..FixedPulses: FixedInstantPulse diff --git a/src/pulses/sinc_pulses.jl b/src/pulses/sinc_pulses.jl index 35db4b2f53dc6bf9a46a9c73595f1d7313f86cc7..257e4ef8fb160a10797b77ba25bc3994944190c0 100644 --- a/src/pulses/sinc_pulses.jl +++ b/src/pulses/sinc_pulses.jl @@ -3,7 +3,7 @@ module SincPulses import JuMP: VariableRef, @constraint, @variable, value import QuadGK: quadgk import Polynomials: fit, Polynomial -import ...BuildingBlocks: RFPulseBlock, set_simple_constraints!, fixed +import ...BuildingBlocks: RFPulseBlock, set_simple_constraints! import ...Variables: flip_angle, phase, amplitude, frequency, VariableType, variables, get_free_variable, duration, effective_time, inverse_bandwidth import ...BuildSequences: global_model import ..FixedPulses: FixedPulse @@ -69,7 +69,7 @@ function SincPulse(; if !symmetric @constraint model res.N_right >= 1 end - set_simple_constraints!(model, res, kwargs) + set_simple_constraints!(res, kwargs) return res end diff --git a/src/readouts/instant_readouts.jl b/src/readouts/instant_readouts.jl index 21e74a6dc23dcd0b048e55f3a029bdcb071370a9..9bf9a299d8fe863e5548da613a7c34b6ec53931b 100644 --- a/src/readouts/instant_readouts.jl +++ b/src/readouts/instant_readouts.jl @@ -1,5 +1,5 @@ module InstantReadouts -import ...BuildingBlocks: BuildingBlock, to_block, fixed, effective_time +import ...BuildingBlocks: BuildingBlock, to_block, effective_time import ...Variables: variables, duration """ @@ -15,6 +15,5 @@ end variables(::Type{<:InstantReadout}) = [] to_block(::Type{<:InstantReadout}) = InstantReadout() duration(::InstantReadout) = 0. -fixed(i::InstantReadout) = i effective_time(::InstantReadout) = 0. end \ No newline at end of file diff --git a/src/sequences.jl b/src/sequences.jl index bd5910cddb7690d1cc9364a4006c3a998c3e4b9a..b66225d8ea6ac09a545efa8ce7d8f9c6d858fd40 100644 --- a/src/sequences.jl +++ b/src/sequences.jl @@ -6,7 +6,7 @@ import Printf: @sprintf import JuMP: @constraint import ...BuildSequences: global_model import ...Variables: variables, start_time, duration, VariableType, get_free_variable, TR, end_time -import ...BuildingBlocks: BuildingBlock, ContainerBlock, to_block, get_children_indices, fixed, BuildingBlockPrinter, _robust_value, get_children_blocks +import ...BuildingBlocks: BuildingBlock, ContainerBlock, to_block, get_children_indices, fixed, BuildingBlockPrinter, _robust_value, get_children_blocks, fixed """ Sequence(building_blocks...; TR=nothing) @@ -36,6 +36,7 @@ struct Sequence <: ContainerBlock end Sequence(blocks...; TR=nothing) = Sequence([blocks...]; TR=TR) +fixed(seq::Sequence) = fixed.(seq._blocks, TR=fixed(seq.TR)) Base.length(seq::Sequence) = length(seq._blocks) Base.getindex(seq::Sequence, index) = seq._blocks[index]