Skip to content

Commit 339c46e

Browse files
committed
RF: Add warning snippet when CompCor fails
1 parent 15dd37f commit 339c46e

File tree

1 file changed

+89
-28
lines changed

1 file changed

+89
-28
lines changed

fmriprep/interfaces/patches.py

Lines changed: 89 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,49 +12,110 @@
1212

1313
from numpy.linalg.linalg import LinAlgError
1414
from nipype.algorithms import confounds as nac
15+
from nipype.interfaces.base import (File, traits)
16+
from nipype.interfaces.mixins import reporting
1517

1618

17-
class RobustACompCor(nac.ACompCor):
18-
"""
19-
Runs aCompCor several times if it suddenly fails with
20-
https://github.com/poldracklab/fmriprep/issues/776
19+
class RetryCompCorInputSpecMixin(reporting.ReportCapableInputSpec):
20+
out_report = File('report.html', usedefault=True, hash_files=False,
21+
desc='filename for warning HTML snippet')
22+
# 'NaN` by default
23+
failure_mode = traits.Enum(
24+
'NaN', 'error',
25+
usedefault=True,
26+
desc='When no components are found or convergence fails, raise an error '
27+
'or silently return columns of NaNs.')
2128

22-
"""
2329

30+
class RetryCompCorMixin(reporting.ReportCapableInterface):
2431
def _run_interface(self, runtime):
32+
warn = self.inputs.failure_mode == 'NaN'
33+
2534
failures = 0
35+
save_exc = None
2636
while True:
37+
success = True
38+
# Identifiy success/failure in both error and NaN mode
2739
try:
28-
runtime = super(RobustACompCor, self)._run_interface(runtime)
40+
runtime = super()._run_interface(runtime)
41+
if warn and self._check_nans():
42+
success = False
43+
except LinAlgError as exc:
44+
success = False
45+
save_exc = exc
46+
47+
if success:
2948
break
30-
except LinAlgError:
31-
failures += 1
32-
if failures > 10:
33-
raise
34-
start = (failures - 1) * 10
35-
sleep(randint(start + 4, start + 10))
49+
50+
failures += 1
51+
if failures > 10:
52+
if warn:
53+
break
54+
raise save_exc
55+
start = (failures - 1) * 10
56+
sleep(randint(start + 4, start + 10))
3657

3758
return runtime
3859

60+
def _check_nans(self):
61+
import numpy as np
62+
outputs = self._list_outputs()
63+
components = np.loadtxt(outputs['components_file'], skiprows=1)
64+
return np.isnan(components).all()
65+
66+
def _generate_report(self):
67+
snippet = ''
68+
if self._check_nans():
69+
snippet = '''\
70+
<p class="elem-desc">
71+
Warning: {} components could not be estimated, due to a linear algebra error.
72+
While not definitive, this may be an indication of a poor mask.
73+
Please inspect the {} contours above to ensure that they are located
74+
in the white matter/CSF.
75+
</p>
76+
'''.format(self._header, 'magenta' if self._header[0] == 'a' else 'blue')
77+
78+
with open(self._out_report, 'w') as fobj:
79+
fobj.write(snippet)
3980

40-
class RobustTCompCor(nac.TCompCor):
81+
82+
class RobustACompCorInputSpec(RetryCompCorInputSpecMixin, nac.ACompCorInputSpec):
83+
pass
84+
85+
86+
class RobustACompCorOutputSpec(reporting.ReportCapableOutputSpec, nac.ACompCorOutputSpec):
87+
pass
88+
89+
90+
class RobustACompCor(RetryCompCorMixin, nac.ACompCor):
4191
"""
42-
Runs tCompCor several times if it suddenly fails with
43-
https://github.com/poldracklab/fmriprep/issues/940
92+
Runs aCompCor several times if it suddenly fails with
93+
https://github.com/poldracklab/fmriprep/issues/776
94+
95+
Warns by default, rather than failing, on linear algebra errors.
96+
https://github.com/poldracklab/fmriprep/issues/1433
4497
4598
"""
99+
input_spec = RobustACompCorInputSpec
100+
output_spec = RobustACompCorOutputSpec
46101

47-
def _run_interface(self, runtime):
48-
failures = 0
49-
while True:
50-
try:
51-
runtime = super(RobustTCompCor, self)._run_interface(runtime)
52-
break
53-
except LinAlgError:
54-
failures += 1
55-
if failures > 10:
56-
raise
57-
start = (failures - 1) * 10
58-
sleep(randint(start + 4, start + 10))
59102

60-
return runtime
103+
class RobustTCompCorInputSpec(RetryCompCorInputSpecMixin, nac.ACompCorInputSpec):
104+
pass
105+
106+
107+
class RobustTCompCorOutputSpec(reporting.ReportCapableOutputSpec, nac.TCompCorOutputSpec):
108+
pass
109+
110+
111+
class RobustTCompCor(RetryCompCorMixin, nac.ACompCor):
112+
"""
113+
Runs tCompCor several times if it suddenly fails with
114+
https://github.com/poldracklab/fmriprep/issues/776
115+
116+
Warns by default, rather than failing, on linear algebra errors.
117+
https://github.com/poldracklab/fmriprep/issues/1433
118+
119+
"""
120+
input_spec = RobustTCompCorInputSpec
121+
output_spec = RobustTCompCorOutputSpec

0 commit comments

Comments
 (0)