Skip to content

Commit 2cb8d46

Browse files
authored
Add a workflow that mocks up qsiprep outputs (#10)
1 parent 8eeaea6 commit 2cb8d46

22 files changed

+1885
-2045
lines changed

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ dependencies = [
2121
"acres",
2222
"datalad",
2323
"nipype",
24+
"nireports",
2425
"pandas",
2526
"pybids >= 0.15.6",
2627
"typer",
28+
"toml",
2729
"pyyaml",
2830
]
2931
dynamic = ["version"]
@@ -187,6 +189,7 @@ ignore = [
187189
"S113",
188190
"S202",
189191
"S602",
192+
"T100",
190193
]
191194

192195
[tool.ruff.lint.flake8-quotes]

src/simbids/cli/parser.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ def _bids_filter(value, parser):
146146
),
147147
)
148148

149+
parser.add_argument(
150+
'bids_app',
151+
choices=['qsiprep', 'qsirecon', 'xcp_d', 'fmriprep'],
152+
help=('BIDS-App to be simulated'),
153+
)
154+
149155
g_bids = parser.add_argument_group('Options for filtering BIDS queries')
150156
g_bids.add_argument(
151157
'--skip_bids_validation',
@@ -336,3 +342,4 @@ def parse_args(args=None, namespace=None):
336342
)
337343

338344
config.execution.participant_label = sorted(participant_label)
345+
return opts

src/simbids/cli/raw_mri.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
LGR = logging.getLogger(__name__)
3232

3333
# Get all the yaml files using importlib
34-
with resources.path('simbids.data.bids-mri', '') as bids_mri_path:
34+
with resources.path('simbids.data.bids_mri', '') as bids_mri_path:
3535
yaml_files = [f.name for f in bids_mri_path.glob('*.yaml')]
3636

3737

@@ -83,12 +83,12 @@ def main():
8383
config_path = Path(args.config_file)
8484
if not config_path.exists():
8585
raise FileNotFoundError(f'Config file {args.config_file} not found')
86+
# For custom config files, pass the string path
87+
simulate_dataset(args.bids_dir, str(config_path), args.fill_files, args.datalad_init)
8688
else:
8789
LGR.info(f'Using bundled config file: {args.config_file}')
88-
config_path = resources.path('simbids.data.bids-mri', args.config_file)
89-
90-
# Create the raw MRI BIDS dataset
91-
simulate_dataset(args.bids_dir, config_path, args.fill_files, args.datalad_init)
90+
# For bundled config files, pass the filename directly
91+
simulate_dataset(args.bids_dir, args.config_file, args.fill_files, args.datalad_init)
9292

9393

9494
if __name__ == '__main__':

src/simbids/cli/run.py

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,12 @@
3030
def main():
3131
"""Entry point."""
3232
import gc
33-
from multiprocessing import Manager, Process
3433

34+
from simbids.cli.parser import parse_args
3535
from simbids.cli.workflow import build_workflow
3636

37-
# Code Carbon
38-
if config.execution.track_carbon:
39-
pass
37+
# Parse arguments
38+
parse_args()
4039

4140
if 'pdb' in config.execution.debug:
4241
from simbids.utils.debug import setup_exceptionhook
@@ -51,22 +50,7 @@ def main():
5150
config_file.parent.mkdir(exist_ok=True, parents=True)
5251
config.to_filename(config_file)
5352

54-
# CRITICAL Call build_workflow(config_file, retval) in a subprocess.
55-
# Because Python on Linux does not ever free virtual memory (VM), running the
56-
# workflow construction jailed within a process preempts excessive VM buildup.
57-
if 'pdb' not in config.execution.debug:
58-
with Manager() as mgr:
59-
retval = mgr.dict()
60-
p = Process(target=build_workflow, args=(str(config_file), retval))
61-
p.start()
62-
p.join()
63-
retval = dict(retval.items()) # Convert to base dictionary
64-
65-
if p.exitcode:
66-
retval['return_code'] = p.exitcode
67-
68-
else:
69-
retval = build_workflow(str(config_file), {})
53+
retval = build_workflow(str(config_file), {})
7054

7155
global EXITCODE
7256
EXITCODE = retval.get('return_code', 0)

src/simbids/cli/workflow.py

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ def build_workflow(config_file, retval):
3636
"""Create the Nipype Workflow that supports the whole execution graph."""
3737
from pathlib import Path
3838

39-
from fmriprep.utils.bids import check_pipeline_version
40-
from fmriprep.utils.misc import check_deps
4139
from niworkflows.utils.bids import collect_participants
4240
from pkg_resources import resource_filename as pkgrf
4341

@@ -48,7 +46,6 @@ def build_workflow(config_file, retval):
4846
config.load(config_file)
4947
build_log = config.loggers.workflow
5048

