Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Eddy Motion Correction (EMC) #62

Closed
wants to merge 8 commits into from
Closed

[WIP] Eddy Motion Correction (EMC) #62

wants to merge 8 commits into from

Conversation

dPys
Copy link
Collaborator

@dPys dPys commented Jan 16, 2020

*Per @arokem 's request to PR the WIP, even though tests + docs are not yet included.
*After an initial glance from folks, plan is to close this WIP PR and eventually separate it into several PR's, perhaps per workflow (and associated interfaces/funcs) @oesteban ?
*About 50% of the code is adapted from fmriprep utilities and qsiprep's implementation of 3dShore, & around 50% is new.
*Supports 3dShore EMC for multishell data, but now implements it exclusively in Dipy as opposed to BrainSuite.
*More importantly, can implement Tensor and SparseFascicle model for LOO prediction on single-shell data!
*Registration routines currently use ANTs, but could probably be adapted to use to Dipy instead. In that case, they would most likely require careful retuning.
*Pictures to come, but initial visual checks seem to indicate at least decent quality performance (perhaps even reasonably good performance) as a starting benchmark.

@pull-assistant
Copy link

pull-assistant bot commented Jan 16, 2020

Score: 0.81

Best reviewed: commit by commit


Optimal code review plan (4 warnings)

     [ENH] Add API to vectors for reorienting bvecs from rasb .tsv and affi...

     [ENH] Add API to vectors for reorienting bvecs from rasb .tsv and affi...

Merge remote-tracking branch 'upstream/master'

dmriprep/interfaces/images.py 57% changes removed in Write out final nois...

Add HMC dev from sprint 2020

.../config/emc_coarse_Affine.json 96% changes removed in Write out final nois...

.../config/emc_precise_Rigid.json 96% changes removed in Write out final nois...

dmriprep/workflows/dwi/emc.py 68% changes removed in Write out final nois...

...p/config/emc_coarse_Rigid.json 96% changes removed in Write out final nois...

...config/emc_precise_Affine.json 96% changes removed in Write out final nois...

dmriprep/interfaces/vectors.py 65% changes removed in Write out final nois...

dmriprep/utils/vectors.py 46% changes removed in Write out final nois...

Write out final noise-free images to 4d file

dmriprep/interfaces/vectors.py 45% changes removed in Write out final nois...

Write out final noise-free images to 4d file

dmriprep/utils/register.py 61% changes removed in Merge branch 'HMC' o...

     Merge branch 'HMC' of https://github.com/dPys/dmriprep-1 into HMC

     mend

Powered by Pull Assistant. Last update 5f51f9d ... 2b34811. Read the comment docs.

@pep8speaks
Copy link

pep8speaks commented Jan 16, 2020

Hello @dPys, Thank you for updating!

Line 2:1: F401 'os' imported but unused

Line 209:16: W292 no newline at end of file

Line 196:41: W292 no newline at end of file

To test for issues locally, pip install flake8 and then run flake8 dmriprep.

Comment last updated at 2020-03-24 17:24:31 UTC

@codecov
Copy link

codecov bot commented Jan 16, 2020

Codecov Report

Merging #62 into master will decrease coverage by 10.19%.
The diff coverage is 32.17%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #62      +/-   ##
==========================================
- Coverage   52.37%   42.17%   -10.2%     
==========================================
  Files          16       21       +5     
  Lines         907     1648     +741     
  Branches      114      172      +58     
==========================================
+ Hits          475      695     +220     
- Misses        431      952     +521     
  Partials        1        1
Impacted Files Coverage Δ
dmriprep/utils/viz.py 10.52% <10.52%> (ø)
dmriprep/utils/images.py 12.74% <12.74%> (ø)
dmriprep/workflows/dwi/emc.py 12.78% <12.78%> (ø)
dmriprep/utils/bids.py 17.58% <23.07%> (+2.19%) ⬆️
dmriprep/utils/register.py 35.55% <35.55%> (ø)
dmriprep/interfaces/images.py 44.3% <40.78%> (+3.13%) ⬆️
dmriprep/utils/vectors.py 80.44% <41.66%> (-19.56%) ⬇️
dmriprep/interfaces/reports.py 53.33% <44.89%> (-7.39%) ⬇️
dmriprep/workflows/dwi/base.py 42.1% <50%> (+0.43%) ⬆️
dmriprep/interfaces/register.py 66.07% <66.07%> (ø)
... and 7 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 127a65d...2b34811. Read the comment docs.

