SequenceApp#

class pypulseqpp.sequences.SequenceApp[source]#

Bases: ABC

A complete sequence, designed from a prescription and played one repetition at a time.

Constructing an application designs it: init_sequence receives the prescription and builds the events and the sampling order. Nothing is played until design(), which starts a new seq, runs loop() – the scan loop, calling kernel() once per repetition – and then finalize(). Calling the application plays one kernel call, so a single repetition or a chunk of the scan is written the same way the whole scan is.

Construction therefore checks a prescription: init_sequence raises when the prescription cannot be designed. It records the values the design chooses or adjusts with resolve(), and the scan time as duration, so that resolved and scan_time() are available without playing the loop.

Class attributes are the settings a user does not prescribe. A subclass that changes one, and nothing else, is the same sequence under a different setting:

class GentleGre2D(Gre2DApp):
    MAX_SLEW = 120.0
Attributes:
  • MAX_GRAD, MAX_SLEW (float) – Gradient (mT/m) and slew (T/m/s) ceilings the sequence is held under, together with what system reports. Every concrete application sets both; there is no default.

  • system (pypulseqpp.Opts) – The limits the sequence was designed under.

  • seq (pypulseqpp.Sequence) – What has been played so far.

Examples

A subclass states its ceilings, designs from the prescription in init_sequence, plays the scan in loop and records the definitions a reconstruction reads in finalize:

>>> import pypulseqpp as pp
>>> import pypulseqpp.sequences as design
>>> class HardPulseTrain(design.SequenceApp):
...     MAX_GRAD = 40.0
...     MAX_SLEW = 150.0
...     NAME = "hard_pulse_train"
...     def init_sequence(self, n_lines: int = 4):
...         self.excitation = design.NonSelectiveExcitation(self.system, 10.0, 0.5e-3)
...         self.n_lines = n_lines
...     def loop(self):
...         for line in range(self.n_lines):
...             self.kernel(line)
...     def kernel(self, line):
...         self.seq.add_block(self.excitation.rf, *self.labels(LIN=line))
...     def finalize(self):
...         self.seq.set_definition("Name", self.NAME)
>>> seq = HardPulseTrain(n_lines=4).design()
>>> seq.num_blocks, seq.get_definition("Name")
(4, 'hard_pulse_train')

Methods

design

Build the whole scan, or the named prescan, into a new seq.

finalize

Complete seq after the loop, for example with its definitions.

init_sequence

Design the events and the sampling order from the prescription.

kernel

Add the blocks of one repetition to seq.

labels

Return the label events that set each label to its new value.

loop

Run the whole scan, calling kernel() once per repetition in play order.

parameters

Return each parameter of init_sequence with its type, default, unit and description.

prescans

Return the prescans played before this sequence, as the loops that play them.

protocol

Return the prescription init_sequence accepts, with its defaults.

resolve

Record the value a prescribed parameter took in the design.

restart_labels

Write every label's next value as a SET, regardless of what was written before.

scan_time

Return the time the whole chain of prescans and main sequence plays, in seconds.

write

Design and write the chain of prescans and the main sequence.

Attributes

NAME

Written as the Name definition and the default file name.

duration

Time the whole chain of prescans and main sequence plays, in seconds, when init_sequence computes it; None otherwise.

main

Module-level entry point of a concrete sequence implementation.

resolved

The prescription as designed, by parameter name, in each parameter's prescribed unit.

MAX_GRAD

MAX_SLEW

Examples using SequenceApp#

A sequence application

A sequence application

Individually optimized 3D fast spin echo

Individually optimized 3D fast spin echo

Conventional 3D fast spin echo

Conventional 3D fast spin echo

Shuffled echo-resolved 3D FSE

Shuffled echo-resolved 3D FSE