Skip to content

Running noninteractively

For scripting, batch processing, and reproducible runs, drive QSMxT from the command line. (Prefer to point and click? See Running interactively — everything below is available there too.)

qsmxt run is the heart of the tool: it discovers every phase/magnitude run in a BIDS dataset and reconstructs a quantitative susceptibility map for each.

Terminal window
qsmxt run <BIDS_DIR> [OUTPUT_DIR]
  • <BIDS_DIR> — input BIDS directory
  • [OUTPUT_DIR] — defaults to <BIDS_DIR>; results go to <OUTPUT_DIR>/derivatives/qsmxt/

With no options, QSMxT runs with sensible defaults end to end. Need a BIDS dataset first? See Converting DICOMs to BIDS below.

Each run flows through the pipeline below. The method at every stage is configurable — see Algorithms.

  1. Masking — generate a brain/region mask (--mask-preset, or custom --mask sections).
  2. Phase offset removal — remove receiver phase offsets on multi-echo data.
  3. Phase unwrapping — romeo or laplacian.
  4. Echo combination / B0 mapping — combine echoes into a field map (--b0-estimation, --b0-weight-type).
  5. Background field removal — vsharp, pdf, lbv, and more.
  6. Dipole inversion — ilsqr (default), rts, tv, tgv, medi, … (31 algorithms).
  7. Referencing — reference the susceptibility values (e.g. to the mean).

Not every inversion runs every stage: total-field methods (TFI, QSMART, AutoQSM, NeXtQSM, MEDI with --medi-smv, multi-echo TGV) skip background field removal, and the wrapped-phase methods (iQSM, iQSM+, single-echo TGV) skip unwrapping and echo combination too. See Algorithms.

Terminal window
qsmxt run study/bids \
--mask-preset robust-threshold \
--unwrapping-algorithm romeo \
--bf-algorithm vsharp \
--qsm-algorithm ilsqr
Option Choices
--qsm-algorithm 20 classical (rts, tv, tkd, tgv, medi, ilsqr, …) and 11 deep-learning (xqsm, qsmnet, iqsm, …)
--unwrapping-algorithm romeo, laplacian
--bf-algorithm vsharp, pdf, lbv, ismv, sharp, resharp, harperella, iharperella, bfrnet, iqfm
--mask-preset robust-threshold, bet, hd-bet, bet-and-phase, rs2-net, mindgrab
--masking-input magnitude-first, magnitude, magnitude-last, phase-quality

Every value of every option is listed in the CLI reference and described in Algorithms.

--masking-input overrides the image the mask is computed from and combines with --mask-preset — e.g. --mask-preset bet --masking-input magnitude-first runs BET on the first-echo magnitude. For fully custom masking, see --mask in Algorithms.

Process only part of a dataset with glob patterns:

Terminal window
# Only these subjects
qsmxt run study/bids --include "sub-01*" "sub-02*"
# Everything except a session
qsmxt run study/bids --exclude "*ses-pilot*"
# Cap the number of echoes used
qsmxt run study/bids --num-echoes 4
Terminal window
# Receiver phase-offset removal (on by default for multi-echo)
qsmxt run study/bids --phase-offset-removal true
# Bipolar readout correction (needs ≥ 3 echoes)
qsmxt run study/bids --bipolar-correction

ROMEO unwrapping has several modes — per-echo (default) or template-based, with inter-echo 2π correction. See qsmxt run --help for the full set of --romeo-* flags.

Reproduce a run exactly by saving settings to a TOML file and passing --config:

Terminal window
qsmxt init > pipeline.toml # generate a starting config
qsmxt run study/bids --config pipeline.toml

See Configuration.

Intermediate results are cached to disk. Re-running the same dataset skips any stage that already completed, so tweaking a late-stage option doesn’t recompute the whole pipeline.

