<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Errors and Crashes
Probably the most important chapter in this section is about how to handle error and crashes. Because at the beginning you will run into a few.
For example
Step1:  Example Crash 1
Step2:  Investigating the crash
Hidden, in the log file you can find the relevant information
Step3:  nipypecli allows you to rerun the crashed node using an additional option -r.
Step4:  When running in the terminal you can also try options that enable the Python or Ipython debugger when re-executing
Step5:  Now you should have a new text file with your crash report.
Step6:  Example Crash 2
Step7:  This will give you the error
Step8:  In a similar way, you will also get an error message if the input type is correct but you have a type in the name
Step9:  Example Crash 3
Step10:  This can be solved by using a MapNode
Step11:  Now, make sure that you specify files that actually exist, otherwise you will have a TraitError again
Step12:  By the way, not that those crashes don't create a crashfile, because they didn't happen during runtime, but still during workflow building.
Example Crash 4
Step13:  SPM problem 2 with *.nii.gz files
Sometimes TraitError can be more misleading.
Step14:  This issue can be solved by unzipping the compressed NIfTI file before giving it as an input to an SPM node. This can either be done by using the Gunzip interface from Nipype or even better if the input is coming from a FSL interface, most of them have an input filed output_type='NIFTI', that you can set to NIFIT.
Example Crash 5
Step15:  This gives you the error
Step16:  Using input fields that don't exist
Let's see what happens if we try to specify a parameter that doesn't exist as an input field
Step17:  This results in the TraitError
Step18:  Now, let's create a new node and connect it to the already occupied input field in_file of the smooth node
<ASSISTANT_TASK:>
Python Code:
%%bash
rm $(pwd)/crash-*
Explanation: Errors and Crashes
Probably the most important chapter in this section is about how to handle error and crashes. Because at the beginning you will run into a few.
For example:
You specified filenames or paths that don't exist.
You try to give an interface a string as input, where a float value is expected or you try to specify a parameter that doesn't exist. Be sure to use the right input type and input name.
You wanted to give a list of inputs [func1.nii, func2.nii, func3.nii] to a node that only expects one input file. MapNode is your solution.
You wanted to run SPM's motion correction on compressed NIfTI files, i.e. *.nii.gz? SPM cannot handle that. Nipype's Gunzip interface can help.
You haven't set up all necessary environment variables. Nipype, for example, doesn't find your MATLAB or SPM version.
You forget to specify a mandatory input field.
You try to connect a node to an input field that another node is already connected to.
Important note about crashfiles. Crashfiles are only created when you run a workflow, not during building a workflow. If you have a typo in a folder path, because they didn't happen during runtime, but still during workflow building.
We will start by removing old crashfiles:
End of explanation
from nipype import SelectFiles, Node, Workflow
from os.path import abspath as opap
from nipype.interfaces.fsl import MCFLIRT, IsotropicSmooth
# Create SelectFiles node
templates={'func': '{subject_id}/ses-test/func/{subject_id}_ses-test_task-fingerfootlips_bold.nii.gz'}
sf = Node(SelectFiles(templates),
          name='selectfiles')
sf.inputs.base_directory = opap('/data/ds000114')
sf.inputs.subject_id = 'sub-11'
# Create Motion Correction Node
mcflirt = Node(MCFLIRT(mean_vol=True,
                       save_plots=True),
               name='mcflirt')
# Create Smoothing node
smooth = Node(IsotropicSmooth(fwhm=4),
              name='smooth')
# Create a preprocessing workflow
wf = Workflow(name="preprocWF")
wf.base_dir = 'working_dir'
# Connect the three nodes to each other
wf.connect([(sf, mcflirt, [("func", "in_file")]),
            (mcflirt, smooth, [("out_file", "in_file")])])
# Let's run the workflow
try:
    wf.run()
except(RuntimeError) as err:
    print("RuntimeError:", err)
else:
    raise
Explanation: Example Crash 1: File doesn't exist
When creating a new workflow, very often the initial errors are OSError, meaning Nipype cannot find the right files. For example, let's try to run a workflow on sub-11, that in our dataset doesn't exist.
Creating the crash
End of explanation
!nipypecli crash $(pwd)/crash-*selectfiles-*.pklz
Explanation: Investigating the crash
Hidden, in the log file you can find the relevant information:
OSError: No files were found matching func template: /data/ds000114/sub-11/ses-test/func/sub-11_ses-test_task-fingerfootlips_bold.nii.gz
Interface SelectFiles failed to run.
170904-05:48:13,727 workflow INFO:
     ***********************************
170904-05:48:13,728 workflow ERROR:
     could not run node: preprocWF.selectfiles
170904-05:48:13,730 workflow INFO:
     crashfile: /repos/nipype_tutorial/notebooks/crash-20170904-054813-neuro-selectfiles-15f5400a-452e-4e0c-ae99-fc0d4b9a44f3.pklz
170904-05:48:13,731 workflow INFO:
     ***********************************
