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

Define fixed for gradients

parent 85aa6e37
No related branches found
No related tags found
No related merge requests found
...@@ -8,8 +8,8 @@ import ..Variables: variables, start_time, duration, end_time, gradient_strength ...@@ -8,8 +8,8 @@ import ..Variables: variables, start_time, duration, end_time, gradient_strength
Parent type for all individual components out of which a sequence can be built. Parent type for all individual components out of which a sequence can be built.
Required methods: Required methods:
- [`duration`](@ref)(block, parameters): returns block duration in ms. - [`duration`](@ref)(block, parameters): Return block duration in ms.
- `to_concrete_block`(sequence, block): converts the block into a `ConcreteBlock`, which will be part of given `Sequence`. - [`fixed`](block): Return an 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. - [`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 abstract type BuildingBlock end
...@@ -68,6 +68,17 @@ Function used internally to convert a wide variety of objects into [`BuildingBlo ...@@ -68,6 +68,17 @@ Function used internally to convert a wide variety of objects into [`BuildingBlo
to_block(bb::BuildingBlock) = bb to_block(bb::BuildingBlock) = bb
"""
fixed(block::BuildingBlock)
Return an equivalent fixed BuildingBlock.
Possible return types are `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
""" """
scanner_constraints!([model, ]building_block, scanner) scanner_constraints!([model, ]building_block, scanner)
......
module ConcreteBlocks
import JuMP: has_values, optimize!, value
import ..Variables: variables, duration
import ..BuildingBlocks: BuildingBlock
struct ConcreteRFPulse
time :: Vector{Number}
amplitude :: Vector{Number}
phase :: Vector{Number}
end
function ConcreteRFPulse(arr::Vector)
@assert all(length.(arr) .== 3)
ConcreteRFPulse(
[a[1] for a in arr],
[a[2] for a in arr],
[a[3] for a in arr],
)
end
ConcreteRFPulse(::Nothing) = nothing
ConcreteRFPulse(values::Tuple{<:AbstractVector, <:AbstractVector, <:AbstractVector}) = ConcreteRFPulse(values...)
struct ConcreteGradient
time :: Vector{Number}
Gx :: Vector{Number}
Gy :: Vector{Number}
Gz :: Vector{Number}
end
function ConcreteGradient(arr::Vector)
if length(arr[1]) == 4
@assert all(length.(arr) .== 4)
ConcreteGradient(
[a[1] for a in arr],
[a[2] for a in arr],
[a[3] for a in arr],
[a[4] for a in arr],
)
elseif length(arr[1]) == 2
@assert all(length.(arr) .== 2)
ConcreteGradient(
[a[1] for a in arr],
[a[2] for a in arr],
)
else
error()
end
end
function ConcreteGradient(times, gradients)
ConcreteGradient(
times,
[g[1] for g in gradients],
[g[2] for g in gradients],
[g[3] for g in gradients],
)
end
ConcreteGradient(::Nothing) = nothing
ConcreteGradient(values::Tuple{<:Vector, <:Vector}) = ConcreteGradient(values...)
ConcreteGradient(values::Tuple{<:Vector, <:Vector, <:Vector, <:Vector}) = ConcreteGradient(values...)
abstract type AbstractConcreteBlock <: BuildingBlock end
"""
ConcreteBlock(duration; pulse=nothing, gradient=nothing, rotate_bvec=false, readout_times=nothing)
A [`BuildingBlock`](@ref) that is fully defined (i.e., there are no variables to be optimised).
"""
struct ConcreteBlock <: AbstractConcreteBlock
duration :: Float64
pulse :: Union{ConcreteRFPulse, Nothing}
gradient :: Union{ConcreteGradient, Nothing}
readout_times :: Vector{Float64}
rotate_gradient :: Bool
end
function ConcreteBlock(duration::Number; pulse=nothing, gradient=nothing, readout_times=Number[], rotate_gradient=false)
ConcreteBlock(duration, ConcreteRFPulse(pulse), ConcreteGradient(gradient), Float64.(readout_times), rotate_gradient)
end
has_values(c::AbstractConcreteBlock) = true
duration(c::AbstractConcreteBlock) = 0.
duration(c::ConcreteBlock) = c.duration
"""
ConcreteBlock(other_building_block)
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(block::BuildingBlock)
if !has_values(block)
error("Making `BuildingBlock` objects concrete is only possible after optimisation.")
end
return to_concrete_block(block)
end
"""
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(cb::ConcreteBlock)
return ConcreteBlock(cb.duration, cb.pulse, cb.gradient, cb.readout_times, cb.rotate_gradient, value.(cb.start_time))
end
variables(::Type{<:AbstractConcreteBlock}) = []
end
\ No newline at end of file
module FixedGradients module FixedGradients
import ...BuildingBlock: GradientBlock import ...BuildingBlock: GradientBlock
import ...Variables: variables, duration import ...Variables: variables, duration, qval
""" """
...@@ -23,25 +23,27 @@ struct FixedGradient <: GradientBlock ...@@ -23,25 +23,27 @@ struct FixedGradient <: GradientBlock
Gx :: Vector{Float64} Gx :: Vector{Float64}
Gy :: Vector{Float64} Gy :: Vector{Float64}
Gz :: Vector{Float64} Gz :: Vector{Float64}
function FixedGradient(time::AbstractVector{<:Number}, Gx::AbstractVector{<:Number}, Gy::AbstractVector{<:Number}, Gz::AbstractVector{<:Number}) rotate :: Bool
function FixedGradient(time::AbstractVector{<:Number}, Gx::AbstractVector{<:Number}, Gy::AbstractVector{<:Number}, Gz::AbstractVector{<:Number}; rotate=false)
@assert length(time) == length(Gx) @assert length(time) == length(Gx)
@assert length(time) == length(Gy) @assert length(time) == length(Gy)
@assert length(time) == length(Gz) @assert length(time) == length(Gz)
new(Float64.(time), Float64.(Gx), Float64.(Gy), Float64.(Gz)) new(Float64.(time), Float64.(Gx), Float64.(Gy), Float64.(Gz), rotate)
end end
end end
function FixedGradient(time::AbstractVector{<:Number}, arr::AbstractVector{<:AbstractVector{<:Number}}) function FixedGradient(time::AbstractVector{<:Number}, arr::AbstractVector{<:AbstractVector{<:Number}}; kwargs...)
@assert all(length.(arr) .== 3) @assert all(length.(arr) .== 3)
FixedGradient( FixedGradient(
time, time,
[a[1] for a in arr], [a[1] for a in arr],
[a[2] for a in arr], [a[2] for a in arr],
[a[3] for a in arr], [a[3] for a in arr];
kwargs...
) )
end end
FixedGradient(time::AbstractVector{<:Number}, Gx::AbstractVector{<:Number}) = FixedGradient(time, Gx, zeros(length(time)), zeros(length(time))) FixedGradient(time::AbstractVector{<:Number}, Gx::AbstractVector{<:Number}; kwargs...) = FixedGradient(time, Gx, zeros(length(time)), zeros(length(time)); kwargs...)
variables(::Type{<:FixedGradient}) = [] variables(::Type{<:FixedGradient}) = []
...@@ -49,4 +51,20 @@ duration(fg::FixedGradient) = maximum(fg.time) ...@@ -49,4 +51,20 @@ duration(fg::FixedGradient) = maximum(fg.time)
Base.show(io::IO, fb::FixedGradient) = print(io, "FixedGradient for $(duration(fb)) ms") Base.show(io::IO, fb::FixedGradient) = print(io, "FixedGradient for $(duration(fb)) ms")
"""
FixedInstantGradient(orientation, qval)
Instantaneous MR gradient with no free variables.
"""
struct FixedInstantGradient <: GradientBlock
orientation :: Any
qval :: Number
end
duraction(instant::FixedInstantGradient) = 0.
qval(instant::FixedInstantGradient) = instant.qval
fixed(f::Union{FixedGradient, FixedInstantGradient}) = f
end end
\ No newline at end of file
...@@ -9,9 +9,9 @@ Arbitrary gradient waveforms can be store din a [`ConcreteBlock`](@ref) ...@@ -9,9 +9,9 @@ Arbitrary gradient waveforms can be store din a [`ConcreteBlock`](@ref)
""" """
module Gradients module Gradients
include("integrate_gradients.jl") include("integrate_gradients.jl")
include("fixed_gradients.jl")
include("pulsed_gradients.jl") include("pulsed_gradients.jl")
include("instant_gradients.jl") include("instant_gradients.jl")
include("fixed_gradients.jl")
import ..BuildingBlock: GradientBlock import ..BuildingBlock: GradientBlock
......
module InstantGradients module InstantGradients
import JuMP: @constraint, @variable, Model, owner_model import JuMP: @constraint, @variable, Model, owner_model
import ...Variables: qval, bval, start_time, duration, variables, get_free_variable, VariableType import ...Variables: qval, bval, start_time, duration, variables, get_free_variable, VariableType
import ...BuildingBlocks: GradientBlock import ...BuildingBlocks: GradientBlock, fixed
import ...ConcreteBlocks: to_concrete_block, AbstractConcreteBlock import ...ConcreteBlocks: to_concrete_block, AbstractConcreteBlock
import ...BuildSequences: @global_model_constructor import ...BuildSequences: @global_model_constructor
import ..FixedGradients: FixedInstantGradient
""" """
InstantGradientBlock(; orientation=:bvec, qval=nothing) InstantGradientBlock(; orientation=:bvec, qval=nothing)
...@@ -40,20 +41,8 @@ bval(instant::InstantGradientBlock) = 0. ...@@ -40,20 +41,8 @@ bval(instant::InstantGradientBlock) = 0.
duration(instant::InstantGradientBlock) = 0. duration(instant::InstantGradientBlock) = 0.
variables(::Type{<:InstantGradientBlock}) = [qval] variables(::Type{<:InstantGradientBlock}) = [qval]
""" function fixed(block::InstantGradientBlock)
ConcreteInstantGradient(orientation, qval) return FixedInstantGradient(block.orientation, value(qval(block)))
Instantaneous MR gradient with no free variables.
See [`InstantGradientBlock`](@ref) for a version where [`qval`](@ref) is variable.
"""
struct ConcreteInstantGradient <: AbstractConcreteBlock
orientation :: Any
qval :: Number
end
function to_concrete_block(block::InstantGradientBlock)
return ConcreteInstantGradient(block.orientation, value(qval(block)))
end end
......
...@@ -6,9 +6,10 @@ module PulsedGradients ...@@ -6,9 +6,10 @@ module PulsedGradients
import JuMP: @constraint, @variable, Model, VariableRef, owner_model, value import JuMP: @constraint, @variable, Model, VariableRef, owner_model, value
import StaticArrays: SVector import StaticArrays: SVector
import ...Variables: qval, bval, rise_time, flat_time, slew_rate, gradient_strength, variables, duration, δ, get_free_variable, VariableType import ...Variables: qval, bval, rise_time, flat_time, slew_rate, gradient_strength, variables, duration, δ, get_free_variable, VariableType
import ...BuildingBlocks: GradientBlock, duration, set_simple_constraints! import ...BuildingBlocks: GradientBlock, duration, set_simple_constraints!, fixed
import ...ConcreteBlocks: ConcreteBlock, to_concrete_block import ...ConcreteBlocks: ConcreteBlock, to_concrete_block
import ...BuildSequences: @global_model_constructor import ...BuildSequences: @global_model_constructor
import ..FixedGradients: FixedGradient
""" """
...@@ -83,7 +84,7 @@ end ...@@ -83,7 +84,7 @@ end
variables(::Type{<:PulsedGradient}) = [qval, δ, gradient_strength, duration, rise_time, flat_time, slew_rate] variables(::Type{<:PulsedGradient}) = [qval, δ, gradient_strength, duration, rise_time, flat_time, slew_rate]
function to_concrete_block(block::PulsedGradient) function fixed(block::PulsedGradient)
if block.orientation == :bvec if block.orientation == :bvec
rotate = true rotate = true
qvec = [value(qval(block)), 0., 0.] qvec = [value(qval(block)), 0., 0.]
...@@ -98,12 +99,11 @@ function to_concrete_block(block::PulsedGradient) ...@@ -98,12 +99,11 @@ function to_concrete_block(block::PulsedGradient)
end end
t_rise = value(rise_time(block)) t_rise = value(rise_time(block))
t_d = value(δ(block)) t_d = value(δ(block))
return ConcreteBlock(t_d + t_rise, gradient=[ return FixedBlock(
(0., zeros(3)), [0., t_rise, t_d, td + t_rise],
(t_rise, qvec), [zeros(3), qvec, qvec, zeros(3)];
(t_d, qvec), rotate=rotate
(t_d + t_rise, zeros(3)), )
], rotate_gradient=rotate)
end end
......
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