Using nifreeze on dwi data

Summary of what happened:

I’m trying to use nifreeze to do eddy motion correction on a DWI data set. The documentation is a bit sparse so there’s a lot of guesswork involved - if anyone who has used nifreeze would be very grateful for some pointers!

Command used (and if a helper script was used, a link to the helper script or the command generated):

from nifreeze.data import dmri
from nifreeze.estimator import Estimator
dwi_data = dmri.from_nii(
    dti.fpath,
    brainmask_file=os.path.dirname(dti.fpath) + "/mask.nii.gz",
    bvec_file=dti.fpath.replace(".nii.gz", ".bvec"),
    bval_file=dti.fpath.replace(".nii.gz", ".bval"),
)
estimator = Estimator("dti")
estimated_affine = estimator.run(
    dwi_data,
    omp_nthreads=1,
    n_jobs=1,
    seed=42,
)

Version:

nifreeze 25.0.0.dev442
nipype 1.11.0.dev0

Environment (Docker, Singularity / Apptainer, custom installation):

Installed in conda environment, python 3.11

Relevant log outputs (up to 20 lines):

DWI(dataobj=<116x116x81x114 (int16)>, affine=<4x4 (float64)>, brainmask=<116x116x81 (bool)>, motion_affines=None, datahdr=None, bzero=<116x116x81 (float64)>, gradients=<4x114 (float32)>, eddy_xfms=None)
Dataset size: 195548x114.
Parallel execution: {'n_jobs': 1, 'omp_nthreads': 1, 'step': 1000000}.
Model: <nifreeze.model.dmri.DTIModel object at 0x14faa7158ad0>.
Processing in </tmp/tmpl46bc4ky>
Realign          vol. <70>:   0%|                                                            | 0/114 [00:07<?, ?vols./s]
ERROR: ERROR EDDYCORR - MODULE NOT COMPLETED
Traceback (most recent call last):
  File "/gpfs01/home/bbzmsc/code/fproc/fproc/pipeline.py", line 93, in run
    module.run(self)
  File "/gpfs01/home/bbzmsc/code/fproc/fproc/module.py", line 47, in run
    self.process()
  File "/gpfs01/home/bbzmsc/code/fproc/pipelines/diffad.py", line 667, in process
    estimated_affine = estimator.run(
                       ^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/nifreeze/estimator.py", line 204, in run
    xform = _run_registration(
            ^^^^^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/nifreeze/registration/ants.py", line 488, in _run_registration
    result = registration.run(cwd=str(dirname)).outputs
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/nipype/interfaces/base/core.py", line 393, in run
    self._check_version_requirements(self.inputs)
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/nipype/interfaces/base/core.py", line 318, in _check_version_requirements
    raise Exception(
Exception: Trait fixed_image_masks (Registration) (version 0.0.0.0 < required 2.2.0)

My initial guess is that this was an issue with it not finding Ants, but ants is installed and present in the path, also antspyx is also installed and working (I am using Ants independently in other parts of the pipeline).

If I leave out the brain mask I get a completely different error:

ERROR: ERROR EDDYCORR - MODULE NOT COMPLETED
Traceback (most recent call last):
  File "/gpfs01/home/bbzmsc/code/fproc/fproc/pipeline.py", line 93, in run
    module.run(self)
  File "/gpfs01/home/bbzmsc/code/fproc/fproc/module.py", line 47, in run
    self.process()
  File "/gpfs01/home/bbzmsc/code/fproc/pipelines/diffad.py", line 666, in process
    estimated_affine = estimator.run(
                       ^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/nifreeze/estimator.py", line 187, in run
    predicted = model.fit_predict(  # type: ignore[union-attr]
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/nifreeze/model/dmri.py", line 197, in fit_predict
    predicted, _ = _exec_predict(
                   ^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/nifreeze/model/dmri.py", line 45, in _exec_predict
    return np.squeeze(model.predict(**kwargs)), chunk
                      ^^^^^^^^^^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/dipy/testing/decorators.py", line 201, in wrapper
    return convert_positional_to_keyword(func, args, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/dipy/testing/decorators.py", line 192, in convert_positional_to_keyword
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/dipy/reconst/dti.py", line 1255, in predict
    predict[i : i + step] = tensor_prediction(
                            ^^^^^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/dipy/reconst/dti.py", line 690, in tensor_prediction
    lower_tri = lower_triangular(qform, b0=S0)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/dipy/testing/decorators.py", line 201, in wrapper
    return convert_positional_to_keyword(func, args, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/dipy/testing/decorators.py", line 192, in convert_positional_to_keyword
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/gpfs01/software/imaging/miniconda3/envs/fproc/lib/python3.11/site-packages/dipy/reconst/dti.py", line 2372, in lower_triangular
    D[..., 6] = -np.log(b0)
    ~^^^^^^^^
ValueError: could not broadcast input array from shape (6751,) into shape (89936,)

This looks like I am getting my data in the wrong format, but not clear what the problem is.

Any help very welcome!

@Martin_Craig,
sorry for my delay in getting back to you over here. Hopefully our email exchange on the topic was helpful.

So, to summarize:

  • I apologize for the usage documentation still requiring more work and usage examples. The project is still in an alpha-equivalent phase. Thanks to your heads-up there is an ongoing PR that updates the usage documentation, and provides some further rationale on how things are expected to be called/chained.
  • The ANTs version issue:
    (...)
    Exception: Trait fixed_image_masks (Registration) (version 0.0.0.0 < required 2.2.0)
    
    is more likely to be related to some underlying issue in Nipype rather than NiFreeze itself: NiFreeze leverages Nipype’s interface to ANTs for the registration step. It is maybe worthwhile adding a small test to demonstrate the bug and opening the corresponding the issue in Nipype.
  • As for the dimensionality issue when employing a brainmask, this is on NiFreeze. Apologies for that. I have opened an issue to keep track of it. I will address it as time permits.

Thanks for your interest in NiFreeze.

@Martin_Craig

The documentation PR has been merged. Hopefully now it tracks faithfully the code.

I have written this simple code snippet to try to demonstrate the data shape mismatch issue when using a brainmask:
Testing NiFreeze DWI data and mask mismatch · GitHub

However, running the code exits without issues for me (I am using random data only to focus on the dimensionality mismatch issue, not the accuracy of the estimation). I would be grateful if you could test it and report if it still fails.

Thanks.