Bedpostx_parallel cannot find bvecs file

Hi Everyone,

Im getting a simple trait error regarding a .bvec file, as follows :

traits.trait_errors.TraitError: The 'bvecs' trait of a XFibres5InputSpec instance must be a pathlike object or string representing an existing file, but a value of '/path/to/dti_raw_rot.bvecs' <class 'str'> was specified.

The file path itself exists. I am using bedpostx_parallel. How can i provide a path like object to Xfibres instead of a string?

Hi @Ziad_Motagaly and welcome to neurostars!

This error indicates that the program can not find the file at that path. Some more details of your code and your computing environment would help us debug your issue.

Best,
Steven

Hi @Steven ,

Thank you !

The computing environment is a SLURM-based HPC cluster. ( sbatch, srun… ) . I am using Nipype bedpostx_parallel (this is where xfibres is called from)
I am currently running it linearly on CPU (and eventually run it on GPU as well).

Hi @Ziad_Motagaly,

The exact code you are using would be helpful.

Best,
Steven

#!/bin/env python

import os
import sys
import subprocess
import configparser

from nipype import DataGrabber, DataSink, IdentityInterface, Node, Workflow, MapNode, JoinNode, Merge
from niflow.nipype1.workflows.dmri.fsl.dti import bedpostx_parallel
from nipype.interfaces import utility
import nipype.interfaces.fsl as fsl
import nipype.interfaces.ants as ants
from nipype.interfaces.freesurfer import ReconAll, MRIsConvert, MRIConvert
from nipype.interfaces.utility import Function

def create_diffusion_prep_pipeline(name='dMRI_preprocessing', bet_frac=0.34):
  input_subject = Node(
    IdentityInterface(
      fields=['dwi', 'bval', 'bvec'],
    ),
    name='input_subject'
  )


def bvec_flip(bvecs_in, flip):
    from os.path import join, basename
    from os import getcwd

    import numpy as np

    print(bvecs_in)
    bvecs = np.loadtxt(bvecs_in).T * flip

    output_file = str(join(getcwd(), basename(bvecs_in)))
    np.savetxt(output_file, bvecs)
    
    return output_file

