1
1
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
2
2
# vi: set ft=python sts=4 ts=4 sw=4 et:
3
3
r"""
4
- *fMRIPrep* settings.
4
+ A Python module to maintain unique, run-wide *fMRIPrep* settings.
5
5
6
6
This module implements the memory structures to keep a consistent, singleton config.
7
-
8
- Example
9
- -------
10
-
11
- .. code-block:: Python
12
-
13
- from fmriprep import config
14
- config_file = config.execution.work_dir / '.fmriprep.toml'
15
- config.to_filename(config_file)
16
- # Call build_workflow(config_file, retval) in a subprocess
17
- with Manager() as mgr:
18
- from .workflow import build_workflow
19
- retval = mgr.dict()
20
- p = Process(target=build_workflow, args=(str(config_file), retval))
21
- p.start()
22
- p.join()
23
- config.load(config_file)
24
- # Access configs from any code section as:
25
- value = config.section.setting
26
-
27
- The module also has a :py:func:`to_filename` function to allow writting out
28
- the settings to hard disk in *ToML* format, which looks like
7
+ Settings are passed across processes via filesystem, and a copy of the settings for
8
+ each run and subject is left under
9
+ ``<output_dir>/sub-<participant_id>/log/<run_unique_id>/fmriprep.toml``.
10
+ Settings are stored using :abbr:`ToML (Tom's Markup Language)`.
11
+ The module has a :py:func:`~fmriprep.config.to_filename` function to allow writting out
12
+ the settings to hard disk in *ToML* format, which looks like:
29
13
30
14
.. code-block:: toml
31
15
90
74
raise_insufficient = false
91
75
92
76
This config file is used to pass the settings across processes,
93
- using the :py:func:`load` function.
77
+ using the :py:func:`~fmriprep.config.load` function.
78
+
79
+ Configuration sections
80
+ ----------------------
81
+ .. autoclass:: environment
82
+ :members:
83
+ .. autoclass:: execution
84
+ :members:
85
+ .. autoclass:: workflow
86
+ :members:
87
+ .. autoclass:: nipype
88
+ :members:
89
+
90
+ Usage
91
+ -----
92
+ A config file is used to pass settings and collect information as the execution
93
+ graph is built across processes.
94
+
95
+ .. code-block:: Python
96
+
97
+ from fmriprep import config
98
+ config_file = config.execution.work_dir / '.fmriprep.toml'
99
+ config.to_filename(config_file)
100
+ # Call build_workflow(config_file, retval) in a subprocess
101
+ with Manager() as mgr:
102
+ from .workflow import build_workflow
103
+ retval = mgr.dict()
104
+ p = Process(target=build_workflow, args=(str(config_file), retval))
105
+ p.start()
106
+ p.join()
107
+ config.load(config_file)
108
+ # Access configs from any code section as:
109
+ value = config.section.setting
110
+
111
+ Other responsibilities
112
+ ----------------------
113
+ Logging
114
+ .......
94
115
95
- Other responsibilities of the config module:
116
+ The :py:mod:`config` is responsible for other conveniency actions.
96
117
97
118
* Switching Python's ``multiprocessing`` to *forkserver* mode.
98
- * Set up new logger levels (25: IMPORTANT, and 15: VERBOSE).
99
- * Set up a warnings filter as soon as possible.
100
- * Initialize runtime descriptive settings (e.g., default FreeSurfer license,
119
+ * Set up a filter for warnings as early as possible.
120
+ * Initialize/crawl runtime descriptive settings (e.g., default FreeSurfer license,
101
121
execution environment, nipype and *fMRIPrep* versions, etc.).
102
122
* Automated I/O magic operations:
103
123
@@ -241,7 +261,16 @@ def get(cls):
241
261
242
262
243
263
class environment (_Config ):
244
- """Read-only options."""
264
+ """
265
+ Read-only options regarding the platform and environment.
266
+
267
+ The ``environment`` section is not loaded in from file,
268
+ only written out when settings are exported.
269
+ This config section is useful when reporting issues,
270
+ and these variables are tracked whenever the user does not
271
+ opt-out using the ``--notrack`` argument.
272
+
273
+ """
245
274
246
275
cpu_count = os .cpu_count ()
247
276
"""Number of available CPUs."""
@@ -264,7 +293,7 @@ class environment(_Config):
264
293
265
294
266
295
class nipype (_Config ):
267
- """Nipype configuration ."""
296
+ """Nipype settings ."""
268
297
269
298
crashfile_format = 'txt'
270
299
"""The file format for crashfiles, either text or pickle."""
@@ -303,10 +332,12 @@ def get_plugin(cls):
303
332
304
333
305
334
class execution (_Config ):
306
- """Configure workflow -level settings."""
335
+ """Configure run -level settings."""
307
336
308
337
bids_dir = None
309
- """An existing path to the dataset, which must be BIDS-compliant."""
338
+ """An existing path to the dataset, which must be BIDS-compliant.
339
+ This config mutates to a :py:class:`~bids.layout.BIDSLayout` after calling
340
+ :py:func:`~fmriprep.config.init_layout`."""
310
341
bids_description_hash = None
311
342
"""Checksum (SHA256) of the ``dataset_description.json`` of the BIDS dataset."""
312
343
bids_filters = None
@@ -378,7 +409,7 @@ class execution(_Config):
378
409
379
410
380
411
class workflow (_Config ):
381
- """Configure anatomical workflow."""
412
+ """Configure the particular execution graph of this workflow."""
382
413
383
414
anat_only = False
384
415
"""Execute the anatomical preprocessing only."""
@@ -408,48 +439,68 @@ class workflow(_Config):
408
439
longitudinal = False
409
440
"""Run FreeSurfer ``recon-all`` with the ``-logitudinal`` flag."""
410
441
medial_surface_nan = None
411
- """Fill medial surface with NaNs (not-a-number) when sampling."""
442
+ """Fill medial surface with :abbr:` NaNs (not-a-number)` when sampling."""
412
443
regressors_all_comps = None
444
+ """Return all CompCor components."""
413
445
regressors_dvars_th = None
446
+ """Threshold for DVARS."""
414
447
regressors_fd_th = None
448
+ """Threshold for :abbr:`FD (frame-wise displacement)`."""
415
449
run_reconall = True
416
450
"""Run FreeSurfer's surface reconstruction."""
417
451
skull_strip_fixed_seed = False
418
452
"""Fix a seed for skull-stripping."""
419
- skull_strip_template = ' OASIS30ANTs'
453
+ skull_strip_template = " OASIS30ANTs"
420
454
"""Change default brain extraction template."""
421
455
spaces = None
422
456
"""Standard and nonstandard spaces."""
423
457
t2s_coreg = None
424
- r"""Co-register echos before generating the T2\* reference of ME-EPI."""
458
+ """Co-register echos before generating the T2\\ * reference of \
459
+ :abbr:`ME-EPI (multi-echo echo-planar imaging)`."""
425
460
use_aroma = None
426
461
"""Run ICA-AROMA."""
427
462
use_bbr = None
428
463
"""Run boundary-based registration for BOLD-to-T1w registration (default: ``True``)."""
429
464
use_syn = None
430
- """Run *fieldmap-less* susceptibility-derived distortions estimation
465
+ """Run *fieldmap-less* susceptibility-derived distortions estimation \
431
466
in the absence of any alternatives."""
432
467
433
468
434
469
class loggers (_Config ):
435
- """Configure loggers."""
470
+ """
471
+ Setup loggers, providing access to them across the *fMRIPrep* run.
472
+
473
+ * Add new logger levels (25: IMPORTANT, and 15: VERBOSE).
474
+ * Add a new sub-logger (``cli``).
475
+ * Logger configuration.
476
+
477
+ See also:
478
+
479
+ .. autofunction: init_loggers
480
+
481
+ """
436
482
437
483
_fmt = "%(asctime)s,%(msecs)d %(name)-2s " "%(levelname)-2s:\n \t %(message)s"
438
484
_datefmt = "%y%m%d-%H:%M:%S"
439
485
440
486
default = logging .getLogger ()
487
+ """The root logger."""
441
488
cli = logging .getLogger ('cli' )
489
+ """Command-line interface logging."""
442
490
workflow = nlogging .getLogger ('nipype.workflow' )
491
+ """NiPype's workflow logger."""
443
492
interface = nlogging .getLogger ('nipype.interface' )
493
+ """NiPype's interface logger."""
444
494
utils = nlogging .getLogger ('nipype.utils' )
495
+ """NiPype's utils logger."""
445
496
446
497
447
498
def from_dict (settings ):
448
499
"""Read settings from a flat dictionary."""
449
500
nipype .load (settings )
450
501
execution .load (settings )
451
502
workflow .load (settings )
452
- set_logger_level ()
503
+ init_loggers ()
453
504
454
505
455
506
def load (filename ):
@@ -461,7 +512,7 @@ def load(filename):
461
512
if sectionname != 'environment' :
462
513
section = getattr (sys .modules [__name__ ], sectionname )
463
514
section .load (configs )
464
- set_logger_level ()
515
+ init_loggers ()
465
516
init_spaces ()
466
517
init_layout ()
467
518
@@ -495,7 +546,7 @@ def to_filename(filename):
495
546
496
547
497
548
def init_layout ():
498
- """Init a new layout ."""
549
+ """Create a new BIDS Layout on :attr:`~execution.bids_dir` ."""
499
550
if execution ._layout is None :
500
551
import re
501
552
from bids .layout import BIDSLayout
@@ -510,8 +561,8 @@ def init_layout():
510
561
execution .layout = execution ._layout
511
562
512
563
513
- def set_logger_level ():
514
- """Set the current log level to all nipype loggers."""
564
+ def init_loggers ():
565
+ """Set the current log level to all loggers."""
515
566
_handler = logging .StreamHandler (stream = sys .stdout )
516
567
_handler .setFormatter (
517
568
logging .Formatter (fmt = loggers ._fmt , datefmt = loggers ._datefmt )
@@ -525,7 +576,7 @@ def set_logger_level():
525
576
526
577
527
578
def init_spaces (checkpoint = True ):
528
- """Get a spatial references ."""
579
+ """Initialize the :attr:`~workflow.spaces` setting ."""
529
580
from niworkflows .utils .spaces import Reference , SpatialReferences
530
581
if (
531
582
getattr (workflow , 'spaces' )
0 commit comments