diff --git a/qsiprep/workflows/recon/interchange.py b/qsiprep/interfaces/interchange.py similarity index 77% rename from qsiprep/workflows/recon/interchange.py rename to qsiprep/interfaces/interchange.py index 4fbabf7b..aa4581f0 100644 --- a/qsiprep/workflows/recon/interchange.py +++ b/qsiprep/interfaces/interchange.py @@ -34,7 +34,7 @@ if overlapping_names: raise Exception("Someone has added overlapping outputs between the anatomical " "and dwi inputs: " + " ".join(overlapping_names)) - + recon_workflow_input_fields = qsiprep_output_names + \ recon_workflow_anatomical_input_fields default_input_set = set(recon_workflow_input_fields) @@ -53,10 +53,34 @@ class ReconWorkflowInputs(SimpleInterface): output_spec = _ReconWorkflowInputsOutputSpec def _run_interface(self, runtime): + inputs = self.inputs.get() for name in recon_workflow_input_fields: - self._results[name] = self.inputs.get(name) + self._results[name] = inputs.get(name) return runtime for name in recon_workflow_input_fields: _ReconWorkflowInputsInputSpec.add_class_trait(name, traits.Any) - _ReconWorkflowInputsOutputSpec.add_class_trait(name, traits.Any) \ No newline at end of file + _ReconWorkflowInputsOutputSpec.add_class_trait(name, traits.Any) + + +class _ReconAnatomicalDataInputSpec(BaseInterfaceInputSpec): + pass + + +class _ReconAnatomicalDataOutputSpec(TraitedSpec): + pass + + +class ReconAnatomicalData(SimpleInterface): + input_spec = _ReconAnatomicalDataInputSpec + output_spec = _ReconAnatomicalDataOutputSpec + + def _run_interface(self, runtime): + inputs = self.inputs.get() + for name in anatomical_workflow_outputs: + self._results[name] = inputs.get(name) + return runtime + +for name in anatomical_workflow_outputs: + _ReconAnatomicalDataInputSpec.add_class_trait(name, traits.Any) + _ReconAnatomicalDataOutputSpec.add_class_trait(name, traits.Any) \ No newline at end of file diff --git a/qsiprep/interfaces/mrtrix.py b/qsiprep/interfaces/mrtrix.py index 03ada1a4..653154c1 100644 --- a/qsiprep/interfaces/mrtrix.py +++ b/qsiprep/interfaces/mrtrix.py @@ -214,16 +214,16 @@ class GenerateMasked5ttInputSpec(Generate5ttInputSpec): mandatory=True, desc='tissue segmentation algorithm') in_file = traits.Either( - File(exists=True), + File(exists=True), traits.Directory(exists=True), argstr='%s', mandatory=True, position=1, desc='input T1w image or FreeSurfer directory') out_file = File( - argstr='%s', - genfile=True, - position=2, + argstr='%s', + genfile=True, + position=2, desc='output image') mask = File(exists=True, argstr='-mask %s') amygdala_hipppocampi_subcortical_gm = traits.Bool( @@ -232,7 +232,7 @@ class GenerateMasked5ttInputSpec(Generate5ttInputSpec): thalami_method = traits.Enum( "nuclei", "first", - "aseg", + "aseg", argstr="-thalami %s") hippocampi_method = traits.Enum( "subfields", @@ -880,10 +880,10 @@ def _run_interface(self, runtime): merge_weights = pe.Node(niu.Merge(num_nodes), name='merge_weights') merge_exemplars = pe.Node(niu.Merge(3), name='merge_exemplars') - compress_exemplars = pe.Node(CompressConnectome2Tck(), + compress_exemplars = pe.Node(CompressConnectome2Tck(), name='compress_exemplars') outputnode = pe.Node( - niu.IdentityInterface(fields=['matfiles', 'tckfiles', 'weights']), + niu.IdentityInterface(fields=['matfiles', 'tckfiles', 'weights']), name='outputnode') workflow.connect(merge_mats, 'out', outputnode, 'matfiles') workflow.connect(merge_tcks, 'out', outputnode, 'tckfiles') @@ -935,7 +935,7 @@ def _run_interface(self, runtime): workflow.connect(c2t_nodes[-1], 'exemplar_weights', merge_weights, 'in%d' % in_num) in_num += 1 - + # Get the exemplar tcks and weights workflow.connect([ (merge_tcks, merge_exemplars, [('out', "in1")]), @@ -960,7 +960,7 @@ def _run_interface(self, runtime): wf_result = workflow.run(**plugin_settings) else: wf_result = workflow.run() - + # Merge the connectivity matrices into a single file merge_node, = [node for node in list(wf_result.nodes) if node.name.endswith('merge_mats')] merged_connectivity_file = op.join(cwd, "combined_connectivity.mat") @@ -1061,30 +1061,30 @@ class _CompressConnectome2TckOutputSpec(TraitedSpec): class CompressConnectome2Tck(SimpleInterface): input_spec = _CompressConnectome2TckInputSpec output_spec = _CompressConnectome2TckOutputSpec - + def _run_interface(self, runtime): out_zip = op.join(runtime.cwd, self.inputs.out_zip) zipfh = zipfile.ZipFile(out_zip, "w") # Get the matrix csvs and add them to the zip - csvfiles = [fname for fname in self.inputs.files if fname.endswith(".csv") + csvfiles = [fname for fname in self.inputs.files if fname.endswith(".csv") and not fname.endswith("weights.csv")] for csvfile in csvfiles: zipfh.write(csvfile, arcname=_rename_connectome(csvfile, suffix='connectome.csv'), compresslevel=8, compress_type=zipfile.ZIP_DEFLATED) - + # Get the sift weights if they exist weightfiles = [fname for fname in self.inputs.files if fname.endswith("weights.csv")] for weightfile in weightfiles: zipfh.write(weightfile, arcname=_rename_connectome(weightfile, suffix='_weights.csv'), compresslevel=8, compress_type=zipfile.ZIP_DEFLATED) - + # Get the tck files tckfiles = [fname for fname in self.inputs.files if fname.endswith(".tck") or fname.endswith(".tck.gz")] for tckfile in tckfiles: - zipfh.write(tckfile, arcname=_rename_connectome(tckfile, suffix='_exemplars.tck'), + zipfh.write(tckfile, arcname=_rename_connectome(tckfile, suffix='_exemplars.tck'), compresslevel=8, compress_type=zipfile.ZIP_DEFLATED) - + zipfh.close() self._results["out_zip"] = out_zip return runtime @@ -1101,7 +1101,10 @@ def _rename_connectome(connectome_csv, suffix="_connectome.csv"): """ parts = connectome_csv.split(os.sep) conn_name = parts[-2] - image_name, = [part for part in parts if part.startswith("sub_") and part.endswith("recon_wf")] + try: + image_name, = [part for part in parts if part.startswith("sub_") and part.endswith("recon_wf")] + except Exception as ex: + raise Exception(f"unable to detect image name from these parts {parts}") image_name = image_name[:-len("_recon_wf")] return "connectome2tck/" +_rebids(image_name) + "_" + conn_name + suffix @@ -1303,9 +1306,9 @@ class _ITKTransformConvertInputSpec(CommandLineInputSpec): mandatory=True, position=0) operation = traits.Enum( - "itk_import", - default="itk_import", - usedefault=True, + "itk_import", + default="itk_import", + usedefault=True, posision=1, argstr="%s") out_transform = traits.File( @@ -1328,13 +1331,13 @@ class ITKTransformConvert(CommandLine): class _TransformHeaderInputSpec(CommandLineInputSpec): transform_file = traits.File( - exists=True, - position=0, + exists=True, + position=0, mandatory=True, argstr="-linear %s") in_image = traits.File( - exists=True, - mandatory=True, + exists=True, + mandatory=True, position=1, argstr="%s") out_image = traits.File( diff --git a/qsiprep/workflows/recon/amico.py b/qsiprep/workflows/recon/amico.py index a626f6d9..e4b5e001 100644 --- a/qsiprep/workflows/recon/amico.py +++ b/qsiprep/workflows/recon/amico.py @@ -9,7 +9,7 @@ import nipype.pipeline.engine as pe from nipype.interfaces import afni, utility as niu from qsiprep.interfaces.bids import ReconDerivativesDataSink -from .interchange import recon_workflow_input_fields +from ...interfaces.interchange import recon_workflow_input_fields from ...engine import Workflow from ...interfaces.amico import NODDI from ...interfaces.reports import CLIReconPeaksReport @@ -57,7 +57,7 @@ def init_amico_noddi_fit_wf(omp_nthreads, available_anatomical_data, : """ noddi_fit = pe.Node( - NODDI(**params), + NODDI(**params), name="recon_noddi", n_procs=omp_nthreads) desc += """\ @@ -91,7 +91,7 @@ def init_amico_noddi_fit_wf(omp_nthreads, available_anatomical_data, (convert_to_fibgz, outputnode, [('fibgz_file', 'fibgz')])]) if plot_reports: plot_peaks = pe.Node( - CLIReconPeaksReport(), + CLIReconPeaksReport(), name='plot_peaks', n_procs=omp_nthreads) ds_report_peaks = pe.Node( diff --git a/qsiprep/workflows/recon/anatomical.py b/qsiprep/workflows/recon/anatomical.py index 4cc4c14e1..e03c491e 100644 --- a/qsiprep/workflows/recon/anatomical.py +++ b/qsiprep/workflows/recon/anatomical.py @@ -28,7 +28,7 @@ from ...interfaces.freesurfer import find_fs_path from ...interfaces.gradients import ExtractB0s from ...interfaces.nilearn import MaskB0Series -from .interchange import (qsiprep_anatomical_ingressed_fields, +from ...interfaces.interchange import (qsiprep_anatomical_ingressed_fields, FS_FILES_TO_REGISTER, anatomical_workflow_outputs, recon_workflow_input_fields) from qsiprep.interfaces.utils import GetConnectivityAtlases diff --git a/qsiprep/workflows/recon/base.py b/qsiprep/workflows/recon/base.py index f50613e2..f3cfdadd 100644 --- a/qsiprep/workflows/recon/base.py +++ b/qsiprep/workflows/recon/base.py @@ -16,19 +16,23 @@ from glob import glob from copy import deepcopy from nipype import __version__ as nipype_ver +import nipype.pipeline.engine as pe +from nipype.utils.filemanip import split_filename from nilearn import __version__ as nilearn_ver from dipy import __version__ as dipy_ver from pkg_resources import resource_filename as pkgrf from ...engine import Workflow from ...utils.sloppy_recon import make_sloppy from ...__about__ import __version__ - +from ...interfaces.bids import QsiReconIngress import logging import json from bids.layout import BIDSLayout from .build_workflow import init_dwi_recon_workflow -from .anatomical import init_recon_anatomical_wf -from .interchange import anatomical_workflow_outputs +from .anatomical import init_recon_anatomical_wf, init_dwi_recon_anatomical_workflow +from ...interfaces.interchange import (anatomical_workflow_outputs, recon_workflow_anatomical_input_fields, + ReconWorkflowInputs, + qsiprep_output_names, recon_workflow_input_fields) LOGGER = logging.getLogger('nipype.workflow') @@ -211,7 +215,10 @@ def init_single_subject_wf( extras_to_make=spec.get('anatomical', []), freesurfer_dir=freesurfer_input, name='anat_ingress_wf') - + + # Connect the anatomical-only inputs. NOTE this is not to the inputnode! + LOGGER.info("Anatomical (T1w) available for recon: %s", available_anatomical_data) + # Fill-in datasinks and reportlet datasinks for the anatomical workflow for _node in anat_ingress_wf.list_node_names(): node_suffix = _node.split('.')[-1] @@ -221,31 +228,81 @@ def init_single_subject_wf( anat_ingress_wf.get_node(_node).inputs.source_file = \ "anat/sub-{}_desc-preproc_T1w.nii.gz".format(subject_id) - # Connect the anatomical-only inputs. NOTE this is not to the inputnode! - LOGGER.info("Anatomical (T1w) available for recon: %s", available_anatomical_data) - to_connect = [('outputnode.' + name, 'qsirecon_anat_wf.inputnode.' + name) - for name in anatomical_workflow_outputs] + # Get the anatomical data (masks, atlases, etc) + atlas_names = spec.get('atlases', []) # create a processing pipeline for the dwis in each session dwi_recon_wfs = {} + dwi_individual_anatomical_wfs = {} + recon_full_inputs = {} + dwi_ingress_nodes = {} for dwi_file in dwi_files: + wf_name = _get_wf_name(dwi_file) + + # Get the preprocessed DWI and all the related preprocessed images + dwi_ingress_nodes[dwi_file] = pe.Node( + QsiReconIngress(dwi_file=dwi_file), + name=wf_name + "_ingressed_dwi_data") + + # Create scan-specific anatomical data (mask, atlas configs, odf ROIs for reports) + dwi_individual_anatomical_wfs[dwi_file], dwi_available_anatomical_data = \ + init_dwi_recon_anatomical_workflow( + atlas_names=atlas_names, + omp_nthreads=omp_nthreads, + infant_mode=False, + prefer_dwi_mask=False, + sloppy=sloppy, + b0_threshold=b0_threshold, + freesurfer_dir=freesurfer_input, + extras_to_make=spec.get('anatomical', []), + name=wf_name + "_anat_wf", + **available_anatomical_data) + + # This node holds all the inputs that will go to the recon workflow. + # It is the definitive place to check what the input files are + recon_full_inputs[dwi_file] = pe.Node(ReconWorkflowInputs(), name=wf_name + "_recon_inputs") + + # This is the actual recon workflow for this dwi file dwi_recon_wfs[dwi_file] = init_dwi_recon_workflow( - dwi_file=dwi_file, - available_anatomical_data=available_anatomical_data, + available_anatomical_data=dwi_available_anatomical_data, workflow_spec=spec, - sloppy=sloppy, - prefer_dwi_mask=False, - infant_mode=False, - b0_threshold=b0_threshold, + name=wf_name + "_recon_wf", reportlets_dir=reportlets_dir, output_dir=output_dir, omp_nthreads=omp_nthreads, skip_odf_plots=skip_odf_plots) - workflow.connect([(anat_ingress_wf, dwi_recon_wfs[dwi_file], to_connect)]) + + # Connect the collected diffusion data (gradients, etc) to the inputnode + workflow.connect([ + + # The dwi data + (dwi_ingress_nodes[dwi_file], recon_full_inputs[dwi_file], [ + (trait, trait) for trait in qsiprep_output_names]), + + # subject anatomical data to dwi + (anat_ingress_wf, dwi_individual_anatomical_wfs[dwi_file], + [("outputnode."+trait, "inputnode."+trait) for trait in anatomical_workflow_outputs]), + (dwi_ingress_nodes[dwi_file], dwi_individual_anatomical_wfs[dwi_file], + [(trait, "inputnode." + trait) for trait in qsiprep_output_names]), + + # subject dwi-specific anatomical to recon inputs + (dwi_individual_anatomical_wfs[dwi_file], recon_full_inputs[dwi_file], [ + ("outputnode." + trait, trait) for trait in recon_workflow_anatomical_input_fields]), + + # recon inputs to recon workflow + (recon_full_inputs[dwi_file], dwi_recon_wfs[dwi_file], + [(trait, "inputnode." + trait) for trait in recon_workflow_input_fields]) + ]) return workflow +def _get_wf_name(dwi_file): + basedir, fname, ext = split_filename(dwi_file) + tokens = fname.split("_") + return "_".join(tokens[:-1]).replace("-", "_") + + def _load_recon_spec(spec_name, sloppy=False): prepackaged_dir = pkgrf("qsiprep", "data/pipelines") prepackaged = [op.split(fname)[1][:-5] for fname in glob(prepackaged_dir+"/*.json")] diff --git a/qsiprep/workflows/recon/build_workflow.py b/qsiprep/workflows/recon/build_workflow.py index edacbfd9..1e09a385 100644 --- a/qsiprep/workflows/recon/build_workflow.py +++ b/qsiprep/workflows/recon/build_workflow.py @@ -4,7 +4,7 @@ from nipype.interfaces import ants, utility as niu from nipype.utils.filemanip import split_filename from qsiprep.interfaces import anatomical -from qsiprep.interfaces.bids import QsiReconIngress, ReconDerivativesDataSink + from .dsi_studio import (init_dsi_studio_recon_wf, init_dsi_studio_export_wf, init_dsi_studio_connectivity_wf, init_dsi_studio_tractography_wf, init_dsi_studio_autotrack_wf) @@ -19,10 +19,7 @@ from .utils import init_conform_dwi_wf, init_discard_repeated_samples_wf from .steinhardt import init_steinhardt_order_param_wf from ...engine import Workflow -from .interchange import (qsiprep_output_names, default_input_set, - recon_workflow_input_fields, recon_workflow_anatomical_input_fields, - ReconWorkflowInputs) -from .anatomical import init_dwi_recon_anatomical_workflow +from ...interfaces.interchange import (default_input_set, recon_workflow_input_fields) LOGGER = logging.getLogger('nipype.interface') @@ -33,50 +30,18 @@ def _check_repeats(nodelist): raise Exception -def init_dwi_recon_workflow(dwi_file, workflow_spec, output_dir, prefer_dwi_mask, - reportlets_dir, available_anatomical_data, omp_nthreads, b0_threshold, - infant_mode, skip_odf_plots, freesurfer_dir=None, - sloppy=False, name="recon_wf"): +def init_dwi_recon_workflow(workflow_spec, output_dir, + reportlets_dir, available_anatomical_data, omp_nthreads, + skip_odf_plots, name="recon_wf"): """Convert a workflow spec into a nipype workflow. """ - # Get the preprocessed DWI and all the related preprocessed images - qsiprep_preprocessed_dwi_data = pe.Node( - QsiReconIngress(dwi_file=dwi_file), - name="qsiprep_preprocessed_dwi_data") - - # Get the anatomical data (masks, atlases, etc) - atlas_names = workflow_spec.get('atlases', []) - registered_anat_wf, available_anatomical_data = init_dwi_recon_anatomical_workflow( - atlas_names=atlas_names, - omp_nthreads=omp_nthreads, - infant_mode=infant_mode, - prefer_dwi_mask=prefer_dwi_mask, - sloppy=sloppy, - b0_threshold=b0_threshold, - extras_to_make=workflow_spec.get('anatomical', []), - freesurfer_dir=freesurfer_dir, - name="qsirecon_anat_wf", - **available_anatomical_data) - - # For doctests - # if not workflow_spec['name'] == 'fake': - # inputnode.inputs.dwi_file = dwi_file - - workflow = Workflow(name=_get_wf_name(dwi_file) + "_" + name) + + workflow = Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=recon_workflow_input_fields), name='inputnode') - # Connect the collected diffusion data (gradients, etc) to the inputnode - workflow.connect([ - (qsiprep_preprocessed_dwi_data, registered_anat_wf, [ - (trait, 'inputnode.' + trait) for trait in qsiprep_output_names]), - (registered_anat_wf, inputnode, [ - ('outputnode.'+trait, trait) for trait in - recon_workflow_input_fields]) - ]) - # Read nodes from workflow spec, make sure we can implement them nodes_to_add = [] for node_spec in workflow_spec['nodes']: @@ -239,8 +204,3 @@ def workflow_from_spec(omp_nthreads, available_anatomical_data, node_spec, def _as_connections(attr_list, src_prefix='', dest_prefix=''): return [(src_prefix + item, dest_prefix + item) for item in attr_list] - -def _get_wf_name(dwi_file): - basedir, fname, ext = split_filename(dwi_file) - tokens = fname.split("_") - return "_".join(tokens[:-1]).replace("-", "_") diff --git a/qsiprep/workflows/recon/converters.py b/qsiprep/workflows/recon/converters.py index 776d106c..bb9e761f 100644 --- a/qsiprep/workflows/recon/converters.py +++ b/qsiprep/workflows/recon/converters.py @@ -11,7 +11,7 @@ import logging from ...interfaces.converters import FODtoFIBGZ from ...interfaces.bids import ReconDerivativesDataSink -from .interchange import recon_workflow_input_fields +from ...interfaces.interchange import recon_workflow_input_fields from ...engine import Workflow from ...interfaces.images import ConformDwi LOGGER = logging.getLogger('nipype.workflow') diff --git a/qsiprep/workflows/recon/dipy.py b/qsiprep/workflows/recon/dipy.py index e094e1bb..04029556 100644 --- a/qsiprep/workflows/recon/dipy.py +++ b/qsiprep/workflows/recon/dipy.py @@ -10,7 +10,7 @@ from nipype.interfaces import afni, utility as niu from qsiprep.interfaces.bids import ReconDerivativesDataSink from ...interfaces.dipy import BrainSuiteShoreReconstruction, KurtosisReconstruction, MAPMRIReconstruction -from .interchange import recon_workflow_input_fields +from ...interfaces.interchange import recon_workflow_input_fields from ...engine import Workflow from ...interfaces.reports import CLIReconPeaksReport @@ -359,7 +359,7 @@ def init_dipy_mapmri_recon_wf(omp_nthreads, available_anatomical_data, name="dip ('fod_sh_mif', 'fod_sh_mif')])]) if plot_reports: plot_peaks = pe.Node( - CLIReconPeaksReport(), + CLIReconPeaksReport(), name='plot_peaks', n_procs=omp_nthreads) ds_report_peaks = pe.Node( @@ -431,7 +431,7 @@ def init_dipy_dki_recon_wf(omp_nthreads, available_anatomical_data, name="dipy_d True writes out a MRTrix mif file with sh coefficients radial_order: int An even integer that represent the order of the basis - + """ inputnode = pe.Node(niu.IdentityInterface(fields=recon_workflow_input_fields), @@ -472,7 +472,7 @@ def init_dipy_dki_recon_wf(omp_nthreads, available_anatomical_data, name="dipy_d if plot_reports and False: plot_peaks = pe.Node( - CLIReconPeaksReport(peaks_only=True), + CLIReconPeaksReport(peaks_only=True), name='plot_peaks', n_procs=omp_nthreads) ds_report_peaks = pe.Node( diff --git a/qsiprep/workflows/recon/dsi_studio.py b/qsiprep/workflows/recon/dsi_studio.py index db4b1a9c..44b68759 100644 --- a/qsiprep/workflows/recon/dsi_studio.py +++ b/qsiprep/workflows/recon/dsi_studio.py @@ -18,7 +18,7 @@ import logging from ...interfaces.bids import ReconDerivativesDataSink from ...interfaces.converters import DSIStudioTrkToTck -from .interchange import recon_workflow_input_fields +from ...interfaces.interchange import recon_workflow_input_fields from ...engine import Workflow from ...interfaces.reports import CLIReconPeaksReport, ConnectivityReport diff --git a/qsiprep/workflows/recon/dynamics.py b/qsiprep/workflows/recon/dynamics.py index 1eee9071..ef5d239b 100644 --- a/qsiprep/workflows/recon/dynamics.py +++ b/qsiprep/workflows/recon/dynamics.py @@ -10,7 +10,7 @@ import logging from qsiprep.interfaces.connectivity import Controllability from qsiprep.interfaces.bids import ReconDerivativesDataSink -from .interchange import recon_workflow_input_fields +from ...interfaces.interchange import recon_workflow_input_fields LOGGER = logging.getLogger('nipype.workflow') diff --git a/qsiprep/workflows/recon/mrtrix.py b/qsiprep/workflows/recon/mrtrix.py index 39590a15..ffe357db 100644 --- a/qsiprep/workflows/recon/mrtrix.py +++ b/qsiprep/workflows/recon/mrtrix.py @@ -2,10 +2,10 @@ MRTrix workflows ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Note that in nipype interfaces the threading-controlling attribute is -``nthreads``, not the typical ``num_threads`` expected by nipype. -To keep threading consistent between nipype and mrtrix, the -``nthreads`` attribute needs to be set in the interface and the +Note that in nipype interfaces the threading-controlling attribute is +``nthreads``, not the typical ``num_threads`` expected by nipype. +To keep threading consistent between nipype and mrtrix, the +``nthreads`` attribute needs to be set in the interface and the ``n_procs`` attribute needs to be set on the Node. @@ -21,7 +21,7 @@ from qsiprep.interfaces.mrtrix import ( EstimateFOD, SS3TEstimateFOD, MRTrixIngress, SS3TDwi2Response, GlobalTractography, MRTrixAtlasGraph, SIFT2, TckGen, MTNormalize) -from .interchange import recon_workflow_input_fields +from ...interfaces.interchange import recon_workflow_input_fields from ...engine import Workflow LOGGER = logging.getLogger('nipype.interface') @@ -47,9 +47,9 @@ def init_mrtrix_csd_recon_wf(omp_nthreads, available_anatomical_data, name="mrtr *Default qsiprep inputs* qsiprep_5tt_hsvs - A hybrid surface volume segmentation 5tt image aligned with the + A hybrid surface volume segmentation 5tt image aligned with the QSIPrep T1w - + Outputs @@ -137,7 +137,7 @@ def init_mrtrix_csd_recon_wf(omp_nthreads, available_anatomical_data, name="mrtr method_5tt = response.pop("method_5tt","dhollander") # Use dwi2response from 3Tissue for updated dhollander estimate_response = pe.Node( - SS3TDwi2Response(**response), + SS3TDwi2Response(**response), name='estimate_response', n_procs=omp_nthreads) @@ -150,13 +150,13 @@ def init_mrtrix_csd_recon_wf(omp_nthreads, available_anatomical_data, name="mrtr if fod_algorithm in ('msmt_csd', 'csd'): estimate_fod = pe.Node( - EstimateFOD(**fod), + EstimateFOD(**fod), name='estimate_fod', n_procs=omp_nthreads) desc += ' Reconstruction was done using MRtrix3 (@mrtrix3).' elif fod_algorithm == 'ss3t': estimate_fod = pe.Node( - SS3TEstimateFOD(**fod), + SS3TEstimateFOD(**fod), name='estimate_fod', n_procs=omp_nthreads) desc += """ \ @@ -191,7 +191,7 @@ def init_mrtrix_csd_recon_wf(omp_nthreads, available_anatomical_data, name="mrtr intensity_norm = pe.Node( MTNormalize( nthreads=omp_nthreads, - inlier_mask='inliers.nii.gz', + inlier_mask='inliers.nii.gz', norm_image='norm.nii.gz'), name='intensity_norm', n_procs=omp_nthreads) @@ -209,7 +209,7 @@ def init_mrtrix_csd_recon_wf(omp_nthreads, available_anatomical_data, name="mrtr if plot_reports: # Make a visual report of the model plot_peaks = pe.Node( - CLIReconPeaksReport(), + CLIReconPeaksReport(), name='plot_peaks', n_procs=omp_nthreads) ds_report_peaks = pe.Node( @@ -233,7 +233,7 @@ def init_mrtrix_csd_recon_wf(omp_nthreads, available_anatomical_data, name="mrtr name='ds_report_odfs', run_without_submitting=True) workflow.connect(plot_peaks, 'odf_report', ds_report_odfs, 'in_file') - + fod_source, fod_key = (estimate_fod, "wm_odf") if not run_mtnormalize \ else (intensity_norm, "wm_normed_odf") workflow.connect(fod_source, fod_key, plot_peaks, "mif_file") @@ -452,7 +452,7 @@ def init_mrtrix_tractography_wf(omp_nthreads, available_anatomical_data, name="m sift_params = params.get("sift2", {}) sift_params['nthreads'] = omp_nthreads tracking = pe.Node( - TckGen(**tracking_params), + TckGen(**tracking_params), name='tractography', n_procs=omp_nthreads) workflow.connect([ @@ -475,7 +475,7 @@ def init_mrtrix_tractography_wf(omp_nthreads, available_anatomical_data, name="m if use_sift2: tck_sift2 = pe.Node( - SIFT2(**sift_params), + SIFT2(**sift_params), name="tck_sift2", n_procs=omp_nthreads) workflow.connect([ @@ -542,13 +542,13 @@ def init_mrtrix_connectivity_wf(omp_nthreads, available_anatomical_data, name="m (inputnode, calc_connectivity, [('atlas_configs', 'atlas_configs'), ('tck_file', 'in_file'), ('sift_weights', 'in_weights')]), - + (calc_connectivity, outputnode, [('connectivity_matfile', 'matfile')]) ]) if plot_reports: plot_connectivity = pe.Node( - ConnectivityReport(), + ConnectivityReport(), name='plot_connectivity', n_procs=omp_nthreads) ds_report_connectivity = pe.Node( diff --git a/qsiprep/workflows/recon/pyafq.py b/qsiprep/workflows/recon/pyafq.py index 5d3f7a5f..327f842d 100644 --- a/qsiprep/workflows/recon/pyafq.py +++ b/qsiprep/workflows/recon/pyafq.py @@ -11,7 +11,7 @@ import AFQ import AFQ.utils.bin as afb from qsiprep.interfaces.pyafq import PyAFQRecon -from .interchange import recon_workflow_input_fields +from ...interfaces.interchange import recon_workflow_input_fields from ...interfaces.bids import ReconDerivativesDataSink LOGGER = logging.getLogger('nipype.workflow') diff --git a/qsiprep/workflows/recon/steinhardt.py b/qsiprep/workflows/recon/steinhardt.py index efe7281b..0a9f906f 100644 --- a/qsiprep/workflows/recon/steinhardt.py +++ b/qsiprep/workflows/recon/steinhardt.py @@ -9,7 +9,7 @@ import nipype.pipeline.engine as pe from nipype.interfaces import afni, utility as niu from qsiprep.interfaces.bids import ReconDerivativesDataSink -from .interchange import recon_workflow_input_fields +from ...interfaces.interchange import recon_workflow_input_fields from ...engine import Workflow from ...interfaces.mrtrix import MRConvert from ...interfaces.anatomical import CalculateSOP @@ -55,7 +55,7 @@ def init_steinhardt_order_param_wf(omp_nthreads, available_anatomical_data, : """ sh_mif_to_nifti = pe.Node( - MRConvert(out_file="SH.nii", args="-strides -1,-2,3"), + MRConvert(out_file="SH.nii", args="-strides -1,-2,3"), name="sh_mif_to_nifti") calc_sop = pe.Node(CalculateSOP(**params), name="calc_sop") desc += """\ diff --git a/qsiprep/workflows/recon/utils.py b/qsiprep/workflows/recon/utils.py index 89bfbc30..974fb87e 100644 --- a/qsiprep/workflows/recon/utils.py +++ b/qsiprep/workflows/recon/utils.py @@ -11,13 +11,13 @@ import nipype.interfaces.utility as niu import logging from qsiprep.interfaces.gradients import RemoveDuplicates -from .interchange import recon_workflow_input_fields +from ...interfaces.interchange import recon_workflow_input_fields from qsiprep.interfaces import ConformDwi from qsiprep.interfaces.mrtrix import MRTrixGradientTable LOGGER = logging.getLogger('nipype.workflow') -def init_conform_dwi_wf(omp_nthreads, available_anatomical_data, +def init_conform_dwi_wf(omp_nthreads, available_anatomical_data, name="conform_dwi", output_suffix="", params={}): """If data were preprocessed elsewhere, ensure the gradients and images conform to LPS+ before running other parts of the pipeline.""" diff --git a/qsiprep/workflows/reports.py b/qsiprep/workflows/reports.py index 71b8299d..e984dad7 100644 --- a/qsiprep/workflows/reports.py +++ b/qsiprep/workflows/reports.py @@ -20,7 +20,7 @@ from ..interfaces.bids import QsiReconIngress from ..interfaces.reports import InteractiveReport from ..utils.bids import collect_data -from .recon.interchange import qsiprep_output_names, recon_workflow_input_fields +from ..interfaces.interchange import qsiprep_output_names, recon_workflow_input_fields LOGGER = logging.getLogger('nipype.workflow')