Skip to content

Commit 4bb27d6

Browse files
authored
Merge pull request #1765 from FCP-INDI/template-space/reho-alff
Calculate ReHo and ALFF in template space
2 parents 356dc30 + 0e19056 commit 4bb27d6

File tree

9 files changed

+178
-20
lines changed

9 files changed

+178
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2121
- Added the ability to ingress TotalReadoutTime from epi field map meta-data from the JSON sidecars.
2222
- Added the ability to use TotalReadoutTime of epi field maps in the calculation of FSL topup distortion correction.
2323
- Difference method (``-``) for ``CPAC.utils.configuration.Configuration`` instances
24+
- Calculate reho and alff when timeseries in template space
2425

2526
### Changed
2627
- Added a level of depth to `working` directories to match `log` and `output` directory structure

CPAC/alff/alff.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ def alff_falff(wf, cfg, strat_pool, pipe_num, opt=None):
246246
"switch": ["run"],
247247
"option_key": "None",
248248
"option_val": "None",
249-
"inputs": [["desc-cleanedNofilt_bold", "desc-brain_bold",
249+
"inputs": [["desc-denoisedNofilt_bold", "desc-brain_bold",
250250
"desc-preproc_bold", "bold"],
251251
"space-bold_desc-brain_mask"],
252252
"outputs": ["alff",
@@ -262,7 +262,7 @@ def alff_falff(wf, cfg, strat_pool, pipe_num, opt=None):
262262
alff.get_node('hp_input').iterables = ('hp', alff.inputs.hp_input.hp)
263263
alff.get_node('lp_input').iterables = ('lp', alff.inputs.lp_input.lp)
264264

265-
node, out = strat_pool.get_data(["desc-cleanedNofilt_bold", "desc-brain_bold",
265+
node, out = strat_pool.get_data(["desc-denoisedNofilt_bold", "desc-brain_bold",
266266
"desc-preproc_bold", "bold"])
267267
wf.connect(node, out, alff, 'inputspec.rest_res')
268268

@@ -275,3 +275,38 @@ def alff_falff(wf, cfg, strat_pool, pipe_num, opt=None):
275275
}
276276

277277
return (wf, outputs)
278+
279+
def alff_falff_space_template(wf, cfg, strat_pool, pipe_num, opt=None):
280+
'''
281+
{"name": "alff_falff_space_template",
282+
"config": ["amplitude_low_frequency_fluctuation"],
283+
"switch": ["run"],
284+
"option_key": "None",
285+
"option_val": "None",
286+
"inputs": [["space-template_desc-denoisedNofilt_bold"],
287+
"space-template_desc-bold_mask"],
288+
"outputs": ["space-template_alff",
289+
"space-template_falff"]}
290+
'''
291+
292+
alff = create_alff(f'alff_falff_{pipe_num}')
293+
294+
alff.inputs.hp_input.hp = \
295+
cfg.amplitude_low_frequency_fluctuation['highpass_cutoff']
296+
alff.inputs.lp_input.lp = \
297+
cfg.amplitude_low_frequency_fluctuation['lowpass_cutoff']
298+
alff.get_node('hp_input').iterables = ('hp', alff.inputs.hp_input.hp)
299+
alff.get_node('lp_input').iterables = ('lp', alff.inputs.lp_input.lp)
300+
301+
node, out = strat_pool.get_data(["space-template_desc-denoisedNofilt_bold"])
302+
wf.connect(node, out, alff, 'inputspec.rest_res')
303+
304+
node, out = strat_pool.get_data("space-template_desc-bold_mask")
305+
wf.connect(node, out, alff, 'inputspec.rest_mask')
306+
307+
outputs = {
308+
'space-template_alff': (alff, 'outputspec.alff_img'),
309+
'space-template_falff': (alff, 'outputspec.falff_img')
310+
}
311+
312+
return (wf, outputs)

CPAC/nuisance/nuisance.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,7 +2532,6 @@ def nuisance_regression(wf, cfg, strat_pool, pipe_num, opt, space):
25322532
outputs = {
25332533
desc_keys[0]: (nuis, 'outputspec.residual_file_path'),
25342534
desc_keys[1]: (nuis, 'outputspec.residual_file_path'),
2535-
desc_keys[2]: (nuis, 'outputspec.residual_file_path')
25362535
}
25372536

25382537
return (wf, outputs)
@@ -2587,13 +2586,10 @@ def nuisance_regression_template(wf, cfg, strat_pool, pipe_num, opt=None):
25872586
"dvars"),
25882587
"TR"],
25892588
"outputs": {"space-template_desc-preproc_bold": {
2590-
"Description": "Preprocessed BOLD image that was nuisance-"
2589+
"Description": "Preprocessed BOLD image that was nusiance-"
25912590
"regressed in template space"},
25922591
"space-template_desc-cleaned_bold": {
2593-
"Description": "Preprocessed BOLD image that was nuisance-"
2594-
"regressed in template space"},
2595-
"space-template_desc-denoisedNofilt_bold": {
2596-
"Description": "Preprocessed BOLD image that was nuisance-"
2592+
"Description": "Preprocessed BOLD image that was nusiance-"
25972593
"regressed in template space"},
25982594
"regressors": {
25992595
"Description": "Regressors that were applied in template space"}}}

CPAC/pipeline/cpac_pipeline.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
warp_bold_mean_to_T1template,
103103
warp_bold_mask_to_T1template,
104104
warp_deriv_mask_to_T1template,
105+
warp_denoiseNofilt_to_T1template,
105106
warp_timeseries_to_EPItemplate,
106107
warp_bold_mean_to_EPItemplate,
107108
warp_bold_mask_to_EPItemplate,
@@ -183,8 +184,8 @@
183184
multiple_regression
184185
)
185186

