Source code for voxelops.schemas.qsirecon
"""QSIRecon schemas: inputs, outputs, and defaults."""
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional, List
[docs]
@dataclass
class QSIReconInputs:
"""Required inputs for QSIRecon diffusion reconstruction.
Parameters
----------
qsiprep_dir : Path
QSIPrep output directory.
participant : str
Participant label (without 'sub-' prefix).
output_dir : Optional[Path], optional
Output directory, by default None.
If None, defaults to qsiprep_dir/../qsirecon.
work_dir : Optional[Path], optional
Working directory, by default None.
If None, defaults to output_dir/../work/qsirecon.
recon_spec : Optional[Path], optional
Path to reconstruction spec YAML file, by default None.
datasets : Optional[dict[str, Path]], optional
Dictionary of dataset names and paths, by default None.
atlases : Optional[List[str]], optional
List of atlases for connectivity, by default None.
"""
qsiprep_dir: Path
participant: str
output_dir: Optional[Path] = None
work_dir: Optional[Path] = None
recon_spec: Optional[Path] = None
datasets: Optional[dict[str, Path]] = None
atlases: Optional[List[str]] = None
[docs]
def __post_init__(self):
"""Ensure paths are Path objects."""
self.qsiprep_dir = Path(self.qsiprep_dir)
if self.output_dir:
self.output_dir = Path(self.output_dir)
if self.work_dir:
self.work_dir = Path(self.work_dir)
if self.recon_spec:
self.recon_spec = Path(self.recon_spec)
if self.datasets:
self.datasets = {k: Path(v) for k, v in self.datasets.items()}
[docs]
@dataclass
class QSIReconOutputs:
"""Expected outputs from QSIRecon.
Parameters
----------
qsirecon_dir : Path
QSIRecon output directory.
participant_dir : Path
Participant-specific directory.
html_report : Path
HTML report file.
work_dir : Path
Working directory.
"""
qsirecon_dir: Path
participant_dir: Path
html_report: Path
work_dir: Path
[docs]
@classmethod
def from_inputs(cls, inputs: QSIReconInputs, output_dir: Path, work_dir: Path):
"""Generate expected output paths from inputs.
Parameters
----------
inputs : QSIReconInputs
QSIReconInputs instance.
output_dir : Path
Resolved output directory.
work_dir : Path
Resolved work directory.
Returns
-------
QSIReconOutputs
QSIReconOutputs with expected paths.
"""
qsirecon_dir = output_dir / "qsirecon"
participant_dir = qsirecon_dir / f"sub-{inputs.participant}"
return cls(
qsirecon_dir=qsirecon_dir,
participant_dir=participant_dir,
html_report=qsirecon_dir / f"sub-{inputs.participant}.html",
work_dir=work_dir,
)
[docs]
@dataclass
class QSIReconDefaults:
"""Default configuration for QSIRecon (brain bank standards).
Parameters
----------
nprocs : int, optional
Number of parallel processes, by default 8.
mem_gb : int, optional
Memory limit in GB, by default 16000.
atlases : List[str], optional
List of atlases for connectivity, by default a long list of atlases.
fs_subjects_dir : Optional[Path], optional
FreeSurfer subjects directory, by default None.
fs_license : Optional[Path], optional
Path to FreeSurfer license file, by default None.
docker_image : str, optional
Docker image to use, by default "pennlinc/qsirecon:latest".
"""
nprocs: int = 8
mem_mb: int = 16000
atlases: List[str] = field(
default_factory=lambda: [
"4S156Parcels",
"4S256Parcels",
"4S356Parcels",
"4S456Parcels",
"4S556Parcels",
"4S656Parcels",
"4S756Parcels",
"4S856Parcels",
"4S956Parcels",
"4S1056Parcels",
"AICHA384Ext",
"Brainnetome246Ext",
"AAL116",
"Gordon333Ext",
]
)
fs_subjects_dir: Optional[Path] = None
fs_license: Optional[Path] = None
docker_image: str = "pennlinc/qsirecon:latest"
[docs]
def __post_init__(self):
"""Ensure paths are Path objects if provided."""
if self.fs_subjects_dir:
self.fs_subjects_dir = Path(self.fs_subjects_dir)
if self.fs_license:
self.fs_license = Path(self.fs_license)