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!
import .SequenceBuilders: SequenceBuilder, start_time, end_time, duration, TR
export SequenceBuilder, start_time, end_time, duration, TR
import .ConcreteBlocks: ConcreteBlock
export ConcreteBlock
import .ConcreteBlocks: ConcreteBlock, Sequence
export ConcreteBlock, Sequence
import .Wait: WaitBlock
export WaitBlock
......@@ -36,4 +36,7 @@ export InstantReadout
import .Scanners: 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
module ConcreteBlocks
import JuMP: has_values
import JuMP: has_values, optimize!, model
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
time :: Vector{Number}
......@@ -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).
"""
struct ConcreteBlock <: AbstractConcreteBlock
builder :: SequenceBuilder
duration :: Float64
pulse :: Union{ConcreteRFPulse, Nothing}
gradient :: Union{ConcreteGradient, Nothing}
readout_times :: Vector{Float64}
end
ConcreteBlock(args...; kwargs...) = BuildingBlockPlaceholder{ConcreteBlock}(args...; kwargs...)
function ConcreteBlock(builder::SequenceBuilder, duration::Number; pulse=nothing, gradient=nothing, readout_times=Number[])
function ConcreteBlock(duration::Number; pulse=nothing, gradient=nothing, readout_times=Number[])
ConcreteBlock(builder, duration, ConcreteRFPulse(pulse), ConcreteGradient(gradient), Float64.(readout_times))
end
to_block(::SequenceBuilder, concrete::AbstractConcreteBlock) = concrete
has_values(::AbstractConcreteBlock) = true
"""
ConcreteBlock(other_building_block)
......@@ -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.
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)
error("Making `BuildingBlock` objects concrete is only possible after optimisation.")
end
return to_concrete_block(builder, block)
return to_concrete_block(block)
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).
This needs to be defined for every [`BuildingBlock`](@ref)
"""
function to_concrete_block(builder::SequenceBuilder, cb::ConcreteBlock)
return ConcreteBlock(builder, cb.duration, cb.pulse, cb.gradient, cb.readout_times)
function to_concrete_block(cb::AbstractConcreteBlock)
return cb
end
properties(::Type{<:ConcreteBlock}) = []
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
\ No newline at end of file
......@@ -5,6 +5,11 @@ import Ipopt
import ..BuildingBlocks: BuildingBlock, BuildingBlockPlaceholder, match_blocks!, duration, apply_simple_constraint!, scanner_constraints!, start_time, end_time
import ...Scanners: Scanner
"""
Parent type for a sequence with free variables ([`SequenceBuilder`](@ref)) or without free variables (`ConcreteSequence`).
"""
abstract type AbstractSequence end
"""
SequenceBuilder(blocks...)
......@@ -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.
A sequence matching these constraints will be produced by calling [`solve`](@ref)(builder) or [`Sequence`](@ref)(builder).
"""
struct SequenceBuilder
struct SequenceBuilder <: AbstractSequence
model :: Model
scanner :: Scanner
blocks :: Vector{<:BuildingBlock}
......@@ -35,6 +40,8 @@ struct SequenceBuilder
end
end
get_blocks(seq::SequenceBuilder) = seq.blocks
function to_block(model::SequenceBuilder, placeholder::BuildingBlockPlaceholder{T}) where {T}
block = T(model, placeholder.args...; placeholder.kwargs...)
if isassigned(placeholder.concrete)
......@@ -45,7 +52,7 @@ function to_block(model::SequenceBuilder, placeholder::BuildingBlockPlaceholder{
return block
end
Base.getindex(model::SequenceBuilder, i::Integer) = model.blocks[i]
Base.getindex(model::AbstractSequence, i::Integer) = get_blocks(model)[i]
function SequenceBuilder(blocks...; kwargs...)
ipopt_opt = optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0)
......@@ -68,12 +75,11 @@ function Base.show(io::IO, builder::SequenceBuilder)
end
Base.length(sb::SequenceBuilder) = length(sb.blocks)
Base.length(sb::AbstractSequence) = length(get_blocks(sb))
builder(bb::BuildingBlock) = bb.builder
owner_model(bb::BuildingBlock) = owner_model(builder(bb))
owner_model(sb::SequenceBuilder) = sb.model
has_values(object::Union{BuildingBlock, SequenceBuilder}) = has_values(owner_model(object))
optimize!(sb::SequenceBuilder) = optimize!(owner_model(sb))
"""
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