@dPys dPys force-pushed the HMC branch 2 times, most recently from dab9f38 to 9045994 Compare January 16, 2020 17:35
@dPys dPys changed the title [WIP] Head Motion Correction [WIP] Eddy Motion Correction (EMC) Jan 16, 2020
Copy link
Member

@oesteban oesteban left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a quick pass trying to identify what elements can be split out from this into bite-sized PRs

The core of this contribution is within the dmriprep/workflow/dwi/emc.py file, and we will need to think about unit tests of those workflows.

"transform_parameters": [ [ 0.2 ], [ 0.15 ] ],
"convergence_threshold": [ 1e-06, 1e-06 ],
"convergence_window_size": [ 20, 20 ],
"metric": [ "Mattes", "Mattes" ],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this choice based on speed?

Wouldn't it make more sense some cross-correlation based measure? MI is just going to exacerbate the problems you mentioned about the different content of each direction (pinging @arokem and @mattcieslak).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree @oesteban -- cross-corr seems like it would be preferable here. Curious what @mattcieslak thinks?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember, the fixed (model-estimated) images here will have the same contrast as the moving images so most metrics would be ok here. MI is much faster than CC, so any benefit of CC would be outweighed by its extra computation time. Also, this is only the coarse iteration.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, but MI has much flatter gradient - I'm going to make up a number here, but 1 CC iteration is as effective as 10 MI iterations.

Comment on lines 18 to 139


class DerivativesDataSink(SimpleInterface):
"""
Saves the `in_file` into a BIDS-Derivatives folder provided
by `base_directory`, given the input reference `source_file`.
>>> from pathlib import Path
>>> import tempfile
>>> from dmriprep.utils.bids import collect_data
>>> tmpdir = Path(tempfile.mkdtemp())
>>> tmpfile = tmpdir / 'a_temp_file.nii.gz'
>>> tmpfile.open('w').close() # "touch" the file
>>> dsink = DerivativesDataSink(base_directory=str(tmpdir))
>>> dsink.inputs.in_file = str(tmpfile)
>>> dsink.inputs.source_file = collect_data('ds114', '01')[0]['t1w'][0]
>>> dsink.inputs.keep_dtype = True
>>> dsink.inputs.suffix = 'target-mni'
>>> res = dsink.run()
>>> res.outputs.out_file # doctest: +ELLIPSIS
'.../dmriprep/sub-01/ses-retest/anat/sub-01_ses-retest_target-mni_T1w.nii.gz'
>>> bids_dir = tmpdir / 'bidsroot' / 'sub-02' / 'ses-noanat' / 'func'
>>> bids_dir.mkdir(parents=True, exist_ok=True)
>>> tricky_source = bids_dir / 'sub-02_ses-noanat_task-rest_run-01_bold.nii.gz'
>>> tricky_source.open('w').close()
>>> dsink = DerivativesDataSink(base_directory=str(tmpdir))
>>> dsink.inputs.in_file = str(tmpfile)
>>> dsink.inputs.source_file = str(tricky_source)
>>> dsink.inputs.keep_dtype = True
>>> dsink.inputs.desc = 'preproc'
>>> res = dsink.run()
>>> res.outputs.out_file # doctest: +ELLIPSIS
'.../dmriprep/sub-02/ses-noanat/func/sub-02_ses-noanat_task-rest_run-01_\
desc-preproc_bold.nii.gz'
"""
input_spec = DerivativesDataSinkInputSpec
output_spec = DerivativesDataSinkOutputSpec
out_path_base = "dmriprep"
_always_run = True

def __init__(self, out_path_base=None, **inputs):
super(DerivativesDataSink, self).__init__(**inputs)
self._results['out_file'] = []
if out_path_base:
self.out_path_base = out_path_base