186-
from CPAC.alff.alff import alff_falff
187-
from CPAC.reho.reho import reho
187+
from CPAC.alff.alff import alff_falff, alff_falff_space_template
188+
from CPAC.reho.reho import reho, reho_space_template
188189

189190
from CPAC.vmhc.vmhc import (
190191
smooth_func_vmhc,
@@ -1282,6 +1283,10 @@ def build_workflow(subject_id, sub_dict, cfg, pipeline_name=None,
12821283
if not rpool.check_rpool('space-template_desc-bold_mask'):
12831284
pipeline_blocks += [warp_bold_mask_to_T1template,
12841285
warp_deriv_mask_to_T1template]
1286+
1287+
target_space_alff = cfg.amplitude_low_frequency_fluctuation['target_space']
1288+
if 'Template' in target_space_alff and not rpool.check_rpool('space-template_desc-denoisedNofilt_bold'):
1289+
pipeline_blocks += [warp_denoiseNofilt_to_T1template]
12851290

12861291
template = cfg.registration_workflows['functional_registration']['func_registration_to_template']['target_template']['using']
12871292

@@ -1324,6 +1329,7 @@ def build_workflow(subject_id, sub_dict, cfg, pipeline_name=None,
13241329
tse_atlases, sca_atlases = gather_extraction_maps(cfg)
13251330
cfg.timeseries_extraction['tse_atlases'] = tse_atlases
13261331
cfg.seed_based_correlation_analysis['sca_atlases'] = sca_atlases
1332+
target_space_reho = cfg.regional_homogeneity['target_space']
13271333

13281334
if not rpool.check_rpool('desc-Mean_timeseries') and \
13291335
'Avg' in tse_atlases:
@@ -1349,11 +1355,21 @@ def build_workflow(subject_id, sub_dict, cfg, pipeline_name=None,
13491355
'MultReg' in sca_atlases:
13501356
pipeline_blocks += [multiple_regression]
13511357

1352-
if not rpool.check_rpool('alff'):
1353-
pipeline_blocks += [alff_falff]
1354-
1355-
if not rpool.check_rpool('reho'):
1356-
pipeline_blocks += [reho]
1358+
if 'Native' in target_space_alff:
1359+
if not rpool.check_rpool('alff'):
1360+
pipeline_blocks += [alff_falff]
1361+
1362+
if 'Template' in target_space_alff:
1363+
if not rpool.check_rpool('space-template_alff'):
1364+
pipeline_blocks += [alff_falff_space_template]
1365+
1366+
if 'Native' in target_space_reho:
1367+
if not rpool.check_rpool('reho'):
1368+
pipeline_blocks += [reho]
1369+
1370+
if 'Template' in target_space_reho:
1371+
if not rpool.check_rpool('space-template_reho'):
1372+
pipeline_blocks += [reho_space_template]
13571373

13581374
if not rpool.check_rpool('vmhc'):
13591375
pipeline_blocks += [smooth_func_vmhc,

CPAC/pipeline/engine.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,10 @@ def __init__(self, rpool=None, name=None, cfg=None, pipe_list=None):
8888

8989
self.run_smoothing = 'smoothed' in cfg.post_processing[
9090
'spatial_smoothing']['output']
91+
self.smoothing_bool = cfg.post_processing['spatial_smoothing']['run']
9192
self.run_zscoring = 'z-scored' in cfg.post_processing[
9293
'z-scoring']['output']
94+
self.zscoring_bool = cfg.post_processing['z-scoring']['run']
9395
self.fwhm = cfg.post_processing['spatial_smoothing']['fwhm']
9496
self.smooth_opts = cfg.post_processing['spatial_smoothing'][
9597
'smoothing_method']
@@ -697,7 +699,7 @@ def post_process(self, wf, label, connection, json_info, pipe_idx, pipe_x,
697699
mask_idx = self.generate_prov_string(mask_prov)[1]
698700
break
699701

700-
if self.run_smoothing:
702+
if self.smoothing_bool:
701703
if label in Outputs.to_smooth:
702704
for smooth_opt in self.smooth_opts:
703705

@@ -736,7 +738,7 @@ def post_process(self, wf, label, connection, json_info, pipe_idx, pipe_x,
736738
pipe_idx, f'spatial_smoothing_{smooth_opt}',
737739
fork=True)
738740

739-
if self.run_zscoring:
741+
if self.zscoring_bool:
740742
for label_con_tpl in post_labels:
741743
label = label_con_tpl[0]
742744
connection = (label_con_tpl[1], label_con_tpl[2])

CPAC/pipeline/schema.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@
9696
str, {'components': int, 'method': str}
9797
),
9898
},
99-
}
99+
},
100+
'target_space': ['Native', 'Template']
100101
}
101102
mutex = { # mutually exclusive booleans
102103
'FSL-BET': {
@@ -823,6 +824,7 @@ def sanitize(filename):
823824
},
824825
'amplitude_low_frequency_fluctuation': {
825826
'run': bool,
827+
'target_space': [In(valid_options['target_space'])],
826828
'highpass_cutoff': [float],
827829
'lowpass_cutoff': [float],
828830
},
@@ -839,15 +841,18 @@ def sanitize(filename):
839841
},
840842
'regional_homogeneity': {
841843
'run': bool,
844+
'target_space': [In(valid_options['target_space'])],
842845
'cluster_size': In({7, 19, 27}),
843846
},
844847
'post_processing': {
845848
'spatial_smoothing': {
849+
'run': bool,
846850
'output': [In({'smoothed', 'nonsmoothed'})],
847851
'smoothing_method': [In({'FSL', 'AFNI'})],
848852
'fwhm': [int]
849853
},
850854
'z-scoring': {
855+
'run': bool,
851856
'output': [In({'z-scored', 'raw'})],
852857
},
853858
},

CPAC/registration/registration.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3662,10 +3662,63 @@ def warp_timeseries_to_T1template_dcan_nhp(wf, cfg, strat_pool, pipe_num, opt=No
36623662

36633663
return (wf, outputs)
36643664

3665+
def warp_denoiseNofilt_to_T1template(wf, cfg, strat_pool, pipe_num, opt=None):
3666+
'''
3667+
Node Block:
3668+
{"name": "transform_denoisedNofilt_to_T1template",
3669+
"config": ["amplitude_low_frequency_fluctuation"],
3670+
"switch": ["run"],
3671+
"option_key": ["target_space"],
3672+
"option_val": "Template",
3673+
"inputs": [(["desc-denoisedNofilt_bold"],
3674+
"from-bold_to-template_mode-image_xfm"),
3675+
"T1w-brain-template-funcreg"],
3676+
"outputs": ["space-template_desc-denoisedNofilt_bold"]}
3677+
'''
3678+
3679+
xfm_prov = strat_pool.get_cpac_provenance(
3680+
'from-bold_to-template_mode-image_xfm')
3681+
reg_tool = check_prov_for_regtool(xfm_prov)
3682+
3683+
num_cpus = cfg.pipeline_setup['system_config'][
3684+
'max_cores_per_participant']
3685+
3686+
num_ants_cores = cfg.pipeline_setup['system_config']['num_ants_threads']
3687+
3688+
apply_xfm = apply_transform(f'warp_denoisedNofilt_to_T1template_{pipe_num}', reg_tool,
3689+
time_series=True, num_cpus=num_cpus,
3690+
num_ants_cores=num_ants_cores)
3691+
3692+
if reg_tool == 'ants':
3693+
apply_xfm.inputs.inputspec.interpolation = cfg.registration_workflows[
3694+
'functional_registration']['func_registration_to_template'][
3695+
'ANTs_pipelines']['interpolation']
3696+
elif reg_tool == 'fsl':
3697+
apply_xfm.inputs.inputspec.interpolation = cfg.registration_workflows[
3698+
'functional_registration']['func_registration_to_template'][
3699+
'FNIRT_pipelines']['interpolation']
3700+
3701+
connect, resource = strat_pool.get_data(["desc-denoisedNofilt_bold"],
3702+
report_fetched=True)
3703+
node, out = connect
3704+
wf.connect(node, out, apply_xfm, 'inputspec.input_image')
3705+
3706+
node, out = strat_pool.get_data("T1w-brain-template-funcreg")
3707+
wf.connect(node, out, apply_xfm, 'inputspec.reference')
3708+
3709+
node, out = strat_pool.get_data("from-bold_to-template_mode-image_xfm")
3710+
wf.connect(node, out, apply_xfm, 'inputspec.transform')
3711+
3712+
outputs = {
3713+
f'space-template_{resource}': (apply_xfm, 'outputspec.output_image')
3714+
}
3715+
3716+
return (wf, outputs)
3717+
36653718

36663719
def single_step_resample_timeseries_to_T1template(wf, cfg, strat_pool,
36673720
pipe_num, opt=None):
3668-
"""
3721+
'''
36693722
Apply motion correction, coreg, anat-to-template transforms on
36703723
slice-time corrected functional timeseries based on fMRIPrep
36713724
pipeline
@@ -3724,7 +3777,7 @@ def single_step_resample_timeseries_to_T1template(wf, cfg, strat_pool,
37243777
"outputs": ["space-template_desc-preproc_bold",
37253778
"space-template_desc-brain_bold",
37263779
"space-template_desc-bold_mask"]}
3727-
""" # noqa: 501
3780+
''' # noqa: 501
37283781
bbr2itk = pe.Node(util.Function(input_names=['reference_file',
37293782
'source_file',
37303783
'transform_file'],

CPAC/reho/reho.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,43 @@ def reho(wf, cfg, strat_pool, pipe_num, opt=None):
149149
}
150150

151151
return (wf, outputs)
152+
153+
154+
def reho_space_template(wf, cfg, strat_pool, pipe_num, opt=None):
155+
'''
156+
{"name": "ReHo_space_template",
157+
"config": ["regional_homogeneity"],
158+
"switch": ["run"],
159+
"option_key": "None",
160+
"option_val": "None",
161+
"inputs": [["space-template_desc-cleaned_bold", "space-template_desc-brain_bold",
162+
"space-template_desc-preproc_bold", "space-template_bold"],
163+
"space-template_desc-bold_mask"],
164+
"outputs": ["space-template_reho"]}
165+
'''
166+
167+
cluster_size = cfg.regional_homogeneity['cluster_size']
168+
169+
# Check the cluster size is supported
170+
if cluster_size not in [7, 19, 27]:
171+
err_msg = 'Cluster size specified: %d, is not ' \
172+
'supported. Change to 7, 19, or 27 and try ' \
173+
'again' % cluster_size
174+
raise Exception(err_msg)
175+
176+
reho = create_reho(f'reho_{pipe_num}')
177+
reho.inputs.inputspec.cluster_size = cluster_size
178+
179+
180+
node, out = strat_pool.get_data(["space-template_desc-cleaned_bold", "space-template_desc-brain_bold",
181+
"space-template_desc-preproc_bold", "space-template_bold"])
182+
wf.connect(node, out, reho, 'inputspec.rest_res_filt')
183+
184+
node, out_file = strat_pool.get_data('space-template_desc-bold_mask')
185+
wf.connect(node, out_file, reho, 'inputspec.rest_mask')
186+
187+
outputs = {
188+
'space-template_reho': (reho, 'outputspec.raw_reho_map')
189+
}
190+
191+
return (wf, outputs)

CPAC/resources/configs/pipeline_config_default.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,8 @@ post_processing:
14721472

14731473
spatial_smoothing:
14741474

1475+
run: On
1476+
14751477
# Smooth the derivative outputs.
14761478
# Set as ['nonsmoothed'] to disable smoothing. Set as ['smoothed', 'nonsmoothed'] to get both.
14771479
#
@@ -1491,6 +1493,8 @@ post_processing:
14911493

14921494
z-scoring:
14931495

1496+
run: On
1497+
14941498
# z-score standardize the derivatives. This may be needed for group-level analysis.
14951499
# Set as ['raw'] to disable z-scoring. Set as ['z-scored', 'raw'] to get both.
14961500
#
@@ -1593,6 +1597,9 @@ amplitude_low_frequency_fluctuation:
15931597
# Calculate Amplitude of Low Frequency Fluctuations (ALFF) and fractional ALFF (f/ALFF) for all voxels.
15941598
run: On
15951599

1600+
# space: Template or Native
1601+
target_space: ['Native']
1602+
15961603
# Frequency cutoff (in Hz) for the high-pass filter used when calculating f/ALFF.
15971604
highpass_cutoff: [0.01]
15981605

@@ -1606,6 +1613,9 @@ regional_homogeneity:
16061613
# Calculate Regional Homogeneity (ReHo) for all voxels.
16071614
run: On
16081615

1616+
# space: Template or Native
1617+
target_space: ['Native']
1618+
16091619
# Number of neighboring voxels used when calculating ReHo
16101620
# 7 (Faces)
16111621
# 19 (Faces + Edges)

0 commit comments

Comments
 (0)