Sequence optimisation
In MRIBuilder an MR Sequence
is defined as a sequence of BuildingBlock
objects. Most BuildingBlock
objects will contain free parameters determining, for example, the duration of the block or the strength/orientation of the MR gradient. In most MR sequence building software, the user will have to set all of these free parameters by computing the appropriate values given a desired echo time, b-value, etc.
In MRIBuilder the internal free parameters are not set directly. Instead, they are inferred using a non-linear, constrained optimisation. For each sequence type, the developer defines how to compute various summary variables from the BuildingBlock
free parameters, such as echo_time
, repetition_time
, resolution
, gradient_strength
, diffusion_time
, etc. A user can then create a specific instantiation of the sequence by fixing any of these summary variables to their desired values (or setting them to :min
/:max
to minimise/maximise them). In addition to the user-defined constraints, this optimisation will also take into account any scanner-defined constraints. Internally, MRIBuilder will then optimise the BuildingBlock
free parameters to match any user-defined constraints and/or objectives. This optimisation uses the Ipopt optimiser accessed through the JuMP.jl library.
Summary variables
MRIBuilder.Variables
— ModuleDefines the functions that can be called on parts of an MRI sequence to query or constrain any variables.
In addition this defines:
variables
: dictionary containing all variables.VariableType
: parent type for any variables (whether number or JuMP variable).get_free_variable
: helper function to create new JuMP variables.VariableNotAvailable
: error raised if variable is not defined for specificAbstractBlock
.set_simple_constraints!
: callapply_simple_constraint!
for each keyword argument.apply_simple_constraint!
: set a simple equality constraint.get_pulse
/get_gradient
/get_readout
: Used to get the pulse/gradient/readout part of a building blockgradient_orientation
: returns the gradient orientation of a waveform if fixed.
MRIBuilder.Variables.VariableType
— TypeParent type for any variable in the MRI sequence.
Each variable can be one of:
- a new JuMP variable
- an expression linking this variable to other JuMP variable
- a number
Create these using get_free_variable
.
MRIBuilder.Variables.alternative_variables
— ConstantDictionary with alternative versions of specific function.
Setting constraints on these alternative functions can be helpful as it avoids some operations, which the optimiser might struggle with.
MRIBuilder.Variables.variables
— ConstantCollection of all functions that return variables that can be used to query or constrain their values.
MRIBuilder.Variables.AbstractBlock
— TypeParent type of all components, building block, and sequences that form an MRI sequence.
MRIBuilder.Variables.VariableNotAvailable
— TypeVariableNotAvailable(building_block, variable, alt_variable)
Exception raised when a variable function does not support a specific AbstractBlock
.
MRIBuilder.Scanners.slew_rate
— Functionslew_rate(gradient)
Vector with maximum slew rate of a gradient along each dimension (kHz/um/ms)
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.N_left
— FunctionN_left(pulse)
The number of zero crossings of the RF pulse before the main peak
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.N_right
— FunctionN_right(pulse)
The number of zero crossings of the RF pulse after the main peak
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.TE
— FunctionTE(sequence)
Echo time of the sequence in ms. Defaults to the result of echo_time
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.TR
— FunctionTR(sequence)
Time on which an MRI sequence repeats itself in ms. Defaults to the result of repetition_time
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.adjust_internal
— Functionadjust_internal(block, names_used; kwargs...)
Returns the adjusted blocks and add any keywords used in the process to names_used
.
This is a helper function used by adjust
.
MRIBuilder.Variables.adjustable
— Methodadjustable(block)
Returns whether a sequence, building block, or component can be adjusted
Can return one of:
:false
: not adjustable:gradient
: expects gradient adjustment parameters:pulse
: expects RF pulse adjustment parameters
MRIBuilder.Variables.apply_simple_constraint!
— Methodapply_simple_constraint!(variable, value)
Add a single constraint or objective to the variable
.
value
can be one of:
nothing
: do nothing:min
: minimise the variable:max
: maximise the variablenumber
: fix variable to this valueequation
: fix variable to the result of this equation
MRIBuilder.Variables.area_under_curve
— Functionarea_under_curve(sequence)
Net dephasing due to gradients in rad/um (same as qvec
).
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.bandwidth
— Functionbandwidth(pulse)
Bandwidth of the RF pulse in kHz. To set constraints it is often better to use inverse_bandwidth
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.bmat
— Functionbmat(sequence)
Full 3x3 diffusion-weighting matrix in ms/um^2.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.bmat_gradient
— Functionbmat_gradient(gradient::GradientBlock, qstart=(0, 0, 0))
Computes the diffusion-weighting matrix due to a single gradient block in rad^2 ms/um^2.
This should be defined for every GradientBlock
, but not be called directly. Instead, the bmat
and bval
should be constrained for specific Pathways
MRIBuilder.Variables.bval
— Functionbval(sequence)
Size of diffusion-weighting in ms/um^2 (trace of bmat
).
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.delay
— Functiondelay(sequence)
Delay between readout and spin echo in an asymmetric spin echo in ms.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.diffusion_time
— Functiondiffusion_time(sequence)
Diffusion time in ms (i.e., time between start of the diffusion-weighted gradients).
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.duration
— Functionduration(block)
duration of the building block in ms.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.duration_dephase
— Functionduration_dephase(sequence)
Net T2' dephasing experienced over a sequence (in ms).
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.duration_transverse
— Functionduration_transverse(sequence)
Net T2 signal loss experienced over a sequence (in ms). This is the total duration spins spent in the transverse plane.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.dwell_time
— Functiondwell_time(readout)
Time between two samples in an ADC
in ms.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.echo_time
— Functionecho_time(sequence)
Echo time of the sequence in ms.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.flat_time
— Functionflat_time(gradient)
Time of gradient pulse at maximum value in ms.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.flip_angle
— Functionflip_angle(pulse)
The flip angle of the RF pulse in degrees
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.fov
— Functionfov(readout)
Size of the field of view in mm. To set constraints it is often better to use inverse_fov
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.frequency
— Functionfrequency(pulse)
The off-resonance frequency of an RF pulse (relative to the Larmor frequency of water) in KHz
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.get_free_variable
— Methodget_free_variable(value; integer=false, start=0.01)
Get a representation of a given variable
given a user-defined constraint.
The result is guaranteed to be a VariableType
.
MRIBuilder.Variables.get_readout
— Functionget_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.
MRIBuilder.Variables.gradient_orientation
— Functiongradient_orientation(building_block)
Returns the gradient orientation.
MRIBuilder.Variables.inverse_bandwidth
— Functioninverse_bandwidth(pulse)
Inverse of bandwidth of the RF pulse in 1/kHz. Also see bandwidth
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.inverse_fov
— Functioninverse_fov(readout)
Inverse of size of the field of view in 1/mm. Also see fov
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.inverse_slice_thickness
— Functioninverse_slice_thickness(pulse)
Inverse of slice thickness of an RF pulse that is active during a gradient in 1/mm. Also, see slice_thickness
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.inverse_voxel_size
— Functioninverse_voxel_size(readout)
Inverse of voxel size in 1/mm. Also see voxel_size
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.make_generic
— Functionmake_generic(sequence/building_block/component)
Returns a generic version of the BaseSequence
, BaseBuildingBlock
, or BaseComponent
- Sequences are all flattened and returned as a single
Sequence
containing onlyBuildingBlock
objects. - Any
BaseBuildingBlock
is converted into aBuildingBlock
. - Pulses are replaced with
GenericPulse
(except for instant pulses). - Instant readouts are replaced with
ADC
.
MRIBuilder.Variables.nsamples
— Functionnsamples(readout)
Number of samples during a readout. During the optimisation this might produce non-integer values.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.oversample
— Functionoversample(readout)
How much to oversample with (nsamples
/ resolution
)
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.qval
— Functionqval(gradient)
The spatial range on which the displacements can be detected due to this gradient in rad/um. This will be a scalar if the orientation is fixed and a scalar otherwise. If you always want a vector, use qvec
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.qval3
— Functionqval3(gradient)
The spatial range with orientation on which the displacements can be detected due to this gradient in rad/um (also see qval
).
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.qval_square
— Functionqval_square(gradient)
Square of qval
in rad^2/um^2.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.qvec
— Functionqvec(sequence)
Net dephasing due to gradients in rad/um.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.ramp_overlap
— Functionramp_overlap(readout)
Fraction of overlap between ADC event and underlying gradient pulse ramp (between 0 and 1).
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.repetition_time
— Functionrepetition_time(sequence)
Time on which an MRI sequence repeats itself in ms.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.resolution
— Functionresolution(readout)
Number of voxels in the final readout. During the optimisation this might produce non-integer values, but this will be fixed after optimsation.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.rise_time
— Functionrise_time(gradient)
Time for gradient pulse to reach its maximum value in ms.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.scanner_constraints!
— Methodscanner_constraints!(block)
Constraints gradient_strength
and slew_rate
to be less than the global_scanner
maximum.
MRIBuilder.Variables.set_simple_constraints!
— Methodset_simple_constraints!(block, kwargs)
Add any constraints or objective functions to the variables of a AbstractBlock
.
Each keyword argument has to match one of the functions in variables
(block). If set to a numeric value, a constraint will be added to fix the function value to that numeric value. If set to :min
or :max
, minimising or maximising this function will be added to the cost function.
MRIBuilder.Variables.slice_thickness
— Functionslice_thickness(pulse)
Slice thickness of an RF pulse that is active during a gradient in mm. To set constraints it is often better to use inverse_slice_thickness
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.spoiler_scale
— Functionspoiler_scale(gradient)
Length-scale on which spins will be dephased by exactly 2π in mm.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.voxel_size
— Functionvoxel_size(readout)
Size of each voxel in mm. To set constraints it is often better to use inverse_voxel_size
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.Δ
— FunctionΔ(sequence)
Diffusion time in ms (i.e., time between start of the diffusion-weighted gradients). Defaults to the result of diffusion_time
.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.
MRIBuilder.Variables.δ
— Functionδ(gradient)
Effective duration of a gradient pulse (rise_time
+ flat_time
) in ms.
This represents a variable within the sequence. Variables can be set during the construction of a AbstractBlock
or used to create constraints after the fact.