From 2f9aa4bd9938cd58f09a721a5bf2972de1325779 Mon Sep 17 00:00:00 2001 From: mauriliogenovese <125388969+mauriliogenovese@users.noreply.github.com> Date: Fri, 21 Mar 2025 19:35:37 +0100 Subject: [PATCH 1/2] fix eddy command and multithreading --- nipype/interfaces/fsl/epi.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 7dda9a49d7..e06273c28d 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -5,11 +5,13 @@ was written to work with FSL version 5.0.4. """ import os +from shutil import which import numpy as np import nibabel as nb import warnings from ...utils.filemanip import split_filename, fname_presuffix +from ...utils.gpu_count import gpu_count from ..base import traits, TraitedSpec, InputMultiPath, File, isdefined from .base import FSLCommand, FSLCommandInputSpec, Info @@ -793,9 +795,12 @@ class EddyInputSpec(FSLCommandInputSpec): requires=["estimate_move_by_susceptibility"], min_ver="6.0.1", ) - num_threads = traits.Int( - 1, usedefault=True, nohash=True, desc="Number of openmp threads to use" + argstr="--nthr=%d", + default_value=1, + usedefault=True, + nohash=True, + desc="Number of openmp threads to use" ) is_shelled = traits.Bool( False, @@ -937,7 +942,7 @@ class Eddy(FSLCommand): """ - _cmd = "eddy_openmp" + _cmd = "eddy_openmp" if which("eddy_openmp") else "eddy_cpu" input_spec = EddyInputSpec output_spec = EddyOutputSpec @@ -963,17 +968,22 @@ def _num_threads_update(self): self.inputs.environ["OMP_NUM_THREADS"] = str(self.inputs.num_threads) def _use_cuda(self): - self._cmd = "eddy_cuda" if self.inputs.use_cuda else "eddy_openmp" + if self.inputs.use_cuda and gpu_count()>0: + # eddy_cuda usually link to eddy_cudaX.X but some versions miss the symlink + # anyway in newer fsl versions eddy automatically use cuda on cuda-capable systems + self._cmd = "eddy_cuda" if which("eddy_cuda") else "eddy" + else: + # older fsl versions has cuda_openmp, newer versions has eddy_cpu + _cmd = "eddy_openmp" if which("eddy_openmp") else "eddy_cpu" def _run_interface(self, runtime): - # If 'eddy_openmp' is missing, use 'eddy' + # If selected command is missing, use generic 'eddy' FSLDIR = os.getenv("FSLDIR", "") cmd = self._cmd if all( ( FSLDIR != "", - cmd == "eddy_openmp", - not os.path.exists(os.path.join(FSLDIR, "bin", cmd)), + not os.path.exists(os.path.join(FSLDIR, "bin", self._cmd)), ) ): self._cmd = "eddy" From 9348f49a9947f0bdc984cc07944a0074351b25dd Mon Sep 17 00:00:00 2001 From: mauriliogenovese <125388969+mauriliogenovese@users.noreply.github.com> Date: Sat, 22 Mar 2025 18:34:40 +0100 Subject: [PATCH 2/2] force 1 thread if eddy run on gpu --- nipype/interfaces/fsl/epi.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index e06273c28d..41f6144beb 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -960,6 +960,8 @@ def __init__(self, **inputs): self._use_cuda() def _num_threads_update(self): + if self.inputs.use_cuda and gpu_count()>0: + self.inputs.num_threads = 1 self._num_threads = self.inputs.num_threads if not isdefined(self.inputs.num_threads): if "OMP_NUM_THREADS" in self.inputs.environ: @@ -969,12 +971,13 @@ def _num_threads_update(self): def _use_cuda(self): if self.inputs.use_cuda and gpu_count()>0: + self.inputs.num_threads = 1 # eddy_cuda usually link to eddy_cudaX.X but some versions miss the symlink # anyway in newer fsl versions eddy automatically use cuda on cuda-capable systems self._cmd = "eddy_cuda" if which("eddy_cuda") else "eddy" else: # older fsl versions has cuda_openmp, newer versions has eddy_cpu - _cmd = "eddy_openmp" if which("eddy_openmp") else "eddy_cpu" + self._cmd = "eddy_openmp" if which("eddy_openmp") else "eddy_cpu" def _run_interface(self, runtime): # If selected command is missing, use generic 'eddy'