Homepage#

Tests codecov Ruff Docs: stable Docs: latest Virtual scanner: try it

PyPI Python Wheels License: MIT Source

pulserverpulserver

pulserver orchestrates MR acquisitions with Pulseq sequences on clinical scanners: sequence design, scanner preparation and reconstruction. It resolves the protocol an operator edits in the scanner UI against a pypulseqpp sequence function, converts the design into the segmented representation a scanner interpreter plays, and routes the raw data of each series, enriched from the sequence that acquired it, to a reconstruction, normally bartorch. Vendor-specific playout belongs to the scanner interpreters, which call pulserver’s services. Passing the checks pypulseqpp provides does not establish scanner or patient safety.

Try the virtual scanner in your browser: https://pulserver.github.io/MaRGE/.

Features#

  • Protocol resolution: the echo time, repetition time and bandwidth a design achieves, the scan time, and the design error for an infeasible prescription.

  • Stateless design calls for every interpreter host process of a scanner, one command per call or through a warm server, and a store of immutable designs named by their content.

  • Segmentation of a NextSequence chain into a binary IR cache, read by an ANSI C library linked into the interpreter, with the prescribed field-of-view offset applied to the logical-frame design as RF and ADC frequency and phase.

  • MRD enrichment: encoding counters, flags, encoding spaces and trajectories from the sequence.

  • Reconstruction plugins run in isolated worker processes, over a live MRD stream, an ISMRMRD file or an assembled acquisition bucket.

pulserver architecturepulserver architecture

Quick start#

pip install pulserver bartorch

A sequence plugin binds a pypulseqpp sequence function, a function that returns the designed sequences, to the scanner protocol, and a reconstruction plugin reconstructs the series it acquires. The client of a scan chooses the reconstruction, independently of the sequence. The plugin below evaluates a protocol by designing the sequence, which states the scan time and refuses a prescription the design cannot realize:

# sequences/gre.py
from pypulseqpp import sequences
from pypulseqpp.sequences.sequence.gre2D_sequence import gre2d
from pulserver.design import Evaluation, SequencePlugin, TimeParam, UIParam


class Gre(SequencePlugin):
    app = gre2d
    protocol = {UIParam.TE: TimeParam("te", range_min=3000, range_max=20000)}  # µs

    def evaluate(self, system, protocol):
        scan = self.app(system, **protocol.arguments)
        return Evaluation(protocol, sequences.duration(scan))
# recon/gre.py
import torch
import bartorch.tools as bt
from bartorch import apps, priors
from pulserver import recon


class Pics(recon.ReconPlugin):
    def recon(self, context, branch, data):
        kspace = torch.from_numpy(data.data.kspace)  # (coils, y, x)
        maps = bt.ecalib(kspace, maps=1)
        image = apps.pics(kspace, maps, regularizers=priors.Wavelet((-1, -2), 0.005))
        return recon.ReconResult(image.abs().numpy())


PLUGIN = Pics()

Scan a phantom on the virtual scanner and reconstruct it:

printf '[Limits]\nB0: 3.0\n[Limits End]\n' > limits.txt
pulserver proxy --store designs --port 9002 --plugins recon &
pulserver scan --plugins sequences --plugin gre --reconstruction gre \
  --limits limits.txt --store designs --recon 127.0.0.1:9002 --output images

The shipped sequences and reconstructions are found by name after the given directories, so --plugin gre_radial2d or --reconstruction pics needs no file of its own. A scan of a shipped sequence that names no reconstruction uses the shipped reconstruction paired with it. On a scanner, the interpreter makes the same design calls, and the reconstruction client streams to the same proxy and names its reconstruction in its config.

Documentation#

The user guide covers installation and support, running the two services, and writing scanner-sequence and reconstruction plugins. The explanations describe the architecture, protocol resolution, the design store, the scanner representation, the virtual scanner and raw-data enrichment, and the examples are a course from a protocol to a reconstructed image, followed by Tours of specialised workflows, each executed when the documentation is built. Every version of the documentation is published at https://pulserver.github.io/pulserver/.

Citation#

pulserver has no project publication. Cite the formats it is built on in work that uses it:

@article{layton2017pulseq,
  title   = {Pulseq: a rapid and hardware-independent pulse sequence prototyping framework},
  author  = {Layton, Kelvin J and Kroboth, Stefan and Jia, Feng and Littin, Sebastian
             and Yu, Huijun and Leupold, Jochen and Nielsen, Jon-Fredrik
             and St{\"o}cker, Tony and Zaitsev, Maxim},
  journal = {Magnetic Resonance in Medicine},
  volume  = {77},
  number  = {4},
  pages   = {1544--1552},
  year    = {2017},
  doi     = {10.1002/mrm.26235}
}

@article{inati2017ismrmrd,
  title   = {{ISMRM} Raw data format: A proposed standard for {MRI} raw datasets},
  author  = {Inati, Souheil J and Naegele, Joseph D and Zwart, Nicholas R
             and Roopchansingh, Vinai and Lizak, Martin J and Hansen, David C
             and Liu, Chia-Ying and Atkinson, David and Kellman, Peter
             and Kozerke, Sebastian and Xue, Hui and Campbell-Washburn, Adrienne E
             and S{\o}rensen, Thomas S and Hansen, Michael S},
  journal = {Magnetic Resonance in Medicine},
  volume  = {77},
  number  = {1},
  pages   = {411--421},
  year    = {2017},
  doi     = {10.1002/mrm.26089}
}

License#

MIT. See License and notices.