Source code for CPAC.alff.alff

# -*- coding: utf-8 -*-

import os
from CPAC.pipeline import nipype_pipeline_engine as pe
from CPAC.pipeline.nodeblock import nodeblock
from nipype.interfaces.afni import preprocess
import nipype.interfaces.utility as util
from CPAC.alff.utils import get_opt_string
from CPAC.utils.utils import check_prov_for_regtool
from CPAC.registration.registration import apply_transform


[docs]def create_alff(wf_name='alff_workflow'): """ Calculate Amplitude of low frequency oscillations (ALFF) and fractional ALFF maps Parameters ---------- wf_name : string Workflow name Returns ------- alff_workflow : workflow object ALFF workflow Notes ----- `Source <https://github.com/FCP-INDI/C-PAC/blob/master/CPAC/alff/alff.py>`_ Workflow Inputs:: hp_input.hp : list of float high pass frequencies lp_input.lp : list of float low pass frequencies inputspec.rest_res : string Path to existing Nifti file. Nuisance signal regressed functional image. inputspec.rest_mask : string Path to existing Nifti file. A mask volume(derived by dilating the motion corrected functional volume) in native space Workflow Outputs:: outputspec.alff_img : string Path to Nifti file. Image containing the sum of the amplitudes in the low frequency band outputspec.falff_img : string Path to Nifti file. Image containing the sum of the amplitudes in the low frequency band divided by the amplitude of the total frequency outputspec.alff_Z_img : string Path to Nifti file. Image containing Normalized ALFF Z scores across full brain in native space outputspec.falff_Z_img : string Path to Nifti file. Image containing Normalized fALFF Z scores across full brain in native space Order of Commands: - Filter the input file rest file( slice-time, motion corrected and nuisance regressed) :: 3dBandpass -prefix residual_filtered.nii.gz 0.009 0.08 residual.nii.gz - Calculate ALFF by taking the standard deviation of the filtered file :: 3dTstat -stdev -mask rest_mask.nii.gz -prefix residual_filtered_3dT.nii.gz residual_filtered.nii.gz - Calculate the standard deviation of the unfiltered file :: 3dTstat -stdev -mask rest_mask.nii.gz -prefix residual_3dT.nii.gz residual.nii.gz - Calculate fALFF :: 3dcalc -a rest_mask.nii.gz -b residual_filtered_3dT.nii.gz -c residual_3dT.nii.gz -expr '(1.0*bool(a))*((1.0*b)/(1.0*c))' -float - Normalize ALFF/fALFF to Z-score across full brain :: fslstats ALFF.nii.gz -k rest_mask.nii.gz -m > mean_ALFF.txt ; mean=$( cat mean_ALFF.txt ) fslstats ALFF.nii.gz -k rest_mask.nii.gz -s > std_ALFF.txt ; std=$( cat std_ALFF.txt ) fslmaths ALFF.nii.gz -sub ${mean} -div ${std} -mas rest_mask.nii.gz ALFF_Z.nii.gz fslstats fALFF.nii.gz -k rest_mask.nii.gz -m > mean_fALFF.txt ; mean=$( cat mean_fALFF.txt ) fslstats fALFF.nii.gz -k rest_mask.nii.gz -s > std_fALFF.txt std=$( cat std_fALFF.txt ) fslmaths fALFF.nii.gz -sub ${mean} -div ${std} -mas rest_mask.nii.gz fALFF_Z.nii.gz .. exec:: from CPAC.alff import create_alff wf = create_alff() wf.write_graph( graph2use='orig', dotfilename='./images/generated/alff.dot' ) High Level Workflow Graph: .. image:: ../../images/generated/alff.png :width: 500 Detailed Workflow Graph: .. image:: ../../images/generated/alff_detailed.png :width: 500 References ---------- .. [1] Zou, Q.-H., Zhu, C.-Z., Yang, Y., Zuo, X.-N., Long, X.-Y., Cao, Q.-J., Wang, Y.-F., et al. (2008). An improved approach to detection of amplitude of low-frequency fluctuation (ALFF) for resting-state fMRI: fractional ALFF. Journal of neuroscience methods, 172(1), 137-41. doi:10.10 Examples -------- >>> alff_w = create_alff() >>> alff_w.inputs.hp_input.hp = [0.01] >>> alff_w.inputs.lp_input.lp = [0.1] >>> alff_w.get_node('hp_input').iterables = ('hp', [0.01]) >>> alff_w.get_node('lp_input').iterables = ('lp', [0.1]) >>> alff_w.inputs.inputspec.rest_res = '/home/data/subject/func/rest_bandpassed.nii.gz' >>> alff_w.inputs.inputspec.rest_mask= '/home/data/subject/func/rest_mask.nii.gz' >>> alff_w.run() # doctest: +SKIP """ wf = pe.Workflow(name=wf_name) input_node = pe.Node(util.IdentityInterface(fields=['rest_res', 'rest_mask']), name='inputspec') input_node_hp = pe.Node(util.IdentityInterface(fields=['hp']), name='hp_input') input_node_lp = pe.Node(util.IdentityInterface(fields=['lp']), name='lp_input') output_node = pe.Node(util.IdentityInterface(fields=['alff_img', 'falff_img']), name='outputspec') # filtering bandpass = pe.Node(interface=preprocess.Bandpass(), name='bandpass_filtering') bandpass.inputs.outputtype = 'NIFTI_GZ' bandpass.inputs.out_file = os.path.join(os.path.curdir, 'residual_filtered.nii.gz') wf.connect(input_node_hp, 'hp', bandpass, 'highpass') wf.connect(input_node_lp, 'lp', bandpass, 'lowpass') wf.connect(input_node, 'rest_res', bandpass, 'in_file') get_option_string = pe.Node(util.Function(input_names=['mask'], output_names=['option_string'], function=get_opt_string), name='get_option_string') wf.connect(input_node, 'rest_mask', get_option_string, 'mask') # standard deviation over frequency try: from nipype.interfaces.afni import utils as afni_utils stddev_filtered = pe.Node(interface=afni_utils.TStat(), name='stddev_filtered') except ImportError: stddev_filtered = pe.Node(interface=preprocess.TStat(), name='stddev_filtered') stddev_filtered.inputs.outputtype = 'NIFTI_GZ' stddev_filtered.inputs.out_file = os.path.join(os.path.curdir, 'alff.nii.gz') wf.connect(bandpass, 'out_file', stddev_filtered, 'in_file') wf.connect(get_option_string, 'option_string', stddev_filtered, 'options') wf.connect(stddev_filtered, 'out_file', output_node, 'alff_img') # standard deviation of the unfiltered nuisance corrected image try: stddev_unfiltered = pe.Node(interface=afni_utils.TStat(), name='stddev_unfiltered') except UnboundLocalError: stddev_unfiltered = pe.Node(interface=preprocess.TStat(), name='stddev_unfiltered') stddev_unfiltered.inputs.outputtype = 'NIFTI_GZ' stddev_unfiltered.inputs.out_file = os.path.join(os.path.curdir, 'residual_3dT.nii.gz') wf.connect(input_node, 'rest_res', stddev_unfiltered, 'in_file') wf.connect(get_option_string, 'option_string', stddev_unfiltered, 'options') # falff calculations try: falff = pe.Node(interface=afni_utils.Calc(), name='falff') except UnboundLocalError: falff = pe.Node(interface=preprocess.Calc(), name='falff') falff.inputs.args = '-float' falff.inputs.expr = '(1.0*bool(a))*((1.0*b)/(1.0*c))' falff.inputs.outputtype = 'NIFTI_GZ' falff.inputs.out_file = os.path.join(os.path.curdir, 'falff.nii.gz') wf.connect(input_node, 'rest_mask', falff, 'in_file_a') wf.connect(stddev_filtered, 'out_file', falff, 'in_file_b') wf.connect(stddev_unfiltered, 'out_file', falff, 'in_file_c') wf.connect(falff, 'out_file', output_node, 'falff_img') return wf
[docs]@nodeblock( name="alff_falff", config=["amplitude_low_frequency_fluctuation"], switch=["run"], inputs=[ ( ["desc-denoisedNofilt_bold", "desc-preproc_bold"], "space-bold_desc-brain_mask", ) ], outputs=["alff", "falff"], ) def alff_falff(wf, cfg, strat_pool, pipe_num, opt=None): alff = create_alff(f'alff_falff_{pipe_num}') alff.inputs.hp_input.hp = \ cfg.amplitude_low_frequency_fluctuation['highpass_cutoff'] alff.inputs.lp_input.lp = \ cfg.amplitude_low_frequency_fluctuation['lowpass_cutoff'] alff.get_node('hp_input').iterables = ('hp', alff.inputs.hp_input.hp) alff.get_node('lp_input').iterables = ('lp', alff.inputs.lp_input.lp) node, out = strat_pool.get_data(["desc-denoisedNofilt_bold", "desc-preproc_bold"]) wf.connect(node, out, alff, 'inputspec.rest_res') node, out = strat_pool.get_data('space-bold_desc-brain_mask') wf.connect(node, out, alff, 'inputspec.rest_mask') outputs = { 'alff': (alff, 'outputspec.alff_img'), 'falff': (alff, 'outputspec.falff_img') } return (wf, outputs)
[docs]@nodeblock( name="alff_falff_space_template", config=["amplitude_low_frequency_fluctuation"], switch=["run"], inputs=[ ( [ "space-template_res-derivative_desc-denoisedNofilt_bold", "space-template_res-derivative_desc-preproc_bold", "space-template_desc-preproc_bold" ], [ "space-template_res-derivative_desc-bold_mask", "space-template_desc-bold_mask" ], "desc-denoisedNofilt_bold", "from-bold_to-template_mode-image_xfm", "T1w-brain-template-deriv", ) ], outputs=["space-template_alff", "space-template_falff", "space-template_res-derivative_desc-denoisedNofilt_bold"], ) def alff_falff_space_template(wf, cfg, strat_pool, pipe_num, opt=None): outputs = {} if strat_pool.check_rpool("desc-denoisedNofilt_bold"): xfm_prov = strat_pool.get_cpac_provenance( 'from-bold_to-template_mode-image_xfm') reg_tool = check_prov_for_regtool(xfm_prov) num_cpus = cfg.pipeline_setup['system_config'][ 'max_cores_per_participant'] num_ants_cores = cfg.pipeline_setup['system_config']['num_ants_threads'] apply_xfm = apply_transform(f'warp_denoisedNofilt_to_T1template_{pipe_num}', reg_tool, time_series=True, num_cpus=num_cpus, num_ants_cores=num_ants_cores) if reg_tool == 'ants': apply_xfm.inputs.inputspec.interpolation = cfg.registration_workflows[ 'functional_registration']['func_registration_to_template'][ 'ANTs_pipelines']['interpolation'] elif reg_tool == 'fsl': apply_xfm.inputs.inputspec.interpolation = cfg.registration_workflows[ 'functional_registration']['func_registration_to_template'][ 'FNIRT_pipelines']['interpolation'] node, out = strat_pool.get_data("desc-denoisedNofilt_bold") wf.connect(node, out, apply_xfm, 'inputspec.input_image') node, out = strat_pool.get_data("T1w-brain-template-deriv") wf.connect(node, out, apply_xfm, 'inputspec.reference') node, out = strat_pool.get_data("from-bold_to-template_mode-image_xfm") wf.connect(node, out, apply_xfm, 'inputspec.transform') outputs = { f'space-template_res-derivative_desc-denoisedNofilt_bold': (apply_xfm, 'outputspec.output_image') } alff = create_alff(f'alff_falff_{pipe_num}') alff.inputs.hp_input.hp = \ cfg.amplitude_low_frequency_fluctuation['highpass_cutoff'] alff.inputs.lp_input.lp = \ cfg.amplitude_low_frequency_fluctuation['lowpass_cutoff'] alff.get_node('hp_input').iterables = ('hp', alff.inputs.hp_input.hp) alff.get_node('lp_input').iterables = ('lp', alff.inputs.lp_input.lp) node, out = strat_pool.get_data(["space-template_res-derivative_desc-denoisedNofilt_bold", "space-template_res-derivative_desc-preproc_bold", "space-template_desc-preproc_bold"]) wf.connect(node, out, alff, 'inputspec.rest_res') node, out = strat_pool.get_data(["space-template_res-derivative_desc-bold_mask", "space-template_desc-bold_mask"]) wf.connect(node, out, alff, 'inputspec.rest_mask') outputs.update({ 'space-template_alff': (alff, 'outputspec.alff_img'), 'space-template_falff': (alff, 'outputspec.falff_img') }) return (wf, outputs)