def _run_interface(self, runtime):
src_fname, _ = _splitext(self.inputs.source_file)
src_fname, dtype = src_fname.rsplit('_', 1)
_, ext = _splitext(self.inputs.in_file[0])
if self.inputs.compress is True and not ext.endswith('.gz'):
ext += '.gz'
elif self.inputs.compress is False and ext.endswith('.gz'):
ext = ext[:-3]

m = BIDS_NAME.search(src_fname)

mod = os.path.basename(os.path.dirname(self.inputs.source_file))

base_directory = runtime.cwd
if isdefined(self.inputs.base_directory):
base_directory = str(self.inputs.base_directory)

out_path = '{}/{subject_id}'.format(self.out_path_base, **m.groupdict())
if m.groupdict().get('session_id') is not None:
out_path += '/{session_id}'.format(**m.groupdict())
out_path += '/{}'.format(mod)

out_path = os.path.join(base_directory, out_path)

os.makedirs(out_path, exist_ok=True)

if isdefined(self.inputs.prefix):
base_fname = os.path.join(out_path, self.inputs.prefix)
else:
base_fname = os.path.join(out_path, src_fname)

formatstr = '{bname}{space}{desc}{suffix}{dtype}{ext}'
if len(self.inputs.in_file) > 1 and not isdefined(self.inputs.extra_values):
formatstr = '{bname}{space}{desc}{suffix}{i:04d}{dtype}{ext}'

space = '_space-{}'.format(self.inputs.space) if self.inputs.space else ''
desc = '_desc-{}'.format(self.inputs.desc) if self.inputs.desc else ''
suffix = '_{}'.format(self.inputs.suffix) if self.inputs.suffix else ''
dtype = '' if not self.inputs.keep_dtype else ('_%s' % dtype)

self._results['compression'] = []
for i, fname in enumerate(self.inputs.in_file):
out_file = formatstr.format(
bname=base_fname,
space=space,
desc=desc,
suffix=suffix,
i=i,
dtype=dtype,
ext=ext)
if isdefined(self.inputs.extra_values):
out_file = out_file.format(extra_value=self.inputs.extra_values[i])
self._results['out_file'].append(out_file)
self._results['compression'].append(_copy_any(fname, out_file))
return runtime
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a DerivativesDataSink:

class DerivativesDataSink(_DDS):
"""A patched DataSink."""
out_path_base = 'dmriprep'

Unless there is some new functionality here, this can go away.

Copy link
Collaborator Author

