Skip to content

Commit 56f78a2

Browse files
authored
Merge pull request #1274 from romainVala/master
FIX: Remove long paths from all LTA output files
2 parents 9b87cb8 + 8d779e2 commit 56f78a2

File tree

5 files changed

+99
-34
lines changed

5 files changed

+99
-34
lines changed

.zenodo.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@
8383
"affiliation": "Department of Psychology, Stanford University",
8484
"orcid": "0000-0001-6755-0259"
8585
},
86+
{
87+
"name": "Valabregue, Romain",
88+
"affiliation": "Cenir, ICM, Paris",
89+
"orcid": "0000-0002-1814-9570"
90+
},
8691
{
8792
"name": "Gorgolewski, Krzysztof J.",
8893
"affiliation": "Department of Psychology, Stanford University",

fmriprep/interfaces/freesurfer.py

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
)
3535
from nipype.interfaces import freesurfer as fs
3636
from nipype.interfaces.base import SimpleInterface
37-
from nipype.interfaces.freesurfer.preprocess import ConcatenateLTA
37+
from nipype.interfaces.freesurfer.preprocess import ConcatenateLTA, RobustRegister
38+
from nipype.interfaces.freesurfer.utils import LTAConvert
39+
from niworkflows.interfaces.registration import BBRegisterRPT, MRICoregRPT
3840

3941

4042
class StructuralReference(fs.RobustTemplate):
@@ -190,7 +192,54 @@ def _run_interface(self, runtime):
190192
return runtime
191193

192194

193-
class PatchedConcatenateLTA(ConcatenateLTA):
195+
class TruncateLTA(object):
196+
"""Mixin to ensure that LTA files do not store overly long paths,
197+
which lead to segmentation faults when read by FreeSurfer tools.
198+
199+
See the following issues for discussion:
200+
201+
* https://github.com/freesurfer/freesurfer/pull/180
202+
* https://github.com/poldracklab/fmriprep/issues/768
203+
* https://github.com/poldracklab/fmriprep/pull/778
204+
* https://github.com/poldracklab/fmriprep/issues/1268
205+
* https://github.com/poldracklab/fmriprep/pull/1274
206+
"""
207+
208+
# Use a tuple in case some object produces multiple transforms
209+
lta_outputs = ('out_lta_file',)
210+
211+
def _post_run_hook(self, runtime):
212+
213+
outputs = self._list_outputs()
214+
215+
for lta_name in self.lta_outputs:
216+
lta_file = outputs[lta_name]
217+
if not isdefined(lta_file):
218+
continue
219+
220+
with open(lta_file, 'r') as f:
221+
lines = f.readlines()
222+
223+
fixed = False
224+
newfile = []
225+
226+
for line in lines:
227+
if line.startswith('filename = ') and len(line.strip("\n")) >= 255:
228+
fixed = True
229+
newfile.append('filename = path_too_long\n')
230+
else:
231+
newfile.append(line)
232+
233+
if fixed:
234+
with open(lta_file, 'w') as f:
235+
f.write(''.join(newfile))
236+
237+
runtime = super(TruncateLTA, self)._post_run_hook(runtime)
238+
239+
return runtime
240+
241+
242+
class PatchedConcatenateLTA(TruncateLTA, ConcatenateLTA):
194243
"""
195244
A temporarily patched version of ``fs.ConcatenateLTA`` to recover from
196245
`this bug <https://www.mail-archive.com/[email protected]/msg55520.html>`_
@@ -199,27 +248,30 @@ class PatchedConcatenateLTA(ConcatenateLTA):
199248
200249
The original FMRIPREP's issue is found
201250
`here <https://github.com/poldracklab/fmriprep/issues/768>`__.
251+
252+
the fix is now done through mixin with TruncateLTA
202253
"""
254+
lta_outputs = ['out_file']
203255

