Skip to content
Snippets Groups Projects
Unverified Commit 17e6745f authored by Michiel Cottaar's avatar Michiel Cottaar
Browse files

Document primary/secondary/tertiary cost functions.

parent 63b4d9c5
No related branches found
No related tags found
1 merge request!4Resolve "Add secondary objective function"
Pipeline #24965 canceled
...@@ -13,10 +13,10 @@ This name will have to be unique. ...@@ -13,10 +13,10 @@ This name will have to be unique.
The next step is to define the sequence constructor: The next step is to define the sequence constructor:
```julia ```julia
function DiffusionSpinEcho(; scanner=DefaultScanner, parameters..., variables...) function DiffusionSpinEcho(; scanner=DefaultScanner, parameters..., vars...)
build_sequence(scanner) do build_sequence(scanner) do
(g1, g2) = dwi_gradients(...) (g1, g2) = dwi_gradients(...)
return Sequence([ seq = Sequence([
:excitation => excitation_pulse(...), :excitation => excitation_pulse(...),
nothing, nothing,
:gradient => g1, :gradient => g1,
...@@ -26,7 +26,10 @@ function DiffusionSpinEcho(; scanner=DefaultScanner, parameters..., variables... ...@@ -26,7 +26,10 @@ function DiffusionSpinEcho(; scanner=DefaultScanner, parameters..., variables...
g2, g2,
nothing, nothing,
:readout => readout_event(...), :readout => readout_event(...),
], name=:DiffusionSpinEcho, variables...) nothing,
], name=:DiffusionSpinEcho, vars...)
add_cost_function!(variables.duration(seq[6]) + variables.duration(seq[7]))
return seq
end end
end end
``` ```
...@@ -42,6 +45,7 @@ The crucial part here are the individual parts used to build the sequence, defin ...@@ -42,6 +45,7 @@ The crucial part here are the individual parts used to build the sequence, defin
:gradient2 => g2, :gradient2 => g2,
nothing, nothing,
:readout => readout_event(...), :readout => readout_event(...),
nothing
] ]
``` ```
...@@ -49,6 +53,17 @@ We can see that this sequence is built in order by an excitation pulse, some unk ...@@ -49,6 +53,17 @@ We can see that this sequence is built in order by an excitation pulse, some unk
Some of these components have been given specific names (e.g., `:excitation => ...`). This is optional, but can be useful to refer to individual components. There are [helper functions](@ref helper_functions) available to create these components. Some of these components have been given specific names (e.g., `:excitation => ...`). This is optional, but can be useful to refer to individual components. There are [helper functions](@ref helper_functions) available to create these components.
After creating the sequence object, we can now add secondary objectives to the cost function (using [`add_cost_function!`](@ref)).
In this example, we have:
```julia
add_cost_function!(variables.duration(seq[6]) + variables.duration(seq[7]))
```
If we check the order of the sequence component, we see that this minimises the sum of the duration of the second gradient and the wait block before this gradient.
This cost function has been added to maximise the time between the second gradient and the readout (and hence minimise the effect of eddy currents on the readout).
Note that this is a secondary cost function that will only take effect if it does not interfere with any user-defined constraints and cost functions (see [sequence optimisation](@ref sequence_optimisation)).
Some secondary cost functions will be automatically defined for you within the individual components (e.g., a trapezoidal gradient has a secondary cost function to maximise the slew rate).
There is even a tertiary cost function, which minimises the total sequence duration.
The next step is to define [summary variables](@ref variables) that the user can constrain when setting up a specific instance of this sequence: The next step is to define [summary variables](@ref variables) that the user can constrain when setting up a specific instance of this sequence:
```julia ```julia
@defvar begin @defvar begin
......
...@@ -11,6 +11,10 @@ In addition to the user-defined constraints, this optimisation will also take in ...@@ -11,6 +11,10 @@ In addition to the user-defined constraints, this optimisation will also take in
Internally, MRIBuilder will then optimise the `BuildingBlock` free parameters to match any user-defined constraints and/or objectives. Internally, MRIBuilder will then optimise the `BuildingBlock` free parameters to match any user-defined constraints and/or objectives.
This optimisation uses the [Ipopt](https://github.com/coin-or/Ipopt) optimiser accessed through the [JuMP.jl](https://jump.dev/JuMP.jl/stable/) library. This optimisation uses the [Ipopt](https://github.com/coin-or/Ipopt) optimiser accessed through the [JuMP.jl](https://jump.dev/JuMP.jl/stable/) library.
In addition to any user-defined objectives, the developer might also define secondary objectives (e.g., manimise the total sequence duration).
These objective functions will only be considered if they do not affect the result of the user-defined primary objective.
More details on these developer-defined secondary objectives can be found in the section on [defining new sequences](@ref defining_sequences)
## [Summary variables](@id variables) ## [Summary variables](@id variables)
All variables are available as members of the [`variables`](@ref) structure. All variables are available as members of the [`variables`](@ref) structure.
```@meta ```@meta
......
...@@ -462,6 +462,8 @@ Terms added at a lower level will be optimised before any terms with a higher le ...@@ -462,6 +462,8 @@ Terms added at a lower level will be optimised before any terms with a higher le
By default, the term is added to the `level=2`, which is appropriate for any cost functions added by the developer, By default, the term is added to the `level=2`, which is appropriate for any cost functions added by the developer,
which will generally only be optimised after any user-defined cost functions (which are added at `level=1` by [`add_simple_constraint!`](@ref) or [`set_simple_constraints!`](@ref). which will generally only be optimised after any user-defined cost functions (which are added at `level=1` by [`add_simple_constraint!`](@ref) or [`set_simple_constraints!`](@ref).
Any sequence will also have a `level=3` cost function, which minimises the total sequence duration.
""" """
function add_cost_function!(func, level=2) function add_cost_function!(func, level=2)
push!(GLOBAL_MODEL[][2], (Float64(level), func)) push!(GLOBAL_MODEL[][2], (Float64(level), func))
......
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