This part tells you that it's an OSError and that it looked for the file /data/ds000114/sub-11/ses-test/func/sub-11_ses-test_task-fingerfootlips_bold.nii.gz.
After the line ***********************************, you can additional see, that it's the node preprocWF.selectfiles that crasehd and that you can find a crashfile to this crash under /opt/tutorial/notebooks.
Reading the crashfile
To get the full picture of the error, we can read the content of the crashfile (that has pklz format by default) with the bash command nipypecli crash. We will get the same information as above, but additionally, we can also see directly the input values of the Node that crashed.
End of explanation
!nipypecli crash -r $(pwd)/crash-*selectfiles-*.pklz
Explanation: nipypecli allows you to rerun the crashed node using an additional option -r.
End of explanation
wf.config['execution']['crashfile_format'] = 'txt'
try:
    wf.run()
except(RuntimeError) as err:
    print("RuntimeError:", err)
else:
    raise
Explanation: When running in the terminal you can also try options that enable the Python or Ipython debugger when re-executing: -d or -i.
If you don't want to have an option to rerun the crashed workflow, you can change the format of crashfile to a text format. You can either change this in a configuration file (you can read more here), or you can directly change the wf.config dictionary before running the workflow.
End of explanation
!cat $(pwd)/crash-*selectfiles-*.txt
Explanation: Now you should have a new text file with your crash report.
End of explanation
from nipype.interfaces.fsl import IsotropicSmooth
try:
    smooth = IsotropicSmooth(fwhm='4')
except(Exception) as err:
    if "TraitError" in str(err.__class__):
        print("TraitError:", err)
    else:
        raise
else:
    raise
Explanation: Example Crash 2: Wrong Input Type or Typo in the parameter
Very simple, if an interface expects a float as input, but you give it a string, it will crash:
End of explanation
IsotropicSmooth.help()
Explanation: This will give you the error: TraitError: The 'fwhm' trait of an IsotropicSmoothInput instance must be a float, but a value of '4' &lt;type 'str'&gt; was specified.
To make sure that you are using the right input types, just check the help section of a given interface. There you can see fwhm: (a float).
End of explanation
from nipype.interfaces.fsl import IsotropicSmooth
try:
    smooth = IsotropicSmooth(output_type='NIFTIiii')
except(Exception) as err:
    if "TraitError" in str(err.__class__):
        print("TraitError:", err)
    else:
        raise
else:
    raise
Explanation: In a similar way, you will also get an error message if the input type is correct but you have a type in the name:
TraitError: The 'output_type' trait of an IsotropicSmoothInput instance must be u'NIFTI_PAIR' or u'NIFTI_PAIR_GZ' or u'NIFTI_GZ' or u'NIFTI', but a value of 'NIFTIiii' &lt;type 'str'&gt; was specified.
End of explanation
from nipype.algorithms.misc import Gunzip
from nipype import Node
files = ['/data/ds000114/sub-01/ses-test/func/sub-01_ses-test_task-fingerfootlips_bold.nii.gz',
         '/data/ds000114/sub-01/ses-test/func/sub-01_ses-test_task-fingerfootlips_bold.nii.gz']
gunzip = Node(Gunzip(), name='gunzip',)
try:
    gunzip.inputs.in_file = files
except(Exception) as err:
    if "TraitError" in str(err.__class__):
        print("TraitError:", err)
    else:
        raise
else:
    raise
Explanation: Example Crash 3: Giving an array as input where a single file is expected
As you can see in the MapNode example, if you try to feed an array as an input into a field that only expects a single file, you will get a TraitError.
End of explanation
from nipype import MapNode
gunzip = MapNode(Gunzip(), name='gunzip', iterfield=['in_file'])
gunzip.inputs.in_file = files
Explanation: This can be solved by using a MapNode:
End of explanation
files = ['/data/ds000114/sub-01/func/sub-01_task-fingerfootlips_bold.nii.gz',
         '/data/ds000114/sub-03/func/sub-03_task-fingerfootlips_bold.nii.gz']
try:
    gunzip.inputs.in_file = files
except(Exception) as err:
    if "TraitError" in str(err.__class__):
        print("TraitError:", err)
    else:
        raise
else:
    raise
Explanation: Now, make sure that you specify files that actually exist, otherwise you will have a TraitError again:
End of explanation
from nipype.interfaces.spm import Smooth
try:
    smooth = Smooth(in_files='/data/ds000114/sub-01/ses-test/anat/sub-01_ses-test_T1w.nii.gz')
except(Exception) as err:
    if "TraitError" in str(err.__class__):
        print("TraitError:", err)
    else:
        raise
else:
    raise
Explanation: By the way, not that those crashes don't create a crashfile, because they didn't happen during runtime, but still during workflow building.
Example Crash 4: SPM doesn't like *.nii.gz files
SPM12 cannot handle compressed NIfTI files (*nii.gz). If you try to run the node nonetheless, it can give you different kind of problems:
SPM Problem 1 with *.nii.gz files
SPM12 has a problem with handling *.nii.gz files. For it a compressed functional image has no temporal dimension and therefore seems to be just a 3D file. So if we try to run the Realign interface on a compressed file, we will get a TraitError error.
End of explanation
from nipype.interfaces.spm import Realign
try:
    realign = Realign(in_files='/data/ds000114/sub-01/ses-test/func/sub-01_ses-test_task-fingerfootlips_bold.nii.gz')