204-
def _list_outputs(self):
205-
outputs = super(PatchedConcatenateLTA, self)._list_outputs()
206-
207-
with open(outputs['out_file'], 'r') as f:
208-
lines = f.readlines()
209-
210-
fixed = False
211-
newfile = []
212-
for line in lines:
213-
if line.startswith('filename = ') and len(line.strip("\n")) >= 255:
214-
fixed = True
215-
newfile.append('filename = path_too_long\n')
216-
else:
217-
newfile.append(line)
218-
219-
if fixed:
220-
with open(outputs['out_file'], 'w') as f:
221-
f.write(''.join(newfile))
222-
return outputs
256+
257+
class PatchedLTAConvert(TruncateLTA, LTAConvert):
258+
"""
259+
LTAconvert is producing a lta file refer as out_lta
260+
truncate filename through mixin TruncateLTA
261+
"""
262+
lta_outputs = ('out_lta',)
263+
264+
265+
class PatchedBBRegisterRPT(TruncateLTA, BBRegisterRPT):
266+
pass
267+
268+
269+
class PatchedMRICoregRPT(TruncateLTA, MRICoregRPT):
270+
pass
271+
272+
273+
class PatchedRobustRegister(TruncateLTA, RobustRegister):
274+
lta_outputs = ('out_reg_file', 'half_source_xfm', 'half_targ_xfm')
223275

224276

225277
class RefineBrainMaskInputSpec(BaseInterfaceInputSpec):

fmriprep/workflows/anatomical.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@
4949
ConcatAffines, RefineBrainMask,
5050
)
5151
from ..utils.misc import fix_multi_T1w_source_name, add_suffix
52+
from ..interfaces.freesurfer import (
53+
PatchedLTAConvert as LTAConvert,
54+
PatchedRobustRegister as RobustRegister)
5255

