Skip to content

Commit d820991

Browse files
authored
Improve memory allocation (#1581)
1 parent 28bf2cc commit d820991

File tree

11 files changed

+100
-49
lines changed

11 files changed

+100
-49
lines changed

xcp_d/data/tests/config.toml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,15 @@ run_uuid = "20240205-123456"
2626
templateflow_home = "~/.cache/templateflow"
2727
work_dir = "work/"
2828
write_graph = false
29+
atlases = ["Gordon"]
2930

3031
[workflow]
31-
cifti = false
32+
file_format = "nifti"
3233
dummy_scans = 0
3334
input_type = "fmriprep"
3435
despike = false
3536
smoothing = 6
3637
combine_runs = false
37-
motion_filter_type = false
38-
band_stop_min = false
39-
band_stop_max = false
4038
motion_filter_order = 4
4139
head_radius = 50
4240
fd_thresh = 0.3
@@ -45,7 +43,6 @@ bandpass_filter = true
4543
high_pass = 0.01
4644
low_pass = 0.1
4745
bpf_order = 2
48-
atlases = []
4946
min_coverage = 0.5
5047
correlation_lengths = []
5148
process_surfaces = false

xcp_d/workflows/anatomical/plotting.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def init_brainsprite_figures_wf(
3232
t1w_available,
3333
t2w_available,
3434
apply_transform,
35+
mem_gb=None,
3536
name='brainsprite_figures_wf',
3637
):
3738
"""Create mosaic and PNG files for executive summary brainsprite.
@@ -61,6 +62,8 @@ def init_brainsprite_figures_wf(
6162
True if a T2w image is available.
6263
apply_transform : bool
6364
Whether to apply the transform to the surfaces.
65+
mem_gb : :obj:`dict` or None
66+
Memory size in GB. If None, a default of 1 GB per volume is used.
6467
%(name)s
6568
Default is "init_brainsprite_figures_wf".
6669
@@ -76,6 +79,9 @@ def init_brainsprite_figures_wf(
7679
rh_pial_surf
7780
template_to_anat_xfm
7881
"""
82+
if mem_gb is None:
83+
mem_gb = {'volume': 1}
84+
7985
workflow = Workflow(name=name)
8086

8187
inputnode = pe.Node(
@@ -140,7 +146,7 @@ def init_brainsprite_figures_wf(
140146
plot_slices = pe.Node(
141147
PlotSlicesForBrainSprite(n_procs=config.nipype.omp_nthreads),
142148
name=f'plot_slices_{image_type}',
143-
mem_gb=config.DEFAULT_MEMORY_MIN_GB,
149+
mem_gb=mem_gb['volume'],
144150
n_procs=config.nipype.omp_nthreads,
145151
)
146152
workflow.connect([

xcp_d/workflows/base.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
)
4141
from xcp_d.utils.doc import fill_doc
4242
from xcp_d.utils.modified_data import calculate_exact_scans, flag_bad_run
43-
from xcp_d.utils.utils import estimate_brain_radius, is_number
43+
from xcp_d.utils.utils import _create_mem_gb, estimate_brain_radius, is_number
4444
from xcp_d.workflows.anatomical.parcellation import init_parcellate_surfaces_wf
4545
from xcp_d.workflows.anatomical.surface import init_postprocess_surfaces_wf
4646
from xcp_d.workflows.anatomical.volume import init_postprocess_anat_wf
@@ -116,7 +116,7 @@ def init_single_subject_wf(subject_id: str, anat_session: str, func_sessions: li
116116
from xcp_d.workflows.base import init_single_subject_wf
117117
118118
with mock_config():
119-
wf = init_single_subject_wf("01", "01", ["01"])
119+
wf = init_single_subject_wf("01", "", [""])
120120
121121
Parameters
122122
----------
@@ -517,6 +517,8 @@ def init_single_subject_wf(subject_id: str, anat_session: str, func_sessions: li
517517
}
518518

519519
n_processed_task_runs = 0
520+
concat_bold_gb = 0
521+
concat_volume_gb = 0
520522
for j_run, bold_file in enumerate(task_files):
521523
run_data = collect_run_data(
522524
layout=config.execution.layout,
@@ -568,6 +570,14 @@ def init_single_subject_wf(subject_id: str, anat_session: str, func_sessions: li
568570
bold_file=bold_file,
569571
)
570572

573+
# Compute memory estimates from the BOLD file header
574+
mem_gbx = _create_mem_gb(bold_file)
575+
576+
# Accumulate memory estimates for the concatenation workflow.
577+
# The concatenated file will be the sum of all runs.
578+
concat_bold_gb += mem_gbx['bold']
579+
concat_volume_gb = max(concat_volume_gb, mem_gbx['volume'])
580+
571581
postprocess_bold_wf = init_postprocess_bold_wf(
572582
bold_file=bold_file,
573583
head_radius=head_radius,
@@ -577,6 +587,7 @@ def init_single_subject_wf(subject_id: str, anat_session: str, func_sessions: li
577587
n_runs=n_runs,
578588
has_multiple_runs=multiscans,
579589
exact_scans=exact_scans,
590+
mem_gb=mem_gbx,
580591
name=f'postprocess_{run_counter}_wf',
581592
)
582593
run_counter += 1
@@ -621,9 +632,14 @@ def init_single_subject_wf(subject_id: str, anat_session: str, func_sessions: li
621632
]) # fmt:skip
622633

623634
if config.workflow.combine_runs and (n_processed_task_runs > 0) and multiscans:
635+
concat_mem_gb = {
636+
'bold': concat_bold_gb,
637+
'volume': concat_volume_gb,
638+
}
624639
concatenate_data_wf = init_concatenate_data_wf(
625640
TR=TR,
626641
head_radius=head_radius,
642+
mem_gb=concat_mem_gb,
627643
name=f'concatenate_entity_set_{ent_set}_wf',
628644
)
629645

xcp_d/workflows/bold/cifti.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from xcp_d import config
1212
from xcp_d.interfaces.utils import ConvertTo32
1313
from xcp_d.utils.doc import fill_doc
14-
from xcp_d.utils.utils import _create_mem_gb
1514
from xcp_d.workflows.bold.connectivity import init_functional_connectivity_cifti_wf
1615
from xcp_d.workflows.bold.metrics import init_alff_wf, init_reho_cifti_wf
1716
from xcp_d.workflows.bold.outputs import init_postproc_derivatives_wf
@@ -38,6 +37,7 @@ def init_postprocess_cifti_wf(
3837
n_runs,
3938
has_multiple_runs,
4039
exact_scans,
40+
mem_gb,
4141
name='cifti_postprocess_wf',
4242
):
4343
"""Organize the cifti processing workflow.
@@ -63,10 +63,13 @@ def init_postprocess_cifti_wf(
6363
6464
run_data = collect_run_data(
6565
layout=layout,
66-
input_type="fmriprep",
6766
bold_file=bold_file,
68-
cifti=True,
67+
file_format="cifti",
68+
target_space="MNI152NLin2009cAsym",
6969
)
70+
run_data['confounds'] = None
71+
72+
from xcp_d.utils.utils import _create_mem_gb
7073
7174
wf = init_postprocess_cifti_wf(
7275
bold_file=bold_file,
@@ -77,6 +80,7 @@ def init_postprocess_cifti_wf(
7780
n_runs=1,
7881
has_multiple_runs=False,
7982
exact_scans=[],
83+
mem_gb=_create_mem_gb(bold_file),
8084
name="cifti_postprocess_wf",
8185
)
8286
@@ -95,6 +99,8 @@ def init_postprocess_cifti_wf(
9599
Whether there are multiple runs for this task or not.
96100
Interacts with the output_run_wise_correlations parameter.
97101
%(exact_scans)s
102+
mem_gb : :obj:`dict`
103+
Dictionary of memory allocations with keys ``'bold'`` and ``'volume'``.
98104
%(name)s
99105
Default is "cifti_postprocess_wf".
100106
@@ -207,7 +213,7 @@ def init_postprocess_cifti_wf(
207213
name='outputnode',
208214
)
209215

210-
mem_gbx = _create_mem_gb(bold_file)
216+
mem_gbx = mem_gb
211217

212218
downcast_data = pe.Node(
213219
ConvertTo32(),
@@ -227,6 +233,7 @@ def init_postprocess_cifti_wf(
227233
TR=TR,
228234
exact_scans=exact_scans,
229235
head_radius=head_radius,
236+
mem_gb=mem_gbx,
230237
)
231238

232239
workflow.connect([
@@ -257,7 +264,7 @@ def init_postprocess_cifti_wf(
257264
]) # fmt:skip
258265

259266
if despike:
260-
despike_wf = init_despike_wf(TR=TR)
267+
despike_wf = init_despike_wf(TR=TR, mem_gb=mem_gbx)
261268

262269
workflow.connect([
263270
(prepare_confounds_wf, despike_wf, [

xcp_d/workflows/bold/concatenation.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121

2222
@fill_doc
23-
def init_concatenate_data_wf(TR, head_radius, name='concatenate_data_wf'):
23+
def init_concatenate_data_wf(TR, head_radius, mem_gb, name='concatenate_data_wf'):
2424
"""Concatenate postprocessed data across runs and directions.
2525
2626
Workflow Graph
@@ -36,13 +36,17 @@ def init_concatenate_data_wf(TR, head_radius, name='concatenate_data_wf'):
3636
wf = init_concatenate_data_wf(
3737
TR=2,
3838
head_radius=50,
39+
mem_gb={"bold": 2.0, "volume": 0.01},
3940
name="concatenate_data_wf",
4041
)
4142
4243
Parameters
4344
----------
4445
%(TR)s
4546
%(head_radius)s
47+
mem_gb : :obj:`dict`
48+
Dictionary of memory allocations with keys ``'bold'`` and ``'volume'``.
49+
This should represent the *total* memory across all runs being concatenated.
4650
%(name)s
4751
Default is "concatenate_data_wf".
4852
@@ -83,9 +87,6 @@ def init_concatenate_data_wf(TR, head_radius, name='concatenate_data_wf'):
8387
fd_thresh = config.workflow.fd_thresh
8488
atlases = config.execution.atlases
8589

86-
# Guess memory needs since they can't be estimated from the inputs
87-
mem_gb = {'bold': 6.0, 'volume': 1.0}
88-
8990
workflow.__desc__ = """
9091
Postprocessing derivatives from multi-run tasks were then concatenated across runs and directions.
9192
"""

xcp_d/workflows/bold/connectivity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def init_functional_connectivity_nifti_wf(
122122
NiftiParcellate(min_coverage=min_coverage),
123123
name='parcellate_data',
124124
iterfield=['atlas', 'atlas_labels'],
125-
mem_gb=mem_gb['bold'],
125+
mem_gb=2 * mem_gb['bold'],
126126
)
127127
workflow.connect([
128128
(inputnode, parcellate_data, [

xcp_d/workflows/bold/metrics.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def init_alff_wf(
147147
high_pass=high_pass,
148148
n_threads=config.nipype.omp_nthreads,
149149
),
150-
mem_gb=mem_gb['bold'],
150+
mem_gb=2 * mem_gb['bold'],
151151
name='alff_compt',
152152
n_procs=config.nipype.omp_nthreads,
153153
)
@@ -274,7 +274,7 @@ def init_reho_cifti_wf(
274274
with mock_config():
275275
wf = init_reho_cifti_wf(
276276
name_source="/path/to/bold.dtseries.nii",
277-
mem_gb={"volume": 0.1},
277+
mem_gb={"bold": 0.1},
278278
name="cifti_reho_wf",
279279
)
280280
@@ -359,12 +359,12 @@ def init_reho_cifti_wf(
359359
lh_reho = pe.Node(
360360
SurfaceReHo(surf_hemi='L'),
361361
name='reho_lh',
362-
mem_gb=mem_gb['bold'],
362+
mem_gb=2 * mem_gb['bold'],
363363
)
364364
rh_reho = pe.Node(
365365
SurfaceReHo(surf_hemi='R'),
366366
name='reho_rh',
367-
mem_gb=mem_gb['bold'],
367+
mem_gb=2 * mem_gb['bold'],
368368
)
369369
subcortical_reho = pe.Node(
370370
ReHoNamePatch(neighborhood='vertices'),
@@ -442,7 +442,7 @@ def init_reho_nifti_wf(name_source, mem_gb, name='reho_nifti_wf'):
442442
with mock_config():
443443
wf = init_reho_nifti_wf(
444444
name_source="/path/to/bold.nii.gz",
445-
mem_gb={"volume": 0.1},
445+
mem_gb={"bold": 0.1},
446446
name="nifti_reho_wf",
447447
)
448448
@@ -484,7 +484,7 @@ def init_reho_nifti_wf(name_source, mem_gb, name='reho_nifti_wf'):
484484
compute_reho = pe.Node(
485485
ReHoNamePatch(neighborhood='vertices'),
486486
name='reho_3d',
487-
mem_gb=mem_gb['bold'],
487+
mem_gb=2 * mem_gb['bold'],
488488
n_procs=1,
489489
)
490490
# Get the svg

xcp_d/workflows/bold/nifti.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from xcp_d import config
1212
from xcp_d.interfaces.utils import ConvertTo32
1313
from xcp_d.utils.doc import fill_doc
14-
from xcp_d.utils.utils import _create_mem_gb
1514
from xcp_d.workflows.bold.connectivity import init_functional_connectivity_nifti_wf
1615
from xcp_d.workflows.bold.metrics import init_alff_wf, init_reho_nifti_wf
1716
from xcp_d.workflows.bold.outputs import init_postproc_derivatives_wf
@@ -38,6 +37,7 @@ def init_postprocess_nifti_wf(
3837
n_runs,
3938
has_multiple_runs,
4039
exact_scans,
40+
mem_gb,
4141
name='bold_postprocess_wf',
4242
):
4343
"""Organize the bold processing workflow.
@@ -66,10 +66,13 @@ def init_postprocess_nifti_wf(
6666
6767
run_data = collect_run_data(
6868
layout=layout,
69-
input_type="fmriprep",
7069
bold_file=bold_file,
71-
cifti=False,
70+
file_format="nifti",
71+
target_space="MNI152NLin2009cAsym",
7272
)
73+
run_data['confounds'] = None
74+
75+
from xcp_d.utils.utils import _create_mem_gb
7376
7477
wf = init_postprocess_nifti_wf(
7578
bold_file=bold_file,
@@ -80,6 +83,7 @@ def init_postprocess_nifti_wf(
8083
n_runs=1,
8184
has_multiple_runs=False,
8285
exact_scans=[],
86+
mem_gb=_create_mem_gb(bold_file),
8387
name="nifti_postprocess_wf",
8488
)
8589
@@ -97,6 +101,8 @@ def init_postprocess_nifti_wf(
97101
Whether there are multiple runs for this task or not.
98102
Interacts with the output_run_wise_correlations parameter.
99103
%(exact_scans)s
104+
mem_gb : :obj:`dict`
105+
Dictionary of memory allocations with keys ``'bold'`` and ``'volume'``.
100106
%(name)s
101107
Default is "nifti_postprocess_wf".
102108
@@ -215,7 +221,7 @@ def init_postprocess_nifti_wf(
215221
name='outputnode',
216222
)
217223

218-
mem_gbx = _create_mem_gb(bold_file)
224+
mem_gbx = mem_gb
219225

220226
downcast_data = pe.Node(
221227
ConvertTo32(),
@@ -240,6 +246,7 @@ def init_postprocess_nifti_wf(
240246
TR=TR,
241247
exact_scans=exact_scans,
242248
head_radius=head_radius,
249+
mem_gb=mem_gbx,
243250
)
244251

245252
workflow.connect([
@@ -271,7 +278,7 @@ def init_postprocess_nifti_wf(
271278
]) # fmt:skip
272279

273280
if despike:
274-
despike_wf = init_despike_wf(TR=TR)
281+
despike_wf = init_despike_wf(TR=TR, mem_gb=mem_gbx)
275282

276283
workflow.connect([
277284
(prepare_confounds_wf, despike_wf, [

0 commit comments

Comments
 (0)