Repository: nipy/nipype

Issue:
Tiny BET configuration and output specification bugs
Hi all,

Just wanted to point out a couple of tiny bugs:
- [BETInputSpec][1]'s default frac value is 0, whereas [BET][2]'s actual default value is 0.5. That should be easy enough to update.
- BETInputSpec includes a "skull" option which does, in fact, result in another .nii file with a __skull_ suffix, however, it is not included in BETOutputSpec's definition or the __list_output_ method. 
- When setting BET's out_file to some location other than the pwd, everything is created properly, but the interface's BETOutputSpec instance (output_spec) seems to list all of the output files' locations (other than the out_file) as if they were still created in the pwd. It seems to have something to do with [FSLCommand][3]'s _gen_fname method and its call to fname_presuffix with _newpath=cwd_, but I haven't yet really tried to understand what might be the repercussions of changing anything there. 

I hope I fork the repo and propose fixes sometime soon, but it's a pretty busy time right now. Just thought it wouldn't hurt to put it here, for future reference if nothing else. 

Thank you for all your amazing work! 
Zvi


[1]: https://github.com/nipy/nipype/blob/master/nipype/interfaces/fsl/preprocess.py
[2]: https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/BET/UserGuide
[3]: https://github.com/nipy/nipype/blob/27490e67a48428699466c0a4cfa36ce25cf7222d/nipype/interfaces/fsl/base.py
Tiny BET configuration and output specification bugs
Hi all,

Just wanted to point out a couple of tiny bugs:
- [BETInputSpec][1]'s default frac value is 0, whereas [BET][2]'s actual default value is 0.5. That should be easy enough to update.
- BETInputSpec includes a "skull" option which does, in fact, result in another .nii file with a __skull_ suffix, however, it is not included in BETOutputSpec's definition or the __list_output_ method. 
- When setting BET's out_file to some location other than the pwd, everything is created properly, but the interface's BETOutputSpec instance (output_spec) seems to list all of the output files' locations (other than the out_file) as if they were still created in the pwd. It seems to have something to do with [FSLCommand][3]'s _gen_fname method and its call to fname_presuffix with _newpath=cwd_, but I haven't yet really tried to understand what might be the repercussions of changing anything there. 

I hope I fork the repo and propose fixes sometime soon, but it's a pretty busy time right now. Just thought it wouldn't hurt to put it here, for future reference if nothing else. 

Thank you for all your amazing work! 
Zvi


[1]: https://github.com/nipy/nipype/blob/master/nipype/interfaces/fsl/preprocess.py
[2]: https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/BET/UserGuide
[3]: https://github.com/nipy/nipype/blob/27490e67a48428699466c0a4cfa36ce25cf7222d/nipype/interfaces/fsl/base.py