if __name__ == '__main__':
    dmri_preprocess_workflow = create_diffusion_prep_pipeline(
        'dmri_preprocess')
    config = configparser.ConfigParser()
    config.read(sys.argv[1])

    PATH='/path/to/my/script'
    subject_list = config['DEFAULT']['id_list'].split(" ")
    visits = list(config['DEFAULT']['visits'])
    subjects_dir = config['DEFAULT']['subjects_dir']
    sessions = list(config['DEFAULT']['sessions'])

    infosource = Node(IdentityInterface(fields=['subject_id', 'visit','session']),
                      name='subjects')
    infosource.iterables = [('subject_id', subject_list), ('visit', visits), ('session', sessions)]

    subject_id_visit = Node(
        interface=Function(
            input_names=['subject_id', 'visit'], output_names=['composite_id'],
            function=lambda subject_id, visit: '{}_{}'.format(subject_id, visit)
        ),
        name='subject_id_visit'
    )



    data_source = Node(DataGrabber(infields=['subject_id', 'visit','session'],
                                   outfields=['dwi', 'bval', 'bvec', 'T1']),
                       name='data_grabber')
    data_source.inputs.sort_filelist = True
    data_source.inputs.base_directory = config['DEFAULT']['base_directory']
    data_source.inputs.template = ''
    data_source.inputs.field_template = {
        'T1': '%s/visit%s/session%s/anat/T1w.nii',
        'dwi': '%s/visit%s/session%s/dwi/dwi_raw.nii.gz',
        'bval': '%s/visit%s/session%s/dwi/dti_raw.bvals',
        'bvec': '%s/visit%s/session%s/dwi/dti_raw.bvecs',
        #'bval': '%s/visit%s/session%s/dwi/dwepi.150.bvals',
        #'bvec': '%s/visit%s/session%s/dwi/dwepi.150.grads'
    }
    data_source.inputs.template_args = {
        template: [['subject_id', 'visit','session']]
        for template in data_source.inputs.field_template.keys()
    }

    flip_bvectors_node = Node(
        interface=Function(
            input_names=['bvecs_in', 'flip'], output_names=['bvecs_out'],
            function=bvec_flip
        ),
        name='flip_bvecs',
    )
    flip_bvectors_node.inputs.flip = (-1, 1, 1)

    recon_all = Node(interface=ReconAll(), name='recon_all')
    recon_all.inputs.directive = 'all'
    recon_all.inputs.subjects_dir = subjects_dir
    recon_all.inputs.openmp = 20
    recon_all.inputs.mprage = True
    recon_all.inputs.parallel = True
    recon_all.interface.num_threads = 20
    recon_all.inputs.flags = "-no-isrunning"


    bedpostx_parallel_wf_params = dict(n_fibres=3,
                                       fudge=1,
                                       burn_in=1000,
                                       n_jumps=1250,
                                       sample_every=25)
    bedpostx_parallel_wf = bedpostx_parallel(
        'nipype_bedpostx_parallel', params=bedpostx_parallel_wf_params)
    


    mri_convert = Node(interface=MRIConvert(), name='mri_convert')
    mri_convert.inputs.out_type = 'nii'
    mri_convert.inputs.subjects_dir = subjects_dir



    workflow = Workflow('diffusion_workflow_new_mgt', base_dir=PATH)
    workflow.connect([
        (infosource, data_source, [('subject_id', 'subject_id'),
                                   ('visit', 'visit'),
				   ('session','session')]),

        (infosource, subject_id_visit, [
            ('subject_id', 'subject_id'),
            ('visit', 'visit')
        ]),

        (data_source, flip_bvectors_node, [('bvec', 'bvecs_in')]),

         (data_source, dmri_preprocess_workflow,
         [
          ('dwi', 'input_subject.dwi'), 
          ('bval', 'input_subject.bval'),
         ]),

        (data_source, recon_all, [('T1', 'T1_files')]),

        (subject_id_visit, recon_all, [('composite_id', 'subject_id')]),


        (flip_bvectors_node, dmri_preprocess_workflow, [('bvecs_out', 'input_subject.bvec')]),

        (recon_all, mri_convert, [('brain', 'in_file')]),

        (mri_convert, dmri_preprocess_workflow, [
          ('out_file', 'input_template.T1'),
          ('out_file', 'input_template.T2')
        ]),
        
        (
            dmri_preprocess_workflow,
            bedpostx_parallel_wf,
            [('output.bval', 'inputnode.bvals'),
             ('output.bvec_rotated', 'inputnode.bvecs'),
             ('output.dwi_rigid_registered', 'inputnode.dwi'),
             ('output.mask', 'inputnode.mask')],
        ),
    ])

    workflow.write_graph(format='pdf', simple_form=False)
    if config['DEFAULT'].get('server', '').lower() == 'margaret':
        
        workflow.run(plugin='Linear')

        #workflow.run(plugin='MultiProc', plugin_args={'n_procs':220, 'memory_gb': 320})

The main two nodes that are involved seem to be “dmri_preprocess_workflow” and “bedpostx_parallel_wf”

diffusion_preprocessing file is as follows :

#!/bin/env python
import inspect
import os

from nipype import IdentityInterface, Node, Workflow
import nipype.interfaces.fsl as fsl
import nipype.interfaces.ants as ants
from niflow.nipype1.workflows.dmri.fsl.epi import create_eddy_correct_pipeline
from nipype.interfaces import utility
from nipype.interfaces.utility.wrappers import Function


def convert_affine_itk_2_ras(input_affine):
    import subprocess
    import os, os.path
    output_file = os.path.join(
        os.getcwd(),
        f'{os.path.basename(input_affine)}.ras'
    )
    subprocess.check_output(
        f'c3d_affine_tool '
        f'-itk {input_affine} '
        f'-o {output_file} -info-full ',
        shell=True
    ).decode('utf8')
    return output_file


ConvertAffine2RAS = Function(
    input_names=['input_affine'], output_names=['affine_ras'],
    function=convert_affine_itk_2_ras
  )


def rotate_gradients_(input_affine, gradient_file):
  import os
  import os.path
  import numpy as np
  from scipy.linalg import polar

  affine = np.loadtxt(input_affine)
  u, p = polar(affine[:3, :3], side='right') 
  gradients = np.loadtxt(gradient_file)
  new_gradients = np.linalg.solve(u, gradients.T).T
  name, ext = os.path.splitext(os.path.basename(gradient_file))
  output_name = os.path.join(
      os.getcwd(),
      f'{name}_rot{ext}'
  )
  np.savetxt(output_name, new_gradients)
          
  return output_name

