Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 34 additions & 16 deletions data/Duke-Heart-4DLabelmaps/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
# Duke-Heart-4DLabelmaps

Gated 4D cardiac labelmaps acquired at Duke University by Dr. Paul Segars.
Gated 4D cardiac labelmaps and landmark files derived from the PROMISE study
CT data acquired at Duke University, Dr. Paul Segars' lab.

## Provenance

The labelmaps were created from the original PROMISE study CT data using the
AS Cardio (ASCardio) segmentation module in Synopsys' Simpleware application.
MONAI Physio calls that module through the `SegmentHeartSimplewareTrimmedBranches`
class.

**Important:** any AI physiological simulation model trained using these
labelmaps must be applied to labelmaps that were also generated with the
ASCardio module in Simpleware (for example via
`SegmentHeartSimplewareTrimmedBranches`). Applying such a model to labelmaps
from a different segmenter will degrade the results.

## Availability

This dataset is **scheduled for public release soon**. It is not distributed
with this repository and has no automatic downloader yet.
The labelmaps (`*_labelmap.nii.gz`) and landmark files (`*_landmark.mrk.json`)
can be downloaded automatically:

In the meantime, contact Stephen Aylward (<saylward@nvidia.com>) to request
access.
```bash
monai-physio-download-data Duke-Heart-4DLabelmaps --directory data/Duke-Heart-4DLabelmaps
```

or from Python with `DownloadData.DownloadDukeHeart4DLabelmapsData`. The archive
is fetched from
<https://github.com/Project-MONAI/monai-physio/releases/download/2026.07.1/Duke-Heart-4DLabelmaps.zip>
and extracted into this directory, creating the `pm00*/` case subdirectories.
Re-running is a no-op once the data is present.

The original PROMISE CT images are not distributed with this repository.

## Effect on the tutorials

Expand All @@ -20,17 +43,12 @@ their organ field, for example:
There are ten of them. Nine form their own chain: Tutorial 4 (duke heart) -> 5
-> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12. The tenth, Tutorial 2 (duke heart), is a
separate optional ICON finetuning variant that the chain does not require.
They will not run until the data is
available. The other 19 tutorial scripts use publicly available datasets and are
unaffected - see [../README.md](../README.md) for download instructions.

Downstream tutorials that consume `duke_heart` outputs (such as the finetuned
distance-map ICON weights used by
`tutorials/tutorial_07_heart_fit_statistical_model_to_patient.py`) fall back to
stock weights and still run, with reduced accuracy.
Download the data before running them. The other 19 tutorial scripts use
publicly available datasets and are unaffected - see [../README.md](../README.md)
for download instructions.

## Expected layout

When available, the data is expected under `data/Duke-Heart-4DLabelmaps/` as
one directory per case (`pm0002/`, `pm0003/`, ...), each holding one labelmap
per gated frame.
The data is placed under `data/Duke-Heart-4DLabelmaps/` as one directory per
case (`pm0002/`, `pm0003/`, ...), each holding one labelmap and one landmark
file per gated frame.
5 changes: 3 additions & 2 deletions data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ the source of truth.
| `KCL-Heart-Model/` | Statistical shape model of the heart | King's College London (KCL) | Automatic | [KCL-Heart-Model/README.md](KCL-Heart-Model/README.md) |
| `CHOP-Valve4D/` | 4D valve reconstruction models | Jolley Lab, CHOP (original FEBio model) | Automatic | [CHOP-Valve4D/README.md](CHOP-Valve4D/README.md) |
| `Chest-CT/` | Ungated 3D chest CT, single static volume | AREN0534 trial, The Cancer Imaging Archive (TCIA) | Automatic | [Chest-CT/README.md](Chest-CT/README.md) |
| `Duke-Heart-4DLabelmaps/` | Gated 4D cardiac labelmaps and landmarks from PROMISE study CT, segmented with Simpleware ASCardio | Duke University (Dr. Paul Segars' lab) | Automatic | [Duke-Heart-4DLabelmaps/README.md](Duke-Heart-4DLabelmaps/README.md) |
| `test/` | pytest-managed cache; not a downloadable dataset | - | N/A | [test/README.md](test/README.md) |

## Automatic Download

`Slicer-Heart-CT`, `KCL-Heart-Model`, `CHOP-Valve4D`, `Chest-CT`, and
`TCIA-4DLung` can be fetched with the `monai-physio-download-data` CLI or
`Slicer-Heart-CT`, `KCL-Heart-Model`, `CHOP-Valve4D`, `Chest-CT`,
`TCIA-4DLung`, and `Duke-Heart-4DLabelmaps` can be fetched with the `monai-physio-download-data` CLI or
`DownloadData`; see each dataset's README for the exact command.
`TCIA-4DLung`'s automatic download is a converted tutorial subset (the
`.nii.gz` phases the tutorials read); the full TCIA 4D-Lung collection is
Expand Down
27 changes: 23 additions & 4 deletions docs/cli_scripts/download_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ Supported Datasets
Physio GitHub release. See ``data/TCIA-4DLung/README.md`` for the
data source, the full-collection manual download, and required
citation.
* - ``Duke-Heart-4DLabelmaps``
- Gated 4D cardiac labelmaps and JSON landmark files from the PROMISE
study CT data (Duke University, Dr. Paul Segars' lab), segmented with
the ASCardio module of Simpleware, from the MONAI Physio GitHub
release. Models trained on them should only be applied to labelmaps
also generated with ASCardio (``SegmentHeartSimplewareTrimmedBranches``).
See ``data/Duke-Heart-4DLabelmaps/README.md``.
* - ``PhysicsNeMo-MGN-Lung-Motion``
- Pretrained PhysicsNeMo MeshGraphNet checkpoint for lung motion, from
the MONAI Physio GitHub release. Used by Lung Tutorial 10 and later
Expand All @@ -55,12 +62,12 @@ Options

.. code-block:: bash

monai-physio-download-data [Slicer-Heart-CT|KCL-Heart-Model|CHOP-Valve4D|Chest-CT|TCIA-4DLung|PhysicsNeMo-MGN-Lung-Motion] [--directory DIRECTORY]
monai-physio-download-data [Slicer-Heart-CT|KCL-Heart-Model|CHOP-Valve4D|Chest-CT|TCIA-4DLung|Duke-Heart-4DLabelmaps|PhysicsNeMo-MGN-Lung-Motion] [--directory DIRECTORY]

``data_name``
Dataset to download. One of ``Slicer-Heart-CT``, ``KCL-Heart-Model``,
``CHOP-Valve4D``, ``Chest-CT``, ``TCIA-4DLung``, or
``PhysicsNeMo-MGN-Lung-Motion``. Required - omitting it prints help and
``CHOP-Valve4D``, ``Chest-CT``, ``TCIA-4DLung``, ``Duke-Heart-4DLabelmaps``,
or ``PhysicsNeMo-MGN-Lung-Motion``. Required - omitting it prints help and
exits.

``--directory``
Expand Down Expand Up @@ -136,6 +143,18 @@ the download entirely once any case's phase volumes are already present -
this is a converted tutorial subset; see ``data/TCIA-4DLung/README.md`` for
how to obtain the full TCIA 4D-Lung collection manually.

For ``Duke-Heart-4DLabelmaps``, the command downloads, extracts, and reuses:

.. code-block:: text

data/Duke-Heart-4DLabelmaps/pm0002/*_labelmap.nii.gz
data/Duke-Heart-4DLabelmaps/pm0002/*_landmark.mrk.json ...

The command uses
:meth:`monai_physio.download_data.DownloadData.DownloadDukeHeart4DLabelmapsData`,
which fetches ``Duke-Heart-4DLabelmaps.zip`` from the MONAI Physio GitHub
release and skips the download once any case's labelmaps are already present.

For ``PhysicsNeMo-MGN-Lung-Motion``, the command downloads, extracts, and
reuses:

Expand All @@ -162,7 +181,7 @@ See Also
``monai-physio-download-data`` entry - DIR-Lab distributes each case
individually and may require registration, so it is manual-only, see
``data/DirLab-4DCT/README.md``. ``Duke-Heart-4DLabelmaps``, which drives the
ten ``duke_heart`` variants, is being released soon; see
ten ``duke_heart`` variants, is downloaded with the CLI; see
``data/Duke-Heart-4DLabelmaps/README.md``. ``PhysicsNeMo-MGN-Lung-Motion``
is the pretrained-checkpoint shortcut for Lung Tutorial 10 (and everything
downstream of it: 11-14), letting a reader skip running Tutorial 9's
Expand Down
13 changes: 9 additions & 4 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ Then fetch the sample datasets, again from the top level of the clone:
# Lung Tutorial 7
monai-physio-download-data Chest-CT --directory data/Chest-CT

# Duke heart tutorials 2 and 4 through 12
monai-physio-download-data Duke-Heart-4DLabelmaps --directory data/Duke-Heart-4DLabelmaps

# No tutorial - transcatheter pulmonary valve experiments only, >2 GB
monai-physio-download-data CHOP-Valve4D --directory data/CHOP-Valve4D

Expand Down Expand Up @@ -97,7 +100,7 @@ Which dataset each tutorial needs:
- CLI
- Lung Tutorial 7, and Tutorial 13
* - ``Duke-Heart-4DLabelmaps``
- Releasing soon
- CLI
- The ten ``duke_heart`` variants, Tutorials 2 and 4 through 12
* - ``CHOP-Valve4D``
- CLI
Expand All @@ -106,9 +109,11 @@ Which dataset each tutorial needs:
Tutorials 5 and 9 need no dataset of their own: they consume the outputs of
Tutorials 4 and 8 respectively.

``Duke-Heart-4DLabelmaps`` is scheduled for public release soon. Until then the
ten ``duke_heart`` variants cannot be run; contact Stephen Aylward
(saylward@nvidia.com) to request access, and see
``Duke-Heart-4DLabelmaps`` downloads as labelmaps and JSON landmark files
created from the PROMISE study CT data (Duke University, Dr. Paul Segars' lab)
with the ASCardio module of Simpleware. Models trained on them should only be
applied to labelmaps also generated with ASCardio, which MONAI Physio runs via
``SegmentHeartSimplewareTrimmedBranches``; see
``data/Duke-Heart-4DLabelmaps/README.md``.

``TCIA-4DLung``'s CLI download is a converted tutorial subset; the full TCIA
Expand Down
8 changes: 8 additions & 0 deletions src/monai_physio/cli/download_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
CHOP_VALVE4D = "CHOP-Valve4D"
CHEST_CT = "Chest-CT"
TCIA_4D_LUNG = "TCIA-4DLung"
DUKE_HEART_4D_LABELMAPS = "Duke-Heart-4DLabelmaps"
PHYSICSNEMO_MGN_LUNG_MOTION = "PhysicsNeMo-MGN-Lung-Motion"


Expand All @@ -29,6 +30,7 @@ def main(argv: Optional[list[str]] = None) -> int:
%(prog)s {CHOP_VALVE4D} --directory data/CHOP-Valve4D
%(prog)s {CHEST_CT} --directory data/Chest-CT
%(prog)s {TCIA_4D_LUNG} --directory data/TCIA-4DLung
%(prog)s {DUKE_HEART_4D_LABELMAPS} --directory data/Duke-Heart-4DLabelmaps
%(prog)s {PHYSICSNEMO_MGN_LUNG_MOTION} --directory tutorials/network_weights
""",
)
Expand All @@ -41,6 +43,7 @@ def main(argv: Optional[list[str]] = None) -> int:
CHOP_VALVE4D,
CHEST_CT,
TCIA_4D_LUNG,
DUKE_HEART_4D_LABELMAPS,
PHYSICSNEMO_MGN_LUNG_MOTION,
],
default=None,
Expand Down Expand Up @@ -90,6 +93,11 @@ def main(argv: Optional[list[str]] = None) -> int:
print(f"Downloaded {TCIA_4D_LUNG} to: {data_dir}")
return 0

if args.data_name == DUKE_HEART_4D_LABELMAPS:
data_dir = DownloadData.DownloadDukeHeart4DLabelmapsData(output_dir)
print(f"Downloaded {DUKE_HEART_4D_LABELMAPS} to: {data_dir}")
return 0

if args.data_name == PHYSICSNEMO_MGN_LUNG_MOTION:
data_dir = DownloadData.DownloadPhysicsNeMoMGNLungMotionData(output_dir)
print(f"Downloaded {PHYSICSNEMO_MGN_LUNG_MOTION} to: {data_dir}")
Expand Down
44 changes: 42 additions & 2 deletions src/monai_physio/download_data.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""
Dataset download and verification helpers.

Slicer-Heart-CT, KCL-Heart-Model, CHOP-Valve4D, Chest-CT, and TCIA-4DLung
are downloaded automatically. Other datasets require manual download, and
Slicer-Heart-CT, KCL-Heart-Model, CHOP-Valve4D, Chest-CT, TCIA-4DLung, and
Duke-Heart-4DLabelmaps are downloaded automatically. Other datasets require manual download, and
the verification helpers check the file layouts used by the repository
tutorials, experiments, and tests.
"""
Expand Down Expand Up @@ -397,6 +397,46 @@ def VerifyTCIA4DLungData(dirname: Union[str, Path]) -> bool:
"""Return True when TCIA-4DLung has at least one case's phase volumes."""
return any(Path(dirname).glob("*_HM10395/*_g0??.nii.gz"))

DUKE_HEART_4D_LABELMAPS_URL = (
"https://github.com/Project-MONAI/monai-physio/releases/download/2026.07.1/"
"Duke-Heart-4DLabelmaps.zip"
)
Comment thread
aylward marked this conversation as resolved.

@staticmethod
def DownloadDukeHeart4DLabelmapsData(dirname: Union[str, Path]) -> Path:
"""Download the Duke-Heart-4DLabelmaps release into ``dirname``.

Fetches ``Duke-Heart-4DLabelmaps.zip`` from the MONAI Physio 2026.07.1
GitHub release and extracts it directly into ``dirname``, giving the
per-case ``pm00*/`` directories of ``*_labelmap.nii.gz`` and
``*_landmark.mrk.json`` files. The labelmaps were generated with the
ASCardio module of Simpleware (``SegmentHeartSimplewareTrimmedBranches``);
models trained on them should only be applied to labelmaps generated
the same way. See ``data/Duke-Heart-4DLabelmaps/README.md``.
Already-populated data is left alone, so re-running is a no-op once
the data is present.

Args:
dirname: Directory where the Duke-Heart-4DLabelmaps dataset should
live.

Returns:
Path to ``dirname``.
"""
data_dir = Path(dirname)
if DownloadData.VerifyDukeHeart4DLabelmapsData(data_dir):
return data_dir
DownloadData._DownloadAndExtractZip(
DownloadData.DUKE_HEART_4D_LABELMAPS_URL, data_dir, extract_dir=data_dir
)
_logger.info("Downloaded Duke-Heart-4DLabelmaps.zip")
return data_dir

@staticmethod
def VerifyDukeHeart4DLabelmapsData(dirname: Union[str, Path]) -> bool:
"""Return True when Duke-Heart-4DLabelmaps has at least one labelmap."""
return any(Path(dirname).glob("pm*/*_labelmap.nii.gz"))
Comment thread
aylward marked this conversation as resolved.

@staticmethod
def _MetaImageHeaderHasBackingData(mhd_file: Path) -> bool:
"""Return True when a MetaImage ``.mhd`` header's pixel data exists.
Expand Down
20 changes: 20 additions & 0 deletions tests/test_download_data_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,23 @@ def fake_download(dirname: Union[str, Path]) -> Path:
assert result == 0
assert calls == [Path("data/TCIA-4DLung")]
assert "Downloaded TCIA-4DLung" in capsys.readouterr().out


def test_download_data_cli_routes_duke_heart_4d_labelmaps(
monkeypatch: pytest.MonkeyPatch,
capsys: pytest.CaptureFixture[str],
) -> None:
"""Duke-Heart-4DLabelmaps routes to its own downloader and default directory."""
calls: list[Path] = []

def fake_download(dirname: Union[str, Path]) -> Path:
calls.append(Path(dirname))
return Path(dirname)

monkeypatch.setattr(DownloadData, "DownloadDukeHeart4DLabelmapsData", fake_download)

result = download_data.main(["Duke-Heart-4DLabelmaps"])

assert result == 0
assert calls == [Path("data/Duke-Heart-4DLabelmaps")]
assert "Downloaded Duke-Heart-4DLabelmaps" in capsys.readouterr().out
Loading