Source code for mrsiprep.io.naming

"""BIDS-like naming helpers."""

from __future__ import annotations

from pathlib import Path

from mrsiprep.utils.misc import normalize_session, normalize_subject


[docs] def prefix(subject: str, session: str | None = None) -> str: parts = [f"sub-{normalize_subject(subject)}"] ses = normalize_session(session) if ses: parts.append(f"ses-{ses}") return "_".join(parts)
[docs] def subject_session_dir(root: Path, subject: str, session: str | None, suffix: str) -> Path: sub_dir = root / f"sub-{normalize_subject(subject)}" ses = normalize_session(session) return sub_dir / f"ses-{ses}" / suffix if ses else sub_dir / suffix
_SYNTHSEG_DESC_PREFIXES = ("synthsegBrain", "synthsegFastInput", "synthsegParc", "brainCSF")
[docs] def anat_derivative(root: Path, subject: str, session: str | None, **entities) -> Path: return _derivative(root, subject, session, _anat_folder(entities), "T1w", **entities)
def _anat_folder(entities: dict) -> str: desc = entities.get("desc") if entities.get("label") in {"GM", "WM", "CSF"}: return "confounds" if desc is not None and any(str(desc).startswith(p) for p in _SYNTHSEG_DESC_PREFIXES): return "anat/synthseg" return "anat"
[docs] def mrsi_derivative(root: Path, subject: str, session: str | None, **entities) -> Path: return _derivative(root, subject, session, _mrsi_folder(entities), "mrsi", **entities)
[docs] def parcellation_derivative(root: Path, subject: str, session: str | None, **entities) -> Path: return _derivative(root, subject, session, "anat/synthseg", "dseg", **entities)
[docs] def mrsi_parcel_dir(root: Path, subject: str, session: str | None) -> Path: return subject_session_dir(root, subject, session, "mrsi/parcel")
[docs] def chimera_derivative(root: Path, subject: str, session: str | None, **entities) -> Path: sub_dir = root / "chimera-atlases" / f"sub-{normalize_subject(subject)}" ses = normalize_session(session) out_dir = sub_dir / f"ses-{ses}" / "anat" if ses else sub_dir / "anat" suffix = entities.pop("suffix_override", "dseg") name_parts = [prefix(subject, session)] for key in ("space", "atlas", "scale", "desc"): value = entities.get(key) if value is not None: value = _format_entity_value(key, value) name_parts.append(f"{key}-{value}") ext = f"_{suffix}.nii.gz" if suffix in {"dseg", "mask", "probseg"} else f".{suffix}" return out_dir / ("_".join(name_parts) + ext)
[docs] def coverage_report_dir(root: Path, subject: str, session: str | None) -> Path: return subject_session_dir(root, subject, session, "reports") / "coverage"
[docs] def coverage_figure_derivative(root: Path, subject: str, session: str | None, extension: str = "png", **entities) -> Path: out_dir = coverage_report_dir(root, subject, session) / "figures" suffix = entities.pop("suffix_override", extension) return _named(out_dir, subject, session, suffix, **entities)
[docs] def coverage_report_html(root: Path, subject: str, session: str | None) -> Path: return coverage_report_dir(root, subject, session) / f"{prefix(subject, session)}_desc-report.html"
[docs] def qc_report_derivative(root: Path, subject: str, session: str | None, step: str, extension: str = "html") -> Path: out_dir = subject_session_dir(root, subject, session, "reports") / "qc-reports" return out_dir / f"{prefix(subject, session)}_step-{step}.{extension}"
[docs] def provenance_derivative(root: Path, subject: str, session: str | None) -> Path: return subject_session_dir(root, subject, session, "reports") / f"{prefix(subject, session)}_desc-provenance.json"
[docs] def resampling_work_path(work_dir: Path, subject: str, session: str | None, **entities) -> Path: """Scratch location (under --work-dir) for resampled maps needed only to render a report, not intended as a permanent BIDS derivative.""" return _derivative(work_dir, subject, session, "resampling", "mrsi", **entities)
_CONFOUND_DESCS = {"brain", "mrsiqc", "qcmask", "spikemask", "crlb", "snr", "fwhm", "t1corr"} def _mrsi_folder(entities: dict) -> str: desc = entities.get("desc") suffix = entities.get("suffix_override") space = entities.get("space") if entities.get("label") in {"GM", "WM", "CSF"}: return "confounds" if desc == "signalt1corr": return "mrsi/orig-t1corr" if desc == "signalpvc": return "mrsi/orig-pvc" if desc in _CONFOUND_DESCS or suffix == "mask": return "confounds" if space == "MNI152NLin2009cAsym": return "mrsi/mni" if space == "T1w": return "mrsi/t1w" return "mrsi/orig" def _named(out_dir: Path, subject: str, session: str | None, suffix: str, **entities) -> Path: suffix = entities.pop("suffix_override", suffix) name_parts = [prefix(subject, session)] order = [ "space", "res", "met", "label", "atlas", "scale", "from_", "to", "mode", "desc", ] for key in order: if key not in entities: continue value = entities[key] if value is None: continue entity = "from" if key == "from_" else key value = _format_entity_value(entity, value) name_parts.append(f"{entity}-{value}") ext = suffix if suffix.startswith(".") else f"_{suffix}.nii.gz" if suffix in {"T1w", "mrsi", "dseg", "mask", "probseg"} else f".{suffix}" filename = "_".join(name_parts) + ext return out_dir / filename def _derivative(root: Path, subject: str, session: str | None, folder: str, suffix: str, **entities) -> Path: out_dir = subject_session_dir(root, subject, session, folder) return _named(out_dir, subject, session, suffix, **entities) def _format_entity_value(entity: str, value) -> str: if entity == "space" and value == "MRSI": return "mrsi" return str(value)