Greetings neurocitizens!
I’m encountering what I believe to be a bug in Deconvolve, an AFNI interface in Nipype. I’m trying to get IRF data by feeding the parameter “[-iresp 1 sub-{self.subject_id}_IRF-all]” into Deconvolve using its args input. I’m running Deconvolve with a Nipype memory cache.
Here’s the bug: When I run Deconvolve with a memory cache, I can’t find any IRF files in its output folder. But when I run Deconvolve on its own, with the Deconvolve.run() method, the IRF files appear. I’m puzzled that the interface is clearly able to produce IRF files but fails to do so when I run it with a cache.
My current Deconvolve method, which uses Deconvolve.run() (attached to a Python class that performs a 1st-level analysis):
def Deconvolve(self):
"""
Runs the 1st-level regression on the smoothed functional image.
Wraps AFNI's 3dDeconvolve.
AFNI command info: https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/programs/3dDeconvolve_sphx.html#ahelp-3ddeconvolve
Nipype interface info: https://nipype.readthedocs.io/en/latest/api/generated/nipype.interfaces.afni.model.html#Deconvolve
Returns
-------
InterfaceResult
Stores information about the outputs of Deconvolve.
"""
# Prepare regressor text files to scan into the interface.
self._break_tsv(self.paths["events_tsv"], self.dirs["subject_info"])
self._break_tsv(self.paths["regressors_tsv"], self.dirs["regressors"])
# Total amount of regressors to include in the analysis
amount_of_regressors = 1 + len(self.regressor_names)
# Create string to pass to interface. Remove all unnecessary whitespace by default.
arg_string = ' '.join(f"""
-input {self.results["SUSAN"].outputs.smoothed_file}
-GOFORIT 4
-polort A
-num_stimts {amount_of_regressors}
-stim_times 1 {self.dirs["subject_info"]/'onset'}.txt 'CSPLINzero(0,18,10)'
-stim_label 1 all
-iresp 1 sub-{self.subject_id}_IRF-all
-fout
""".replace("\n", " ").split())
# Add individual stim files to the string.
for i, regressor_name in enumerate(self.regressor_names):
stim_number = i + 2
stim_file_info = f"-stim_file {stim_number} {self.dirs['regressors']/regressor_name}.txt -stim_base {stim_number}"
stim_label_info = f"-stim_label {stim_number} {regressor_name}"
arg_string += f" {stim_file_info} {stim_label_info}"
# Create output dir for Deconvolve stuff.
deconvolve_dir = self.dirs["output"]/"nipype-interfaces-afni-model-Deconvolve"
deconvolve_dir.mkdir(exist_ok=True)
# Run the Deconvolve interface.
return Deconvolve().run(
cwd=str(deconvolve_dir),
args=arg_string
)
My old Deconvolve method, which uses caching:
def Deconvolve(self):
"""
Runs the 1st-level regression on the smoothed functional image.
Wraps AFNI's 3dDeconvolve.
AFNI command info: https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/programs/3dDeconvolve_sphx.html#ahelp-3ddeconvolve
Nipype interface info: https://nipype.readthedocs.io/en/latest/api/generated/nipype.interfaces.afni.model.html#Deconvolve
Returns
-------
InterfaceResult
Stores information about the outputs of Deconvolve.
"""
# Prepare regressor text files to scan into the interface.
self._break_tsv(self.paths["events_tsv"], self.dirs["subject_info"])
self._break_tsv(self.paths["regressors_tsv"], self.dirs["regressors"])
# Total amount of regressors to include in the analysis
amount_of_regressors = 1 + len(self.regressor_names)
# Create string to pass to interface. Remove all unnecessary whitespace by default.
arg_string = ' '.join(f"""
-input {self.results["SUSAN"].outputs.smoothed_file}
-GOFORIT 4
-polort A
-num_stimts {amount_of_regressors}
-stim_times 1 {self.dirs["subject_info"]/'onset'}.txt 'CSPLINzero(0,18,10)'
-stim_label 1 all
-iresp 1 sub-{self.subject_id}_IRF-all
-fout
""".replace("\n", " ").split())
# Add individual stim files to the string.
for i, regressor_name in enumerate(self.regressor_names):
stim_number = i + 2
stim_file_info = f"-stim_file {stim_number} {self.dirs['regressors']/regressor_name}.txt -stim_base {stim_number}"
stim_label_info = f"-stim_label {stim_number} {regressor_name}"
arg_string += f" {stim_file_info} {stim_label_info}"
# Create output dir for Deconvolve stuff.
deconvolve_dir = self.dirs["output"]/"nipype-interfaces-afni-model-Deconvolve"
deconvolve_dir.mkdir(exist_ok=True)
# Run the Deconvolve interface.
return self.memory.cache(Deconvolve)(
args=arg_string
)
I really like caching because I struggle to piece together bonafide Nipype workflows. What might I be doing wrong?
Unrelated bonus question: I totally overuse the “args” input all Nipype interfaces have. It’s super convenient, because it lets me copy-paste my lab’s AFNI workflows straight into Python! Is there a downside to overusing “args”?