Sequence applications#

TL;DR

  • A SequenceApp separates the prescription (init_sequence), the sampling order (loop), one repetition (kernel) and the Pulseq definitions required by reconstruction (finalize).

  • design() creates a fresh sequence, runs loop and applies finalize. A direct application call adds one kernel, so single-repetition inspection and complete design use the same code path.

  • The init_sequence signature is the prescription exposed by protocol, parameters, the command line and protocol editors. Fixed design choices are class attributes, and construction caps the supplied system limits to the application’s MAX_GRAD and MAX_SLEW.

  • Construction checks a prescription. The resolved prescription and the scan time are recorded by init_sequence and read without playing the loop.

  • kernel records encoding indices as Pulseq labels. evaluate_labels() recovers their ADC order from the sequence, so sampling figures can use the implemented acquisition order.

  • Prescans are written by write() as separate files, each naming the next with NextSequence, so each file retains a single repeating unit.

A SequenceApp combines a prescription, sampling order, and repetition kernel into a complete sequence.

Application structure#

Concern

Method

Result

Prescription

init_sequence

Modules, timing, and sampling arrays.

Sampling order

loop

Repetition order for the complete acquisition.

One repetition

kernel

Blocks and labels for one shot or TR.

Metadata

finalize

Pulseq definitions required by reconstruction.

Construction runs init_sequence without adding acquisition blocks. design() creates a fresh sequence, runs loop, and applies finalize. Direct application calls add one kernel, so single-repetition inspection and complete design use the same code path.

Prescription and settings#

The init_sequence signature is the prescription exposed by protocol, the command line, and protocol editors. Its NumPy-style Parameters section defines units and defaults. Fixed design choices are class attributes. Every concrete application specifies MAX_GRAD and MAX_SLEW; construction caps the supplied system limits to these values.

class GentleEpi(Epi2DApp):
    MAX_SLEW = 60.0

Changing a design limit redesigns the gradient waveforms and may alter echo spacing, acquisition duration, and constraint estimates.

Checking a prescription#

A protocol editor checks a prescription whenever a value changes, and shows the resulting timing before anything is written. Construction is that check: init_sequence designs the events and the timing, and raises when the prescription cannot be designed. The loop contributes only the blocks, whose number grows with the matrix, so the check ends at construction. It does not evaluate the waveforms against gradient, PNS or SAR limits, which take the designed sequence (Gradient, PNS and SAR constraints).

Two results are read from the constructed application:

  • resolved, the prescription as designed. A value the design chooses, such as the shortest echo time for te=None, or adjusts, such as a receiver bandwidth whose dwell time is rounded to the ADC raster, is recorded by init_sequence with resolve() and reported in place of the requested value.

  • scan_time(), the duration of the whole chain, prescans included. init_sequence computes it from the timing it designed and stores it as duration; without it, the chain is designed and timed, at the cost of writing it.

parameters() describes the prescription to the editor: the type, default, unit and choices of each parameter, read from the annotation, the default and the Parameters section. The unit is the parenthesised group in the first sentence of a parameter’s description, Echo time (s)., and the choices of a string parameter are the values its documented type lists in braces.

Encoding labels#

kernel records encoding indices with Pulseq label extensions. The principal labels are LIN, PAR, ECO, SEG, REP, and SET. evaluate_labels() recovers their ADC order directly from the sequence. Sampling figures can therefore use the implemented acquisition order rather than reconstructing it from the prescription.

Prescans#

Loops returned by prescans() are written by write() as separate files before the imaging sequence. Each file names the next with NextSequence. The chain represents one acquisition while retaining a single repeating unit per file for repetition-based analyses.

See also#