study/bids/derivatives/qsmxt/
└── sub-01/
├── anat/
│ ├── sub-01_…_Chimap.nii
│ ├── sub-01_…_Chimap.json
│ ├── sub-01_…_mask.nii
│ ├── sub-01_…_desc-qsm_mask.nii
│ └── sub-01_…_part-mag_T2starw.nii
└── fmap/
├── sub-01_…_desc-total_fieldmap.nii
└── sub-01_…_desc-total_magnitude.nii

Outputs are uncompressed NIfTI (.nii), each with a JSON sidecar recording how it was made (GeneratedBy, units, and for susceptibility maps the reference). The total field is published in Hz under fmap/. Every file and its name is listed in Output files.

mask is the brain mask; desc-qsm_mask is the part of it the susceptibility map is defined on — the brain mask less the rim that background-field removal eroded. The Chimap is referenced over, and is 0 outside, desc-qsm_mask; the χ-separation maps (--do-chisep) are fitted over it and are 0 outside it too.

At the top of derivatives/qsmxt/, methods.md describes the processing in prose ready for a methods section, with citations for the exact methods used for your data and parameters; pipeline.svg draws the same pipeline, one box per step (pipeline.mmd is the same graph in Mermaid); pipeline_config.toml holds the resolved settings (reusable with --config), and qsmxt.log the log.

Some things are only decided as a run goes: a mask supplied with --use-custom-masks that cannot be used is computed instead, R2′ is measured where a multi-echo spin-echo scan allows and estimated otherwise. Once every run is done, methods.md and the graph are written from what the runs did: a choice every run made is stated as done, and the graph’s boxes say how many runs skipped a step or decided something in it. They cover every run in the output directory that completed with the current settings, whichever command processed it, so re-running one subject with --include does not narrow them; a run last processed with other settings, or whose last attempt did not finish, is left out. A run processed differently from the rest gets its own methods text and graph in changes/ (<run>_methods.md, <run>_desc-ran_pipeline.mmd and .svg); the folder is only there when some run differs. Each run’s methods text, a record of what each step did and why (*_runrecord.json), and its graph are also kept in its workflow/ directory.

qsmxt run --dry prints the pipeline graph and the methods text as planned, without running anything or writing any file.

Every susceptibility map is referenced (see Referencing), and each map’s sidecar records what with QsmReference (mean, none, or the region), QsmReferenceOffsetPpm (the value subtracted), QsmReferenceVoxels (how many voxels it was measured over) and, for a region, QsmReferenceLabels (its label ids). The same facts for every map of every run are collected in desc-reference_summary.tsv at the top of the derivatives:

Column Meaning
subject, session, acquisition, reconstruction, inversion, run The run’s BIDS entities
map The map, by its BIDS suffix with any desc- (Chimap, desc-singlepass_Chimap, desc-cosmos_Chimap, …)
reference What zero was pinned to (QsmReference)
offset_ppm The value subtracted, in ppm (QsmReferenceOffsetPpm)
n_voxels Voxels the reference was measured over (QsmReferenceVoxels)

It is the file to scan for a subject whose reference region came out small or empty.

Some workflows want the maps back in DICOM — to push them into a PACS, open them in a clinical viewer, or hand them to a radiologist beside the source study. --export-dicom writes a DICOM series for every final map alongside the NIfTIs:

Terminal window
qsmxt run study/bids --export-dicom

Each map gets its own folder under the subject’s extra_files/, one file per slice:

study/bids/derivatives/qsmxt/
└── sub-01/
├── anat/
│ └── sub-01_…_Chimap.nii
└── extra_files/
└── sub-01_Chimap_dicoms/
├── sub-01_Chimap_0001.dcm
├── sub-01_Chimap_0002.dcm
└── …

Every final map the run produced is exported. χ needs no extra flag; the supplementary maps are exported once you’ve asked for them:

Map Produced by Folder suffix / --dicom-outputs token
Susceptibility (χ) the default pipeline Chimap
SWI --do-swi swi
SWI minIP --do-swi minIP
T2* --do-t2starmap T2starmap
R2* --do-r2starmap R2starmap
R2 --do-r2map R2map
R2′ --do-r2primemap R2primemap
Paramagnetic χ --do-chisep desc-paramagnetic_Chimap
Diamagnetic χ --do-chisep desc-diamagnetic_Chimap
Total χ --do-chisep desc-total_Chimap