5356
TEMPLATE_MAP = {
5457
'MNI152NLin2009cAsym': 'mni_icbm152_nlin_asym_09c',
@@ -533,7 +536,7 @@ def _get_first(in_list):
533536
# 2. Reorient template to RAS, if needed (mri_robust_template may set to LIA)
534537
t1_reorient = pe.Node(image.Reorient(), name='t1_reorient')
535538

536-
lta_to_fsl = pe.MapNode(fs.utils.LTAConvert(out_fsl=True), iterfield=['in_lta'],
539+
lta_to_fsl = pe.MapNode(LTAConvert(out_fsl=True), iterfield=['in_lta'],
537540
name='lta_to_fsl')
538541

539542
concat_affines = pe.MapNode(
@@ -813,9 +816,9 @@ def init_surface_recon_wf(omp_nthreads, hires, name='surface_recon_wf'):
813816

814817
skull_strip_extern = pe.Node(FSInjectBrainExtracted(), name='skull_strip_extern')
815818

816-
fsnative_2_t1_xfm = pe.Node(fs.RobustRegister(auto_sens=True, est_int_scale=True),
819+
fsnative_2_t1_xfm = pe.Node(RobustRegister(auto_sens=True, est_int_scale=True),
817820
name='fsnative_2_t1_xfm')
818-
t1_2_fsnative_xfm = pe.Node(fs.utils.LTAConvert(out_lta=True, invert=True),
821+
t1_2_fsnative_xfm = pe.Node(LTAConvert(out_lta=True, invert=True),
819822
name='t1_2_fsnative_xfm')
820823

821824
autorecon_resume_wf = init_autorecon_resume_wf(omp_nthreads=omp_nthreads)
@@ -1279,7 +1282,7 @@ def init_anat_derivatives_wf(output_dir, output_spaces, template, freesurfer,
12791282
DerivativesDataSink(base_directory=output_dir, suffix=suffix_fmt(template, 'warp')),
12801283
name='ds_t1_mni_warp', run_without_submitting=True)
12811284

1282-
lta_2_itk = pe.Node(fs.utils.LTAConvert(out_itk=True), name='lta_2_itk')
1285+
lta_2_itk = pe.Node(LTAConvert(out_itk=True), name='lta_2_itk')
12831286

12841287
ds_t1_fsnative = pe.Node(
12851288
DerivativesDataSink(base_directory=output_dir, suffix=suffix_fmt('fsnative', 'affine')),

fmriprep/workflows/bold/registration.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
import os.path as op
1818

1919
from nipype.pipeline import engine as pe
20-
from nipype.interfaces import utility as niu, fsl, c3, freesurfer as fs
21-
from niworkflows.interfaces.registration import FLIRTRPT, BBRegisterRPT, MRICoregRPT
20+
from nipype.interfaces import utility as niu, fsl, c3
21+
from niworkflows.interfaces.registration import FLIRTRPT
2222
from niworkflows.interfaces.utils import GenerateSamplingReference
2323
from niworkflows.interfaces.fixes import FixHeaderApplyTransforms as ApplyTransforms
2424

@@ -28,7 +28,11 @@
2828
from ...interfaces.nilearn import Merge
2929
from ...interfaces.images import extract_wm
3030
# See https://github.com/poldracklab/fmriprep/issues/768
31-
from ...interfaces.freesurfer import PatchedConcatenateLTA as ConcatenateLTA
31+
from ...interfaces.freesurfer import (
32+
PatchedConcatenateLTA as ConcatenateLTA,
33+
PatchedBBRegisterRPT as BBRegisterRPT,
34+
PatchedMRICoregRPT as MRICoregRPT,
35+
PatchedLTAConvert as LTAConvert)
3236

3337

3438
DEFAULT_MEMORY_MIN_GB = 0.01
@@ -420,8 +424,8 @@ def init_bbreg_wf(use_bbr, bold2t1w_dof, omp_nthreads, name='bbreg_wf'):
420424
lta_concat = pe.Node(ConcatenateLTA(out_file='out.lta'), name='lta_concat')
421425
# XXX LTA-FSL-ITK may ultimately be able to be replaced with a straightforward
422426
# LTA-ITK transform, but right now the translation parameters are off.
423-
lta2fsl_fwd = pe.Node(fs.utils.LTAConvert(out_fsl=True), name='lta2fsl_fwd')
424-
lta2fsl_inv = pe.Node(fs.utils.LTAConvert(out_fsl=True, invert=True), name='lta2fsl_inv')
427+
lta2fsl_fwd = pe.Node(LTAConvert(out_fsl=True), name='lta2fsl_fwd')
428+
lta2fsl_inv = pe.Node(LTAConvert(out_fsl=True, invert=True), name='lta2fsl_inv')
425429
fsl2itk_fwd = pe.Node(c3.C3dAffineTool(fsl2ras=True, itk_transform=True),
426430
name='fsl2itk_fwd', mem_gb=DEFAULT_MEMORY_MIN_GB)
427431
fsl2itk_inv = pe.Node(c3.C3dAffineTool(fsl2ras=True, itk_transform=True),
@@ -478,7 +482,7 @@ def init_bbreg_wf(use_bbr, bold2t1w_dof, omp_nthreads, name='bbreg_wf'):
478482
transforms = pe.Node(niu.Merge(2), run_without_submitting=True, name='transforms')
479483
reports = pe.Node(niu.Merge(2), run_without_submitting=True, name='reports')
480484

481-
lta_ras2ras = pe.MapNode(fs.utils.LTAConvert(out_lta=True), iterfield=['in_lta'],
485+
lta_ras2ras = pe.MapNode(LTAConvert(out_lta=True), iterfield=['in_lta'],
482486
name='lta_ras2ras', mem_gb=2)
483487
compare_transforms = pe.Node(niu.Function(function=compare_xforms), name='compare_transforms')
484488

@@ -659,7 +663,7 @@ def init_fsl_bbr_wf(use_bbr, bold2t1w_dof, name='fsl_bbr_wf'):
659663
select_transform = pe.Node(niu.Select(), run_without_submitting=True, name='select_transform')
660664
select_report = pe.Node(niu.Select(), run_without_submitting=True, name='select_report')
661665

662-
fsl_to_lta = pe.MapNode(fs.utils.LTAConvert(out_lta=True), iterfield=['in_fsl'],
666+
fsl_to_lta = pe.MapNode(LTAConvert(out_lta=True), iterfield=['in_fsl'],
663667
name='fsl_to_lta')
664668

665669
workflow.connect([

fmriprep/workflows/bold/resampling.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
from ...interfaces.freesurfer import (
2828
MedialNaNs,
2929
# See https://github.com/poldracklab/fmriprep/issues/768
30-
PatchedConcatenateLTA as ConcatenateLTA
30+
PatchedConcatenateLTA as ConcatenateLTA,
31+
PatchedLTAConvert as LTAConvert
3132
)
3233
from ..anatomical import TEMPLATE_MAP
3334

@@ -116,7 +117,7 @@ def select_target(subject_id, space):
116117
mem_gb=DEFAULT_MEMORY_MIN_GB)
117118
rename_src.inputs.subject = spaces
118119

119-
resampling_xfm = pe.Node(fs.utils.LTAConvert(in_lta='identity.nofile', out_lta=True),
120+
resampling_xfm = pe.Node(LTAConvert(in_lta='identity.nofile', out_lta=True),
120121
name='resampling_xfm')
121122
set_xfm_source = pe.Node(ConcatenateLTA(out_type='RAS2RAS'), name='set_xfm_source')
122123

0 commit comments

Comments
 (0)