Source code for voxelops.schemas.qsiprep

"""QSIPrep schemas: inputs, outputs, and defaults."""

from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional, List


[docs] @dataclass class QSIPrepInputs: """Required inputs for QSIPrep diffusion preprocessing. Parameters ---------- bids_dir : Path BIDS dataset directory. participant : str Participant label (without 'sub-' prefix). output_dir : Optional[Path], optional Output directory, by default None. If None, defaults to bids_dir/../derivatives/qsiprep. work_dir : Optional[Path], optional Working directory, by default None. If None, defaults to output_dir/../work/qsiprep. bids_filters : Optional[Path], optional Path to BIDS filters JSON file, by default None. """ bids_dir: Path participant: str output_dir: Optional[Path] = None work_dir: Optional[Path] = None bids_filters: Optional[Path] = None # Path to BIDS filters JSON file
[docs] def __post_init__(self): """Ensure paths are Path objects.""" self.bids_dir = Path(self.bids_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.bids_filters: self.bids_filters = Path(self.bids_filters)
[docs] @dataclass class QSIPrepOutputs: """Expected outputs from QSIPrep. Parameters ---------- qsiprep_dir : Path QSIPrep output directory. participant_dir : Path Participant-specific directory. html_report : Path HTML report file. work_dir : Path Working directory. figures_dir : Path QC figures directory. """ qsiprep_dir: Path participant_dir: Path html_report: Path work_dir: Path figures_dir: Path
[docs] @classmethod def from_inputs(cls, inputs: QSIPrepInputs, output_dir: Path, work_dir: Path): """Generate expected output paths from inputs. Parameters ---------- inputs : QSIPrepInputs QSIPrepInputs instance. output_dir : Path Resolved output directory. work_dir : Path Resolved work directory. Returns ------- QSIPrepOutputs QSIPrepOutputs with expected paths. """ qsiprep_dir = output_dir / "qsiprep" participant_dir = qsiprep_dir / f"sub-{inputs.participant}" return cls( qsiprep_dir=qsiprep_dir, participant_dir=participant_dir, html_report=qsiprep_dir / f"sub-{inputs.participant}.html", work_dir=work_dir, figures_dir=participant_dir / "figures", )
[docs] @dataclass class QSIPrepDefaults: """Default configuration for QSIPrep (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. output_resolution : float, optional Output resolution in mm, by default 1.6. anatomical_template : List[str], optional List of output spaces, by default ["MNI152NLin2009cAsym"]. longitudinal : bool, optional Enable longitudinal processing, by default False. subject_anatomical_reference : str, optional Anatomical reference for longitudinal processing, by default "unbiased". skip_bids_validation : bool, optional Skip BIDS validation, by default False. fs_license : Optional[Path], optional Path to FreeSurfer license file, by default None. docker_image : str, optional Docker image to use, by default "pennlinc/qsiprep:latest". """ nprocs: int = 8 mem_mb: int = 16000 output_resolution: float = 1.6 anatomical_template: List[str] = field( default_factory=lambda: ["MNI152NLin2009cAsym"] ) longitudinal: bool = False subject_anatomical_reference: str = "unbiased" skip_bids_validation: bool = False fs_license: Optional[Path] = None docker_image: str = "pennlinc/qsiprep:latest"
[docs] def __post_init__(self): """Ensure fs_license is Path object if provided.""" if self.fs_license: self.fs_license = Path(self.fs_license)