RotateGradientsAffine = Function(
  input_names=['input_affine', 'gradient_file'],
  output_names=['rotated_gradients'],
  function=rotate_gradients_
)


def create_diffusion_prep_pipeline(name='dMRI_preprocessing', bet_frac=0.34):
  input_subject = Node(
    IdentityInterface(
      fields=['dwi', 'bval', 'bvec'],
    ),
    name='input_subject'
  )

  input_template = Node(
    IdentityInterface(
      fields=['T1', 'T2'],
    ),
    name='input_template'
  )

  output = Node(
    IdentityInterface(
      fields=[
        'dwi_rigid_registered', 'bval', 'bvec_rotated', 'mask', 'rigid_dwi_2_template'
      ]
    ),
    name='output'
  )

  fslroi = Node(interface=fsl.ExtractROI(), name='fslroi')
  fslroi.inputs.t_min = 0
  fslroi.inputs.t_size = 1

  bet = Node(interface=fsl.BET(), name='bet')
  bet.inputs.mask = True
  bet.inputs.frac = bet_frac

  eddycorrect = create_eddy_correct_pipeline('eddycorrect')
  eddycorrect.inputs.inputnode.ref_num = 0

  rigid_registration = Node(
      interface=ants.RegistrationSynQuick(),
      name='affine_reg'
  )
  rigid_registration.inputs.num_threads = 8
  rigid_registration.inputs.transform_type = 'a'

  conv_affine = Node(
      interface=ConvertAffine2RAS,
      name='convert_affine_itk_2_ras'
  )

  rotate_gradients = Node(
      interface=RotateGradientsAffine,
      name='rotate_gradients'
  )

  transforms_to_list = Node(
      interface=utility.Merge(1),
      name='transforms_to_list'
  )

  apply_registration = Node(
      interface=ants.ApplyTransforms(),
      name='apply_registration'
  )
  apply_registration.inputs.dimension = 3
  apply_registration.inputs.input_image_type = 3
  apply_registration.inputs.interpolation = 'NearestNeighbor'

  apply_registration_mask = Node(
      interface=ants.ApplyTransforms(),
      name='apply_registration_mask'
  )
  apply_registration_mask.inputs.dimension = 3
  apply_registration_mask.inputs.input_image_type = 3
  apply_registration_mask.inputs.interpolation = 'NearestNeighbor'

  workflow = Workflow(
      name=name,
  )
  workflow.connect([
    (input_subject, fslroi, [('dwi', 'in_file')]),
    (fslroi, bet, [('roi_file', 'in_file')]),
    (input_subject, eddycorrect, [('dwi', 'inputnode.in_file')]),
    (fslroi, rigid_registration, [('roi_file', 'moving_image')]),
    (input_template, rigid_registration, [('T2', 'fixed_image')]),
    (rigid_registration, transforms_to_list, [('out_matrix', 'in1')]),
    (rigid_registration, conv_affine, [('out_matrix', 'input_affine')]),
    (input_subject, rotate_gradients, [('bvec', 'gradient_file')]),
    (conv_affine, rotate_gradients, [('affine_ras', 'input_affine')]),
    (transforms_to_list, apply_registration, [('out', 'transforms')]),
    (eddycorrect, apply_registration, [('outputnode.eddy_corrected', 'input_image')]),
    (input_template, apply_registration, [('T2', 'reference_image')]),

    (transforms_to_list, apply_registration_mask, [('out', 'transforms')]),
    (bet, apply_registration_mask, [('mask_file', 'input_image')]),
    (input_template, apply_registration_mask, [('T2', 'reference_image')]),

    (conv_affine, output, [('affine_ras', 'rigid_dwi_2_template')]),
    (apply_registration, output, [('output_image', 'dwi_rigid_registered')]),
    (rotate_gradients, output, [('rotated_gradients', 'bvec_rotated')]),
    (input_subject, output, [('bval', 'bval')]),
    (apply_registration_mask, output, [('output_image', 'mask')]),
  ])

  return workflow