51-
output_dir = config.execution.output_dir
5249
version = config.environment.version
5350

5451
retval['return_code'] = 1
@@ -64,15 +61,6 @@ def build_workflow(config_file, retval):
6461
banner += ['#' * len(banner[1])]
6562
build_log.log(25, f'\n{" " * 9}'.join(banner))
6663

67-
# warn if older results exist: check for dataset_description.json in output folder
68-
msg = check_pipeline_version(
69-
'SimBIDS',
70-
version,
71-
output_dir / 'dataset_description.json',
72-
)
73-
if msg is not None:
74-
build_log.warning(msg)
75-
7664
# Please note this is the input folder's dataset_description.json
7765
dset_desc_path = config.execution.bids_dir / 'dataset_description.json'
7866
if dset_desc_path.exists():
@@ -103,6 +91,7 @@ def build_workflow(config_file, retval):
10391
"Building SimBIDS's workflow:",
10492
f'BIDS dataset path: {config.execution.bids_dir}.',
10593
f'Participant list: {subject_list}.',
94+
f'BIDS-App: {config.workflow.bids_app}.',
10695
f'Run identifier: {config.execution.run_uuid}.',
10796
f'Output spaces: {config.execution.output_spaces}.',
10897
]
@@ -114,16 +103,6 @@ def build_workflow(config_file, retval):
114103

115104
retval['workflow'] = init_simbids_wf()
116105

117-
# Check workflow for missing commands
118-
missing = check_deps(retval['workflow'])
119-
if missing:
120-
build_log.critical(
121-
'Cannot run SimBIDS. Missing dependencies:%s',
122-
'\n\t* '.join([''] + [f'{cmd} (Interface: {iface})' for iface, cmd in missing]),
123-
)
124-
retval['return_code'] = 127 # 127 == command not found.
125-
return retval
126-
127106
config.to_filename(config_file)
128107
build_log.info(
129108
'SimBIDS workflow graph with %d nodes built successfully.',

src/simbids/config.py

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@
206206

207207
# Debug modes are names that influence the exposure of internal details to
208208
# the user, either through additional derivatives or increased verbosity
209-
DEBUG_MODES = ('compcor', 'fieldmaps', 'pdb')
209+
DEBUG_MODES = ('pdb',)
210210

211211

212212
class _Config:
@@ -481,9 +481,7 @@ def init(cls):
481481
'sourcedata',
482482
'models',
483483
re.compile(r'^\.'),
484-
re.compile(
485-
r'sub-[a-zA-Z0-9]+(/ses-[a-zA-Z0-9]+)?/(beh|dwi|eeg|ieeg|meg|perf)'
486-
),
484+
re.compile(r'sub-[a-zA-Z0-9]+(/ses-[a-zA-Z0-9]+)?/(beh|eeg|ieeg|meg|perf)'),
487485
),
488486
)
489487
cls._layout = BIDSLayout(
@@ -541,15 +539,8 @@ class workflow(_Config):
541539

542540
ignore = None
543541
"""Ignore particular steps for *SimBIDS*."""
544-
cifti_output = None
545-
"""Generate HCP Grayordinates, accepts either ``'91k'`` (default) or ``'170k'``."""
546-
dummy_scans = None
547-
"""Set a number of initial scans to be considered nonsteady states."""
548-
slice_time_ref = 0.5
549-
"""The time of the reference slice to correct BOLD values to, as a fraction
550-
acquisition time. 0 indicates the start, 0.5 the midpoint, and 1 the end
551-
of acquisition. The alias `start` corresponds to 0, and `middle` to 0.5.
552-
The default value is 0.5."""
542+
bids_app = 'qsiprep'
543+
"""The BIDS App to simulate."""
553544

554545

555546
class loggers:
@@ -738,14 +729,5 @@ def init_spaces(checkpoint=True):
738729
if 'MNI152NLin6Asym' not in spaces.get_spaces(nonstandard=False, dim=(3,)):
739730
spaces.add(Reference('MNI152NLin6Asym', {}))
740731

741-
# Ensure user-defined spatial references for outputs are correctly parsed.
742-
# Certain options require normalization to a space not explicitly defined by users.
743-
# These spaces will not be included in the final outputs.
744-
cifti_output = workflow.cifti_output
745-
if cifti_output:
746-
# CIFTI grayordinates to corresponding FSL-MNI resolutions.
747-
vol_res = '2' if cifti_output == '91k' else '1'
748-
spaces.add(Reference('MNI152NLin6Asym', {'res': vol_res}))
749-
750732
# Make the SpatialReferences object available
751733
workflow.spaces = spaces

0 commit comments

Comments
 (0)