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

Create new Sequence type for concrete blocks.

parent cf4e1b8f
No related branches found
No related tags found
No related merge requests found
...@@ -18,8 +18,8 @@ export BuildingBlock, scanner_constraints! ...@@ -18,8 +18,8 @@ export BuildingBlock, scanner_constraints!
import .SequenceBuilders: SequenceBuilder, start_time, end_time, duration, TR import .SequenceBuilders: SequenceBuilder, start_time, end_time, duration, TR
export SequenceBuilder, start_time, end_time, duration, TR export SequenceBuilder, start_time, end_time, duration, TR
import .ConcreteBlocks: ConcreteBlock import .ConcreteBlocks: ConcreteBlock, Sequence
export ConcreteBlock export ConcreteBlock, Sequence
import .Wait: WaitBlock import .Wait: WaitBlock
export WaitBlock export WaitBlock
...@@ -36,4 +36,7 @@ export InstantReadout ...@@ -36,4 +36,7 @@ export InstantReadout
import .Scanners: Scanner, Siemens_Connectom, Siemens_Prisma, Siemens_Terra import .Scanners: Scanner, Siemens_Connectom, Siemens_Prisma, Siemens_Terra
export Scanner, Siemens_Connectom, Siemens_Prisma, Siemens_Terra export Scanner, Siemens_Connectom, Siemens_Prisma, Siemens_Terra
using JuMP
export @constraint, @objective, objective_function, optimize!, has_values, value
end end
module ConcreteBlocks module ConcreteBlocks
import JuMP: has_values import JuMP: has_values, optimize!, model
import ..BuildingBlocks: BuildingBlock, BuildingBlockPlaceholder, properties import ..BuildingBlocks: BuildingBlock, BuildingBlockPlaceholder, properties
import ..SequenceBuilders: SequenceBuilder import ..SequenceBuilders: SequenceBuilder, to_block, AbstractSequence
abstract type AbstractConcreteBlock end abstract type AbstractConcreteBlock <: BuildingBlock end
struct ConcreteRFPulse struct ConcreteRFPulse
time :: Vector{Number} time :: Vector{Number}
...@@ -50,19 +50,19 @@ ConcreteGradient(values::Tuple{<:Vector, <:Vector, <:Vector, <:Vector}) = Concre ...@@ -50,19 +50,19 @@ ConcreteGradient(values::Tuple{<:Vector, <:Vector, <:Vector, <:Vector}) = Concre
A [`BuildingBlock`](@ref) that is fully defined (i.e., there are no variables to be optimised). A [`BuildingBlock`](@ref) that is fully defined (i.e., there are no variables to be optimised).
""" """
struct ConcreteBlock <: AbstractConcreteBlock struct ConcreteBlock <: AbstractConcreteBlock
builder :: SequenceBuilder
duration :: Float64 duration :: Float64
pulse :: Union{ConcreteRFPulse, Nothing} pulse :: Union{ConcreteRFPulse, Nothing}
gradient :: Union{ConcreteGradient, Nothing} gradient :: Union{ConcreteGradient, Nothing}
readout_times :: Vector{Float64} readout_times :: Vector{Float64}
end end
ConcreteBlock(args...; kwargs...) = BuildingBlockPlaceholder{ConcreteBlock}(args...; kwargs...) function ConcreteBlock(duration::Number; pulse=nothing, gradient=nothing, readout_times=Number[])
function ConcreteBlock(builder::SequenceBuilder, duration::Number; pulse=nothing, gradient=nothing, readout_times=Number[])
ConcreteBlock(builder, duration, ConcreteRFPulse(pulse), ConcreteGradient(gradient), Float64.(readout_times)) ConcreteBlock(builder, duration, ConcreteRFPulse(pulse), ConcreteGradient(gradient), Float64.(readout_times))
end end
to_block(::SequenceBuilder, concrete::AbstractConcreteBlock) = concrete
has_values(::AbstractConcreteBlock) = true
""" """
ConcreteBlock(other_building_block) ConcreteBlock(other_building_block)
...@@ -72,27 +72,48 @@ Creates a [`ConcreteBlock`](@ref) from another [`BuildingBlock`](@ref). ...@@ -72,27 +72,48 @@ Creates a [`ConcreteBlock`](@ref) from another [`BuildingBlock`](@ref).
This will raise an error if the other [`BuildingBlock`](@ref) has not been optimised yet. This will raise an error if the other [`BuildingBlock`](@ref) has not been optimised yet.
If it has been optimised, then [`to_concrete_block`](@ref) will be called. If it has been optimised, then [`to_concrete_block`](@ref) will be called.
""" """
function ConcreteBlock(builder::SequenceBuilder, block::BuildingBlock) function ConcreteBlock(block::BuildingBlock)
if !has_values(block) if !has_values(block)
error("Making `BuildingBlock` objects concrete is only possible after optimisation.") error("Making `BuildingBlock` objects concrete is only possible after optimisation.")
end end
return to_concrete_block(builder, block) return to_concrete_block(block)
end end
""" """
to_concrete_block(builder, other_building_block) to_concrete_block(other_building_block)
Internal function used to create [`ConcreteBlock`](@ref) from any [`BuildingBlock`](@ref). Internal function used to create [`ConcreteBlock`](@ref) from any [`BuildingBlock`](@ref).
This needs to be defined for every [`BuildingBlock`](@ref) This needs to be defined for every [`BuildingBlock`](@ref)
""" """
function to_concrete_block(builder::SequenceBuilder, cb::ConcreteBlock) function to_concrete_block(cb::AbstractConcreteBlock)
return ConcreteBlock(builder, cb.duration, cb.pulse, cb.gradient, cb.readout_times) return cb
end end
properties(::Type{<:ConcreteBlock}) = [] properties(::Type{<:ConcreteBlock}) = []
has_values(c::ConcreteBlock) = true has_values(c::ConcreteBlock) = true
"""
Sequence(builder::SequenceBuilder)
A fully defined sequence with no free variables.
When created from a [`SequenceBuilder`](@ref), all non-fixed variables are optimised given any constraints
and the resulting sequence is returned.
"""
struct Sequence <: AbstractSequence
blocks :: Vector{<:AbstractConcreteBlock}
TR :: Number
end
function Sequence(seq::SequenceBuilder)
if !has_values(seq)
optimize!(seq.model)
end
return Sequence(ConcreteBlock.(seq.blocks), value(seq.TR))
end
end end
\ No newline at end of file
...@@ -5,6 +5,11 @@ import Ipopt ...@@ -5,6 +5,11 @@ import Ipopt
import ..BuildingBlocks: BuildingBlock, BuildingBlockPlaceholder, match_blocks!, duration, apply_simple_constraint!, scanner_constraints!, start_time, end_time import ..BuildingBlocks: BuildingBlock, BuildingBlockPlaceholder, match_blocks!, duration, apply_simple_constraint!, scanner_constraints!, start_time, end_time
import ...Scanners: Scanner import ...Scanners: Scanner
"""
Parent type for a sequence with free variables ([`SequenceBuilder`](@ref)) or without free variables (`ConcreteSequence`).
"""
abstract type AbstractSequence end
""" """
SequenceBuilder(blocks...) SequenceBuilder(blocks...)
...@@ -13,7 +18,7 @@ Defines a sequence as a series of [`BuildingBlock`](@ref) objects. ...@@ -13,7 +18,7 @@ Defines a sequence as a series of [`BuildingBlock`](@ref) objects.
After defining the blocks, the user can add one or more constraints and an objective function to the properties of the [`BuildingBlock`](@ref) objects. After defining the blocks, the user can add one or more constraints and an objective function to the properties of the [`BuildingBlock`](@ref) objects.
A sequence matching these constraints will be produced by calling [`solve`](@ref)(builder) or [`Sequence`](@ref)(builder). A sequence matching these constraints will be produced by calling [`solve`](@ref)(builder) or [`Sequence`](@ref)(builder).
""" """
struct SequenceBuilder struct SequenceBuilder <: AbstractSequence
model :: Model model :: Model
scanner :: Scanner scanner :: Scanner
blocks :: Vector{<:BuildingBlock} blocks :: Vector{<:BuildingBlock}
...@@ -35,6 +40,8 @@ struct SequenceBuilder ...@@ -35,6 +40,8 @@ struct SequenceBuilder
end end
end end
get_blocks(seq::SequenceBuilder) = seq.blocks
function to_block(model::SequenceBuilder, placeholder::BuildingBlockPlaceholder{T}) where {T} function to_block(model::SequenceBuilder, placeholder::BuildingBlockPlaceholder{T}) where {T}
block = T(model, placeholder.args...; placeholder.kwargs...) block = T(model, placeholder.args...; placeholder.kwargs...)
if isassigned(placeholder.concrete) if isassigned(placeholder.concrete)
...@@ -45,7 +52,7 @@ function to_block(model::SequenceBuilder, placeholder::BuildingBlockPlaceholder{ ...@@ -45,7 +52,7 @@ function to_block(model::SequenceBuilder, placeholder::BuildingBlockPlaceholder{
return block return block
end end
Base.getindex(model::SequenceBuilder, i::Integer) = model.blocks[i] Base.getindex(model::AbstractSequence, i::Integer) = get_blocks(model)[i]
function SequenceBuilder(blocks...; kwargs...) function SequenceBuilder(blocks...; kwargs...)
ipopt_opt = optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0) ipopt_opt = optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0)
...@@ -68,12 +75,11 @@ function Base.show(io::IO, builder::SequenceBuilder) ...@@ -68,12 +75,11 @@ function Base.show(io::IO, builder::SequenceBuilder)
end end
Base.length(sb::SequenceBuilder) = length(sb.blocks) Base.length(sb::AbstractSequence) = length(get_blocks(sb))
builder(bb::BuildingBlock) = bb.builder builder(bb::BuildingBlock) = bb.builder
owner_model(bb::BuildingBlock) = owner_model(builder(bb)) owner_model(bb::BuildingBlock) = owner_model(builder(bb))
owner_model(sb::SequenceBuilder) = sb.model owner_model(sb::SequenceBuilder) = sb.model
has_values(object::Union{BuildingBlock, SequenceBuilder}) = has_values(owner_model(object)) has_values(object::Union{BuildingBlock, SequenceBuilder}) = has_values(owner_model(object))
optimize!(sb::SequenceBuilder) = optimize!(owner_model(sb))
""" """
TR(sequence::SequenceBuilder) TR(sequence::SequenceBuilder)
......
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