def init_topup_wf(omp_nthreads=1, debug=False, name="pepolar_estimate_wf"): """ Create the PEPOLAR field estimation workflow based on FSL's ``topup``. Workflow Graph .. workflow :: :graph2use: orig :simple_form: yes from sdcflows.workflows.fit.pepolar import init_topup_wf wf = init_topup_wf() Parameters ---------- debug : :obj:`bool` Whether a fast configuration of topup (less accurate) should be applied. name : :obj:`str` Name for this workflow omp_nthreads : :obj:`int` Parallelize internal tasks across the number of CPUs given by this option. Inputs ------ in_data : :obj:`list` of :obj:`str` A list of EPI files that will be fed into TOPUP. metadata : :obj:`list` of :obj:`dict` A list of dictionaries containing the metadata corresponding to each file in ``in_data``. Outputs ------- fmap : :obj:`str` The path of the estimated fieldmap. fmap_ref : :obj:`str` The path of an unwarped conversion of files in ``in_data``. fmap_mask : :obj:`str` The path of mask corresponding to the ``fmap_ref`` output. fmap_coeff : :obj:`str` or :obj:`list` of :obj:`str` The path(s) of the B-Spline coefficients supporting the fieldmap. """ from nipype.interfaces.fsl.epi import TOPUP from niworkflows.interfaces.nibabel import MergeSeries from niworkflows.interfaces.images import IntraModalMerge from ...interfaces.epi import GetReadoutTime from ...interfaces.utils import Flatten from ...interfaces.bspline import TOPUPCoeffReorient from ..ancillary import init_brainextraction_wf workflow = Workflow(name=name) workflow.__postdesc__ = f"""\ {_PEPOLAR_DESC} with `topup` (@topup; FSL {TOPUP().version}). """ inputnode = pe.Node(niu.IdentityInterface(fields=INPUT_FIELDS), name="inputnode") outputnode = pe.Node( niu.IdentityInterface(fields=[ "fmap", "fmap_ref", "fmap_coeff", "fmap_mask", "jacobians", "xfms", "out_warps", ]), name="outputnode", ) flatten = pe.Node(Flatten(), name="flatten") concat_blips = pe.Node(MergeSeries(), name="concat_blips") readout_time = pe.MapNode( GetReadoutTime(), name="readout_time", iterfield=["metadata", "in_file"], run_without_submitting=True, ) topup = pe.Node( TOPUP(config=_pkg_fname("sdcflows", f"data/flirtsch/b02b0{'_quick' * debug}.cnf")), name="topup", ) merge_corrected = pe.Node(IntraModalMerge(hmc=False, to_ras=False), name="merge_corrected") fix_coeff = pe.Node(TOPUPCoeffReorient(), name="fix_coeff", run_without_submitting=True) brainextraction_wf = init_brainextraction_wf() # fmt: off workflow.connect([ (inputnode, flatten, [("in_data", "in_data"), ("metadata", "in_meta")]), (flatten, readout_time, [("out_data", "in_file"), ("out_meta", "metadata")]), (flatten, concat_blips, [("out_data", "in_files")]), (flatten, topup, [(("out_meta", _pe2fsl), "encoding_direction")]), (readout_time, topup, [("readout_time", "readout_times")]), (concat_blips, topup, [("out_file", "in_file")]), (topup, merge_corrected, [("out_corrected", "in_files")]), (topup, fix_coeff, [("out_fieldcoef", "in_coeff"), ("out_corrected", "fmap_ref")]), (topup, outputnode, [("out_field", "fmap"), ("out_jacs", "jacobians"), ("out_mats", "xfms"), ("out_warps", "out_warps")]), (merge_corrected, brainextraction_wf, [("out_avg", "inputnode.in_file") ]), (merge_corrected, outputnode, [("out_avg", "fmap_ref")]), (brainextraction_wf, outputnode, [("outputnode.out_mask", "fmap_mask") ]), (fix_coeff, outputnode, [("out_coeff", "fmap_coeff")]), ]) # fmt: on return workflow
def init_fmap_wf(omp_nthreads, fmap_bspline, name='fmap_wf'): """ Fieldmap workflow - when we have a sequence that directly measures the fieldmap we just need to mask it (using the corresponding magnitude image) to remove the noise in the surrounding air region, and ensure that units are Hz. .. workflow :: :graph2use: orig :simple_form: yes from fmriprep.workflows.fieldmap.fmap import init_fmap_wf wf = init_fmap_wf(omp_nthreads=6, fmap_bspline=False) """ workflow = Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=['magnitude', 'fieldmap']), name='inputnode') outputnode = pe.Node( niu.IdentityInterface(fields=['fmap', 'fmap_ref', 'fmap_mask']), name='outputnode') # Merge input magnitude images magmrg = pe.Node(IntraModalMerge(), name='magmrg') # Merge input fieldmap images fmapmrg = pe.Node(IntraModalMerge(zero_based_avg=False, hmc=False), name='fmapmrg') # de-gradient the fields ("bias/illumination artifact") n4_correct = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True), name='n4_correct', n_procs=omp_nthreads) bet = pe.Node(BETRPT(generate_report=True, frac=0.6, mask=True), name='bet') ds_fmap_mask = pe.Node(DerivativesDataSink(suffix='fmap_mask'), name='ds_report_fmap_mask', run_without_submitting=True) workflow.connect([ (inputnode, magmrg, [('magnitude', 'in_files')]), (inputnode, fmapmrg, [('fieldmap', 'in_files')]), (magmrg, n4_correct, [('out_file', 'input_image')]), (n4_correct, bet, [('output_image', 'in_file')]), (bet, outputnode, [('mask_file', 'fmap_mask'), ('out_file', 'fmap_ref')]), (inputnode, ds_fmap_mask, [('fieldmap', 'source_file')]), (bet, ds_fmap_mask, [('out_report', 'in_file')]), ]) if fmap_bspline: # despike_threshold=1.0, mask_erode=1), fmapenh = pe.Node(FieldEnhance(unwrap=False, despike=False), name='fmapenh', mem_gb=4, n_procs=omp_nthreads) workflow.connect([ (bet, fmapenh, [('mask_file', 'in_mask'), ('out_file', 'in_magnitude')]), (fmapmrg, fmapenh, [('out_file', 'in_file')]), (fmapenh, outputnode, [('out_file', 'fmap')]), ]) else: torads = pe.Node(FieldToRadS(), name='torads') prelude = pe.Node(fsl.PRELUDE(), name='prelude') tohz = pe.Node(FieldToHz(), name='tohz') denoise = pe.Node(fsl.SpatialFilter(operation='median', kernel_shape='sphere', kernel_size=3), name='denoise') demean = pe.Node(niu.Function(function=demean_image), name='demean') cleanup_wf = cleanup_edge_pipeline(name='cleanup_wf') applymsk = pe.Node(fsl.ApplyMask(), name='applymsk') workflow.connect([ (bet, prelude, [('mask_file', 'mask_file'), ('out_file', 'magnitude_file')]), (fmapmrg, torads, [('out_file', 'in_file')]), (torads, tohz, [('fmap_range', 'range_hz')]), (torads, prelude, [('out_file', 'phase_file')]), (prelude, tohz, [('unwrapped_phase_file', 'in_file')]), (tohz, denoise, [('out_file', 'in_file')]), (denoise, demean, [('out_file', 'in_file')]), (demean, cleanup_wf, [('out', 'inputnode.in_file')]), (bet, cleanup_wf, [('mask_file', 'inputnode.in_mask')]), (cleanup_wf, applymsk, [('outputnode.out_file', 'in_file')]), (bet, applymsk, [('mask_file', 'mask_file')]), (applymsk, outputnode, [('out_file', 'fmap')]), ]) return workflow
def init_phdiff_wf(omp_nthreads, phasetype='phasediff', name='phdiff_wf'): """ Estimates the fieldmap using a phase-difference image and one or more magnitude images corresponding to two or more :abbr:`GRE (Gradient Echo sequence)` acquisitions. The `original code was taken from nipype <https://github.com/nipy/nipype/blob/master/nipype/workflows/dmri/fsl/artifacts.py#L514>`_. .. workflow :: :graph2use: orig :simple_form: yes from fmriprep.workflows.fieldmap.phdiff import init_phdiff_wf wf = init_phdiff_wf(omp_nthreads=1) Outputs:: outputnode.fmap_ref - The average magnitude image, skull-stripped outputnode.fmap_mask - The brain mask applied to the fieldmap outputnode.fmap - The estimated fieldmap in Hz """ workflow = Workflow(name=name) workflow.__desc__ = """\ A deformation field to correct for susceptibility distortions was estimated based on a field map that was co-registered to the BOLD reference, using a custom workflow of *fMRIPrep* derived from D. Greve's `epidewarp.fsl` [script](http://www.nmr.mgh.harvard.edu/~greve/fbirn/b0/epidewarp.fsl) and further improvements of HCP Pipelines [@hcppipelines]. """ inputnode = pe.Node( niu.IdentityInterface(fields=['magnitude', 'phasediff']), name='inputnode') outputnode = pe.Node( niu.IdentityInterface(fields=['fmap', 'fmap_ref', 'fmap_mask']), name='outputnode') def _pick1st(inlist): return inlist[0] # Read phasediff echo times meta = pe.Node(ReadSidecarJSON(), name='meta', mem_gb=0.01, run_without_submitting=True) # Merge input magnitude images magmrg = pe.Node(IntraModalMerge(), name='magmrg') # de-gradient the fields ("bias/illumination artifact") n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True), name='n4', n_procs=omp_nthreads) bet = pe.Node(BETRPT(generate_report=True, frac=0.6, mask=True), name='bet') ds_report_fmap_mask = pe.Node(DerivativesDataSink(desc='brain', suffix='mask'), name='ds_report_fmap_mask', mem_gb=0.01, run_without_submitting=True) # uses mask from bet; outputs a mask # dilate = pe.Node(fsl.maths.MathsCommand( # nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate') # phase diff -> radians pha2rads = pe.Node(niu.Function(function=siemens2rads), name='pha2rads') # FSL PRELUDE will perform phase-unwrapping prelude = pe.Node(fsl.PRELUDE(), name='prelude') denoise = pe.Node(fsl.SpatialFilter(operation='median', kernel_shape='sphere', kernel_size=5), name='denoise') demean = pe.Node(niu.Function(function=demean_image), name='demean') cleanup_wf = cleanup_edge_pipeline(name="cleanup_wf") compfmap = pe.Node(Phasediff2Fieldmap(), name='compfmap') # The phdiff2fmap interface is equivalent to: # rad2rsec (using rads2radsec from nipype.workflows.dmri.fsl.utils) # pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='ComputeFieldmapFUGUE') # rsec2hz (divide by 2pi) if phasetype == "phasediff": # Read phasediff echo times meta = pe.Node(ReadSidecarJSON(), name='meta', mem_gb=0.01) # phase diff -> radians pha2rads = pe.Node(niu.Function(function=siemens2rads), name='pha2rads') # Read phasediff echo times meta = pe.Node(ReadSidecarJSON(), name='meta', mem_gb=0.01, run_without_submitting=True) workflow.connect([ (meta, compfmap, [('out_dict', 'metadata')]), (inputnode, pha2rads, [('phasediff', 'in_file')]), (pha2rads, prelude, [('out', 'phase_file')]), (inputnode, ds_report_fmap_mask, [('phasediff', 'source_file')]), ]) elif phasetype == "phase": workflow.__desc__ += """\ The phase difference used for unwarping was calculated using two separate phase measurements [@pncprocessing]. """ # Special case for phase1, phase2 images meta = pe.MapNode(ReadSidecarJSON(), name='meta', mem_gb=0.01, run_without_submitting=True, iterfield=['in_file']) phases2fmap = pe.Node(Phases2Fieldmap(), name='phases2fmap') workflow.connect([ (meta, phases2fmap, [('out_dict', 'metadatas')]), (inputnode, phases2fmap, [('phasediff', 'phase_files')]), (phases2fmap, prelude, [('out_file', 'phase_file')]), (phases2fmap, compfmap, [('phasediff_metadata', 'metadata')]), (phases2fmap, ds_report_fmap_mask, [('out_file', 'source_file')]) ]) workflow.connect([ (inputnode, meta, [('phasediff', 'in_file')]), (inputnode, magmrg, [('magnitude', 'in_files')]), (magmrg, n4, [('out_avg', 'input_image')]), (n4, prelude, [('output_image', 'magnitude_file')]), (n4, bet, [('output_image', 'in_file')]), (bet, prelude, [('mask_file', 'mask_file')]), (prelude, denoise, [('unwrapped_phase_file', 'in_file')]), (denoise, demean, [('out_file', 'in_file')]), (demean, cleanup_wf, [('out', 'inputnode.in_file')]), (bet, cleanup_wf, [('mask_file', 'inputnode.in_mask')]), (cleanup_wf, compfmap, [('outputnode.out_file', 'in_file')]), (compfmap, outputnode, [('out_file', 'fmap')]), (bet, outputnode, [('mask_file', 'fmap_mask'), ('out_file', 'fmap_ref')]), (bet, ds_report_fmap_mask, [('out_report', 'in_file')]), ]) return workflow
def init_magnitude_wf(omp_nthreads, name='magnitude_wf'): """ Prepare the magnitude part of :abbr:`GRE (gradient-recalled echo)` fieldmaps. Average (if not done already) the magnitude part of the :abbr:`GRE (gradient recalled echo)` images, run N4 to correct for B1 field nonuniformity, and skull-strip the preprocessed magnitude. Workflow Graph .. workflow :: :graph2use: orig :simple_form: yes from sdcflows.workflows.fmap import init_magnitude_wf wf = init_magnitude_wf(omp_nthreads=6) Parameters ---------- omp_nthreads : int Maximum number of threads an individual process may use name : str Name of workflow (default: ``prepare_magnitude_w``) Inputs ------ magnitude : pathlike Path to the corresponding magnitude path(s). Outputs ------- fmap_ref : pathlike Path to the fieldmap reference calculated in this workflow. fmap_mask : pathlike Path to a binary brain mask corresponding to the reference above. """ workflow = Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=['magnitude']), name='inputnode') outputnode = pe.Node( niu.IdentityInterface(fields=['fmap_ref', 'fmap_mask', 'mask_report']), name='outputnode') # Merge input magnitude images magmrg = pe.Node(IntraModalMerge(hmc=False), name='magmrg') # de-gradient the fields ("bias/illumination artifact") n4_correct = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True), name='n4_correct', n_procs=omp_nthreads) bet = pe.Node(BETRPT(generate_report=True, frac=0.6, mask=True), name='bet') workflow.connect([ (inputnode, magmrg, [('magnitude', 'in_files')]), (magmrg, n4_correct, [('out_avg', 'input_image')]), (n4_correct, bet, [('output_image', 'in_file')]), (bet, outputnode, [('mask_file', 'fmap_mask'), ('out_file', 'fmap_ref'), ('out_report', 'mask_report')]), ]) return workflow
def init_phdiff_wf(omp_nthreads, name='phdiff_wf'): """ Distortion correction of EPI sequences using phase-difference maps. Estimates the fieldmap using a phase-difference image and one or more magnitude images corresponding to two or more :abbr:`GRE (Gradient Echo sequence)` acquisitions. The `original code was taken from nipype <https://github.com/nipy/nipype/blob/master/nipype/workflows/dmri/fsl/artifacts.py#L514>`_. .. workflow :: :graph2use: orig :simple_form: yes from sdcflows.workflows.phdiff import init_phdiff_wf wf = init_phdiff_wf(omp_nthreads=1) **Parameters**: omp_nthreads : int Maximum number of threads an individual process may use **Inputs**: magnitude : pathlike Path to the corresponding magnitude path(s). phasediff : pathlike Path to the corresponding phase-difference file. metadata : dict Metadata dictionary corresponding to the phasediff input **Outputs**: fmap_ref : pathlike The average magnitude image, skull-stripped fmap_mask : pathlike The brain mask applied to the fieldmap fmap : pathlike The estimated fieldmap in Hz """ workflow = Workflow(name=name) workflow.__desc__ = """\ A deformation field to correct for susceptibility distortions was estimated based on a field map that was co-registered to the BOLD reference, using a custom workflow of *fMRIPrep* derived from D. Greve's `epidewarp.fsl` [script](http://www.nmr.mgh.harvard.edu/~greve/fbirn/b0/epidewarp.fsl) and further improvements of HCP Pipelines [@hcppipelines]. """ inputnode = pe.Node( niu.IdentityInterface(fields=['magnitude', 'phasediff', 'metadata']), name='inputnode') outputnode = pe.Node( niu.IdentityInterface(fields=['fmap', 'fmap_ref', 'fmap_mask']), name='outputnode') # Merge input magnitude images magmrg = pe.Node(IntraModalMerge(), name='magmrg') # de-gradient the fields ("bias/illumination artifact") n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True), name='n4', n_procs=omp_nthreads) bet = pe.Node(BETRPT(generate_report=True, frac=0.6, mask=True), name='bet') # uses mask from bet; outputs a mask # dilate = pe.Node(fsl.maths.MathsCommand( # nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate') # phase diff -> radians pha2rads = pe.Node(niu.Function(function=siemens2rads), name='pha2rads') # FSL PRELUDE will perform phase-unwrapping prelude = pe.Node(fsl.PRELUDE(), name='prelude') denoise = pe.Node(fsl.SpatialFilter(operation='median', kernel_shape='sphere', kernel_size=3), name='denoise') demean = pe.Node(niu.Function(function=demean_image), name='demean') cleanup_wf = cleanup_edge_pipeline(name="cleanup_wf") compfmap = pe.Node(Phasediff2Fieldmap(), name='compfmap') # The phdiff2fmap interface is equivalent to: # rad2rsec (using rads2radsec from nipype.workflows.dmri.fsl.utils) # pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='ComputeFieldmapFUGUE') # rsec2hz (divide by 2pi) workflow.connect([ (inputnode, compfmap, [('metadata', 'metadata')]), (inputnode, magmrg, [('magnitude', 'in_files')]), (magmrg, n4, [('out_avg', 'input_image')]), (n4, prelude, [('output_image', 'magnitude_file')]), (n4, bet, [('output_image', 'in_file')]), (bet, prelude, [('mask_file', 'mask_file')]), (inputnode, pha2rads, [('phasediff', 'in_file')]), (pha2rads, prelude, [('out', 'phase_file')]), (prelude, denoise, [('unwrapped_phase_file', 'in_file')]), (denoise, demean, [('out_file', 'in_file')]), (demean, cleanup_wf, [('out', 'inputnode.in_file')]), (bet, cleanup_wf, [('mask_file', 'inputnode.in_mask')]), (cleanup_wf, compfmap, [('outputnode.out_file', 'in_file')]), (compfmap, outputnode, [('out_file', 'fmap')]), (bet, outputnode, [('mask_file', 'fmap_mask'), ('out_file', 'fmap_ref')]), ]) return workflow
def init_magnitude_wf(omp_nthreads, name="magnitude_wf"): """ Prepare the magnitude part of :abbr:`GRE (gradient-recalled echo)` fieldmaps. Average (if not done already) the magnitude part of the :abbr:`GRE (gradient recalled echo)` images, run N4 to correct for B1 field nonuniformity, and skull-strip the preprocessed magnitude. Workflow Graph .. workflow :: :graph2use: orig :simple_form: yes from sdcflows.workflows.fit.fieldmap import init_magnitude_wf wf = init_magnitude_wf(omp_nthreads=6) Parameters ---------- omp_nthreads : :obj:`int` Maximum number of threads an individual process may use name : :obj:`str` Name of workflow (default: ``magnitude_wf``) Inputs ------ magnitude : :obj:`os.PathLike` Path to the corresponding magnitude path(s). Outputs ------- fmap_ref : :obj:`os.PathLike` Path to the fieldmap reference calculated in this workflow. fmap_mask : :obj:`os.PathLike` Path to a binary brain mask corresponding to the reference above. """ from niworkflows.interfaces.images import IntraModalMerge from ..ancillary import init_brainextraction_wf workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=["magnitude"]), name="inputnode") outputnode = pe.Node( niu.IdentityInterface(fields=["fmap_ref", "fmap_mask", "mask_report"]), name="outputnode", ) # Merge input magnitude images # Do not reorient to RAS to preserve the validity of PhaseEncodingDirection magmrg = pe.Node(IntraModalMerge(hmc=False, to_ras=False), name="magmrg") brainextraction_wf = init_brainextraction_wf() # fmt: off workflow.connect([ (inputnode, magmrg, [("magnitude", "in_files")]), (magmrg, brainextraction_wf, [("out_avg", "inputnode.in_file")]), (brainextraction_wf, outputnode, [ ("outputnode.out_file", "fmap_ref"), ("outputnode.out_mask", "fmap_mask"), ("outputnode.out_probseg", "fmap_probseg"), ]), ]) # fmt: on return workflow
def init_fmap_wf(omp_nthreads=1, debug=False, mode="phasediff", name="fmap_wf"): """ Estimate the fieldmap based on a field-mapping MRI acquisition. Estimates the fieldmap using either one phase-difference map or image and one or more magnitude images corresponding to two or more :abbr:`GRE (Gradient Echo sequence)` acquisitions. When we have a sequence that directly measures the fieldmap, we just need to mask it (using the corresponding magnitude image) to remove the noise in the surrounding air region, and ensure that units are Hz. Workflow Graph .. workflow :: :graph2use: orig :simple_form: yes from sdcflows.workflows.fit.fieldmap import init_fmap_wf wf = init_fmap_wf(omp_nthreads=6) Parameters ---------- omp_nthreads : :obj:`int` Maximum number of threads an individual process may use. debug : :obj:`bool` Run on debug mode name : :obj:`str` Unique name of this workflow. Inputs ------ magnitude : :obj:`list` of :obj:`str` Path to the corresponding magnitude image for anatomical reference. fieldmap : :obj:`list` of :obj:`tuple`(:obj:`str`, :obj:`dict`) Path to the fieldmap acquisition (``*_fieldmap.nii[.gz]`` of BIDS). Outputs ------- fmap : :obj:`str` Path to the estimated fieldmap. fmap_ref : :obj:`str` Path to a preprocessed magnitude image reference. fmap_coeff : :obj:`str` or :obj:`list` of :obj:`str` The path(s) of the B-Spline coefficients supporting the fieldmap. fmap_mask : :obj:`str` Path to a binary brain mask corresponding to the ``fmap`` and ``fmap_ref`` pair. """ from ...interfaces.bspline import ( BSplineApprox, DEFAULT_LF_ZOOMS_MM, DEFAULT_HF_ZOOMS_MM, DEFAULT_ZOOMS_MM, ) workflow = Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=["magnitude", "fieldmap"]), name="inputnode") outputnode = pe.Node( niu.IdentityInterface( fields=["fmap", "fmap_ref", "fmap_mask", "fmap_coeff"]), name="outputnode", ) magnitude_wf = init_magnitude_wf(omp_nthreads=omp_nthreads) bs_filter = pe.Node(BSplineApprox(), n_procs=omp_nthreads, name="bs_filter") bs_filter.interface._always_run = debug bs_filter.inputs.bs_spacing = ([DEFAULT_LF_ZOOMS_MM, DEFAULT_HF_ZOOMS_MM] if not debug else [DEFAULT_ZOOMS_MM]) bs_filter.inputs.extrapolate = not debug # fmt: off workflow.connect([ (inputnode, magnitude_wf, [("magnitude", "inputnode.magnitude")]), (magnitude_wf, bs_filter, [("outputnode.fmap_mask", "in_mask")]), (magnitude_wf, outputnode, [ ("outputnode.fmap_mask", "fmap_mask"), ("outputnode.fmap_ref", "fmap_ref"), ]), (bs_filter, outputnode, [("out_extrapolated" if not debug else "out_field", "fmap"), ("out_coeff", "fmap_coeff")]), ]) # fmt: on if mode == "phasediff": workflow.__postdesc__ = """\ A *B<sub>0</sub>* nonuniformity map (or *fieldmap*) was estimated from the phase-drift map(s) measure with two consecutive GRE (gradient-recalled echo) acquisitions. """ phdiff_wf = init_phdiff_wf(omp_nthreads, debug=debug) # fmt: off workflow.connect([ (inputnode, phdiff_wf, [("fieldmap", "inputnode.phase")]), (magnitude_wf, phdiff_wf, [ ("outputnode.fmap_ref", "inputnode.magnitude"), ("outputnode.fmap_mask", "inputnode.mask"), ]), (phdiff_wf, bs_filter, [ ("outputnode.fieldmap", "in_data"), ]), ]) # fmt: on else: from niworkflows.interfaces.images import IntraModalMerge from ...interfaces.fmap import CheckB0Units workflow.__postdesc__ = """\ A *B<sub>0</sub>* nonuniformity map (or *fieldmap*) was directly measured with an MRI scheme designed with that purpose such as SEI (Spiral-Echo Imaging). """ # Merge input fieldmap images (assumes all are given in the same units!) fmapmrg = pe.Node( IntraModalMerge(zero_based_avg=False, hmc=False, to_ras=False), name="fmapmrg", ) units = pe.Node(CheckB0Units(), name="units", run_without_submitting=True) # fmt: off workflow.connect([ (inputnode, units, [(("fieldmap", _get_units), "units")]), (inputnode, fmapmrg, [(("fieldmap", _get_file), "in_files")]), (fmapmrg, units, [("out_avg", "in_file")]), (units, bs_filter, [("out_file", "in_data")]), ]) # fmt: on return workflow
def init_fmap_wf(omp_nthreads, fmap_bspline, name='fmap_wf'): """ Estimate the fieldmap based on a field-mapping MRI acquisition. When we have a sequence that directly measures the fieldmap, we just need to mask it (using the corresponding magnitude image) to remove the noise in the surrounding air region, and ensure that units are Hz. Workflow Graph .. workflow :: :graph2use: orig :simple_form: yes from sdcflows.workflows.fmap import init_fmap_wf wf = init_fmap_wf(omp_nthreads=6, fmap_bspline=False) Parameters ---------- omp_nthreads : int Maximum number of threads an individual process may use. fmap_bspline : bool Whether the fieldmap estimate will be smoothed using BSpline basis. name : str Unique name of this workflow. Inputs ------ magnitude : str Path to the corresponding magnitude image for anatomical reference. fieldmap : str Path to the fieldmap acquisition (``*_fieldmap.nii[.gz]`` of BIDS). Outputs ------- fmap : str Path to the estimated fieldmap. fmap_ref : str Path to a preprocessed magnitude image reference. fmap_mask : str Path to a binary brain mask corresponding to the ``fmap`` and ``fmap_ref`` pair. """ workflow = Workflow(name=name) workflow.__desc__ = """\ A B0-nonuniformity map (or *fieldmap*) was directly measured with an MRI scheme designed with that purpose (typically, a spiral pulse sequence). """ inputnode = pe.Node( niu.IdentityInterface(fields=['magnitude', 'fieldmap']), name='inputnode') outputnode = pe.Node( niu.IdentityInterface(fields=['fmap', 'fmap_ref', 'fmap_mask']), name='outputnode') magnitude_wf = init_magnitude_wf(omp_nthreads=omp_nthreads) workflow.connect([ (inputnode, magnitude_wf, [('magnitude', 'inputnode.magnitude')]), (magnitude_wf, outputnode, [('outputnode.fmap_mask', 'fmap_mask'), ('outputnode.fmap_ref', 'fmap_ref')]), ]) # Merge input fieldmap images fmapmrg = pe.Node(IntraModalMerge(zero_based_avg=False, hmc=False), name='fmapmrg') applymsk = pe.Node(fsl.ApplyMask(), name='applymsk') fmap_postproc_wf = init_fmap_postproc_wf(omp_nthreads=omp_nthreads, fmap_bspline=fmap_bspline) workflow.connect([ (inputnode, fmapmrg, [('fieldmap', 'in_files')]), (fmapmrg, applymsk, [('out_file', 'in_file')]), (magnitude_wf, applymsk, [('outputnode.fmap_mask', 'mask_file')]), (applymsk, fmap_postproc_wf, [('out_file', 'inputnode.fmap')]), (magnitude_wf, fmap_postproc_wf, [('outputnode.fmap_mask', 'inputnode.fmap_mask'), ('outputnode.fmap_ref', 'inputnode.fmap_ref')]), (fmap_postproc_wf, outputnode, [('outputnode.out_fmap', 'fmap')]), ]) return workflow