Discussion:
Thanks for these notes. Can you verify these are true for all versions of BET? In particular, if the default frac value varies by version, we should encode that.
I couldn't find any documentation for previous versions of BET, however, I searched for "BET" references in [FSL's release history](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/WhatsNew) and did not find any mention of changing it. [BET's FAQ page](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/BET/FAQ) does also mention that the default value is 0.5, if that helps. 
@ZviBaratz - just a quick note that BET does not have a default for `frac`. 

https://github.com/nipy/nipype/blob/master/nipype/interfaces/fsl/preprocess.py#L45

in nipype, for something to have a default and be used two things need to happen.

1. a default value needs to be set
2. the metadata `usedefault=True` has to be added.

the way nipype deals with defaults is therefore not consistent across interfaces. we will likely implement a clear default policy for nipype 2.0, but i'm inclined not to introduce this in nipype 1.x.
@satra - Thank you for the note. 
Also, I'm excited to hear 2.0 is in the works! I am actually trying to create a django application to better support analysis configuration and execution serialization for [our lab](http://neuroimaging.tau.ac.il/) and would be more than happy to also become involved in the future development of nipype if I can. I subscribed to the mailing list and will follow up soon.
Just to follow up on this - BET still seems to return incorrect output paths. If anyone has an idea for a quick fix I will gladly come up a PR. Maybe during next week's Nilearn's event would be a good time to resolve this.
Thanks for these notes. Can you verify these are true for all versions of BET? In particular, if the default frac value varies by version, we should encode that.
I couldn't find any documentation for previous versions of BET, however, I searched for "BET" references in [FSL's release history](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/WhatsNew) and did not find any mention of changing it. [BET's FAQ page](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/BET/FAQ) does also mention that the default value is 0.5, if that helps. 
@ZviBaratz - just a quick note that BET does not have a default for `frac`. 

https://github.com/nipy/nipype/blob/master/nipype/interfaces/fsl/preprocess.py#L45

in nipype, for something to have a default and be used two things need to happen.

1. a default value needs to be set
2. the metadata `usedefault=True` has to be added.

the way nipype deals with defaults is therefore not consistent across interfaces. we will likely implement a clear default policy for nipype 2.0, but i'm inclined not to introduce this in nipype 1.x.
@satra - Thank you for the note. 
Also, I'm excited to hear 2.0 is in the works! I am actually trying to create a django application to better support analysis configuration and execution serialization for [our lab](http://neuroimaging.tau.ac.il/) and would be more than happy to also become involved in the future development of nipype if I can. I subscribed to the mailing list and will follow up soon.
Just to follow up on this - BET still seems to return incorrect output paths. If anyone has an idea for a quick fix I will gladly come up a PR. Maybe during next week's Nilearn's event would be a good time to resolve this.

Resolving patch:
diff --git a/nipype/interfaces/fsl/preprocess.py b/nipype/interfaces/fsl/preprocess.py
--- a/nipype/interfaces/fsl/preprocess.py
+++ b/nipype/interfaces/fsl/preprocess.py
@@ -173,45 +173,50 @@ def _gen_outfilename(self):
     def _list_outputs(self):
         outputs = self.output_spec().get()
         outputs["out_file"] = self._gen_outfilename()
+
+        basename = os.path.basename(outputs['out_file'])
+        cwd = os.path.dirname(outputs['out_file'])
+        kwargs = {'basename': basename, 'cwd': cwd}
+
         if (isdefined(self.inputs.mesh) and self.inputs.mesh) or (
             isdefined(self.inputs.surfaces) and self.inputs.surfaces
         ):
             outputs["meshfile"] = self._gen_fname(
-                outputs["out_file"], suffix="_mesh.vtk", change_ext=False
+                suffix="_mesh.vtk", change_ext=False, **kwargs
             )
         if (isdefined(self.inputs.mask) and self.inputs.mask) or (
             isdefined(self.inputs.reduce_bias) and self.inputs.reduce_bias
         ):
-            outputs["mask_file"] = self._gen_fname(outputs["out_file"], suffix="_mask")
+            outputs["mask_file"] = self._gen_fname(suffix="_mask", **kwargs)
         if isdefined(self.inputs.outline) and self.inputs.outline:
             outputs["outline_file"] = self._gen_fname(
-                outputs["out_file"], suffix="_overlay"
+                suffix="_overlay", **kwargs
             )
         if isdefined(self.inputs.surfaces) and self.inputs.surfaces:
             outputs["inskull_mask_file"] = self._gen_fname(
-                outputs["out_file"], suffix="_inskull_mask"
+                suffix="_inskull_mask", **kwargs
             )
             outputs["inskull_mesh_file"] = self._gen_fname(
-                outputs["out_file"], suffix="_inskull_mesh"
+                suffix="_inskull_mesh", **kwargs
             )
             outputs["outskull_mask_file"] = self._gen_fname(
-                outputs["out_file"], suffix="_outskull_mask"
+                suffix="_outskull_mask", **kwargs
             )
             outputs["outskull_mesh_file"] = self._gen_fname(
-                outputs["out_file"], suffix="_outskull_mesh"
+                suffix="_outskull_mesh", **kwargs
             )
             outputs["outskin_mask_file"] = self._gen_fname(
-                outputs["out_file"], suffix="_outskin_mask"
+                suffix="_outskin_mask", **kwargs
             )
             outputs["outskin_mesh_file"] = self._gen_fname(
-                outputs["out_file"], suffix="_outskin_mesh"
+                suffix="_outskin_mesh", **kwargs
             )
             outputs["skull_mask_file"] = self._gen_fname(
-                outputs["out_file"], suffix="_skull_mask"
+                suffix="_skull_mask", **kwargs
             )
         if isdefined(self.inputs.skull) and self.inputs.skull:
             outputs["skull_file"] = self._gen_fname(
-                outputs["out_file"], suffix="_skull"
+                suffix="_skull", **kwargs
             )
         if isdefined(self.inputs.no_output) and self.inputs.no_output:
             outputs["out_file"] = Undefined


Test patch: