Skip to content

Commit

Permalink
[REF] Move PETVolume pipeline to new clinica.pipelines.pet module (
Browse files Browse the repository at this point in the history
…aramis-lab#1226)

* move PETVolume pipeline to new pet module

* update tests

* forgot to update pipeline code...

* fix broken pet linear pipeline
  • Loading branch information
NicolasGensollen authored Jul 11, 2024
1 parent c05f24d commit ed6def0
Show file tree
Hide file tree
Showing 18 changed files with 518 additions and 339 deletions.
1 change: 0 additions & 1 deletion clinica/pipelines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
machine_learning_spatial_svm,
pet,
pet_surface,
pet_volume,
statistics_surface,
statistics_volume,
statistics_volume_correction,
Expand Down
2 changes: 1 addition & 1 deletion clinica/pipelines/pet/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from . import linear
from . import linear, volume
2 changes: 1 addition & 1 deletion clinica/pipelines/pet/linear/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def _build_input_node(self):
import nipype.interfaces.utility as nutil
import nipype.pipeline.engine as npe

from clinica.pipelines.pet.utils import get_suvr_mask
from clinica.utils.exceptions import (
ClinicaBIDSError,
ClinicaCAPSError,
Expand All @@ -67,7 +68,6 @@ def _build_input_node(self):
from clinica.utils.image import get_mni_template
from clinica.utils.input_files import T1W_NII, T1W_TO_MNI_TRANSFORM
from clinica.utils.inputs import clinica_file_reader
from clinica.utils.pet import get_suvr_mask
from clinica.utils.stream import cprint
from clinica.utils.ux import print_images_to_process

Expand Down
137 changes: 137 additions & 0 deletions clinica/pipelines/pet/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
from pathlib import Path
from typing import List, Union

import pandas as pd

from clinica.utils.pet import SUVRReferenceRegion, Tracer

__all__ = [
"get_suvr_mask",
"read_psf_information",
]


def get_suvr_mask(region: Union[str, SUVRReferenceRegion]) -> Path:
"""Returns the path to the SUVR mask from SUVR reference region label.
Parameters
----------
region : str or SUVRReferenceRegion
The label of the SUVR reference region.
Supported labels are: 'pons', 'cerebellumPons', 'pons2', and 'cerebellumPons2'
Returns
-------
Path :
The path to the SUVR mask.
"""
masks_dir = Path(__file__).resolve().parents[2] / "resources" / "masks"

return masks_dir / _get_suvr_reference_region_labels_filename(
SUVRReferenceRegion(region)
)


def _get_suvr_reference_region_labels_filename(region: SUVRReferenceRegion) -> str:
if region == SUVRReferenceRegion.PONS:
return "region-pons_eroded-6mm_mask.nii.gz"
if region == SUVRReferenceRegion.CEREBELLUM_PONS:
return "region-cerebellumPons_eroded-6mm_mask.nii.gz"
if region == SUVRReferenceRegion.PONS2:
return "region-pons_remove-extrabrain_eroded-2it_mask.nii.gz"
if region == SUVRReferenceRegion.CEREBELLUM_PONS2:
return "region-cerebellumPons_remove-extrabrain_eroded-3it_mask.nii.gz"


def read_psf_information(
pvc_psf_tsv_path: Path,
subject_ids: List[str],
session_ids: List[str],
pet_tracer: Union[str, Tracer],
) -> List[List[int]]:
"""Read PSF information from TSV file.
Parameters
----------
pvc_psf_tsv_path : Path
The path to the TSV file containing the following columns:
'participant_id', 'session_id', 'acq_label', 'psf_x',
'psf_y', and 'psf_z'
subject_ids : List[str]
List of participant IDs.
ex: ['sub-CLNC01', 'sub-CLNC01']
.. warning::
Must have the same length as `session_ids`.
session_ids : List[str]
List of session IDs.
ex: ['ses-M000', 'ses-M018']
.. warning::
Must have the same length as `subject_ids`.
pet_tracer : str or Tracer
The tracer we want to select in the 'acq_label' column.
Other tracers will not be read in this function
Returns
-------
psf : List[List[int]]
The PSF information following [subject_ids, session_ids] order.
Examples
--------
Example of pvc_psf_tsv:
participant_id session_id acq_label psf_x psf_y psf_z
sub-CLNC01 ses-M000 FDG 8 9 10
sub-CLNC01 ses-M018 FDG 8 9 10
sub-CLNC01 ses-M000 AV45 7 6 5
sub-CLNC02 ses-M000 FDG 8 9 10
sub-CLNC03 ses-M000 FDG 8 9 10
"""
pet_tracer = Tracer(pet_tracer)
df = _read_psf_dataframe(pvc_psf_tsv_path)
psf = []
for subject, session in zip(subject_ids, session_ids):
result = df.query(
f"participant_id == '{subject}' and session_id == '{session}' and acq_label == '{pet_tracer.value}'"
)
if len(result) == 0:
raise RuntimeError(
f"Subject {subject} with session {session} and tracer {pet_tracer.value} "
f"that you want to proceed was not found in the TSV file containing "
f"PSF specifications ({pvc_psf_tsv_path})."
)
if len(result) > 1:
raise RuntimeError(
f"Subject {subject} with session {session} and tracer {pet_tracer.value} "
f"that you want to proceed was found multiple times "
f"in the TSV file containing PSF specifications ({pvc_psf_tsv_path})."
)
psf.append(result[["psf_x", "psf_y", "psf_z"]].values.tolist()[0])

return psf


def _read_psf_dataframe(filename: Path) -> pd.DataFrame:
valid_columns = {
"participant_id",
"session_id",
"acq_label",
"psf_x",
"psf_y",
"psf_z",
}
df = pd.read_csv(filename, sep="\t")
column_mismatch = valid_columns.symmetric_difference(set(df.columns))
if column_mismatch:
raise IOError(
f"The file {filename} must contain the following columns (separated by tabulations):\n"
f"{valid_columns}\n"
f"The provided TSV file contains the following columns instead:{list(df.columns)}\n"
f"Pay attention to the spaces (there should be none)."
)
return df
1 change: 1 addition & 0 deletions clinica/pipelines/pet/volume/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import cli
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List, Optional, Tuple
from typing import List, Optional

import click

Expand Down Expand Up @@ -92,9 +92,10 @@ def cli(
"""
from networkx import Graph

from clinica.pipelines.pet_volume.pet_volume_pipeline import PETVolume
from clinica.utils.ux import print_end_pipeline

from .pipeline import PETVolume

parameters = {
"group_label": group_label,
"acq_label": acq_label,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
"version": ">=12"
}
]
}
}
Loading

0 comments on commit ed6def0

Please sign in to comment.