@dPys dPys Jan 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep! (didn't see that it already lived in init.py initially.

class _RescaleB0InputSpec(BaseInterfaceInputSpec):
in_file = File(exists=True, mandatory=True, desc='b0s file')
mask_file = File(exists=True, mandatory=True, desc='mask file')


class _RescaleB0OutputSpec(TraitedSpec):
out_ref = File(exists=True, desc='One average b0 file')
out_ref = File(exists=True, desc='One median b0 file')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid changes out of scope. This one should've been picked up during the review of #25 - that said, I think it is better "average" here, as it needs to be informative.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good.

Comment on lines 132 to 149
class ImageMath(CommandLine):
input_spec = ImageMathInputSpec
output_spec = ImageMathOutputSpec
_cmd = 'ImageMath'

def _gen_filename(self, name):
if name == 'out_file':
output = self.inputs.out_file
if not isdefined(output):
_, fname, ext = split_filename(self.inputs.in_file)
output = fname + "_" + self.inputs.operation + ext
return output
return None

def _list_outputs(self):
outputs = self.output_spec().get()
outputs['out_file'] = os.path.abspath(self._gen_filename('out_file'))
return outputs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look at that! https://github.com/poldracklab/niworkflows/blob/4e9181fd31f3a1b216b5edcf040bd5533c400e9d/niworkflows/interfaces/ants.py#L11-L77

Please use ImageMath from niworkflows (and PR against niworkflows if some functionality is missing)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the reason for redefining it outside of niworkflows is that we need it to be able to take an explicit secondary argument and file. In other words, as defined here, it is actually quite different. But we could monkey-patch it?

Copy link
Collaborator

@josephmje josephmje Jan 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can import the niworkflows version and then add to it (similar to the DerivativesDataSink and BIDSDataGrabberOutputSpec examples here: https://github.com/nipreps/dmriprep/blob/master/dmriprep/interfaces/__init__.py#L13-L20)

Comment on lines 112 to 157
class ReorientVectors(SimpleInterface):
"""
Reorient Vectors
Example
-------
>>> os.chdir(tmpdir)
>>> oldrasb = str(data_dir / 'dwi.tsv')
>>> oldrasb_mat = np.loadtxt(str(data_dir / 'dwi.tsv'), skiprows=1)
>>> # The simple case: all affines are identity
>>> affine_list = np.zeros((len(oldrasb_mat[:, 3][oldrasb_mat[:, 3] != 0]), 4, 4))
>>> for i in range(4):
>>> affine_list[:, i, i] = 1
>>> reor_vecs = ReorientVectors()
>>> reor_vecs = ReorientVectors()
>>> reor_vecs.inputs.affines = affine_list
>>> reor_vecs.inputs.in_rasb = oldrasb
>>> res = reor_vecs.run()
>>> out_rasb = res.outputs.out_rasb
>>> out_rasb_mat = np.loadtxt(out_rasb, skiprows=1)
>>> npt.assert_equal(oldrasb_mat, out_rasb_mat)
True
"""

input_spec = _ReorientVectorsInputSpec
output_spec = _ReorientVectorsOutputSpec

def _run_interface(self, runtime):
from nipype.utils.filemanip import fname_presuffix
reor_table = reorient_vecs_from_ras_b(
rasb_file=self.inputs.rasb_file,
affines=self.inputs.affines,
b0_threshold=self.inputs.b0_threshold,
)

cwd = Path(runtime.cwd).absolute()
reor_rasb_file = fname_presuffix(
self.inputs.rasb_file, use_ext=False, suffix='_reoriented.tsv',
newpath=str(cwd))
np.savetxt(str(reor_rasb_file), reor_table,
delimiter='\t', header='\t'.join('RASB'),
fmt=['%.8f'] * 3 + ['%g'])

self._results['out_rasb'] = reor_rasb_file
return runtime
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this part of #49 ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but with added functionality. All future changes for this interface will be redirected to the #49 PR

Comment on lines +165 to +209
def splitext(fname):
"""Splits filename and extension (.gz safe)
>>> splitext('some/file.nii.gz')
('file', '.nii.gz')
>>> splitext('some/other/file.nii')
('file', '.nii')
>>> splitext('otherext.tar.gz')
('otherext', '.tar.gz')
>>> splitext('text.txt')
('text', '.txt')
"""
from pathlib import Path
basename = str(Path(fname).name)
stem = Path(basename.rstrip('.gz')).stem
return stem, basename[len(stem):]


def _copy_any(src, dst):
import os
import gzip
from shutil import copyfileobj
from nipype.utils.filemanip import copyfile

src_isgz = src.endswith('.gz')
dst_isgz = dst.endswith('.gz')
if not src_isgz and not dst_isgz:
copyfile(src, dst, copy=True, use_hardlink=True)
return False # Make sure we do not reuse the hardlink later

# Unlink target (should not exist)
if os.path.exists(dst):
os.unlink(dst)

src_open = gzip.open if src_isgz else open
with src_open(src, 'rb') as f_in:
with open(dst, 'wb') as f_out:
if dst_isgz:
# Remove FNAME header from gzip (poldracklab/fmriprep#1480)
gz_out = gzip.GzipFile('', 'wb', 9, f_out, 0.)
copyfileobj(f_in, gz_out)
gz_out.close()
else:
copyfileobj(f_in, f_out)

return True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comes from nipype, why not just import them?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't see these functions in nipype, but maybe I missed them somewhere?

@@ -0,0 +1,113 @@
import numpy as np
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new file makes a lot of sense, especially if we can come up with unit tests for all these helper functions.

Could you send a separate PR to split the currently existing functions (extract_b0 and rescale_b0) out to this file so they don't show up in the diff?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

dmriprep/utils/vectors.py Outdated Show resolved Hide resolved
@@ -375,3 +375,109 @@ def bvecs2ras(affine, bvecs, norm=True, bvec_norm_epsilon=0.2):
rotated_bvecs[~b0s] /= norms_bvecs[~b0s, np.newaxis]
rotated_bvecs[b0s] = np.zeros(3)
return rotated_bvecs


def reorient_vecs_from_ras_b(rasb_file, affines, b0_threshold=B0_THRESHOLD):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would try to keep the b0 threshold encoded in the vector representation object, meaning, no need to keep dragging it all around. Please remove.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I would incorporate the reorientation into the vectors object. Will comment on this at #49. We definitely should push that one first.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense

dmriprep/utils/vectors.py Outdated Show resolved Hide resolved
@dPys
Copy link
Collaborator Author

dPys commented Jan 18, 2020

Thank you @oesteban for all of your helpful feedback. I will be out of town next week so won't be able to work a ton on this after tomorrow. But will do my best to keep the dev of EMC moving...

In the meantime, @arokem -- anything that we can think of to speed up the way that sfm predicts signal (i.e. from a given vector coordinate) would be helpful. If it can't be the ElasticNet itself, then we might have to get creative to make it viable with LOO here. Please let me know if there's anything that can be done.

More soon.
@dPys

@mattcieslak
Copy link

@arokem @dPys one thing that made shoreline reasonably fast with 3dSHORE is that I used the L2 (with LShore and NShore) fit instead of L1 or elasticnet. This reduces the problem to a couple dot products and still resulted in very good signal prediction. Would this work with a sfm?

@arokem
Copy link
Collaborator

arokem commented Jan 18, 2020 via email

Rename to EMC (Eddy Motion Correction) and fix several workflow bugs
@dPys dPys force-pushed the HMC branch 2 times, most recently from cf5d7c2 to 8b9c73e Compare February 4, 2020 17:00
@dPys dPys added the effort: high This task will probably require many person-hours label Feb 4, 2020
@dPys dPys self-assigned this Feb 4, 2020
@dPys
Copy link
Collaborator Author

dPys commented Feb 4, 2020

@arokem @oesteban @mattcieslak -- The EMC WIP should now run from start to finish. I've also gone ahead and replaced every ANTs reg call with a dipy / pure-python equivalent. These new reg routines are based on @arokem 's api.py file, but have been modified to read and write to files from disk. The routines have also been more or less tuned to the original coarse/precise rigid/affine reg parameters used with the ANTs calls.

Another note--

With these further upgrades, I'm also seeing a dramatic speedup for EMC as a whole. To improve efficiency, I initialized the signal prediction step using the tensor model on the first iteration, which allows us to get a really good coarse transformation to start. The subsequent iteration(s), used for precise transforms, are then performed with the more computationally expensive sfm model. At least from visual inspection, the impact of SFM for predicting signal with single-shell data is pretty excellent. A note: sfm is now incorporated with a ridge/L2 solver, which made prediction much faster.

To get a sense of EMC's effectiveness at this point, here is a before-and-after:
Screen Shot 2020-02-04 at 11 19 45 AM
Screen Shot 2020-02-04 at 11 19 58 AM
Not bad as a start, and I think we can improve it further through a number of additional steps:

  1. Include more iterations of signal prediction (above used only 1 of sfm). Also, when we are actually able to benchmark emc, we could think about tinkering a bit with the alpha hyperparameter since 0.001 might not be optimal for Ridge even if it was for the ElasticNet.
  2. Include a lightweight denoising step, within emc only, that we use solely to improve registration quality (i.e. to generate even more precise affine transforms that can later be applied to the non-denoised dwi).
  3. Support for multiple runs (i.e. using multiple runs to inform the sfm prediction, even if preprocessing ultimately occurs on each dwi run separately).
  4. Mean imputation of dropout slices (@mattcieslak -- I noticed that you've already been working on something like this in qsiprep?)
  5. I like the idea of keeping SDC separate from EMC (ideally preceding it), but it might be worth creating an input to emc that optionally accepts the SDC transforms for each volume, so that we can combine them with the emc transforms to minimize the amount of resampling that occurs. We should also start thinking about how exactly SD map might "provide additional information about the EC distortions and movements" (Andersson and Sotiropoulos, 2016).

If anyone wish to try running this on your own from my fork, here's how you could do it (note that it assumes a rough median/mean b0 template has already been created and can be used as input):

from dmriprep.workflows.dwi.emc import init_emc_wf
from pathlib import Path
import numpy as np
import nibabel as nib
import nipype.pipeline.engine as pe
from nipype.interfaces import utility as niu
import os.path as op

data_dir = Path('/Users/derekpisner/Downloads/test_subs/SWU4/sub-0025629/ses-1/dwi')

wf_emc = pe.Workflow(name='emc_correction')

inputnode = pe.Node(niu.IdentityInterface(fields=['dwi_files', 'in_bval', 'in_bvec', 'b0_template']),
    name='inputnode')

inputnode.inputs.dwi_file = str(data_dir / 'sub-0025629_ses-1_dwi.nii.gz')
inputnode.inputs.in_bval = str(data_dir / 'sub-0025629_ses-1_dwi.bval')
inputnode.inputs.in_bvec = str(data_dir / 'sub-0025629_ses-1_dwi.bvec')
inputnode.inputs.b0_template = str(data_dir / 'sub-0025629_b0_template.nii.gz')

emc_wf_node = init_emc_wf('emc_wf')
    
wf_emc.connect([
    (inputnode, emc_wf_node, [('dwi_file', 'meta_inputnode.dwi_file'),
                              ('in_bval', 'meta_inputnode.in_bval'),
                              ('in_bvec', 'meta_inputnode.in_bvec'),
                              ('b0_template', 'meta_inputnode.b0_template')])
])

cfg = dict(execution={'stop_on_first_crash': False, 'parameterize_dirs': True,
'crashfile_format': 'txt', 'remove_unnecessary_outputs': False, 'hash_method': 'content', 'poll_sleep_duration': 0})
for key in cfg.keys():
    for setting, value in cfg[key].items():
        wf_emc.config[key][setting] = value

wf_emc.base_dir = str(data_dir)
res = wf_emc.run(plugin='MultiProc')

Now, to actually PR this beast, I propose the following six separate PR's (@oesteban -- please confirm):

  1. Reorient vectors interface (FYI: now relies on a method that has been integrated into the DiffusionGradientTable class)
  2. Registration routines (currently included as a separate module register.py in both utils and interfaces)
  3. Signal prediction interface
  4. Miscellaneous image-handling utilities and interfaces (i.e. utils/images.py and interfaces/images.py)
  5. Motion reports interfaces + figures/viz
  6. EMC workflows (i.e. emc.py)

@oesteban
Copy link
Member

Taking up from where @dPys left off:

  1. Reorient vectors interface (FYI: now relies on a method that has been integrated into the DiffusionGradientTable class)

I think we have pretty much all we need already merged. Will look back at this if something is missing.

  1. Registration routines (currently included as a separate module register.py in both utils and interfaces)

@arokem is working on this.

  1. Signal prediction interface

I'll extract the code from this PR and separate on to a new one.

  1. Miscellaneous image-handling utilities and interfaces (i.e. utils/images.py and interfaces/images.py)

I think this is already done in part of in full by @josephmje. As for 1, will come back to this PR if anything is needed.

  1. Motion reports interfaces + figures/viz

Let's leave this out for now, this is being worked out on a different repo.

  1. EMC workflows (i.e. emc.py)

Will extract this after 3 is merged.

@oesteban
Copy link
Member

Okay, pushed Derek's branch (and his commits) to https://github.com/nipreps/dmriprep/tree/feat/wip/hmc-dpys, just to be sure we don't lose any lines.

@oesteban
Copy link
Member

Closing for clarity.

@oesteban oesteban closed this Apr 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
effort: high This task will probably require many person-hours
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants