From 7d116577fb1b5e42328eef909cf5cc7101178ace Mon Sep 17 00:00:00 2001
From: Michiel Cottaar <MichielCottaar@protonmail.com>
Date: Thu, 30 May 2024 16:05:50 +0100
Subject: [PATCH] Add variables. in documentation links

---
 docs/src/defining_sequence.md            | 11 +++++-----
 docs/src/implemented_sequences.md        |  8 +++----
 docs/src/scanners.md                     |  2 +-
 src/components/abstract_types.jl         |  4 ++--
 src/components/instant_gradients.jl      |  4 ++--
 src/components/pulses/constant_pulses.jl | 10 ++++-----
 src/components/pulses/instant_pulses.jl  |  4 ++--
 src/components/pulses/sinc_pulses.jl     | 12 +++++------
 src/containers/abstract.jl               |  6 +++---
 src/containers/base_sequences.jl         |  2 +-
 src/containers/building_blocks.jl        |  6 +++---
 src/parts/epi_readouts.jl                | 12 +++++------
 src/parts/helper_functions.jl            |  2 +-
 src/parts/trapezoids.jl                  | 16 +++++++-------
 src/pathways.jl                          | 27 ++++++++++++------------
 src/sequences/diffusion_spin_echoes.jl   | 25 +++++++++++-----------
 src/sequences/gradient_echoes.jl         | 17 ++++++---------
 src/sequences/spin_echoes.jl             | 17 ++++++---------
 src/variables.jl                         | 13 ++++++------
 19 files changed, 92 insertions(+), 106 deletions(-)

