-
Notifications
You must be signed in to change notification settings - Fork 305
[MRG] FIX: Output NaN columns for CompCor on failure #1443
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e64860d
15dd37f
339c46e
ba43f41
58968ee
da0a79b
84c51d1
31da5ac
bc52a78
c083051
5b20a28
ea4f9ba
74371b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,49 +12,104 @@ | |
|
||
from numpy.linalg.linalg import LinAlgError | ||
from nipype.algorithms import confounds as nac | ||
from nipype.interfaces.base import File | ||
from nipype.interfaces.mixins import reporting | ||
|
||
|
||
class RobustACompCor(nac.ACompCor): | ||
""" | ||
Runs aCompCor several times if it suddenly fails with | ||
https://github.com/poldracklab/fmriprep/issues/776 | ||
class RetryCompCorInputSpecMixin(reporting.ReportCapableInputSpec): | ||
out_report = File('report.html', usedefault=True, hash_files=False, | ||
desc='filename for warning HTML snippet') | ||
|
||
""" | ||
|
||
class RetryCompCorMixin(reporting.ReportCapableInterface): | ||
def _run_interface(self, runtime): | ||
warn = self.inputs.failure_mode == 'NaN' | ||
|
||
failures = 0 | ||
save_exc = None | ||
while True: | ||
success = True | ||
# Identifiy success/failure in both error and NaN mode | ||
try: | ||
runtime = super(RobustACompCor, self)._run_interface(runtime) | ||
runtime = super()._run_interface(runtime) | ||
if warn and self._is_allnans(): | ||
success = False | ||
except LinAlgError as exc: | ||
success = False | ||
save_exc = exc | ||
|
||
if success: | ||
break | ||
except LinAlgError: | ||
failures += 1 | ||
if failures > 10: | ||
raise | ||
start = (failures - 1) * 10 | ||
sleep(randint(start + 4, start + 10)) | ||
|
||
failures += 1 | ||
if failures > 10: | ||
if warn: | ||
break | ||
raise save_exc | ||
start = (failures - 1) * 10 | ||
sleep(randint(start + 4, start + 10)) | ||
|
||
return runtime | ||
|
||
def _is_allnans(self): | ||
import numpy as np | ||
outputs = self._list_outputs() | ||
components = np.loadtxt(outputs['components_file'], skiprows=1) | ||
return np.isnan(components).all() | ||
|
||
def _generate_report(self): | ||
snippet = '<!-- {} completed without error -->'.format(self._header) | ||
if self._is_allnans(): | ||
snippet = '''\ | ||
<p class="elem-desc"> | ||
Warning: {} components could not be estimated, due to a linear algebra error. | ||
While not definitive, this may be an indication of a poor mask. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add a strict check here that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could do that, but why raise an error instead of issue a warning? The whole point of this is not to crash. People who care about CompCor can worry about why, but if they don't, the masks don't matter at all. |
||
Please inspect the {} contours above to ensure that they are located | ||
in the white matter/CSF. | ||
</p> | ||
'''.format(self._header, 'magenta' if self._header[0] == 'a' else 'blue') | ||
|
||
with open(self._out_report, 'w') as fobj: | ||
fobj.write(snippet) | ||
|
||
class RobustTCompCor(nac.TCompCor): | ||
|
||
class RobustACompCorInputSpec(RetryCompCorInputSpecMixin, nac.CompCorInputSpec): | ||
pass | ||
|
||
|
||
class RobustACompCorOutputSpec(reporting.ReportCapableOutputSpec, nac.CompCorOutputSpec): | ||
pass | ||
|
||
|
||
class RobustACompCor(RetryCompCorMixin, nac.ACompCor): | ||
""" | ||
Runs tCompCor several times if it suddenly fails with | ||
https://github.com/poldracklab/fmriprep/issues/940 | ||
Runs aCompCor several times if it suddenly fails with | ||
https://github.com/poldracklab/fmriprep/issues/776 | ||
|
||
Warns by default, rather than failing, on linear algebra errors. | ||
https://github.com/poldracklab/fmriprep/issues/1433 | ||
|
||
""" | ||
input_spec = RobustACompCorInputSpec | ||
output_spec = RobustACompCorOutputSpec | ||
|
||
def _run_interface(self, runtime): | ||
failures = 0 | ||
while True: | ||
try: | ||
runtime = super(RobustTCompCor, self)._run_interface(runtime) | ||
break | ||
except LinAlgError: | ||
failures += 1 | ||
if failures > 10: | ||
raise | ||
start = (failures - 1) * 10 | ||
sleep(randint(start + 4, start + 10)) | ||
|
||
return runtime | ||
class RobustTCompCorInputSpec(RetryCompCorInputSpecMixin, nac.TCompCorInputSpec): | ||
pass | ||
|
||
|
||
class RobustTCompCorOutputSpec(reporting.ReportCapableOutputSpec, nac.TCompCorOutputSpec): | ||
pass | ||
|
||
|
||
class RobustTCompCor(RetryCompCorMixin, nac.TCompCor): | ||
""" | ||
Runs tCompCor several times if it suddenly fails with | ||
https://github.com/poldracklab/fmriprep/issues/776 | ||
|
||
Warns by default, rather than failing, on linear algebra errors. | ||
https://github.com/poldracklab/fmriprep/issues/1433 | ||
|
||
""" | ||
input_spec = RobustTCompCorInputSpec | ||
output_spec = RobustTCompCorOutputSpec |
Uh oh!
There was an error while loading. Please reload this page.