except(Exception) as err:
    if "TraitError" in str(err.__class__):
        print("TraitError:", err)
    else:
        raise
else:
    raise
Explanation: SPM problem 2 with *.nii.gz files
Sometimes TraitError can be more misleading.
End of explanation
from nipype.interfaces.spm import Realign
realign = Realign(register_to_mean=True)
try:
    realign.run()
except(ValueError) as err:
    print("ValueError:", err)
else:
    raise
Explanation: This issue can be solved by unzipping the compressed NIfTI file before giving it as an input to an SPM node. This can either be done by using the Gunzip interface from Nipype or even better if the input is coming from a FSL interface, most of them have an input filed output_type='NIFTI', that you can set to NIFIT.
Example Crash 5: Nipype cannot find the right software
Especially at the beginning, just after installation, you sometimes forgot to specify some environment variables. If you try to use an interface where the environment variables of the software are not specified, e.g. if you try to run:
python
from nipype.interfaces.freesurfer import MRIConvert
convert = MRIConvert(in_file='/data/ds000114/sub-01/ses-test/anat/sub-01_ses-test_T1w.nii.gz',
                     out_type='nii')
you might get an errors, such as:
IOError: command 'mri_convert' could not be found on host mnotter
Interface MRIConvert failed to run.
Or if you try to use SPM, but forgot to tell Nipype where to find it. If you forgot to tell the system where to find MATLAB (or MCR), then you will get the same kind of error as above. But if you forgot to specify which SPM you want to use, you'll get the following RuntimeError:
Standard error:
MATLAB code threw an exception:
SPM not in matlab path
You can solve this issue by specifying the path to your SPM version:
python
from nipype.interfaces.matlab import MatlabCommand
MatlabCommand.set_default_paths('/opt/spm12-r7219/spm12_mcr/spm12')
Example Crash 6: You forget mandatory inputs or use input fields that don't exist
One of the simpler errors are the ones connected to input and output fields.
Forgetting mandatory input fields
Let's see what happens if you forget a [Mandatory] input field.
End of explanation
realign.help()
Explanation: This gives you the error:
ValueError: Realign requires a value for input 'in_files'. For a list of required inputs, see Realign.help()
As described by the error text, if we use the help() function, we can actually see, which inputs are mandatory and which are optional.
End of explanation
from nipype.interfaces.afni import Despike
try:
    despike = Despike(in_file='/data/ds000114/sub-01/ses-test/func/sub-01_ses-test_task-fingerfootlips_bold.nii.gz',
                      output_type='NIFTI')
except(Exception) as err:
    if "TraitError" in str(err.__class__):
        print("TraitError:", err)
    else:
        raise
else:
    raise
Explanation: Using input fields that don't exist
Let's see what happens if we try to specify a parameter that doesn't exist as an input field:
End of explanation
from nipype import SelectFiles, Node, Workflow
from os.path import abspath as opap
from nipype.interfaces.fsl import MCFLIRT, IsotropicSmooth
# Create SelectFiles node
templates={'func': '{subject_id}/func/{subject_id}_task-fingerfootlips_bold.nii.gz'}
sf = Node(SelectFiles(templates),
          name='selectfiles')
sf.inputs.base_directory = opap('/data/ds000114')
sf.inputs.subject_id = 'sub-01'
# Create Motion Correction Node
mcflirt = Node(MCFLIRT(mean_vol=True,
                       save_plots=True),
               name='mcflirt')
# Create Smoothing node
smooth = Node(IsotropicSmooth(fwhm=4),
              name='smooth')
# Create a preprocessing workflow
wf = Workflow(name="preprocWF")
wf.base_dir = 'working_dir'
# Connect the three nodes to each other
wf.connect([(sf, mcflirt, [("func", "in_file")]),
            (mcflirt, smooth, [("out_file", "in_file")])])
Explanation: This results in the TraitError:
TraitError: Cannot set the undefined 'output_type' attribute of a 'DespikeInputSpec' object.
So what went wrong? If you use the help() function, you will see that the correct input filed is called outputtype and not output_type.
Example Crash 7: Trying to connect a node to an input field that is already occupied
Sometimes when you build a new workflow, you might forget that an output field was already connected and you try to connect a new node to the already occupied field.
First, let's create a simple workflow:
End of explanation
# Create a new node
mcflirt_NEW = Node(MCFLIRT(mean_vol=True),
                   name='mcflirt_NEW')
# Connect it to an already connected input field
try:
    wf.connect([(mcflirt_NEW, smooth, [("out_file", "in_file")])])
except(Exception) as err:
    print("Exception:", err)
else:
    raise
Explanation: Now, let's create a new node and connect it to the already occupied input field in_file of the smooth node:
End of explanation
<END_TASK>