diff --git a/.circleci/config.yml b/.circleci/config.yml index 2cecfb5697..b2e556f5ed 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -37,6 +37,9 @@ commands: cd .. build-images: steps: + - run: + name: "Logging into GitHub Container Registry" + command: echo "${GITHUB_REGISTRY_TOKEN}" | docker login https://docker.pkg.github.com -u ${GITHUB_REGISTRY_NAME} --password-stdin - run: name: "Building Docker image" command: | diff --git a/CPAC/GUI/interface/windows/main_window.py b/CPAC/GUI/interface/windows/main_window.py index 64319882ae..68b195d9fa 100644 --- a/CPAC/GUI/interface/windows/main_window.py +++ b/CPAC/GUI/interface/windows/main_window.py @@ -268,7 +268,7 @@ def runAnalysis1(self, pipeline, sublist, p): pass CPAC.pipeline.cpac_runner.run(sublist, pipeline, p, - plugin='MultiProc', + plugin='LegacyMultiProc', plugin_args=plugin_args) def runIndividualAnalysis(self, event): diff --git a/CPAC/alff/alff.py b/CPAC/alff/alff.py index 6f8fc87020..fe34c67082 100644 --- a/CPAC/alff/alff.py +++ b/CPAC/alff/alff.py @@ -276,7 +276,7 @@ def run_alff(input_fmri, func_brain_mask, hp=0.01, lp=0.1, out_dir=None, if run: workflow.run( - plugin='MultiProc', plugin_args={'n_procs': num_cores_per_subject}) + plugin='LegacyMultiProc', plugin_args={'n_procs': num_cores_per_subject}) outpath = glob.glob(os.path.join(workflow_dir, output, '*')) return outpath diff --git a/CPAC/anat_preproc/anat_preproc.py b/CPAC/anat_preproc/anat_preproc.py index b99c117770..f24d2953d3 100644 --- a/CPAC/anat_preproc/anat_preproc.py +++ b/CPAC/anat_preproc/anat_preproc.py @@ -377,18 +377,23 @@ def skullstrip_anatomical(method='afni', config=None, wf_name='skullstrip_anatom elif method == 'niworkflows-ants': # Skull-stripping using niworkflows-ants - anat_skullstrip_ants = init_brain_extraction_wf(tpl_target_path=config.niworkflows_ants_template_path, - tpl_mask_path=config.niworkflows_ants_mask_path, - tpl_regmask_path=config.niworkflows_ants_regmask_path, - name='anat_skullstrip_ants') + anat_skullstrip_ants = init_brain_extraction_wf( + tpl_target_path=config.niworkflows_ants_template_path, + tpl_mask_path=config.niworkflows_ants_mask_path, + tpl_regmask_path=config.niworkflows_ants_regmask_path, + name='anat_skullstrip_ants', + omp_nthreads=config.num_ants_threads, + mem_gb=( + config.maximumMemoryPerParticipant / config.num_ants_threads + )) preproc.connect(inputnode, 'anat_data', anat_skullstrip_ants, 'inputnode.in_files') - preproc.connect(anat_skullstrip_ants, 'copy_xform.out_file', + preproc.connect(anat_skullstrip_ants, 'outputnode.out_file', outputnode, 'skullstrip') - preproc.connect(anat_skullstrip_ants, 'copy_xform.out_file', + preproc.connect(anat_skullstrip_ants, 'outputnode.out_file', outputnode, 'brain') preproc.connect(anat_skullstrip_ants, 'atropos_wf.copy_xform.out_mask', diff --git a/CPAC/anat_preproc/ants.py b/CPAC/anat_preproc/ants.py index 5278ed2978..ae6f518f39 100644 --- a/CPAC/anat_preproc/ants.py +++ b/CPAC/anat_preproc/ants.py @@ -1,72 +1,79 @@ -# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- -# vi: set ft=python sts=4 ts=4 sw=4 et: -""" -Nipype translation of ANTs workflows +"""Nipype translation of ANTs workflows ------------------------------------ + +This functionality is adapted from nipreps/niworkflows: +https://www.nipreps.org/niworkflows/api/niworkflows.anat.ants.html +https://github.com/nipreps/niworkflows/blob/master/niworkflows/anat/ants.py +https://www.nipreps.org/niworkflows/ +https://fmriprep.org/en/stable/ +https://poldracklab.stanford.edu/ """ -# This functionality is adapted from poldracklab/niworkflows: -# https://github.com/poldracklab/niworkflows/blob/master/niworkflows/anat/ants.py -# https://fmriprep.readthedocs.io/ -# https://poldracklab.stanford.edu/ -# We are temporarily maintaining our own copy for more granular control. - -# general purpose -from collections import OrderedDict -from multiprocessing import cpu_count -from pkg_resources import resource_filename as pkgr_fn -from packaging.version import parse as parseversion, Version - -# nipype -from nipype.pipeline import engine as pe -from nipype.interfaces import utility as niu -from nipype.interfaces.fsl.maths import ApplyMask -from nipype.interfaces.ants import N4BiasFieldCorrection, Atropos, MultiplyImages - -from ..utils.misc import get_template_specs -# niworkflows -from ..utils.interfaces.ants import ( - ImageMath, - ResampleImageBySpacing, - AI, - ThresholdImage, -) -from CPAC.utils.interfaces.fixes import ( - FixHeaderRegistration as Registration, - FixHeaderApplyTransforms as ApplyTransforms, -) -from CPAC.utils.interfaces.utils import CopyXForm - - -ATROPOS_MODELS = { - 'T1w': OrderedDict([ - ('nclasses', 3), - ('csf', 1), - ('gm', 2), - ('wm', 3), - ]), - 'T2w': OrderedDict([ - ('nclasses', 3), - ('csf', 3), - ('gm', 2), - ('wm', 1), - ]), - 'FLAIR': OrderedDict([ - ('nclasses', 3), - ('csf', 1), - ('gm', 3), - ('wm', 2), - ]), -} +import sys + +from importlib.util import find_spec, module_from_spec +from CPAC.info import __version__ + + +def get_template(in_template, raise_empty=False, label=None, suffix=None, + desc=None, **kwargs): + '''Override templateflow.api.get to support plugging + niworkflows-ants into C-PAC. + + Overrides https://www.templateflow.org/python-client/master/_modules/templateflow/api.html#get # noqa: E501 + + Parameters + ---------- + in_template: dict + + raise_empty: boolean, optional + Raise exception if no files were matched + + Returns + ------- + path: str + ''' + # tpl_mask_path + if (label == 'brain' and suffix == 'probseg') or ( + desc == 'brain' and suffix == 'mask' + ): + return in_template['tpl_mask_path'] + + # tpl_regmask_path + if desc == 'BrainCerebellumExtraction' and suffix == 'mask': + return in_template['tpl_regmask_path'] + + +def get_template_specs(in_template, template_spec=None, default_resolution=1): + '''Override niworkflows.utils.misc.get_template_specs to support + plugging niworkflows-ants into C-PAC. + + Overrides https://github.com/nipreps/niworkflows/blob/df77431a26fa3f3e4b2aff790fa3b4b2c41dd650/niworkflows/utils/misc.py#L17-L77 # noqa: E501 + + Parameters + ---------- + in_template: dict + + template_spec: dict or None + + default_resolution: int, float, or None + + Returns + ------- + tpl_target_path: str + + common_spec: dict + ''' + return (in_template['tpl_target_path'], in_template) def init_brain_extraction_wf(tpl_target_path, tpl_mask_path, - tpl_regmask_path, + tpl_regmask_path, name='brain_extraction_wf', template_spec=None, use_float=True, normalization_quality='precise', - omp_nthreads=None, + omp_nthreads=1, mem_gb=3.0, bids_suffix='T1w', atropos_refine=True, @@ -74,555 +81,132 @@ def init_brain_extraction_wf(tpl_target_path, atropos_model=None, use_laplacian=True, bspline_fitting_distance=200): - """ - A Nipype implementation of the official ANTs' ``antsBrainExtraction.sh`` - workflow (only for 3D images). - The official workflow is built as follows (and this implementation - follows the same organization): - 1. Step 1 performs several clerical tasks (adding padding, calculating - the Laplacian of inputs, affine initialization) and the core - spatial normalization. - 2. Maps the brain mask into target space using the normalization - calculated in 1. - 3. Superstep 1b: smart binarization of the brain mask - 4. Superstep 6: apply ATROPOS and massage its outputs - 5. Superstep 7: use results from 4 to refine the brain mask - .. workflow:: - :graph2use: orig - :simple_form: yes - from niworkflows.anat import init_brain_extraction_wf - wf = init_brain_extraction_wf() - **Parameters** - in_template : str - Name of the skull-stripping template ('OASIS30ANTs', 'NKI', or - path). - The brain template from which regions will be projected - Anatomical template created using e.g. LPBA40 data set with - ``buildtemplateparallel.sh`` in ANTs. - The workflow will automatically search for a brain probability - mask created using e.g. LPBA40 data set which have brain masks - defined, and warped to anatomical template and - averaged resulting in a probability image. - use_float : bool - Whether single precision should be used - normalization_quality : str - Use more precise or faster registration parameters - (default: ``precise``, other possible values: ``testing``) - omp_nthreads : int - Maximum number of threads an individual process may use - mem_gb : float - Estimated peak memory consumption of the most hungry nodes - in the workflow - bids_suffix : str - Sequence type of the first input image. For a list of acceptable values - see https://bids-specification.readthedocs.io/en/latest/\ -04-modality-specific-files/01-magnetic-resonance-imaging-data.html#anatomy-imaging-data - atropos_refine : bool - Enables or disables the whole ATROPOS sub-workflow - atropos_use_random_seed : bool - Whether ATROPOS should generate a random seed based on the - system's clock - atropos_model : tuple or None - Allows to specify a particular segmentation model, overwriting - the defaults based on ``bids_suffix`` - use_laplacian : bool - Enables or disables alignment of the Laplacian as an additional - criterion for image registration quality (default: True) - bspline_fitting_distance : float - The size of the b-spline mesh grid elements, in mm (default: 200) - name : str, optional - Workflow name (default: antsBrainExtraction) - **Inputs** - in_files - List of input anatomical images to be brain-extracted, - typically T1-weighted. - If a list of anatomical images is provided, subsequently - specified images are used during the segmentation process. - However, only the first image is used in the registration - of priors. - Our suggestion would be to specify the T1w as the first image. - in_mask - (optional) Mask used for registration to limit the metric - computation to a specific region. - **Outputs** - out_file - Skull-stripped and :abbr:`INU (intensity non-uniformity)`-corrected ``in_files`` - out_mask - Calculated brain mask - bias_corrected - The ``in_files`` input images, after :abbr:`INU (intensity non-uniformity)` - correction, before skull-stripping. - bias_image - The :abbr:`INU (intensity non-uniformity)` field estimated for each - input in ``in_files`` - out_segm - Output segmentation by ATROPOS - out_tpms - Output :abbr:`TPMs (tissue probability maps)` by ATROPOS - """ - # from templateflow.api import get as get_template - wf = pe.Workflow(name) - - template_spec = template_spec or {} - - # suffix passed via spec takes precedence - template_spec['suffix'] = template_spec.get('suffix', bids_suffix) - - # # Get probabilistic brain mask if available - inputnode = pe.Node(niu.IdentityInterface(fields=['in_files', 'in_mask']), - name='inputnode') - - # # Try to find a registration mask, set if available - if tpl_regmask_path: - inputnode.inputs.in_mask = str(tpl_regmask_path) - - outputnode = pe.Node(niu.IdentityInterface( - fields=['out_file', 'out_mask', 'bias_corrected', 'bias_image', - 'out_segm', 'out_tpms']), - name='outputnode') - - copy_xform = pe.Node(CopyXForm( - fields=['out_file', 'out_mask', 'bias_corrected', 'bias_image']), - name='copy_xform', run_without_submitting=True) - - trunc = pe.MapNode(ImageMath(operation='TruncateImageIntensity', op2='0.01 0.999 256'), - name='truncate_images', iterfield=['op1']) - inu_n4 = pe.MapNode( - N4BiasFieldCorrection( - dimension=3, save_bias=False, copy_header=True, - n_iterations=[50] * 4, convergence_threshold=1e-7, shrink_factor=4, - bspline_fitting_distance=bspline_fitting_distance), - n_procs=omp_nthreads, name='inu_n4', iterfield=['input_image']) - - res_tmpl = pe.Node(ResampleImageBySpacing( - out_spacing=(4, 4, 4), apply_smoothing=True), name='res_tmpl') - res_tmpl.inputs.input_image = tpl_target_path - res_target = pe.Node(ResampleImageBySpacing( - out_spacing=(4, 4, 4), apply_smoothing=True), name='res_target') - - lap_tmpl = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), - name='lap_tmpl') - lap_tmpl.inputs.op1 = tpl_target_path - lap_target = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), - name='lap_target') - mrg_tmpl = pe.Node(niu.Merge(2), name='mrg_tmpl') - mrg_tmpl.inputs.in1 = tpl_target_path - mrg_target = pe.Node(niu.Merge(2), name='mrg_target') - - # Initialize transforms with antsAI - init_aff = pe.Node(AI( - metric=('Mattes', 32, 'Regular', 0.25), - transform=('Affine', 0.1), - search_factor=(15, 0.1), - principal_axes=False, - convergence=(10, 1e-6, 10), - verbose=True), - name='init_aff', - n_procs=omp_nthreads) - - # Tolerate missing ANTs at construction time - _ants_version = Registration().version - if _ants_version and parseversion(_ants_version) >= Version('2.3.0'): - init_aff.inputs.search_grid = (40, (0, 40, 40)) - - # Set up spatial normalization - settings_file = 'antsBrainExtraction_%s.json' if use_laplacian \ - else 'antsBrainExtractionNoLaplacian_%s.json' - norm = pe.Node(Registration(from_file=pkgr_fn( - 'CPAC.anat_preproc', 'data/'+settings_file % normalization_quality)), - name='norm', - n_procs=omp_nthreads, - mem_gb=mem_gb) - norm.inputs.float = use_float - fixed_mask_trait = 'fixed_image_mask' - if _ants_version and parseversion(_ants_version) >= Version('2.2.0'): - fixed_mask_trait += 's' - - map_brainmask = pe.Node( - ApplyTransforms(interpolation='Gaussian', float=True), - name='map_brainmask', - mem_gb=1 - ) - map_brainmask.inputs.input_image = str(tpl_mask_path) - - thr_brainmask = pe.Node(ThresholdImage( - dimension=3, th_low=0.5, th_high=1.0, inside_value=1, - outside_value=0), name='thr_brainmask') - - # Morphological dilation, radius=2 - dil_brainmask = pe.Node(ImageMath(operation='MD', op2='2'), - name='dil_brainmask') - # Get largest connected component - get_brainmask = pe.Node(ImageMath(operation='GetLargestComponent'), - name='get_brainmask') - - # Refine INU correction - inu_n4_final = pe.MapNode( - N4BiasFieldCorrection( - dimension=3, save_bias=True, copy_header=True, - n_iterations=[50] * 5, convergence_threshold=1e-7, shrink_factor=4, - bspline_fitting_distance=bspline_fitting_distance), - n_procs=omp_nthreads, name='inu_n4_final', iterfield=['input_image']) - - # Apply mask - apply_mask = pe.MapNode(ApplyMask(), iterfield=['in_file'], name='apply_mask') - - wf.connect([ - (inputnode, trunc, [('in_files', 'op1')]), - (inputnode, copy_xform, [(('in_files', _pop), 'hdr_file')]), - (inputnode, inu_n4_final, [('in_files', 'input_image')]), - (inputnode, init_aff, [('in_mask', 'fixed_image_mask')]), - (inputnode, norm, [('in_mask', fixed_mask_trait)]), - (inputnode, map_brainmask, [(('in_files', _pop), 'reference_image')]), - (trunc, inu_n4, [('output_image', 'input_image')]), - (inu_n4, res_target, [ - (('output_image', _pop), 'input_image')]), - (res_tmpl, init_aff, [('output_image', 'fixed_image')]), - (res_target, init_aff, [('output_image', 'moving_image')]), - (init_aff, norm, [('output_transform', 'initial_moving_transform')]), - (norm, map_brainmask, [ - ('reverse_transforms', 'transforms'), - ('reverse_invert_flags', 'invert_transform_flags')]), - (map_brainmask, thr_brainmask, [('output_image', 'input_image')]), - (thr_brainmask, dil_brainmask, [('output_image', 'op1')]), - (dil_brainmask, get_brainmask, [('output_image', 'op1')]), - (inu_n4_final, apply_mask, [('output_image', 'in_file')]), - (get_brainmask, apply_mask, [('output_image', 'mask_file')]), - (get_brainmask, copy_xform, [('output_image', 'out_mask')]), - (apply_mask, copy_xform, [('out_file', 'out_file')]), - (inu_n4_final, copy_xform, [('output_image', 'bias_corrected'), - ('bias_image', 'bias_image')]), - (copy_xform, outputnode, [ - ('out_file', 'out_file'), - ('out_mask', 'out_mask'), - ('bias_corrected', 'bias_corrected'), - ('bias_image', 'bias_image')]), - ]) + '''We monkeypatch `init_brain_extraction_wf` from niworkflows.anat + to use `tpl_target_path`, `tpl_mask_path` and `tpl_regmask_path` + from pipeline config instead of from datalad templates. + + .. exec:: + from CPAC.anat_preproc.ants import init_brain_extraction_wf + wf = init_brain_extraction_wf( + '/ants_template/oasis/T_template0.nii.gz', + '/ants_template/oasis/' + 'T_template0_BrainCerebellumProbabilityMask.nii.gz', + '/ants_template/oasis/' + 'T_template0_BrainCerebellumRegistrationMask.nii.gz' + ) + wf.write_graph( + graph2use='orig', + dotfilename='./images/generated/niworkflows_ants.dot' + ) - if use_laplacian: - lap_tmpl = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), - name='lap_tmpl') - lap_tmpl.inputs.op1 = tpl_target_path - lap_target = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'), - name='lap_target') - mrg_tmpl = pe.Node(niu.Merge(2), name='mrg_tmpl') - mrg_tmpl.inputs.in1 = tpl_target_path - mrg_target = pe.Node(niu.Merge(2), name='mrg_target') - wf.connect([ - (inu_n4, lap_target, [ - (('output_image', _pop), 'op1')]), - (lap_tmpl, mrg_tmpl, [('output_image', 'in2')]), - (inu_n4, mrg_target, [('output_image', 'in1')]), - (lap_target, mrg_target, [('output_image', 'in2')]), - (mrg_tmpl, norm, [('out', 'fixed_image')]), - (mrg_target, norm, [('out', 'moving_image')]), - ]) - else: - norm.inputs.fixed_image = tpl_target_path - wf.connect([ - (inu_n4, norm, [ - (('output_image', _pop), 'moving_image')]), - ]) - - if atropos_refine: - atropos_model = atropos_model or list(ATROPOS_MODELS[bids_suffix].values()) - atropos_wf = init_atropos_wf( - use_random_seed=atropos_use_random_seed, - omp_nthreads=omp_nthreads, - mem_gb=mem_gb, - in_segmentation_model=atropos_model, + High Level Workflow Graph: + + .. image:: ../../images/generated/niworkflows_ants.png + :width: 500 + + Detailed Workflow Graph: + + .. image:: ../../images/generated/niworkflows_ants_detailed.png + :width: 500 + + Parameters + ---------- + tpl_target_path: str + path to brain extraction template + + tpl_mask_path: str + path to probabilistic brain mask + + tpl_regmask_path: str + path to registration mask + + # TODO: import other paramters from niworkflows + + updated + + Returns + ------- + wf: Workflow + + Examples + -------- + >>> from CPAC.anat_preproc.ants import init_brain_extraction_wf + >>> wf = init_brain_extraction_wf( + ... '/ants_template/oasis/T_template0.nii.gz', + ... '/ants_template/oasis/' + ... 'T_template0_BrainCerebellumProbabilityMask.nii.gz', + ... '/ants_template/oasis/' + ... 'T_template0_BrainCerebellumRegistrationMask.nii.gz') + >>> wf.name + 'brain_extraction_wf' + >>> wf.inputs.lap_tmpl.op1 + '/ants_template/oasis/T_template0.nii.gz' + >>> wf.inputs.res_tmpl.in_file + '/ants_template/oasis/T_template0.nii.gz' + >>> getattr(wf.inputs.atropos_wf, '01_atropos').number_of_tissue_classes + 3 + ''' + # monkeypatch `get_template_specs` and `get_template` to use paths + # specified in pipeline config rather than datalad templates + mp_niworkflows_ants = _monkeypatch_in_template('niworkflows.anat.ants') + + in_template = { + 'tpl_target_path': tpl_target_path, + 'tpl_mask_path': tpl_mask_path, + 'tpl_regmask_path': tpl_regmask_path + } + + return mp_niworkflows_ants.init_brain_extraction_wf( + in_template=in_template, name=name, template_spec=template_spec, + use_float=use_float, normalization_quality=normalization_quality, + omp_nthreads=omp_nthreads, mem_gb=mem_gb, bids_suffix=bids_suffix, + atropos_refine=atropos_refine, + atropos_use_random_seed=atropos_use_random_seed, + atropos_model=atropos_model, use_laplacian=use_laplacian, + bspline_fitting_distance=bspline_fitting_distance) + + +def _monkeypatch_in_template(module_name): + '''Function to monkeypatch `in_template` to work with a dictionary + of local paths to templates rather than a string name of a + templateflow template. + + Parameters + ---------- + module_name: str + name of module to monkeypatch + + Returns + ------- + module: module + monkeypatched module + ''' + spec = find_spec(module_name) + patched_source = '\n'.join([ + f'# MONKEYPATCHED for C-PAC {__version__}', + spec.loader.get_source('niworkflows.anat.ants').replace( + 'from ..utils.misc import get_template_specs', + 'from CPAC.anat_preproc.ants import get_template_specs').replace( + 'from templateflow.api import get as get_template', + 'from CPAC.anat_preproc.ants import get_template' + ).replace( + 'in_template : str\n Name of the skull-stripping template ' + '(\'OASIS30ANTs\', \'NKI\', or\n path).\n The brain ' + 'template from which regions will be projected\n ' + 'Anatomical template created using e.g. LPBA40 data set with\n' + ' ``buildtemplateparallel.sh`` in ANTs.\n The ' + 'workflow will automatically search for a brain probability\n' + ' mask created using e.g. LPBA40 data set which have brain ' + 'masks\n defined, and warped to anatomical template ' + 'and\n averaged resulting in a probability image.', + 'in_template : dict\n Local paths to templates, keyed with ' + '{\n \'tpl_target_path\', \'tpl_mask_path\', ' + '\'tpl_regmask_path\'\n }. See CPAC.anat_preproc.ants for ' + 'details.' ) - sel_wm = pe.Node(niu.Select(index=atropos_model[-1] - 1), name='sel_wm', - run_without_submitting=True) - - wf.disconnect([ - (get_brainmask, apply_mask, [('output_image', 'mask_file')]), - (copy_xform, outputnode, [('out_mask', 'out_mask')]), - ]) - wf.connect([ - (inu_n4, atropos_wf, [ - ('output_image', 'inputnode.in_files')]), - (thr_brainmask, atropos_wf, [ - ('output_image', 'inputnode.in_mask')]), - (get_brainmask, atropos_wf, [ - ('output_image', 'inputnode.in_mask_dilated')]), - (atropos_wf, sel_wm, [('outputnode.out_tpms', 'inlist')]), - (sel_wm, inu_n4_final, [('out', 'weight_image')]), - (atropos_wf, apply_mask, [ - ('outputnode.out_mask', 'mask_file')]), - (atropos_wf, outputnode, [ - ('outputnode.out_mask', 'out_mask'), - ('outputnode.out_segm', 'out_segm'), - ('outputnode.out_tpms', 'out_tpms')]), - ]) - return wf - - -def init_atropos_wf(name='atropos_wf', - use_random_seed=True, - omp_nthreads=None, - mem_gb=3.0, - padding=10, - in_segmentation_model=list(ATROPOS_MODELS['T1w'].values())): - """ - Implements supersteps 6 and 7 of ``antsBrainExtraction.sh``, - which refine the mask previously computed with the spatial - normalization to the template. - **Parameters** - use_random_seed : bool - Whether ATROPOS should generate a random seed based on the - system's clock - omp_nthreads : int - Maximum number of threads an individual process may use - mem_gb : float - Estimated peak memory consumption of the most hungry nodes - in the workflow - padding : int - Pad images with zeros before processing - in_segmentation_model : tuple - A k-means segmentation is run to find gray or white matter - around the edge of the initial brain mask warped from the - template. - This produces a segmentation image with :math:`$K$` classes, - ordered by mean intensity in increasing order. - With this option, you can control :math:`$K$` and tell - the script which classes represent CSF, gray and white matter. - Format (K, csfLabel, gmLabel, wmLabel). - Examples: - - ``(3,1,2,3)`` for T1 with K=3, CSF=1, GM=2, WM=3 (default) - - ``(3,3,2,1)`` for T2 with K=3, CSF=3, GM=2, WM=1 - - ``(3,1,3,2)`` for FLAIR with K=3, CSF=1 GM=3, WM=2 - - ``(4,4,2,3)`` uses K=4, CSF=4, GM=2, WM=3 - name : str, optional - Workflow name (default: atropos_wf) - **Inputs** - in_files - :abbr:`INU (intensity non-uniformity)`-corrected files. - in_mask - Brain mask calculated previously - **Outputs** - out_mask - Refined brain mask - out_segm - Output segmentation - out_tpms - Output :abbr:`TPMs (tissue probability maps)` - """ - wf = pe.Workflow(name) - - inputnode = pe.Node(niu.IdentityInterface( - fields=['in_files', 'in_mask', 'in_mask_dilated']), name='inputnode') - outputnode = pe.Node(niu.IdentityInterface( - fields=['out_mask', 'out_segm', 'out_tpms']), name='outputnode') - - copy_xform = pe.Node(CopyXForm( - fields=['out_mask', 'out_segm', 'out_tpms']), - name='copy_xform', run_without_submitting=True) - - # Run atropos (core node) - atropos = pe.Node(Atropos( - dimension=3, - initialization='KMeans', - number_of_tissue_classes=in_segmentation_model[0], - n_iterations=3, - convergence_threshold=0.0, - mrf_radius=[1, 1, 1], - mrf_smoothing_factor=0.1, - likelihood_model='Gaussian', - use_random_seed=use_random_seed), - name='01_atropos', n_procs=omp_nthreads, mem_gb=mem_gb) - - # massage outputs - pad_segm = pe.Node(ImageMath(operation='PadImage', op2='%d' % padding), - name='02_pad_segm') - pad_mask = pe.Node(ImageMath(operation='PadImage', op2='%d' % padding), - name='03_pad_mask') - - # Split segmentation in binary masks - sel_labels = pe.Node(niu.Function( - function=_select_labels, output_names=['out_wm', 'out_gm', 'out_csf']), - name='04_sel_labels') - sel_labels.inputs.labels = list(reversed(in_segmentation_model[1:])) - - # Select largest components (GM, WM) - # ImageMath ${DIMENSION} ${EXTRACTION_WM} GetLargestComponent ${EXTRACTION_WM} - get_wm = pe.Node(ImageMath(operation='GetLargestComponent'), - name='05_get_wm') - get_gm = pe.Node(ImageMath(operation='GetLargestComponent'), - name='06_get_gm') - - # Fill holes and calculate intersection - # ImageMath ${DIMENSION} ${EXTRACTION_TMP} FillHoles ${EXTRACTION_GM} 2 - # MultiplyImages ${DIMENSION} ${EXTRACTION_GM} ${EXTRACTION_TMP} ${EXTRACTION_GM} - fill_gm = pe.Node(ImageMath(operation='FillHoles', op2='2'), - name='07_fill_gm') - mult_gm = pe.Node(MultiplyImages( - dimension=3, output_product_image='08_mult_gm.nii.gz'), name='08_mult_gm') - - # MultiplyImages ${DIMENSION} ${EXTRACTION_WM} ${ATROPOS_WM_CLASS_LABEL} ${EXTRACTION_WM} - # ImageMath ${DIMENSION} ${EXTRACTION_TMP} ME ${EXTRACTION_CSF} 10 - relabel_wm = pe.Node(MultiplyImages( - dimension=3, second_input=in_segmentation_model[-1], - output_product_image='09_relabel_wm.nii.gz'), name='09_relabel_wm') - me_csf = pe.Node(ImageMath(operation='ME', op2='10'), name='10_me_csf') - - # ImageMath ${DIMENSION} ${EXTRACTION_GM} addtozero ${EXTRACTION_GM} ${EXTRACTION_TMP} - # MultiplyImages ${DIMENSION} ${EXTRACTION_GM} ${ATROPOS_GM_CLASS_LABEL} ${EXTRACTION_GM} - # ImageMath ${DIMENSION} ${EXTRACTION_SEGMENTATION} addtozero ${EXTRACTION_WM} ${EXTRACTION_GM} - add_gm = pe.Node(ImageMath(operation='addtozero'), - name='11_add_gm') - relabel_gm = pe.Node(MultiplyImages( - dimension=3, second_input=in_segmentation_model[-2], - output_product_image='12_relabel_gm.nii.gz'), name='12_relabel_gm') - add_gm_wm = pe.Node(ImageMath(operation='addtozero'), - name='13_add_gm_wm') - - # Superstep 7 - # Split segmentation in binary masks - sel_labels2 = pe.Node(niu.Function( - function=_select_labels, output_names=['out_gm', 'out_wm']), - name='14_sel_labels2') - sel_labels2.inputs.labels = in_segmentation_model[2:] - - # ImageMath ${DIMENSION} ${EXTRACTION_MASK} addtozero ${EXTRACTION_MASK} ${EXTRACTION_TMP} - add_7 = pe.Node(ImageMath(operation='addtozero'), name='15_add_7') - # ImageMath ${DIMENSION} ${EXTRACTION_MASK} ME ${EXTRACTION_MASK} 2 - me_7 = pe.Node(ImageMath(operation='ME', op2='2'), name='16_me_7') - # ImageMath ${DIMENSION} ${EXTRACTION_MASK} GetLargestComponent ${EXTRACTION_MASK} - comp_7 = pe.Node(ImageMath(operation='GetLargestComponent'), - name='17_comp_7') - # ImageMath ${DIMENSION} ${EXTRACTION_MASK} MD ${EXTRACTION_MASK} 4 - md_7 = pe.Node(ImageMath(operation='MD', op2='4'), name='18_md_7') - # ImageMath ${DIMENSION} ${EXTRACTION_MASK} FillHoles ${EXTRACTION_MASK} 2 - fill_7 = pe.Node(ImageMath(operation='FillHoles', op2='2'), - name='19_fill_7') - # ImageMath ${DIMENSION} ${EXTRACTION_MASK} addtozero ${EXTRACTION_MASK} \ - # ${EXTRACTION_MASK_PRIOR_WARPED} - add_7_2 = pe.Node(ImageMath(operation='addtozero'), name='20_add_7_2') - # ImageMath ${DIMENSION} ${EXTRACTION_MASK} MD ${EXTRACTION_MASK} 5 - md_7_2 = pe.Node(ImageMath(operation='MD', op2='5'), name='21_md_7_2') - # ImageMath ${DIMENSION} ${EXTRACTION_MASK} ME ${EXTRACTION_MASK} 5 - me_7_2 = pe.Node(ImageMath(operation='ME', op2='5'), name='22_me_7_2') - - # De-pad - depad_mask = pe.Node(ImageMath(operation='PadImage', op2='-%d' % padding), - name='23_depad_mask') - depad_segm = pe.Node(ImageMath(operation='PadImage', op2='-%d' % padding), - name='24_depad_segm') - depad_gm = pe.Node(ImageMath(operation='PadImage', op2='-%d' % padding), - name='25_depad_gm') - depad_wm = pe.Node(ImageMath(operation='PadImage', op2='-%d' % padding), - name='26_depad_wm') - depad_csf = pe.Node(ImageMath(operation='PadImage', op2='-%d' % padding), - name='27_depad_csf') - - msk_conform = pe.Node(niu.Function(function=_conform_mask), name='msk_conform') - merge_tpms = pe.Node(niu.Merge(in_segmentation_model[0]), name='merge_tpms') - wf.connect([ - (inputnode, copy_xform, [(('in_files', _pop), 'hdr_file')]), - (inputnode, pad_mask, [('in_mask', 'op1')]), - (inputnode, atropos, [('in_files', 'intensity_images'), - ('in_mask_dilated', 'mask_image')]), - (inputnode, msk_conform, [(('in_files', _pop), 'in_reference')]), - (atropos, pad_segm, [('classified_image', 'op1')]), - (pad_segm, sel_labels, [('output_image', 'in_segm')]), - (sel_labels, get_wm, [('out_wm', 'op1')]), - (sel_labels, get_gm, [('out_gm', 'op1')]), - (get_gm, fill_gm, [('output_image', 'op1')]), - (get_gm, mult_gm, [('output_image', 'first_input')]), - (fill_gm, mult_gm, [('output_image', 'second_input')]), - (get_wm, relabel_wm, [('output_image', 'first_input')]), - (sel_labels, me_csf, [('out_csf', 'op1')]), - (mult_gm, add_gm, [('output_product_image', 'op1')]), - (me_csf, add_gm, [('output_image', 'op2')]), - (add_gm, relabel_gm, [('output_image', 'first_input')]), - (relabel_wm, add_gm_wm, [('output_product_image', 'op1')]), - (relabel_gm, add_gm_wm, [('output_product_image', 'op2')]), - (add_gm_wm, sel_labels2, [('output_image', 'in_segm')]), - (sel_labels2, add_7, [('out_wm', 'op1'), - ('out_gm', 'op2')]), - (add_7, me_7, [('output_image', 'op1')]), - (me_7, comp_7, [('output_image', 'op1')]), - (comp_7, md_7, [('output_image', 'op1')]), - (md_7, fill_7, [('output_image', 'op1')]), - (fill_7, add_7_2, [('output_image', 'op1')]), - (pad_mask, add_7_2, [('output_image', 'op2')]), - (add_7_2, md_7_2, [('output_image', 'op1')]), - (md_7_2, me_7_2, [('output_image', 'op1')]), - (me_7_2, depad_mask, [('output_image', 'op1')]), - (add_gm_wm, depad_segm, [('output_image', 'op1')]), - (relabel_wm, depad_wm, [('output_product_image', 'op1')]), - (relabel_gm, depad_gm, [('output_product_image', 'op1')]), - (sel_labels, depad_csf, [('out_csf', 'op1')]), - (depad_csf, merge_tpms, [('output_image', 'in1')]), - (depad_gm, merge_tpms, [('output_image', 'in2')]), - (depad_wm, merge_tpms, [('output_image', 'in3')]), - (depad_mask, msk_conform, [('output_image', 'in_mask')]), - (msk_conform, copy_xform, [('out', 'out_mask')]), - (depad_segm, copy_xform, [('output_image', 'out_segm')]), - (merge_tpms, copy_xform, [('out', 'out_tpms')]), - (copy_xform, outputnode, [ - ('out_mask', 'out_mask'), - ('out_segm', 'out_segm'), - ('out_tpms', 'out_tpms')]), ]) - return wf - - -def _pop(in_files): - if isinstance(in_files, (list, tuple)): - return in_files[0] - return in_files - - -def _select_labels(in_segm, labels): - from os import getcwd - import numpy as np - import nibabel as nb - from nipype.utils.filemanip import fname_presuffix - - out_files = [] - - cwd = getcwd() - nii = nb.load(in_segm) - for l in labels: - data = (nii.get_data() == l).astype(np.uint8) - newnii = nii.__class__(data, nii.affine, nii.header) - newnii.set_data_dtype('uint8') - out_file = fname_presuffix(in_segm, suffix='_class-%02d' % l, - newpath=cwd) - newnii.to_filename(out_file) - out_files.append(out_file) - return out_files - - -def _conform_mask(in_mask, in_reference): - """Ensures the mask headers make sense and match those of the T1w""" - from pathlib import Path - import nibabel as nb - from nipype.utils.filemanip import fname_presuffix - - ref = nb.load(in_reference) - nii = nb.load(in_mask) - hdr = nii.header.copy() - hdr.set_data_dtype('int16') - hdr.set_slope_inter(1, 0) - - qform, qcode = ref.header.get_qform(coded=True) - if qcode is not None: - hdr.set_qform(qform, int(qcode)) - - sform, scode = ref.header.get_sform(coded=True) - if scode is not None: - hdr.set_sform(sform, int(scode)) - - if '_maths' in in_mask: # Cut the name at first _maths occurrence - ext = ''.join(Path(in_mask).suffixes) - basename = Path(in_mask).name - in_mask = basename.split('_maths')[0] + ext - - out_file = fname_presuffix(in_mask, suffix='_mask', - newpath=str(Path())) - nii.__class__(nii.get_data().astype('int16'), ref.affine, - hdr).to_filename(out_file) - return out_file + module = module_from_spec(spec) + patched_code = compile(patched_source, module.__spec__.origin, 'exec') + exec(patched_code, module.__dict__) + sys.modules[module_name] = module + return module diff --git a/CPAC/aroma/aroma_test.py b/CPAC/aroma/aroma_test.py index 0ca7517702..356a6c3f10 100644 --- a/CPAC/aroma/aroma_test.py +++ b/CPAC/aroma/aroma_test.py @@ -64,7 +64,7 @@ def run_warp_nipype(inputs,output_dir=None,run=True): warp_workflow.connect(t_node,'outputspec.struct',dataSink,'epi2struct') warp_workflow.connect(t_node,'outputspec.anat_func',dataSink,'anat_func') if run == True: - warp_workflow.run(plugin='MultiProc', plugin_args ={'n_procs': num_of_cores}) + warp_workflow.run(plugin='LegacyMultiProc', plugin_args ={'n_procs': num_of_cores}) #outpath = glob.glob(os.path.join(workflow_dir, "EPI_DistCorr","*"))[0] #return outpath else: diff --git a/CPAC/cwas/tests/test_cwas.py b/CPAC/cwas/tests/test_cwas.py index 89166bcfc7..41b8b0aa4a 100755 --- a/CPAC/cwas/tests/test_cwas.py +++ b/CPAC/cwas/tests/test_cwas.py @@ -98,7 +98,7 @@ def run_cwas(self): # Run it! start = time.clock() - c.run(plugin='MultiProc', plugin_args={'n_procs' : 4}) + c.run(plugin='LegacyMultiProc', plugin_args={'n_procs' : 4}) end = time.clock() print("time: %.2gs" % (end-start)) diff --git a/CPAC/distortion_correction/tests/test_distortion_correction.py b/CPAC/distortion_correction/tests/test_distortion_correction.py index b0347e2716..057dc1e35b 100644 --- a/CPAC/distortion_correction/tests/test_distortion_correction.py +++ b/CPAC/distortion_correction/tests/test_distortion_correction.py @@ -73,7 +73,7 @@ def run_warp_nipype(inputs,output_dir=None,run=True): warp_workflow.connect(t_node,'outputspec.struct',dataSink,'epi2struct') warp_workflow.connect(t_node,'outputspec.anat_func',dataSink,'anat_func') if run == True: - warp_workflow.run(plugin='MultiProc', plugin_args ={'n_procs': num_of_cores}) + warp_workflow.run(plugin='LegacyMultiProc', plugin_args ={'n_procs': num_of_cores}) #outpath = glob.glob(os.path.join(workflow_dir, "EPI_DistCorr","*"))[0] #return outpath else: diff --git a/CPAC/info.py b/CPAC/info.py index 723b0ed64f..d048d0e7cb 100644 --- a/CPAC/info.py +++ b/CPAC/info.py @@ -144,14 +144,14 @@ def get_cpac_gitversion(): "lockfile==0.12.2", "matplotlib==3.1.3", "networkx==2.4", - "nibabel==2.3.3", + "nibabel==3.0.1", "nilearn==0.4.1", "nipype==1.5.1", "nose==1.3.7", "numpy==1.16.4", "pandas==0.23.4", "patsy==0.5.0", - "prov==1.5.0", + "prov==1.5.2", "psutil==5.4.6", "pygraphviz==1.3.1", "python-dateutil==2.7.3", diff --git a/CPAC/pipeline/cpac_basc_pipeline.py b/CPAC/pipeline/cpac_basc_pipeline.py index fd76f5791a..3428ed9175 100644 --- a/CPAC/pipeline/cpac_basc_pipeline.py +++ b/CPAC/pipeline/cpac_basc_pipeline.py @@ -46,7 +46,7 @@ def prep_basc_workflow(c, subject_infos): wf.connect(b, 'outputspec.ismap_imgs', ds, 'ismap_imgs') - wf.run(plugin='MultiProc', + wf.run(plugin='LegacyMultiProc', plugin_args={'n_procs': c.numCoresPerSubject}) diff --git a/CPAC/pipeline/cpac_cwas_pipeline.py b/CPAC/pipeline/cpac_cwas_pipeline.py index 8ef371e4ba..9c32287944 100644 --- a/CPAC/pipeline/cpac_cwas_pipeline.py +++ b/CPAC/pipeline/cpac_cwas_pipeline.py @@ -37,7 +37,7 @@ def prep_cwas_workflow(c, subject_infos): wf.connect(cw, 'outputspec.p_map', ds, 'p_map') - wf.run(plugin='MultiProc', + wf.run(plugin='LegacyMultiProc', plugin_args={'n_procs': c.numCoresPerSubject}) diff --git a/CPAC/pipeline/cpac_group_runner.py b/CPAC/pipeline/cpac_group_runner.py index e491a665b1..d300a4e9db 100644 --- a/CPAC/pipeline/cpac_group_runner.py +++ b/CPAC/pipeline/cpac_group_runner.py @@ -1798,7 +1798,7 @@ def run_isc_group(pipeline_dir, out_dir, working_dir, crash_dir, isc_wf.inputs.inputspec.permutations = permutations isc_wf.inputs.inputspec.std = std_filter isc_wf.inputs.inputspec.collapse_subj = False - isc_wf.run(plugin='MultiProc', + isc_wf.run(plugin='LegacyMultiProc', plugin_args={'n_procs': num_cpus}) if isfc: @@ -1828,7 +1828,7 @@ def run_isc_group(pipeline_dir, out_dir, working_dir, crash_dir, isfc_wf.inputs.inputspec.permutations = permutations isfc_wf.inputs.inputspec.std = std_filter isfc_wf.inputs.inputspec.collapse_subj = False - isfc_wf.run(plugin='MultiProc', + isfc_wf.run(plugin='LegacyMultiProc', plugin_args={'n_procs': num_cpus}) diff --git a/CPAC/pipeline/cpac_pipeline.py b/CPAC/pipeline/cpac_pipeline.py index 79095e5a7d..575cd9a7e3 100644 --- a/CPAC/pipeline/cpac_pipeline.py +++ b/CPAC/pipeline/cpac_pipeline.py @@ -137,7 +137,7 @@ # config.enable_debug_mode() def run_workflow(sub_dict, c, run, pipeline_timing_info=None, p_name=None, - plugin='MultiProc', plugin_args=None, test_config=False): + plugin='LegacyMultiProc', plugin_args=None, test_config=False): ''' Function to prepare and, optionally, run the C-PAC workflow @@ -199,7 +199,7 @@ def run_workflow(sub_dict, c, run, pipeline_timing_info=None, p_name=None, sub_mem_gb, num_cores_per_sub, num_ants_cores = check_config_resources(c) if not plugin: - plugin = 'MultiProc' + plugin = 'LegacyMultiProc' if plugin_args: plugin_args['memory_gb'] = sub_mem_gb diff --git a/CPAC/pipeline/cpac_randomise_pipeline.py b/CPAC/pipeline/cpac_randomise_pipeline.py index 777dd38ac6..fb2686b837 100644 --- a/CPAC/pipeline/cpac_randomise_pipeline.py +++ b/CPAC/pipeline/cpac_randomise_pipeline.py @@ -70,7 +70,7 @@ def prep_randomise_workflow(c, subject_infos): wf.connect(rw,'outputspec.pval_file',ds,'pval_file') wf.connect(rw,'outputspec.size_file',ds,'size_file') - wf.run(plugin='MultiProc', + wf.run(plugin='LegacyMultiProc', plugin_args={'n_procs': c.numCoresPerSubject}) return wf diff --git a/CPAC/randomise/test_randomise.py b/CPAC/randomise/test_randomise.py index 43d4826afa..9eeac36258 100644 --- a/CPAC/randomise/test_randomise.py +++ b/CPAC/randomise/test_randomise.py @@ -40,7 +40,7 @@ def run_randomize(inputs,output_dir=None,run=True): randomise_workflow.connect(t_node,'outputspec.tstat_files',dataSink,'tstat_files') randomise_workflow.connect(t_node,'outputspec.t_corrected_p_files',dataSink,'t_corrected_p_files') if run == True: - randomise_workflow.run(plugin='MultiProc', plugin_args ={'n_procs': num_of_cores}) + randomise_workflow.run(plugin='LegacyMultiProc', plugin_args ={'n_procs': num_of_cores}) else: return randomise_workflow, randomise_workflow.base_dir diff --git a/CPAC/registration/registration.py b/CPAC/registration/registration.py index c700cd5e29..5ce4e8009b 100644 --- a/CPAC/registration/registration.py +++ b/CPAC/registration/registration.py @@ -676,7 +676,6 @@ def create_register_func_to_epi(name='register_func_to_epi', reg_option='ANTS', def create_wf_calculate_ants_warp(name='create_wf_calculate_ants_warp', num_threads=1, reg_ants_skull=1): - ''' Calculates the nonlinear ANTS registration transform. This workflow employs the antsRegistration tool: diff --git a/CPAC/registration/utils.py b/CPAC/registration/utils.py index a1b03ed5ba..8e38da03d7 100644 --- a/CPAC/registration/utils.py +++ b/CPAC/registration/utils.py @@ -195,6 +195,9 @@ def hardcoded_reg(moving_brain, reference_brain, moving_skull, if fixed_image_mask is not None: regcmd.append("-x") regcmd.append(str(fixed_image_mask)) + + # DEBUG: Add verbosity + regcmd.append('-v 1') # write out the actual command-line entry for testing/validation later command_file = os.path.join(os.getcwd(), 'command.txt') diff --git a/Dockerfile b/Dockerfile index 46b7333362..a2735e120d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,5 @@ #using neurodebian runtime as parent image -FROM neurodebian:bionic-non-free -MAINTAINER The C-PAC Team +FROM docker.pkg.github.com/fcp-indi/c-pac/neurodebian_bionic-non-free_ants-2.3.4:ants ARG DEBIAN_FRONTEND=noninteractive @@ -150,12 +149,6 @@ RUN mkdir /ants_template && \ mv /tmp/MICCAI2012-Multi-Atlas-Challenge-Data /ants_template/oasis && \ rm -rf /tmp/Oasis.zip /tmp/MICCAI2012-Multi-Atlas-Challenge-Data -# install ANTs -ENV PATH=/usr/lib/ants:$PATH -RUN apt-get install -y ants -# RUN export ANTSPATH=/usr/lib/ants -ENV ANTSPATH=/usr/lib/ants/ - # install ICA-AROMA RUN mkdir -p /opt/ICA-AROMA RUN curl -sL https://github.com/rhr-pruim/ICA-AROMA/archive/v0.4.3-beta.tar.gz | tar -xzC /opt/ICA-AROMA --strip-components 1 @@ -174,6 +167,7 @@ ENV PATH=/usr/local/miniconda/bin:$PATH RUN conda update conda -y && \ conda install -y \ blas \ + cython \ matplotlib==3.1.3 \ networkx==2.4 \ nose==1.3.7 \ @@ -216,8 +210,8 @@ RUN mkdir -p /ndmg_atlases/label && \ COPY dev/docker_data/default_pipeline.yml /cpac_resources/default_pipeline.yml COPY dev/circleci_data/pipe-test_ci.yml /cpac_resources/pipe-test_ci.yml - COPY . /code + RUN pip install -e /code COPY dev/docker_data /code/docker_data diff --git a/cpac_install.sh b/cpac_install.sh index fc1ec320ca..877efc9aad 100755 --- a/cpac_install.sh +++ b/cpac_install.sh @@ -98,11 +98,11 @@ pip_packages=( "future==0.16.0" "INDI-Tools" "lockfile==0.12.2" - "nibabel==2.3.3" + "nibabel==3.0.1" "nilearn==0.4.1" "nipype==1.5.1" "patsy==0.5.0" - "prov==1.5.0" + "prov==1.5.2" "psutil==5.4.6" "pygraphviz==1.3.1" "simplejson==3.15.0" diff --git a/dev/docker_data/install_ants.sh b/dev/docker_data/install_ants.sh new file mode 100755 index 0000000000..d94b49a6fd --- /dev/null +++ b/dev/docker_data/install_ants.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +antsBuildInstructions="https://github.com/ANTsX/ANTs/wiki/Compiling-ANTs-on-Linux-and-Mac-OS" + +echo " +This script will download ANTs, build and install under the current directory. + +Developer tools including compilers, git and cmake must be installed + +If you encounter errors, please see the installation instructions at + + $antsBuildInstructions +" + +if [ $# -ne 1 ] +then + echo " +Takes one commandline argument, the version of ANTs to install. +" +exit 0 +fi + +echo " +Build will proceed in 5 seconds +" + +sleep 5 + +mkdir -p /antsinstall + +workingDir=/antsinstall +cd ${workingDir} +# Clone the repo +git clone https://github.com/ANTsX/ANTs.git + +# If you want to build a particular release, do so here +cd ANTs +git checkout $1 +cd - + +# Number of threads used by make +buildThreads=4 + +# Where to build, should be an empty directory +buildDir=${workingDir}/build +installDir=/usr/lib/ants + +mkdir -p $buildDir $installDir + +cd $buildDir + +cmake ${workingDir}/ANTs -DCMAKE_INSTALL_PREFIX=${installDir} +make 2>&1 | tee build.log +cd ANTS-build +make install 2>&1 | tee install.log diff --git a/dev/docker_data/run.py b/dev/docker_data/run.py index 9c2828bb24..8135b4f7db 100755 --- a/dev/docker_data/run.py +++ b/dev/docker_data/run.py @@ -600,7 +600,7 @@ def resolve_aws_credential(source): CPAC.pipeline.cpac_runner.run( data_config_file, pipeline_config_file, - plugin='MultiProc' if plugin_args['n_procs'] > 1 else 'Linear', + plugin='LegacyMultiProc' if plugin_args['n_procs'] > 1 else 'Linear', plugin_args=plugin_args, tracking=not args.tracking_opt_out, test_config = 1 if args.analysis_level == "test_config" else 0 diff --git a/requirements.txt b/requirements.txt index 3d615f804b..473c08bcbf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,20 +1,20 @@ boto3==1.7.37 click==6.7 configparser==3.7.4 -cython future==0.16.0 git+git://github.com/FCP-INDI/INDI-Tools.git@master lockfile==0.12.2 matplotlib==3.1.3 networkx==2.4 -nibabel==2.3.3 +nibabel==3.0.1 nilearn==0.4.1 nipype==1.5.1 +niworkflows==1.3.2 nose==1.3.7 numpy==1.16.4 pandas==0.23.4 patsy==0.5.0 -prov==1.5.0 +prov==1.5.2 psutil==5.6.6 python-dateutil==2.7.3 pyyaml==5.3 @@ -25,4 +25,4 @@ simplejson==3.15.0 scikit-learn==0.22.1 traits==4.6.0 PyBASC==0.4.5 -pathlib==1.0.1 \ No newline at end of file +pathlib==1.0.1