To export only some of them, pass those tokens to --dicom-outputs (case-insensitive, comma- or space-separated):

Terminal window
qsmxt run study/bids --do-chisep --export-dicom \
--dicom-outputs chimap,desc-paramagnetic_chimap,desc-diamagnetic_chimap

SMWI, the segmentation and the multi-orientation reconstructions stay NIfTI-only.

Filing them beside the source study. By default the derived series carry a synthesised identity: patient fields are left empty and a stable StudyInstanceUID is derived from the subject and session. That’s fine for a local viewer, but a PACS will file the maps as a study of their own. Point --source-dicom at the original DICOMs and QSMxT inherits the identity from the first readable DICOM it finds there — PatientID, StudyInstanceUID, FrameOfReferenceUID, study date/time, accession number — so the maps land beside the acquisition they came from:

Terminal window
qsmxt run study/bids --export-dicom --source-dicom /data/dicoms/sub-01

SeriesInstanceUID and SOPInstanceUID are always newly generated: these are distinct derived series, never a rewrite of the originals. Every instance is tagged DERIVED\SECONDARY, and each map gets a stable SeriesNumber so viewers list them in a predictable order.

A few more things worth knowing:

  • Slice geometry (ImageOrientationPatient, ImagePositionPatient, SliceLocation, spacing) is read from the output NIfTI’s affine, so the series overlays the source acquisition in a viewer and reflects any oblique resampling the run applied.
  • Instances are uncompressed MR Image Storage, Explicit VR Little Endian.
  • Export is best-effort: a failure is logged and the run still succeeds.
  • --export-dicom is a pipeline setting, so it can live in a config file as export_dicom = true under [pipeline], and it carries through to qsmxt slurm. --source-dicom and --dicom-outputs are flags on qsmxt run itself.

This is the mirror image of dicom-convert below, which brings DICOMs in. Both directions are built into the binary — no external converter to install.

QSMxT needs BIDS-formatted input. The dicom-convert command builds it for you from a directory of DICOMs, applying an automatic best-guess classification to every series with no prompts — ideal for scripting and batch jobs.

Terminal window
qsmxt dicom-convert <DICOM_DIR> <OUTPUT_DIR>
  • <DICOM_DIR> — input directory, searched recursively
  • <OUTPUT_DIR> — output BIDS directory

Before writing anything, inspect how QSMxT classifies your data:

Terminal window
qsmxt dicom-convert /data/dicoms study/bids --dry-run

Example output:

Detected 4 unique series (auto-classified):
acq-SWI3mm SWI_3mm [Magnitude] 2×TEs=[9.4…19.7]ms (uncombined, 32 coils)
acq-SWI3mm SWI_3mm [Magnitude] 2×TEs=[9.4…19.7]ms
acq-SWI3mm SWI_3mm [Magnitude] 2×TEs=[9.4…19.7]ms (filtered)
acq-SWI3mm SWI_3mm [Phase] 2×TEs=[9.4…19.7]ms

Each row is a unique series, deduplicated across subjects, so you review a classification once even if many subjects share it.

  • Gradient-echo magnitude and phase — split correctly even when a vendor packs both under a single SeriesInstanceUID (e.g. some Philips/GE exports).
  • Multi-echo — echoes are detected and labelled echo-N; the dry run reports the echo count and TE range.
  • T1-weighted structurals — MPRAGE / MP2RAGE / T1w series are recognised as T1w, not magnitude.
  • Individual coil images — each coil element of an uncombined acquisition is converted separately and labelled rec-uncombined_coil-NN, instead of overwriting one another.
  • Derived reconstructions — a scanner-filtered magnitude (e.g. a SWI-filtered series) is kept alongside the plain one with a desc-filtered label rather than colliding with it.

