voxelops 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- voxelops/__init__.py +98 -0
- voxelops/exceptions.py +158 -0
- voxelops/runners/__init__.py +13 -0
- voxelops/runners/_base.py +191 -0
- voxelops/runners/heudiconv.py +202 -0
- voxelops/runners/qsiparc.py +150 -0
- voxelops/runners/qsiprep.py +187 -0
- voxelops/runners/qsirecon.py +173 -0
- voxelops/schemas/__init__.py +41 -0
- voxelops/schemas/heudiconv.py +121 -0
- voxelops/schemas/qsiparc.py +107 -0
- voxelops/schemas/qsiprep.py +140 -0
- voxelops/schemas/qsirecon.py +154 -0
- voxelops/utils/__init__.py +1 -0
- voxelops/utils/bids.py +486 -0
- voxelops-0.1.0.dist-info/METADATA +221 -0
- voxelops-0.1.0.dist-info/RECORD +19 -0
- voxelops-0.1.0.dist-info/WHEEL +4 -0
- voxelops-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""QSIParc schemas: inputs, outputs, and defaults."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from parcellate.interfaces.models import AtlasDefinition
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class QSIParcInputs:
|
|
12
|
+
"""Required inputs for QSIParc parcellation.
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
qsirecon_dir : Path
|
|
17
|
+
QSIRecon output directory.
|
|
18
|
+
participant : str
|
|
19
|
+
Participant label (without 'sub-' prefix).
|
|
20
|
+
output_dir : Optional[Path], optional
|
|
21
|
+
Output directory, by default None.
|
|
22
|
+
If None, defaults to qsirecon_dir parent.
|
|
23
|
+
session : Optional[str], optional
|
|
24
|
+
Session label (without 'ses-' prefix), by default None.
|
|
25
|
+
atlases : Optional[list[AtlasDefinition]], optional
|
|
26
|
+
List of atlas definitions, by default None.
|
|
27
|
+
n_jobs : Optional[int], optional
|
|
28
|
+
Number of jobs to run in parallel, by default None.
|
|
29
|
+
n_procs : Optional[int], optional
|
|
30
|
+
Number of processors to use, by default None.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
qsirecon_dir: Path
|
|
34
|
+
participant: str
|
|
35
|
+
output_dir: Optional[Path] = None
|
|
36
|
+
session: Optional[str] = None
|
|
37
|
+
atlases: Optional[list[AtlasDefinition]] = None
|
|
38
|
+
n_jobs: Optional[int] = None
|
|
39
|
+
n_procs: Optional[int] = None
|
|
40
|
+
|
|
41
|
+
def __post_init__(self):
|
|
42
|
+
"""Ensure paths are Path objects."""
|
|
43
|
+
self.qsirecon_dir = Path(self.qsirecon_dir)
|
|
44
|
+
if self.output_dir:
|
|
45
|
+
self.output_dir = Path(self.output_dir)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class QSIParcOutputs:
|
|
50
|
+
"""Expected outputs from QSIParc.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
output_dir : Path
|
|
55
|
+
Parcellation output directory.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
output_dir: Path
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def from_inputs(cls, inputs: QSIParcInputs, output_dir: Path):
|
|
62
|
+
"""Generate expected output paths from inputs.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
inputs : QSIParcInputs
|
|
67
|
+
QSIParcInputs instance.
|
|
68
|
+
output_dir : Path
|
|
69
|
+
Resolved output directory.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
QSIParcOutputs
|
|
74
|
+
QSIParcOutputs with expected paths.
|
|
75
|
+
"""
|
|
76
|
+
return cls(output_dir=output_dir)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class QSIParcDefaults:
|
|
81
|
+
"""Default configuration for QSIParc (brain bank standards).
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
mask : Optional[str], optional
|
|
86
|
+
Mask to apply during parcellation ("gm", "wm", "brain", or path), by default "gm".
|
|
87
|
+
force : bool, optional
|
|
88
|
+
Whether to overwrite existing outputs, by default False.
|
|
89
|
+
background_label : int, optional
|
|
90
|
+
Label value for background voxels, by default 0.
|
|
91
|
+
resampling_target : Optional[str], optional
|
|
92
|
+
Resampling strategy ("data", "labels", "atlas", or None), by default "data".
|
|
93
|
+
log_level : str, optional
|
|
94
|
+
Logging verbosity (e.g., "INFO", "DEBUG"), by default "INFO".
|
|
95
|
+
n_jobs : Optional[int], optional
|
|
96
|
+
Number of jobs to run in parallel, by default 1.
|
|
97
|
+
n_procs : Optional[int], optional
|
|
98
|
+
Number of processors to use, by default 1.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
mask: Optional[str] = "gm"
|
|
102
|
+
force: bool = False
|
|
103
|
+
background_label: int = 0
|
|
104
|
+
resampling_target: Optional[str] = "data"
|
|
105
|
+
log_level: str = "INFO"
|
|
106
|
+
n_jobs: Optional[int] = 1
|
|
107
|
+
n_procs: Optional[int] = 1
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""QSIPrep schemas: inputs, outputs, and defaults."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class QSIPrepInputs:
|
|
10
|
+
"""Required inputs for QSIPrep diffusion preprocessing.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
bids_dir : Path
|
|
15
|
+
BIDS dataset directory.
|
|
16
|
+
participant : str
|
|
17
|
+
Participant label (without 'sub-' prefix).
|
|
18
|
+
output_dir : Optional[Path], optional
|
|
19
|
+
Output directory, by default None.
|
|
20
|
+
If None, defaults to bids_dir/../derivatives/qsiprep.
|
|
21
|
+
work_dir : Optional[Path], optional
|
|
22
|
+
Working directory, by default None.
|
|
23
|
+
If None, defaults to output_dir/../work/qsiprep.
|
|
24
|
+
bids_filters : Optional[Path], optional
|
|
25
|
+
Path to BIDS filters JSON file, by default None.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
bids_dir: Path
|
|
29
|
+
participant: str
|
|
30
|
+
output_dir: Optional[Path] = None
|
|
31
|
+
work_dir: Optional[Path] = None
|
|
32
|
+
bids_filters: Optional[Path] = None # Path to BIDS filters JSON file
|
|
33
|
+
|
|
34
|
+
def __post_init__(self):
|
|
35
|
+
"""Ensure paths are Path objects."""
|
|
36
|
+
self.bids_dir = Path(self.bids_dir)
|
|
37
|
+
if self.output_dir:
|
|
38
|
+
self.output_dir = Path(self.output_dir)
|
|
39
|
+
if self.work_dir:
|
|
40
|
+
self.work_dir = Path(self.work_dir)
|
|
41
|
+
if self.bids_filters:
|
|
42
|
+
self.bids_filters = Path(self.bids_filters)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class QSIPrepOutputs:
|
|
47
|
+
"""Expected outputs from QSIPrep.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
qsiprep_dir : Path
|
|
52
|
+
QSIPrep output directory.
|
|
53
|
+
participant_dir : Path
|
|
54
|
+
Participant-specific directory.
|
|
55
|
+
html_report : Path
|
|
56
|
+
HTML report file.
|
|
57
|
+
work_dir : Path
|
|
58
|
+
Working directory.
|
|
59
|
+
figures_dir : Path
|
|
60
|
+
QC figures directory.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
qsiprep_dir: Path
|
|
64
|
+
participant_dir: Path
|
|
65
|
+
html_report: Path
|
|
66
|
+
work_dir: Path
|
|
67
|
+
figures_dir: Path
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def from_inputs(cls, inputs: QSIPrepInputs, output_dir: Path, work_dir: Path):
|
|
71
|
+
"""Generate expected output paths from inputs.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
inputs : QSIPrepInputs
|
|
76
|
+
QSIPrepInputs instance.
|
|
77
|
+
output_dir : Path
|
|
78
|
+
Resolved output directory.
|
|
79
|
+
work_dir : Path
|
|
80
|
+
Resolved work directory.
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
QSIPrepOutputs
|
|
85
|
+
QSIPrepOutputs with expected paths.
|
|
86
|
+
"""
|
|
87
|
+
qsiprep_dir = output_dir / "qsiprep"
|
|
88
|
+
participant_dir = qsiprep_dir / f"sub-{inputs.participant}"
|
|
89
|
+
|
|
90
|
+
return cls(
|
|
91
|
+
qsiprep_dir=qsiprep_dir,
|
|
92
|
+
participant_dir=participant_dir,
|
|
93
|
+
html_report=qsiprep_dir / f"sub-{inputs.participant}.html",
|
|
94
|
+
work_dir=work_dir,
|
|
95
|
+
figures_dir=participant_dir / "figures",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class QSIPrepDefaults:
|
|
101
|
+
"""Default configuration for QSIPrep (brain bank standards).
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
nprocs : int, optional
|
|
106
|
+
Number of parallel processes, by default 8.
|
|
107
|
+
mem_gb : int, optional
|
|
108
|
+
Memory limit in GB, by default 16000.
|
|
109
|
+
output_resolution : float, optional
|
|
110
|
+
Output resolution in mm, by default 1.6.
|
|
111
|
+
anatomical_template : List[str], optional
|
|
112
|
+
List of output spaces, by default ["MNI152NLin2009cAsym"].
|
|
113
|
+
longitudinal : bool, optional
|
|
114
|
+
Enable longitudinal processing, by default False.
|
|
115
|
+
subject_anatomical_reference : str, optional
|
|
116
|
+
Anatomical reference for longitudinal processing, by default "unbiased".
|
|
117
|
+
skip_bids_validation : bool, optional
|
|
118
|
+
Skip BIDS validation, by default False.
|
|
119
|
+
fs_license : Optional[Path], optional
|
|
120
|
+
Path to FreeSurfer license file, by default None.
|
|
121
|
+
docker_image : str, optional
|
|
122
|
+
Docker image to use, by default "pennlinc/qsiprep:latest".
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
nprocs: int = 8
|
|
126
|
+
mem_mb: int = 16000
|
|
127
|
+
output_resolution: float = 1.6
|
|
128
|
+
anatomical_template: List[str] = field(
|
|
129
|
+
default_factory=lambda: ["MNI152NLin2009cAsym"]
|
|
130
|
+
)
|
|
131
|
+
longitudinal: bool = False
|
|
132
|
+
subject_anatomical_reference: str = "unbiased"
|
|
133
|
+
skip_bids_validation: bool = False
|
|
134
|
+
fs_license: Optional[Path] = None
|
|
135
|
+
docker_image: str = "pennlinc/qsiprep:latest"
|
|
136
|
+
|
|
137
|
+
def __post_init__(self):
|
|
138
|
+
"""Ensure fs_license is Path object if provided."""
|
|
139
|
+
if self.fs_license:
|
|
140
|
+
self.fs_license = Path(self.fs_license)
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""QSIRecon schemas: inputs, outputs, and defaults."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class QSIReconInputs:
|
|
10
|
+
"""Required inputs for QSIRecon diffusion reconstruction.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
qsiprep_dir : Path
|
|
15
|
+
QSIPrep output directory.
|
|
16
|
+
participant : str
|
|
17
|
+
Participant label (without 'sub-' prefix).
|
|
18
|
+
output_dir : Optional[Path], optional
|
|
19
|
+
Output directory, by default None.
|
|
20
|
+
If None, defaults to qsiprep_dir/../qsirecon.
|
|
21
|
+
work_dir : Optional[Path], optional
|
|
22
|
+
Working directory, by default None.
|
|
23
|
+
If None, defaults to output_dir/../work/qsirecon.
|
|
24
|
+
recon_spec : Optional[Path], optional
|
|
25
|
+
Path to reconstruction spec YAML file, by default None.
|
|
26
|
+
datasets : Optional[dict[str, Path]], optional
|
|
27
|
+
Dictionary of dataset names and paths, by default None.
|
|
28
|
+
atlases : Optional[List[str]], optional
|
|
29
|
+
List of atlases for connectivity, by default None.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
qsiprep_dir: Path
|
|
33
|
+
participant: str
|
|
34
|
+
output_dir: Optional[Path] = None
|
|
35
|
+
work_dir: Optional[Path] = None
|
|
36
|
+
recon_spec: Optional[Path] = None
|
|
37
|
+
datasets: Optional[dict[str, Path]] = None
|
|
38
|
+
atlases: Optional[List[str]] = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def __post_init__(self):
|
|
42
|
+
"""Ensure paths are Path objects."""
|
|
43
|
+
self.qsiprep_dir = Path(self.qsiprep_dir)
|
|
44
|
+
if self.output_dir:
|
|
45
|
+
self.output_dir = Path(self.output_dir)
|
|
46
|
+
if self.work_dir:
|
|
47
|
+
self.work_dir = Path(self.work_dir)
|
|
48
|
+
if self.recon_spec:
|
|
49
|
+
self.recon_spec = Path(self.recon_spec)
|
|
50
|
+
if self.datasets:
|
|
51
|
+
self.datasets = {k: Path(v) for k, v in self.datasets.items()}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class QSIReconOutputs:
|
|
57
|
+
"""Expected outputs from QSIRecon.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
qsirecon_dir : Path
|
|
62
|
+
QSIRecon output directory.
|
|
63
|
+
participant_dir : Path
|
|
64
|
+
Participant-specific directory.
|
|
65
|
+
html_report : Path
|
|
66
|
+
HTML report file.
|
|
67
|
+
work_dir : Path
|
|
68
|
+
Working directory.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
qsirecon_dir: Path
|
|
72
|
+
participant_dir: Path
|
|
73
|
+
html_report: Path
|
|
74
|
+
work_dir: Path
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def from_inputs(cls, inputs: QSIReconInputs, output_dir: Path, work_dir: Path):
|
|
78
|
+
"""Generate expected output paths from inputs.
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
inputs : QSIReconInputs
|
|
83
|
+
QSIReconInputs instance.
|
|
84
|
+
output_dir : Path
|
|
85
|
+
Resolved output directory.
|
|
86
|
+
work_dir : Path
|
|
87
|
+
Resolved work directory.
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
QSIReconOutputs
|
|
92
|
+
QSIReconOutputs with expected paths.
|
|
93
|
+
"""
|
|
94
|
+
qsirecon_dir = output_dir / "qsirecon"
|
|
95
|
+
participant_dir = qsirecon_dir / f"sub-{inputs.participant}"
|
|
96
|
+
|
|
97
|
+
return cls(
|
|
98
|
+
qsirecon_dir=qsirecon_dir,
|
|
99
|
+
participant_dir=participant_dir,
|
|
100
|
+
html_report=qsirecon_dir / f"sub-{inputs.participant}.html",
|
|
101
|
+
work_dir=work_dir,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@dataclass
|
|
106
|
+
class QSIReconDefaults:
|
|
107
|
+
"""Default configuration for QSIRecon (brain bank standards).
|
|
108
|
+
|
|
109
|
+
Parameters
|
|
110
|
+
----------
|
|
111
|
+
nprocs : int, optional
|
|
112
|
+
Number of parallel processes, by default 8.
|
|
113
|
+
mem_gb : int, optional
|
|
114
|
+
Memory limit in GB, by default 16000.
|
|
115
|
+
atlases : List[str], optional
|
|
116
|
+
List of atlases for connectivity, by default a long list of atlases.
|
|
117
|
+
fs_subjects_dir : Optional[Path], optional
|
|
118
|
+
FreeSurfer subjects directory, by default None.
|
|
119
|
+
fs_license : Optional[Path], optional
|
|
120
|
+
Path to FreeSurfer license file, by default None.
|
|
121
|
+
docker_image : str, optional
|
|
122
|
+
Docker image to use, by default "pennlinc/qsirecon:latest".
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
nprocs: int = 8
|
|
126
|
+
mem_mb: int = 16000
|
|
127
|
+
atlases: List[str] = field(
|
|
128
|
+
default_factory=lambda: [
|
|
129
|
+
"4S156Parcels",
|
|
130
|
+
"4S256Parcels",
|
|
131
|
+
"4S356Parcels",
|
|
132
|
+
"4S456Parcels",
|
|
133
|
+
"4S556Parcels",
|
|
134
|
+
"4S656Parcels",
|
|
135
|
+
"4S756Parcels",
|
|
136
|
+
"4S856Parcels",
|
|
137
|
+
"4S956Parcels",
|
|
138
|
+
"4S1056Parcels",
|
|
139
|
+
"AICHA384Ext",
|
|
140
|
+
"Brainnetome246Ext",
|
|
141
|
+
"AAL116",
|
|
142
|
+
"Gordon333Ext",
|
|
143
|
+
]
|
|
144
|
+
)
|
|
145
|
+
fs_subjects_dir: Optional[Path] = None
|
|
146
|
+
fs_license: Optional[Path] = None
|
|
147
|
+
docker_image: str = "pennlinc/qsirecon:latest"
|
|
148
|
+
|
|
149
|
+
def __post_init__(self):
|
|
150
|
+
"""Ensure paths are Path objects if provided."""
|
|
151
|
+
if self.fs_subjects_dir:
|
|
152
|
+
self.fs_subjects_dir = Path(self.fs_subjects_dir)
|
|
153
|
+
if self.fs_license:
|
|
154
|
+
self.fs_license = Path(self.fs_license)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Utility modules for VoxelOps."""
|