From 3d05939b4cbc499a9b76df5a716768387cee11b1 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Fri, 3 Feb 2023 13:01:21 +0100 Subject: [PATCH 1/2] add eddy interface --- pydra/tasks/fsl/epi/__init__.py | 0 pydra/tasks/fsl/epi/eddy.py | 481 ++++++++++++++++++++++++++++++++ 2 files changed, 481 insertions(+) create mode 100644 pydra/tasks/fsl/epi/__init__.py create mode 100644 pydra/tasks/fsl/epi/eddy.py diff --git a/pydra/tasks/fsl/epi/__init__.py b/pydra/tasks/fsl/epi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pydra/tasks/fsl/epi/eddy.py b/pydra/tasks/fsl/epi/eddy.py new file mode 100644 index 0000000..b2ca99e --- /dev/null +++ b/pydra/tasks/fsl/epi/eddy.py @@ -0,0 +1,481 @@ +from pydra.engine import specs +from pydra import ShellCommandTask + +input_fields = [ + ( + "in_acqp", + str, + { + "help_string": "File containing acquisition parameters.", + "argstr": "--acqp={in_acqp}", + "mandatory": True, + }, + ), + ( + "in_bval", + str, + { + "help_string": "File containing the b-values for all volumes in –imain.", + "argstr": "--bvals={in_bval}", + "mandatory": True, + }, + ), + ( + "in_bvec", + str, + { + "help_string": "File containing the b-vectors for all volumes in –imain.", + "argstr": "--bvecs={in_bvec}", + "mandatory": True, + }, + ), + ( + "in_file", + str, + { + "help_string": "File containing all the images to estimate distortions for.", + "argstr": "--imain={in_file}", + "mandatory": True, + }, + ), + ( + "in_index", + str, + { + "help_string": "File containing indices for all volumes in –imain into –acqp and –topup.", + "argstr": "--index={in_index}", + "mandatory": True, + }, + ), + ( + "in_mask", + str, + { + "help_string": "Mask to indicate brain.", + "argstr": "--mask={in_mask}", + "mandatory": True, + }, + ), + ( + "cnr_maps", + bool, + { + "help_string": "Output CNR-Maps.", + "argstr": "--cnr_maps", + }, + ), + ( + "dont_peas", + bool, + { + "help_string": "Do NOT perform a post-eddy alignment of shells.", + "argstr": "--dont_peas", + }, + ), + ( + "dont_sep_offs_move", + bool, + { + "help_string": "Do NOT attempt to separate field offset from subject movement.", + "argstr": "--dont_sep_offs_move", + }, + ), + ( + "estimate_move_by_susceptibility", + bool, + { + "help_string": "Estimate how susceptibility field changes with subject movement.", + "argstr": "--estimate_move_by_susceptibility", + }, + ), + ( + "fep", + bool, + { + "help_string": "Fill empty planes in x- or y-directions.", + "argstr": "--fep", + }, + ), + ( + "field", + specs.File, + { + "help_string": "Non-topup derived fieldmap scaled in Hz.", + "argstr": "--field={field}", + }, + ), + ( + "field_mat", + specs.File, + { + "help_string": ( + "Matrix specifying the relative positions of the fieldmap, –field, " + "and the first volume of the input file, –imain." + ), + "argstr": "--field_mat={field_mat}", + }, + ), + ( + "flm", # (‘quadratic’ or ‘linear’ or ‘cubic’) + str, + { + "help_string": "First level EC model.", + "argstr": "--flm={flm}", + }, + ), + ( + "fudge_factor", + float, + { + "help_string": "Fudge factor for hyperparameter error variance.", + "argstr": "--ff={fudge_factor}", + }, + ), + ( + "fwhm", + float, + { + "help_string": "FWHM for conditioning filter when estimating the parameters.", + "argstr": "--fwhm={fwhm}", + }, + ), + ( + "in_topup_fieldcoef", + specs.File, + { + "help_string": "Topup results file containing the field coefficients.", + "argstr": "--topup={in_topup_fieldcoef}", + "requires": [ + "in_topup_movpar", + ], + }, + ), + ( + "in_topup_movpar", + specs.File, + { + "help_string": "Topup results file containing the movement parameters (movpar.txt).", + "requires": [ + "in_topup_fieldcoef", + ], + }, + ), + ( + "initrand", + bool, + { + "help_string": "Resets rand for when selecting voxels.", + "argstr": "--initrand", + }, + ), + ( + "interp", # (‘spline’ or ‘trilinear’) + str, + { + "help_string": "Interpolation model for estimation step.", + "argstr": "--interp=%s", + }, + ), + ( + "is_shelled", + bool, + { + "help_string": ( + "Override internal check to ensure that date are " + "acquired on a set of b-value shells." + ), + "argstr": "--data_is_shelled", + }, + ), + ( + "json", + specs.File, + { + "help_string": "Name of .json text file with information about slice timing.", + "argstr": "--json={json}", + "xor": ( + "slice_order", + ), + "requires": [ + "mporder", + ], + }, + ), + ( + "mbs_ksp", + int, + { + "help_string": "Knot-spacing for MBS field estimation.", + "argstr": "--mbs_ksp={mbs_ksp}mm", + "requires": [ + "estimate_move_by_susceptibility", + ], + }, + ), + ( + "mbs_lambda", + int, + { + "help_string": "Weighting of regularisation for MBS estimation.", + "argstr": "--mbs_lambda={mbs_lambda}", + "requires": [ + "estimate_move_by_susceptibility", + ], + }, + ), + ( + "mbs_niter", + int, + { + "help_string": "Number of iterations for MBS estimation.", + "argstr": "--mbs_niter={mbs_niter}", + "requires": [ + "estimate_move_by_susceptibility", + ], + }, + ), + ( + "method", # (‘jac’ or ‘lsr’) + str, + { + "help_string": "Final resampling method (jacobian/least squares).", + "argstr": "--resamp={method}", + }, + ), + ( + "mporder", + int, + { + "help_string": "Order of slice-to-vol movement model.", + "argstr": "--mporder={mporder}", + "requires": [ + "use_cuda", + ], + }, + ), + ( + "multiband_factor", + int, + { + "help_string": "Multi-band factor.", + "argstr": "--mb={multiband_factor}", + }, + ), + ( + "multiband_offset", # (0 or 1 or -1) + int, + { + "help_string": "Multi-band offset (-1 if bottom slice removed, 1 if top slice removed.", + "argstr": "--mb_offs={multiband_offset}", + "requires": [ + "multiband_factor", + ], + }, + ), + ( + "niter", + int, + { + "help_string": "Number of iterations.", + "argstr": "--niter={niter}", + }, + ), + ( + "num_threads", + int, + { + "help_string": "Number of openmp threads to use.", + }, + ), + ( + "nvoxhp", + int, + { + "help_string": "Number of voxels used to estimate the hyperparameters.", + "argstr": "--nvoxhp={nvoxhp}", + }, + ), + ( + "out_base", + str, + { + "help_string": "Basename for output image.", + "argstr": "--out={out_base}", + }, + ), + ( + "outlier_nstd", + int, + { + "help_string": "Number of std off to qualify as outlier.", + "argstr": "--ol_nstd", + "requires": [ + "repol", + ], + }, + ), + ( + "outlier_nvox", + int, + { + "help_string": "Min number of voxels in a slice for inclusion in outlier detection.", + "argstr": "--ol_nvox", + "requires": [ + "repol", + ], + }, + ), + ( + "outlier_pos", + bool, + { + "help_string": "Consider both positive and negative outliers if set.", + "argstr": "--ol_pos", + "requires": [ + "repol", + ], + }, + ), + ( + "outlier_sqr", + bool, + { + "help_string": "Consider outliers among sums-of-squared differences if set.", + "argstr": "--ol_sqr", + "requires": [ + "repol", + ], + }, + ), + ( + "outlier_type", # (‘sw’ or ‘gw’ or ‘both’) + str, + { + "help_string": "Type of outliers, slicewise (sw), groupwise (gw) or both (both).", + "argstr": "--ol_type", + "requires": [ + "repol", + ], + }, + ), + ( + "output_type", # (‘NIFTI’ or ‘NIFTI_PAIR’ or ‘NIFTI_GZ’ or ‘NIFTI_PAIR_GZ’) + str, + { + "help_string": "FSL output type.", + }, + ), + ( + "repol", + bool, + { + "help_string": "Detect and replace outlier slices.", + "argstr": "--repol", + }, + ), + ( + "residuals", + bool, + { + "help_string": "Output Residuals.", + "argstr": "--residuals", + }, + ), + ( + "session", + specs.File, + { + "help_string": "File containing session indices for all volumes in –imain.", + "argstr": "--session={session}", + }, + ), + ( + "slice2vol_interp", # (‘trilinear’ or ‘spline’) + str, + { + "help_string": "Slice-to-vol interpolation model for estimation step.", + "argstr": "--s2v_interp={slice2vol_interp", + "requires": [ + "mporder", + ], + }, + ), + ( + "slice2vol_lambda", + int, + { + "help_string": "Regularisation weight for slice-to-vol movement (reasonable range 1-10).", + "argstr": "--s2v_lambda={slice2vol_lambda}", + "requires": [ + "mporder", + ], + }, + ), + ( + "slice2vol_niter", + int, + { + "help_string": "Number of iterations for slice-to-vol.", + "argstr": "--s2v_niter={slice2vol_niter}", + "requires": [ + "mporder", + ], + }, + ), + ( + "slice_order", + specs.File, + { + "help_string": "Name of text file completely specifying slice/group acquisition.", + "argstr": "--slspec={slice_order}", + "xor": ( + "json", + ), + "requires": [ + "mporder", + ], + }, + ), + ( + "slm", # (‘none’ or ‘linear’ or ‘quadratic’) + str, + { + "help_string": "Second level EC model.", + "argstr": "--slm={slm}", + }, + ), + ( + "use_cuda", + bool, + { + "help_string": "Run eddy using cuda gpu.", + }, + ), +] + +eddy_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) + +output_fields = [] + +eddy_output_spec = specs.SpecInfo( + name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) +) + + +class Eddy(ShellCommandTask): + """ + Example + ------- +>>> eddy = Eddy() +>>> eddy.inputs.in_file = "epi.nii" +>>> eddy.inputs.in_mask = "epi_mask.nii" +>>> eddy.inputs.in_index = "epi_index.txt" +>>> eddy.inputs.in_acqp = "epi_acqp.txt" +>>> eddy.inputs.in_bvec = "bvecs.scheme" +>>> eddy.inputs.in_bval = "bvals.scheme" +>>> eddy.cmdline + ‘eddy_openmp –flm=quadratic –ff=10.0 –acqp=epi_acqp.txt –bvals=bvals.scheme –bvecs=bvecs.scheme –imain=epi.nii –index=epi_index.txt –mask=epi_mask.nii –interp=spline –resamp=jac –niter=5 –nvoxhp=1000 –out=…/eddy_corrected –slm=none’ + """ + input_spec = eddy_input_spec + output_spec = eddy_output_spec + executable = "eddy_openmp" From 881747494605de6420b68bfb1647b38a194f1580 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 3 Feb 2023 12:04:47 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pydra/tasks/fsl/epi/eddy.py | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/pydra/tasks/fsl/epi/eddy.py b/pydra/tasks/fsl/epi/eddy.py index b2ca99e..769476d 100644 --- a/pydra/tasks/fsl/epi/eddy.py +++ b/pydra/tasks/fsl/epi/eddy.py @@ -193,9 +193,7 @@ { "help_string": "Name of .json text file with information about slice timing.", "argstr": "--json={json}", - "xor": ( - "slice_order", - ), + "xor": ("slice_order",), "requires": [ "mporder", ], @@ -428,9 +426,7 @@ { "help_string": "Name of text file completely specifying slice/group acquisition.", "argstr": "--slspec={slice_order}", - "xor": ( - "json", - ), + "xor": ("json",), "requires": [ "mporder", ], @@ -457,25 +453,24 @@ output_fields = [] -eddy_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) +eddy_output_spec = specs.SpecInfo(name="Output", fields=output_fields, bases=(specs.ShellOutSpec,)) class Eddy(ShellCommandTask): """ - Example - ------- ->>> eddy = Eddy() ->>> eddy.inputs.in_file = "epi.nii" ->>> eddy.inputs.in_mask = "epi_mask.nii" ->>> eddy.inputs.in_index = "epi_index.txt" ->>> eddy.inputs.in_acqp = "epi_acqp.txt" ->>> eddy.inputs.in_bvec = "bvecs.scheme" ->>> eddy.inputs.in_bval = "bvals.scheme" ->>> eddy.cmdline - ‘eddy_openmp –flm=quadratic –ff=10.0 –acqp=epi_acqp.txt –bvals=bvals.scheme –bvecs=bvecs.scheme –imain=epi.nii –index=epi_index.txt –mask=epi_mask.nii –interp=spline –resamp=jac –niter=5 –nvoxhp=1000 –out=…/eddy_corrected –slm=none’ + Example + ------- + >>> eddy = Eddy() + >>> eddy.inputs.in_file = "epi.nii" + >>> eddy.inputs.in_mask = "epi_mask.nii" + >>> eddy.inputs.in_index = "epi_index.txt" + >>> eddy.inputs.in_acqp = "epi_acqp.txt" + >>> eddy.inputs.in_bvec = "bvecs.scheme" + >>> eddy.inputs.in_bval = "bvals.scheme" + >>> eddy.cmdline + ‘eddy_openmp –flm=quadratic –ff=10.0 –acqp=epi_acqp.txt –bvals=bvals.scheme –bvecs=bvecs.scheme –imain=epi.nii –index=epi_index.txt –mask=epi_mask.nii –interp=spline –resamp=jac –niter=5 –nvoxhp=1000 –out=…/eddy_corrected –slm=none’ """ + input_spec = eddy_input_spec output_spec = eddy_output_spec executable = "eddy_openmp"