Output is a BIDS tree of sub-*/anat/ NIfTIs with JSON sidecars (EchoTime in seconds), ready for the pipeline. Already have NIfTIs? You can assemble a BIDS dataset by hand — see Input data for the expected layout, and run qsmxt validate to check it’s pipeline-ready.

For large cohorts, QSMxT can fan work out across an HPC cluster instead of running everything on one machine.

Terminal window
qsmxt slurm study/bids --account myaccount

--account (the SLURM account to charge) is required. This writes SLURM batch scripts for your dataset to <OUTPUT_DIR>/derivatives/qsmxt/slurm/, and with --submit submits them. Run qsmxt slurm --help for the available options (partition, time limits, resource requests, and run selection).

qsmxt slurm accepts the same pipeline options as qsmxt run (algorithms, masking, per-algorithm parameters, --config, --num-echoes, --force, --clean-intermediates, --debug, and DICOM export’s --source-dicom and --dicom-outputs, …), so any qsmxt run command becomes a SLURM one by swapping the subcommand and adding the scheduler flags:

Terminal window
qsmxt slurm study/bids --qsm-algorithm tgv --unwrapping-algorithm laplacian \
--account myaccount --time 04:00:00

The settings are checked, and every run is checked against them, before any script is written, so a bad setting is reported once rather than by every job. The resolved pipeline is written to <OUTPUT_DIR>/derivatives/qsmxt/pipeline_config.toml and every generated job runs against that file.

  • One job per run (qsmxt_<run>.sh) runs qsmxt run --no-dataset-steps --include <run>: that run’s pipeline and nothing else. It logs to logs/<run>.log and writes nothing at dataset level.
  • One aggregation job (qsmxt_aggregate.sh) runs qsmxt aggregate over all the runs once every run job has succeeded (--dependency=afterok:<all run job ids>). It does what a local qsmxt run does after its runs finish:
    • multi-orientation (COSMOS/STI) reconstruction across the runs of each group;
    • desc-reference_summary.tsv, the dataset-level statistics table and cohort figures;
    • BIDS-Prov records under prov/;
    • dataset_description.json, pipeline_config.toml, methods.md, pipeline.mmd/.svg, changes/;
    • qsmxt.log, which collects every run’s log followed by its own;
    • --clean-intermediates, if you asked for it.

The result is the same dataset a local qsmxt run produces, apart from timestamps and the command recorded in the provenance (qsmxt slurm …).

--submit submits the run jobs and then the aggregation job with the dependency. Without it, bash <OUTPUT_DIR>/derivatives/qsmxt/slurm/submit.sh does the same.

Each job’s memory request is estimated from its run’s size and the pipeline. The aggregation job is sized for the largest multi-orientation group. --mem sets one figure for every job instead, with a warning for any run estimated to need more.

If a run job fails, SLURM never starts the aggregation job: with afterok it stays pending (or is cancelled, depending on the cluster’s settings). Fix the cause, re-run that run’s script (sbatch slurm/qsmxt_<run>.sh; its finished steps are cached), then submit slurm/qsmxt_aggregate.sh yourself. qsmxt aggregate refuses any run that has not completed under the same configuration, and names it.

Even without a scheduler, a single qsmxt run is parallel. QSMxT processes runs concurrently and detects available memory to choose a safe degree of parallelism automatically, so it fills your cores without exhausting RAM.

Because intermediate results are cached to disk, a job that is requeued or resumed picks up where it left off rather than recomputing completed stages — handy when a cluster preempts or time-limits a job.

  1. Convert and validate on a login node or small interactive job:
    Terminal window
    qsmxt dicom-convert /data/dicoms study/bids
    qsmxt validate study/bids
  2. Dial in settings (locally or via the TUI) and save them:
    Terminal window
    qsmxt init > pipeline.toml
  3. Generate and submit the jobs (one per run, then the aggregation job):
    Terminal window
    qsmxt slurm study/bids --config pipeline.toml --account myaccount --submit