diff --git a/docs/src/defining_sequence.md b/docs/src/defining_sequence.md
index 9f24c93..a58f070 100644
--- a/docs/src/defining_sequence.md
+++ b/docs/src/defining_sequence.md
@@ -56,11 +56,10 @@ The next step is to define [summary variables](@ref variables) that the user can
     echo_time(ge::DiffusionSpinEcho) = 2 * (variables.effective_time(ge, :refocus) - variables.effective_time(ge, :excitation))
 end
 ```
-For this sequence, we can see that we define the [`diffusion_time`](@ref) as the time between the start of the first and second gradient pulse, and the [`echo_time`](@ref) as twice the time between the refocus and excitation pulses.
+For this sequence, we can see that we define the [`variables.diffusion_time`](@ref) as the time between the start of the first and second gradient pulse, and the [`variables.echo_time`](@ref) as twice the time between the refocus and excitation pulses.
 These variables need to be defined within a [`@defvar`](@ref) block.
-They will be available as function calls within the [`variables`](@ref) object.
 
-In addition to these sequence-specific summary variables, there are also a lot of variables already pre-defined on individual components, such as the [`slice_thickness](@ref) of the RF pulse or the [`gradient_strength`](@ref) of the gradient pulses. To access these summary variables on a sequence-level, we need to tell MRIBuilder for which RF pulses/gradients we are interested in computing these variables:
+In addition to these sequence-specific summary variables, there are also a lot of variables already pre-defined on individual components, such as the [`variables.slice_thickness](@ref) of the RF pulse or the [`variables.gradient_strength`](@ref) of the gradient pulses. To access these summary variables on a sequence-level, we need to tell MRIBuilder for which RF pulses/gradients we are interested in computing these variables:
 ```julia
 get_pulse(seq::DiffusionSpinEcho) = (excitation=seq[:excitation], refocus=seq[:refocus])
 get_gradient(seq::DiffusionSpinEcho) = (gradient=seq[:gradient], gradient2=seq[:gradient2])
@@ -74,7 +73,7 @@ using MRIBuilder
 sequence = DiffusionSpinEcho(bval=1., TE=:min, slice_thickness=2.)
 variables.flip_angle(sequence)
 ```
-Here we can see that we get the [`flip_angle`](@ref) for each of the two RF pulses defined using [`get_pulse`](@ref) above.
+Here we can see that we get the [`variables.flip_angle`](@ref) for each of the two RF pulses defined using [`get_pulse`](@ref) above.
 
 The final component to defining summary variables is to define one or more default coherence pathways using [`get_pathway`]:
 ```julia
@@ -84,8 +83,8 @@ Here the coherence [`Pathway`](@ref) sets out what a specific set of spins might
 In this case the sequence experiences two RF pulses and is excited by the first pulse and flipped by the second (`[90, 180]`).
 It is then observed during the first readout (`1`). 
 For such a [`Pathway`](@ref) we can compute:
-- the time that the spin spends in each longitudinal and transverse direction, which is particularly useful in the transverse direction to compute the amount of T2-weighting ([`duration_transverse`](@ref)) and the amount of time spent dephasing to compute the amount of T2*-weighting ([`duration_dephase`](@ref)).
-- the diffusion weighting experienced ([`bval`](@ref), [`bmat`](@ref), and [`qvec`](@ref))
+- the time that the spin spends in each longitudinal and transverse direction, which is particularly useful in the transverse direction to compute the amount of T2-weighting ([`variables.duration_transverse`](@ref)) and the amount of time spent dephasing to compute the amount of T2*-weighting ([`variables.duration_dephase`](@ref)).
+- the diffusion weighting experienced ([`variables.bval`](@ref), [`variables.bmat`](@ref), and [`variables.net_dephasing`](@ref))
 By defining a default pathway for the sequence, the user can now put constraints on any or all of these variables.
 
 
diff --git a/docs/src/implemented_sequences.md b/docs/src/implemented_sequences.md
index cd98327..aaa8086 100644
--- a/docs/src/implemented_sequences.md
+++ b/docs/src/implemented_sequences.md
@@ -8,7 +8,7 @@ To get help on a specific sequence, either follow the link in the sequence list
 
 When reading the help, you will notice that there are two type of expected inputs:
 - `Parameters`: these define the type of components that will be includes, e.g., the shape of the excitation pulse or the readout strategy. These parameters have to be set to certain fixed values. If unset, they will be determined by their default value as defined in the documentation.
-- `Variables`: These are a special type of parameters. In addition to being set to a fixed value, they can also be set to `:min` or `:max` to minimise or maximise the variable. If they are unset, they will be determined based on the other variables. For more details, see the section on [sequence optimisation](@ref sequence_optimisation).
+- `Variables`: These are a special type of parameters. In addition to being set to a fixed value, they can also be set to `:min` or `:max` to minimise or maximise the variable. If they are unset, they will be determined based on the other variables. For more details, see the section on [sequence optimisation](@ref sequence_optimisation). All variables are available in the [`variables`](@ref) module.
 
 As an example, the following creates and plots a [`DiffusionSpinEcho`](@ref) that has a b-value of 1, a minimal echo time, and a slice thickness of 2 mm:
 ```@example
@@ -22,7 +22,7 @@ nothing # hide
 ```
 ![DWI sequence diagram](dwi_1_min_2.png)
 
-If we want a specific [`diffusion_time`](@ref), we can just add it to the constraints, and the rest of the sequence will adapt as needed:
+If we want a specific [`variables.diffusion_time`](@ref), we can just add it to the constraints, and the rest of the sequence will adapt as needed:
 ```@example
 using MRIBuilder # hide
 using CairoMakie # hide
@@ -34,7 +34,7 @@ nothing # hide
 ```
 ![DWI sequence diagram with fixed diffusion time](dwi_1_80_min_2.png)
 
-We can even directly set some aspect of one of the sequence components, such as slowing down the gradient [`rise_time`](@ref)
+We can even directly set some aspect of one of the sequence components, such as slowing down the gradient [`variables.rise_time`](@ref)
 and the additional constraint will just be included in the [sequence optimisation](@ref sequence_optimisation):
 ```@example
 using MRIBuilder # hide
@@ -48,7 +48,7 @@ nothing # hide
 ![DWI sequence diagram with fixed diffusion time and rise time](dwi_1_80_min_2_15.png)
 
 Note that the previous sequences do not contain a realistic readout.
-Most sequences will only include an instant readout, unless you directly set the [`voxel_size`](@ref) and [`resolution`](@ref).
+Most sequences will only include an instant readout, unless you directly set the [`variables.voxel_size`](@ref) and [`variables.resolution`](@ref).
 ```@example
 using MRIBuilder # hide
 using CairoMakie # hide
diff --git a/docs/src/scanners.md b/docs/src/scanners.md
index 3adaa3f..dfc0b1b 100644
--- a/docs/src/scanners.md
+++ b/docs/src/scanners.md
@@ -3,7 +3,7 @@ The MRI scanner that is used during acquisition puts various constraints on the
 These constraints include safety considerations, such as tissue heating, and hardware constraints, such as maximum gradient strength and slew rate.
 Currently, MRIBuilder only considers the latter.
 
-To define a sequence appropriate for a specific scanner, a user would define a new [`Scanner`](@ref) with the appropriate [`B0`](@ref), maximum [`gradient_strength`](@ref), and maximum [`slew_rate`](@ref).
+To define a sequence appropriate for a specific scanner, a user would define a new [`Scanner`](@ref) with the appropriate [`B0`](@ref), maximum [`variables.gradient_strength`](@ref), and maximum [`variables.slew_rate`](@ref).
 This scanner would then be passed on to the [sequence optimisation](@ref sequence_optimisation).
 
 For ease of use, the `gradient_strength` and `slew_rate` of many scanners have already been pre-defined.
diff --git a/src/components/abstract_types.jl b/src/components/abstract_types.jl
index bb2f9c4..bcbfe7d 100644
--- a/src/components/abstract_types.jl
+++ b/src/components/abstract_types.jl
@@ -6,7 +6,7 @@ Super-type for all individual components that form an MRI sequence (i.e., RF pul
 
 RF pulses, instant gradients, and readouts are grouped together into [`EventComponent`](@ref).
 
-These all should have a [`duration`](@ref) in addition to any other relevant [`variables`](@ref).
+These all should have a [`variables.duration`](@ref) in addition to any other relevant [`variables`](@ref).
 """
 abstract type BaseComponent <: AbstractBlock end
 
@@ -39,7 +39,7 @@ variables.gradient_strength
 """
 Super-type for all RF pulses, instant gradients and readouts that might play out during a gradient waveform.
 
-These all have an [`effective_time`](@ref), which should quantify at what single time one can approximate the RF pulse or readout to have taken place.
+These all have an [`variables.effective_time`](@ref), which should quantify at what single time one can approximate the RF pulse or readout to have taken place.
 """
 abstract type EventComponent <: BaseComponent end
 
diff --git a/src/components/instant_gradients.jl b/src/components/instant_gradients.jl
index ca2def1..cf113d3 100644
--- a/src/components/instant_gradients.jl
+++ b/src/components/instant_gradients.jl
@@ -15,8 +15,8 @@ If the `orientation` is set an [`InstantGradient1D`](@ref) is returned, otherwis
 - `group`: name of the group to which this gradient belongs (used for scaling and rotating).
 
 ## Variables
-- [`qval`](@ref): Spatial frequency on which spins will be dephased due to this pulsed gradient in rad/um (scalar if `orientation` is set and vector otherwise).
-- [`spoiler_scale`](@ref): Length-scale on which spins will be dephased by exactly 2Ï€ in mm.
+- [`variables.qvec`](@ref): Spatial frequency on which spins will be dephased due to this pulsed gradient in rad/um.
+- [`variables.spoiler_scale`](@ref): Length-scale on which spins will be dephased by exactly 2Ï€ in mm.
 """
 abstract type InstantGradient{N} <: EventComponent end
 
diff --git a/src/components/pulses/constant_pulses.jl b/src/components/pulses/constant_pulses.jl
index 9ba22d7..ee9fa0d 100644
--- a/src/components/pulses/constant_pulses.jl
+++ b/src/components/pulses/constant_pulses.jl
@@ -14,11 +14,11 @@ Represents an radio-frequency pulse with a constant amplitude and frequency (i.e
 - `group`: name of the group to which this pulse belongs. This is used for scaling or adding phases/off-resonance frequencies.
 
 ## Variables
-- [`flip_angle`](@ref): rotation expected for on-resonance spins in degrees.
-- [`duration`](@ref): duration of the RF pulse in ms.
-- [`amplitude`](@ref): amplitude of the RF pulse in kHz.
-- [`phase`](@ref): phase at the start of the RF pulse in degrees.
-- [`frequency`](@ref): frequency of the RF pulse relative to the Larmor frequency (in kHz).
+- [`variables.flip_angle`](@ref): rotation expected for on-resonance spins in degrees.
+- [`variables.duration`](@ref): duration of the RF pulse in ms.
+- [`variables.amplitude`](@ref): amplitude of the RF pulse in kHz.
+- [`variables.phase`](@ref): phase at the start of the RF pulse in degrees.
+- [`variables.frequency`](@ref): frequency of the RF pulse relative to the Larmor frequency (in kHz).
 """
 struct ConstantPulse <: RFPulseComponent
     amplitude :: VariableType
diff --git a/src/components/pulses/instant_pulses.jl b/src/components/pulses/instant_pulses.jl
index 5a16b83..38dc108 100644
--- a/src/components/pulses/instant_pulses.jl
+++ b/src/components/pulses/instant_pulses.jl
@@ -13,8 +13,8 @@ Return an instant RF pulse that rotates all spins by `flip_angle` around an axis
 - `group`: name of the group to which this pulse belongs. This is used for scaling or adding phases/off-resonance frequencies.
 
 ## Variables
-- [`flip_angle`](@ref): angle by which spins are rotated in degrees.
-- [`phase`](@ref): angle of axis around which spins are rotated in degrees.
+- [`variables.flip_angle`](@ref): angle by which spins are rotated in degrees.
+- [`variables.phase`](@ref): angle of axis around which spins are rotated in degrees.
 """
 struct InstantPulse <: RFPulseComponent
     flip_angle :: VariableType
diff --git a/src/components/pulses/sinc_pulses.jl b/src/components/pulses/sinc_pulses.jl
index 55f7878..478ff10 100644
--- a/src/components/pulses/sinc_pulses.jl
+++ b/src/components/pulses/sinc_pulses.jl
@@ -17,12 +17,12 @@ Represents a radio-frequency pulse with a sinc-like amplitude and constant frequ
 - `group`: name of the group to which this pulse belongs. This is used for scaling or adding phases/off-resonance frequencies.
 
 ## Variables
-- [`flip_angle`](@ref): rotation expected for on-resonance spins in degrees.
-- [`duration`](@ref): duration of the RF pulse in ms.
-- [`amplitude`](@ref): amplitude of the RF pulse in kHz.
-- [`phase`](@ref): phase at the start of the RF pulse in degrees.
-- [`frequency`](@ref): frequency of the RF pulse relative to the Larmor frequency (in kHz).
-- [`bandwidth`](@ref): width of the rectangular function in frequency space (in kHz). If the `duration` is short (compared with 1/`bandwidth`), this bandwidth will only be approximate.
+- [`variables.flip_angle`](@ref): rotation expected for on-resonance spins in degrees.
+- [`variables.duration`](@ref): duration of the RF pulse in ms.
+- [`variables.amplitude`](@ref): amplitude of the RF pulse in kHz.
+- [`variables.phase`](@ref): phase at the start of the RF pulse in degrees.
+- [`variables.frequency`](@ref): frequency of the RF pulse relative to the Larmor frequency (in kHz).
+- [`variables.bandwidth`](@ref): width of the rectangular function in frequency space (in kHz). If the `duration` is short (compared with 1/`bandwidth`), this bandwidth will only be approximate.
 """
 struct SincPulse <: RFPulseComponent
     apodise :: Bool
diff --git a/src/containers/abstract.jl b/src/containers/abstract.jl
index 195af76..41a5cee 100644
--- a/src/containers/abstract.jl
+++ b/src/containers/abstract.jl
@@ -15,7 +15,7 @@ abstract type ContainerBlock <: AbstractBlock end
 
 Returns the start time of component with given `indices` with respect to the start of the [`ContainerBlock`](@ref).
 
-Also see [`variables.duration`](@ref), [`end_time`](@ref), and [`effective_time`](@ref)
+Also see [`variables.duration`](@ref), [`end_time`](@ref), and [`variables.effective_time`](@ref)
 """
 function start_time(container::ContainerBlock, index1, index2, indices...)
     start_time(container, index1) + start_time(container[index1], index2, indices...)
@@ -27,7 +27,7 @@ end
 
 Returns the start time of component with given `indices` with respect to the start of the [`ContainerBlock`](@ref).
 
-Also see [`variables.duration`](@ref), [`start_time`](@ref), and [`effective_time`](@ref)
+Also see [`variables.duration`](@ref), [`start_time`](@ref), and [`variables.effective_time`](@ref)
 """
 end_time(container::ContainerBlock, index, indices...) = start_time(container, index) + end_time(container[index], indices...)
 end_time(block::AbstractBlock) = variables.duration(block)
@@ -43,7 +43,7 @@ end
 
 Returns the start time of component with given `indices` with respect to the start of the [`ContainerBlock`](@ref).
 
-This will crash if the component does not have an [`effective_time`](@ref) (e.g., if it is (part of) a gradient waveform).
+This will crash if the component does not have an [`variables.effective_time`](@ref) (e.g., if it is (part of) a gradient waveform).
 
 Also see [`variables.duration`](@ref), [`start_time`](@ref), and [`end_time`](@ref)
 """
diff --git a/src/containers/base_sequences.jl b/src/containers/base_sequences.jl
index e1963ab..c26e2c7 100644
--- a/src/containers/base_sequences.jl
+++ b/src/containers/base_sequences.jl
@@ -141,7 +141,7 @@ Defines an MRI sequence from a vector of building blocks.
 ## Arguments
 - `blocks`: The actual building blocks that will be played in sequence. All the building blocks must be of type [`ContainerBlock`](@ref), which means that they cannot only contain actual [`BaseBuildingBlock`](@ref) objects, but also other [`BaseSequence`](@ref) objects.
     Objects of a different type are converted into a [`ContainerBlock`](@ref) internally:
-    - numbers/`nothing`/`:min`/`:max` : replaced with a [`Wait`](@ref) block with the appropriate constraint/objective added to its [`duration`](@ref).
+    - numbers/`nothing`/`:min`/`:max` : replaced with a [`Wait`](@ref) block with the appropriate constraint/objective added to its [`variables.duration`](@ref).
     - RF pulse or readout: will be embedded within a [`BuildingBlock`](@ref) of the appropriate length
 
 Specific named sequences might define additional variables.
diff --git a/src/containers/building_blocks.jl b/src/containers/building_blocks.jl
index 0e3322f..d409092 100644
--- a/src/containers/building_blocks.jl
+++ b/src/containers/building_blocks.jl
@@ -19,7 +19,7 @@ Main interface:
 - [`waveform_sequence`](@ref) returns just the gradient waveform as a sequence of [`GradientWaveform`](@ref) objects.
 - [`waveform`](@ref) returns just the gradient waveform as a sequence of (time, gradient_strength) tuples.
 - [`events`](@ref) returns the RF pulses and readouts.
-- [`qval`](@ref) returns area under curve for (part of) the gradient waveform.
+- [`variables.qvec`](@ref) returns area under curve for (part of) the gradient waveform.
 
 Sub-types need to implement:
 - `Base.keys`: returns sequence of keys to all the components.
@@ -239,7 +239,7 @@ variables.qvec
 
 Computes the addition to the [`variables.bmat`](@ref) contributed by a specific building block or gradient.
 
-`qstart` represents the [`qvec`](@ref) at the start of this component.
+`qstart` represents the [`variables.qvec`](@ref) at the start of this component.
 
 If `first_event` is set to something else than `nothing`, only the gradient waveform after this RF pulse/Readout will be considered.
 Similarly, if `last_event` is set to something else than `nothing`, only the gradient waveform up to this RF pulse/Readout will be considered.
@@ -380,7 +380,7 @@ end
 """
 An empty BuildingBlock representing dead time.
 
-It only has a single variable, namely its [`duration`](@ref).
+It only has a single variable, namely its [`variables.duration`](@ref).
 """
 struct Wait <: BaseBuildingBlock
     duration :: VariableType
diff --git a/src/parts/epi_readouts.jl b/src/parts/epi_readouts.jl
index a2a35be..ed89c70 100644
--- a/src/parts/epi_readouts.jl
+++ b/src/parts/epi_readouts.jl
@@ -11,16 +11,16 @@ import ...Pathways: PathwayWalker, update_walker_till_time!, walk_pathway!
 Defines an (accelerated) EPI readout.
 
 ## Parameters
-- [`resolution`](@ref): Resolution of the final image in the frequency- and phase-encode directions.
+- [`variables.resolution`](@ref): Resolution of the final image in the frequency- and phase-encode directions.
 - `recenter`: if true, the signal will be recentred in k-space after the EPI readout.
 - `group`: name of the group used to rotate the readout gradients (default: :FOV).
 
 ## Variables:
-- [`voxel_size`](@ref): size of the voxel in the frequency- and phase-encode directions.
-- [`fov`](@ref): size of the FOV in the frequency- and phase-encode directions.
-- [`ramp_overlap`](@ref): what fraction of the gradient ramp should overlap with the readout.
-- [`oversample`](@ref): by how much to oversample in the frequency-encode direcion.
-- [`dwell_time`](@ref): dwell time in the frequency-encode direction
+- [`variables.voxel_size`](@ref): size of the voxel in the frequency- and phase-encode directions.
+- [`variables.fov`](@ref): size of the FOV in the frequency- and phase-encode directions.
+- [`variables.ramp_overlap`](@ref): what fraction of the gradient ramp should overlap with the readout.
+- [`variables.oversample`](@ref): by how much to oversample in the frequency-encode direcion.
+- [`variables.dwell_time`](@ref): dwell time in the frequency-encode direction
 """
 struct EPIReadout{N} <: BaseSequence{N}
     start_gradient :: Trapezoid
diff --git a/src/parts/helper_functions.jl b/src/parts/helper_functions.jl
index 95906c1..49d609e 100644
--- a/src/parts/helper_functions.jl
+++ b/src/parts/helper_functions.jl
@@ -296,7 +296,7 @@ Returns two DWI gradients that are guaranteed to cancel each other out.
 - `scanner`: Used for testing. Do not set this parameter at this level (instead set it for the total sequence using [`build_sequence`](@ref)).
 
 ## Variables
-- [`spoiler_scale`](@ref): maximum spoiler scale (before applying any reductions due to `scale`).
+- [`variables.spoiler_scale`](@ref): maximum spoiler scale (before applying any reductions due to `scale`).
 - Any other parameters expected by [`Trapezoid`](@ref).
 """
 function gradient_spoiler(; optimise=false, scanner=nothing, orientation=[0, 0, 1], group=:FOV, spoiler_scale=1., duration=:min, variables...)
diff --git a/src/parts/trapezoids.jl b/src/parts/trapezoids.jl
index 8e078a2..f2a4ed6 100644
--- a/src/parts/trapezoids.jl
+++ b/src/parts/trapezoids.jl
@@ -37,13 +37,13 @@ Defines a trapezoidal pulsed gradient
 Variables can be set during construction or afterwards as an attribute.
 If not set, they will be determined during the sequence optimisation.
 ### Timing variables
-- [`rise_time`](@ref): Time of the gradient to reach from 0 to maximum in ms. If explicitly set to 0, the scanner slew rate will be ignored.
-- [`flat_time`](@ref): Time that the gradient stays at maximum strength in ms.
-- [`δ`](@ref): effective pulse duration (`rise_time` + `flat_time`) in ms.
-- [`duration`](@ref): total pulse duration (2 * `rise_time` + `flat_time`) in ms.
+- [`variables.rise_time`](@ref): Time of the gradient to reach from 0 to maximum in ms. If explicitly set to 0, the scanner slew rate will be ignored.
+- [`variables.flat_time`](@ref): Time that the gradient stays at maximum strength in ms.
+- [`variables.δ`](@ref): effective pulse duration (`rise_time` + `flat_time`) in ms.
+- [`variables.duration`](@ref): total pulse duration (2 * `rise_time` + `flat_time`) in ms.
 ### Gradient variables
-- [`gradient_strength`](@ref): Maximum gradient strength achieved during the pulse in kHz/um
-- [`qval`](@ref): Spatial scale on which spins will be dephased due to this pulsed gradient in rad/um (given by `δ` * `gradient_strength`).
+- [`variables.gradient_strength`](@ref): Maximum gradient strength achieved during the pulse in kHz/um
+- [`variables.qvec`](@ref): Spatial scale on which spins will be dephased due to this pulsed gradient in rad/um (given by `δ` * `gradient_strength`).
 
 The `bvalue` can be constrained for multiple gradient pulses by creating a `Pathway`.
 """
@@ -232,8 +232,8 @@ Parameters and variables are identical as for [`Trapezoid`](@ref) with the addit
 - `ramp_overlap`: how much the gradient ramp should overlap with the ADC. 0 for no overlap, 1 for full overlap (default: 1). Can be set to `nothing` to become a free variable.
 
 ## Variables
-- [`fov`](@ref): FOV of the output image along this single k-space line in mm.
-- [`voxel_size`](@ref): size of each voxel along this single k-space line in mm.
+- [`variables.fov`](@ref): FOV of the output image along this single k-space line in mm.
+- [`variables.voxel_size`](@ref): size of each voxel along this single k-space line in mm.
 """
 struct LineReadout{N} <: BaseTrapezoid{N}
     trapezoid :: Trapezoid{N}
diff --git a/src/pathways.jl b/src/pathways.jl
index 54ba18c..0f6bc28 100644
--- a/src/pathways.jl
+++ b/src/pathways.jl
@@ -2,7 +2,7 @@ module Pathways
 import LinearAlgebra: norm, tr
 import StaticArrays: SVector, SMatrix
 import ..Components: NoGradient, RFPulseComponent, ReadoutComponent, InstantGradient, GradientWaveform
-import ..Containers: BaseSequence, Sequence, BaseBuildingBlock, waveform, events, waveform_sequence, start_time, AlternativeBlocks
+import ..Containers: BaseSequence, Sequence, BaseBuildingBlock, waveform, events, waveform_sequence, start_time, AlternativeBlocks, ContainerBlock
 import ..Variables: VariableType, get_pathway, variables, @defvar, AbstractBlock
 
 
@@ -14,7 +14,7 @@ Describes how a specific spin/isochromat might experience the sequence.
 Only a single pathway through the RF pulses is considered,
 so that at every point in time the spins are in one of the following four states:
 - +longitudinal: initial relaxed state
-- +transverse: excited state. During this time gradients will affect the [`area_under_curve`](@ref) (or [`qval`](@ref)) and [`bval`](@ref).
+- +transverse: excited state. During this time gradients will affect the [`variables.area_under_curve`](@ref) (or [`variables.qval`](@ref)) and [`variables.bval`](@ref).
 - -longitudinal: inverse state
 - -transverse: inverse excited state. During this time all gradients will have the inverse effect compared with +transverse.
 
@@ -28,22 +28,21 @@ The RF pulses cause mappings between these different states as described below.
     - `:excite`/90: Takes spin state one step along the following sequence +longitudinal -> +transverse -> -longitudinal -> -transverse -> +longitudinal
     - `:neg_excite`/270/-90: Inverse step compared with `:excite`.
 - `readout_index`: After encountering the number of pulses as defined in `pulse_effects`, continue the `Pathway` until the readout given by `index` is reached. If set to 0 the `Pathway` is terminated immediately after the last RF pulse.
-- `group`: which gradient grouping to consider for the `qvec` and `bmat`. If not set, all gradients will be considered (using their current alignment).
+- `group`: which gradient grouping to consider for the `net_dephasing` and `bmat`. If not set, all gradients will be considered (using their current alignment).
 
 ## Attributes
 Over the pathway the following values are computed. Each can be accessed by calling the appropriate function:
 
 ### Timings
-- [`duration_state`](@ref): The total amount of time spent in a specific state in this pathway (+longitudinal, +transverse, -longitudinal, or -transverse)
-- [`duration_transverse`](@ref): The total amount of time the spins spent in the transverse plane in ms. This can be used to quantify the expected effect of T2-decay.
-- [`duration_dephase`](@ref): The total amount of time the spins spent in the +transverse relative to -transverse state in ms. The absolute value of this can be used to quantify the expected effect of T2'-decay.
+- [`variables.duration_state`](@ref): The total amount of time spent in a specific state in this pathway (+longitudinal, +transverse, -longitudinal, or -transverse)
+- [`variables.duration_transverse`](@ref): The total amount of time the spins spent in the transverse plane in ms. This can be used to quantify the expected effect of T2-decay.
+- [`variables.duration_dephase`](@ref): The total amount of time the spins spent in the +transverse relative to -transverse state in ms. The absolute value of this can be used to quantify the expected effect of T2'-decay.
 
 ### Effect of gradients
 The area under curve, q-values, and b-values are computed separately for each group of gradients (depending on the `group` keyword set during construction).
-- [`qvec`](@ref): Net displacement vector in k-space/q-space.
-- [`qval`](@ref)/[`area_under_curve`](@ref): size of the displacement in k-space/q-space. For a spoiled pathway, this should be large compared with 1/voxel size; for unspoiled pathways it should be (close to) zero.
-- [`bmat`](@ref): Net diffusion weighting due to gradients along the `Pathway` in matrix form.
-- [`bval`](@ref): Net diffusion weighting due to gradients along the `Pathway` as a single number.
+- [`variables.net_dephasing`](@ref): Net displacement vector in k-space/q-space.
+- [`variables.bmat`](@ref): Net diffusion weighting due to gradients along the `Pathway` in matrix form.
+- [`variables.bval`](@ref): Net diffusion weighting due to gradients along the `Pathway` as a single number.
 """
 struct Pathway <: AbstractBlock
     # user provided
@@ -97,7 +96,7 @@ end
 Returns the total amount of time that spins following the given [`Pathway`](@ref) spent in the transverse plane.
 This determines the amount of T2-weighting as ``e^{t/T_2}``, where ``t`` is the `duration_transverse`.
 
-Also see [`duration_dephase`](@ref) for T2'-weighting.
+Also see [`variables.duration_dephase`](@ref) for T2'-weighting.
 """
 variables.duration_transverse
 
@@ -110,7 +109,7 @@ end
 Returns the net time that spins following the given [`Pathway`](@ref) spent in the +transverse versus the -transverse state.
 This determines the amount of T2'-weighting as ``e^{t/T_2'}``, where ``t`` is the `duration_dephase`.
 
-Also see [`duration_transverse`](@ref) for T2-weighting.
+Also see [`variables.duration_transverse`](@ref) for T2-weighting.
 """
 variables.duration_dephase
 
@@ -262,7 +261,7 @@ For individual pulses and gradients, the following behaviour is implemented:
 - If a pulse is encountered, call [`update_walker_pulse!`](@ref)`(walker, pulse_effects, pulse_effective_time)`
 - If a gradient is encountered, call [`update_walker_gradient!`](@ref)(gradient, walker, gradient_start_time)
 
-For overlapping gradients/pulses, one should first encounter the part of the gradient before the [`effective_time`](@ref) of the pulse,
+For overlapping gradients/pulses, one should first encounter the part of the gradient before the [`variables.effective_time`](@ref) of the pulse,
 then apply the pulse, and then the rest of the gradient.
 This effective time can be passed on to [`update_walker_gradient!`](@ref) to allow part of the gradient waveform to be applied.
 
@@ -457,7 +456,7 @@ The following steps will be taken:
 - update the appropriate `walker.qvec` and `walker.bmat` based on the gradient waveform. This will require appropriate `qvec`/`bmat` functions to be defined for the gradient building block.
 - update `walker.last_gradient_time` to the time at the end of the gradient.
 
-This requires [`bmat_gradient`](@ref) and [`qvec`](@ref) to be implemented for the [`GradientWaveform`](@ref).
+This requires [`variables.bmat_gradient`](@ref) and [`variables.qvec`](@ref) to be implemented for the [`GradientWaveform`](@ref).
 """
 update_walker_gradient!(gradient::NoGradient, walker::PathwayWalker, gradient_start_time::VariableType) = nothing
 
diff --git a/src/sequences/diffusion_spin_echoes.jl b/src/sequences/diffusion_spin_echoes.jl
index 80f741e..4e52614 100644
--- a/src/sequences/diffusion_spin_echoes.jl
+++ b/src/sequences/diffusion_spin_echoes.jl
@@ -5,7 +5,7 @@ import ...Containers: start_time
 import ...Variables: get_pulse, get_readout, get_gradient, variables, @defvar
 import ...Pathways: Pathway, get_pathway
 import ...BuildSequences: build_sequence
-import ...Scanners: Default_Scanner
+import ...Scanners: Default_Scanner, Scanner
 
 const DiffusionSpinEcho = Sequence{:DiffusionSpinEcho}
 const DW_SE = DiffusionSpinEcho
@@ -22,20 +22,19 @@ By default, an instant excitation pulse and readout event are used.
 If image parameters are provided, this will switch to a sinc pulse and EPI readout.
 
 ## Parameters
-- [`excitation`](@ref): properties of the excitation pulse as described in [`excitation_pulse`](@ref).
-- [`gradient`](@ref): properties of the diffusion-weighting gradients as described in [`dwi_gradients`](@ref).
-- [`refocus`](@ref): properties of the refocus pulse as described in [`refocus_pulse`](@ref).
-- [`readout`](@ref): properties of the readout as described in [`readout_event`](@ref).
-- [`spoiler`](@ref): if set adds a spoiler [`gradient_spoiler`](@ref) gradient after the readout (e.g., `spoiler=()` to add a gradient in the z-direction of the `FOV` coordinate system that fully dephases spins over 1 mm).
-- Image parameters ([`resolution`](@ref)/[`fov`](@ref)/[`voxel_size`](@ref)/[`slice_thickness`](@ref)): describe the properties of the resulting image. See [`interpret_image_size`](@ref) for details.
-- [`optim`](@ref): parameters to pass on to the Ipopt optimiser (see https://coin-or.github.io/Ipopt/OPTIONS.html).
-- [`scanner`](@ref): Sets the [`Scanner`](@ref) used to constraint the gradient parameters. If not set, the [`Default_Scanner`](@ref) will be used.
+- `excitation`: properties of the excitation pulse as described in [`excitation_pulse`](@ref).
+- `gradient`: properties of the diffusion-weighting gradients as described in [`dwi_gradients`](@ref).
+- `refocus`: properties of the refocus pulse as described in [`refocus_pulse`](@ref).
+- `readout`: properties of the readout as described in [`readout_event`](@ref).
+- Image parameters ([`variables.resolution`](@ref)/[`variables.fov`](@ref)/[`variables.voxel_size`](@ref)/[`variables.slice_thickness`](@ref)): describe the properties of the resulting image. See [`interpret_image_size`](@ref) for details.
+- `optim`: parameters to pass on to the Ipopt optimiser (see https://coin-or.github.io/Ipopt/OPTIONS.html).
+- `scanner`: Sets the [`Scanner`](@ref) used to constraint the gradient parameters. If not set, the [`Default_Scanner`](@ref) will be used.
 
 ## Variables
-- [`TE`](@ref)/[`echo_time`](@ref): echo time between excitation pulse and spin echo in ms.
-- [`delay`](@ref): delay between the readout and the peak of the spin echo in ms (positive number indicates that readout is after the spin echo). Defaults to zero.
-- [`duration`](@ref): total duration of the sequence from start of excitation pulse to end of readout or spoiler in ms.
-- [`Δ`](@ref)/[`diffusion_time`](@ref): Time from the start of one diffusion-weighted gradient till the other in ms.
+- [`variables.TE`](@ref)/[`variables.echo_time`](@ref): echo time between excitation pulse and spin echo in ms.
+- [`variables.delay`](@ref): delay between the readout and the peak of the spin echo in ms (positive number indicates that readout is after the spin echo). Defaults to zero.
+- [`variables.duration`](@ref): total duration of the sequence from start of excitation pulse to end of readout or spoiler in ms.
+- [`variables.Δ`](@ref)/[`variables.diffusion_time`](@ref): Time from the start of one diffusion-weighted gradient till the other in ms.
 """
 function DiffusionSpinEcho(; delay=0., excitation=(), gradient=(), refocus=(), readout=(), optim=(), spoiler=nothing, resolution=nothing, fov=nothing, voxel_size=nothing, slice_thickness=nothing, scanner=Default_Scanner, variables...)
     build_sequence(scanner; optim...) do
diff --git a/src/sequences/gradient_echoes.jl b/src/sequences/gradient_echoes.jl
index ef05752..ab9ec7e 100644
--- a/src/sequences/gradient_echoes.jl
+++ b/src/sequences/gradient_echoes.jl
@@ -19,27 +19,22 @@ If image parameters are provided, this will switch to a sinc pulse and EPI reado
 ## Parameters
 - `excitation`: properties of the excitation pulse as described in [`excitation_pulse`](@ref).
 - `readout`: properties of the readout as described in [`readout_event`](@ref).
-- `spoiler`: if set adds a spoiler [`gradient_spoiler`](@ref) gradient after the readout (e.g., `spoiler=()` to add a gradient in the z-direction of the `FOV` coordinate system that fully dephases spins over 1 mm).
-- Image parameters ([`resolution`](@ref)/[`fov`](@ref)/[`voxel_size`](@ref)/[`slice_thickness`](@ref)): describe the properties of the resulting image. See [`interpret_image_size`](@ref) for details.
+- Image parameters ([`variables.resolution`](@ref)/[`variables.fov`](@ref)/[`variables.voxel_size`](@ref)/[`variables.slice_thickness`](@ref)): describe the properties of the resulting image. See [`interpret_image_size`](@ref) for details.
 - `optim`: parameters to pass on to the Ipopt optimiser (see https://coin-or.github.io/Ipopt/OPTIONS.html).
 - `scanner`: Sets the [`Scanner`](@ref) used to constraint the gradient parameters. If not set, the [`Default_Scanner`](@ref) will be used.
 
 ## Variables
-- [`TE`](@ref)/[`echo_time`](@ref): echo time between excitation pulse and readout in ms (required).
-- [`duration`](@ref): total duration of the sequence from start of excitation pulse to end of readout or spoiler in ms.
+- [`variables.TE`](@ref)/[`variables.echo_time`](@ref): echo time between excitation pulse and readout in ms (required).
+- [`variables.duration`](@ref): total duration of the sequence from start of excitation pulse to end of readout in ms.
 """
-function GradientEcho(; excitation=(), readout=(), optim=(), spoiler=nothing, resolution=nothing, fov=nothing, voxel_size=nothing, slice_thickness=nothing, scanner=Default_Scanner, variables...)
+function GradientEcho(; excitation=(), readout=(), optim=(), resolution=nothing, fov=nothing, voxel_size=nothing, slice_thickness=nothing, scanner=Default_Scanner, variables...)
     build_sequence(scanner; optim...) do
         (slice_thickness, _, extra_readout_params) = interpret_image_size(fov, resolution, voxel_size, slice_thickness)
-        parts = Any[
+        return Sequence([
             :excitation => excitation_pulse(; slice_thickness=slice_thickness, excitation...),
             nothing,
             :readout => readout_event(; extra_readout_params..., readout...),
-        ]
-        if !isnothing(spoiler)
-            push!(parts, gradient_spoiler(; spoiler...))
-        end
-        return Sequence(parts; name=:GradientEcho, variables...)
+        ]; name=:GradientEcho, variables...)
     end
 end
 
diff --git a/src/sequences/spin_echoes.jl b/src/sequences/spin_echoes.jl
index 83fea19..8ecdea4 100644
--- a/src/sequences/spin_echoes.jl
+++ b/src/sequences/spin_echoes.jl
@@ -20,30 +20,25 @@ If image parameters are provided, this will switch to a sinc pulse and EPI reado
 - [`excitation`](@ref): properties of the excitation pulse as described in [`excitation_pulse`](@ref).
 - [`refocus`](@ref): properties of the refocus pulse as described in [`refocus_pulse`](@ref).
 - [`readout`](@ref): properties of the readout as described in [`readout_event`](@ref).
-- [`spoiler`](@ref): if set adds a spoiler [`gradient_spoiler`](@ref) gradient after the readout (e.g., `spoiler=()` to add a gradient in the z-direction of the `FOV` coordinate system that fully dephases spins over 1 mm).
-- Image parameters ([`resolution`](@ref)/[`fov`](@ref)/[`voxel_size`](@ref)/[`slice_thickness`](@ref)): describe the properties of the resulting image. See [`interpret_image_size`](@ref) for details.
+- Image parameters ([`variables.resolution`](@ref)/[`variables.fov`](@ref)/[`variables.voxel_size`](@ref)/[`variables.slice_thickness`](@ref)): describe the properties of the resulting image. See [`interpret_image_size`](@ref) for details.
 - [`optim`](@ref): parameters to pass on to the Ipopt optimiser (see https://coin-or.github.io/Ipopt/OPTIONS.html).
 - [`scanner`](@ref): Sets the [`Scanner`](@ref) used to constraint the gradient parameters. If not set, the [`Default_Scanner`](@ref) will be used.
 
 ## Variables
-- [`TE`](@ref)/[`echo_time`](@ref): echo time between excitation pulse and spin echo in ms (required).
-- [`delay`](@ref): delay between the readout and the peak of the spin echo in ms (positive number indicates that readout is after the spin echo). Defaults to zero.
-- [`duration`](@ref): total duration of the sequence from start of excitation pulse to end of readout or spoiler in ms.
+- [`variables.TE`](@ref)/[`variables.echo_time`](@ref): echo time between excitation pulse and spin echo in ms (required).
+- [`variables.delay`](@ref): delay between the readout and the peak of the spin echo in ms (positive number indicates that readout is after the spin echo). Defaults to zero.
+- [`variables.duration`](@ref): total duration of the sequence from start of excitation pulse to end of readout or spoiler in ms.
 """
 function SpinEcho(; delay=0., excitation=(), refocus=(), readout=(), optim=(), spoiler=nothing, resolution=nothing, fov=nothing, voxel_size=nothing, slice_thickness=nothing, scanner=Default_Scanner, variables...)
     build_sequence(scanner; optim...) do
         (slice_thickness, _, extra_readout_params) = interpret_image_size(fov, resolution, voxel_size, slice_thickness)
-        parts = Any[
+        return Sequence(Any[
             :excitation => excitation_pulse(; slice_thickness=slice_thickness, excitation...),
             nothing,
             :refocus => refocus_pulse(; slice_thickness=slice_thickness, refocus...),
             nothing,
             :readout => readout_event(; extra_readout_params..., readout...),
-        ]
-        if !isnothing(spoiler)
-            push!(parts, gradient_spoiler(; spoiler...))
-        end
-        return Sequence(parts; name=:SpinEcho, delay=delay, variables...)
+        ]; name=:SpinEcho, delay=delay, variables...)
     end
 end
 
diff --git a/src/variables.jl b/src/variables.jl
index ee824f3..2ca9341 100644
--- a/src/variables.jl
+++ b/src/variables.jl
@@ -2,10 +2,9 @@
 Defines the functions that can be called on parts of an MRI sequence to query or constrain any variables.
 
 In addition this defines:
-- [`variables`](@ref): dictionary containing all variables.
+- [`variables`](@ref): module containing all variables.
 - [`VariableType`](@ref): parent type for any variables (whether number or JuMP variable).
 - [`get_free_variable`](@ref): helper function to create new JuMP variables.
-- [`VariableNotAvailable`](@ref): error raised if variable is not defined for specific [`AbstractBlock`](@ref).
 - [`set_simple_constraints!`](@ref): call [`apply_simple_constraint!`](@ref) for each keyword argument.
 - [`apply_simple_constraint!`](@ref): set a simple equality constraint.
 - [`get_pulse`](@ref)/[`get_gradient`](@ref)/[`get_readout`](@ref): Used to get the pulse/gradient/readout part of a building block
@@ -252,7 +251,7 @@ def_alternate_variable!(:qval_square, :qvec, qv -> sum(q -> q * q, qv), nothing,
 """
     qval(gradient)
 
-The norm of the [`qvec`](@ref).
+The norm of the [`variables.qvec`](@ref).
 """
 variables.qval
 
@@ -261,7 +260,7 @@ variables.qval
 
 Spatial scale in mm over which the spoiler gradient will dephase by 2Ï€.
 
-Automatically computed based on [`qvec`](@ref).
+Automatically computed based on [`variables.qvec`](@ref).
 """
 variables.spoiler_scale
 
@@ -276,14 +275,14 @@ end
 """
     gradient_strength_norm(gradient)
 
-The norm of the [`gradient_strength`](@ref).
+The norm of the [`variables.gradient_strength`](@ref).
 """
 variables.gradient_strength_norm
 
 """
     slew_rate_norm(gradient)
 
-The norm of the [`slew_rate`](@ref).
+The norm of the [`variables.slew_rate`](@ref).
 """
 variables.slew_rate_norm
 
@@ -555,7 +554,7 @@ function make_generic end
 """
     scanner_constraints!(block)
 
-Constraints [`gradient_strength`](@ref) and [`slew_rate`](@ref) to be less than the [`global_scanner`](@ref) maximum.
+Constraints [`variables.gradient_strength`](@ref) and [`variables.slew_rate`](@ref) to be less than the [`global_scanner`](@ref) maximum.
 """
 function scanner_constraints!(bb::AbstractBlock)
     for (var, max_value) in [
-- 
GitLab