From b47a1247766989dd161e05dcfdfe2f6e00cb290b Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 14:28:31 -0400 Subject: [PATCH 01/16] Create pydra.py --- nipreps/synthstrip/wrappers/pydra.py | 104 +++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 nipreps/synthstrip/wrappers/pydra.py diff --git a/nipreps/synthstrip/wrappers/pydra.py b/nipreps/synthstrip/wrappers/pydra.py new file mode 100644 index 0000000..036a63f --- /dev/null +++ b/nipreps/synthstrip/wrappers/pydra.py @@ -0,0 +1,104 @@ +import nest_asyncio +nest_asyncio.apply() +import pydra +import os +import attr + +_fs_home = os.getenv("FREESURFER_HOME", None) +_default_model_path = Path(_fs_home) / "models" / "synthstrip.1.pt" if _fs_home else None + + +_SynthStripInputSpec = pydra.specs.SpecInfo( + name='SynthStripInputSpec', + fields=[ + ( + 'in_file', + attr.ib( + type=str, + metadata={ + 'argstr': "-i", + 'help_string': 'Input image to be brain extracted', + 'mandatory': True, + }, + ), + ), + ( + 'use_gpu', + bool, + False, + { + 'argstr': "-g", + 'help_string': 'Use GPU', + }, + ), + ( + 'model', + pydra.specs.File, + str(_default_model_path), + { + 'argstr': "--model", + "help_string": "file containing model's weights", + }, + ), + ( + 'border_mm', + int, + 1, + { + 'argstr': "-b", + "help_string": "Mask border threshold in mm", + }, + ), + ( + 'out_file', + str, + # MAKE DEFAULT HERE BASED ON 'in_file' + { + 'argstr': "-o", + "help_string": "store brain-extracted input to file", + }, + ), + ( + 'out_mask', + str, + # MAKE DEFAULT HERE BASED ON 'in_file' + { + 'argstr': "-m", + "help_string": "store brainmask to file", + }, + ), + ( + 'no_csf', + bool, + False, + { + 'argstr': "--no-csf", + 'help_string': 'Exclude CSF from brain border', + }, + ), + + ], + bases=(pydra.specs.ShellSpec,), +) + +_SynthStripOutputSpec = pydra.specs.SpecInfo( + name='SynthStripOutputSpec', + fields=[ + ( + 'out_file', + pydra.specs.File, + 'tmp' # SET THIS TO 'out_file' of input_spec + ), + ( + 'out_mask', + pydra.specs.File, + 'tmp' # SET THIS TO 'out_mask' of input_spec + ), + ], + + bases=(pydra.specs.ShellOutSpec,), +) + +SynthStrip = pydra.ShellCommandTask( + name='SynthStrip', executable="nipreps-synthstrip", input_spec = _SynthStripInputSpec, output_spec=_SynthStripOutputSpec +) From 7648e1c242a884dc8bb7a0abbb4471225c8badc3 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 14:34:19 -0400 Subject: [PATCH 02/16] Update pydra.py Reorder args, match help string with program --- nipreps/synthstrip/wrappers/pydra.py | 59 ++++++++++++++-------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/nipreps/synthstrip/wrappers/pydra.py b/nipreps/synthstrip/wrappers/pydra.py index 036a63f..d9b03ce 100644 --- a/nipreps/synthstrip/wrappers/pydra.py +++ b/nipreps/synthstrip/wrappers/pydra.py @@ -17,27 +17,36 @@ type=str, metadata={ 'argstr': "-i", - 'help_string': 'Input image to be brain extracted', + 'help_string': 'Input image to skullstrip', 'mandatory': True, }, ), ), ( - 'use_gpu', - bool, - False, + 'out_file', + str, + # MAKE DEFAULT HERE BASED ON 'in_file' { - 'argstr': "-g", - 'help_string': 'Use GPU', + 'argstr': "-o", + "help_string": "Save stripped image to path", }, ), ( - 'model', - pydra.specs.File, - str(_default_model_path), + 'out_mask', + str, + # MAKE DEFAULT HERE BASED ON 'in_file' { - 'argstr': "--model", - "help_string": "file containing model's weights", + 'argstr': "-m", + "help_string": "Save binary brain mask to path", + }, + ), + ( + 'use_gpu', + bool, + False, + { + 'argstr': "-g", + 'help_string': 'Use the GPU', }, ), ( @@ -49,24 +58,6 @@ "help_string": "Mask border threshold in mm", }, ), - ( - 'out_file', - str, - # MAKE DEFAULT HERE BASED ON 'in_file' - { - 'argstr': "-o", - "help_string": "store brain-extracted input to file", - }, - ), - ( - 'out_mask', - str, - # MAKE DEFAULT HERE BASED ON 'in_file' - { - 'argstr': "-m", - "help_string": "store brainmask to file", - }, - ), ( 'no_csf', bool, @@ -76,7 +67,15 @@ 'help_string': 'Exclude CSF from brain border', }, ), - + ( + 'model', + pydra.specs.File, + str(_default_model_path), + { + 'argstr': "--model", + "help_string": "file containing model's weights", + }, + ) ], bases=(pydra.specs.ShellSpec,), ) From 79fcf89e6ce7abfb26593700ded65346620d5b20 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 14:54:01 -0400 Subject: [PATCH 03/16] Update pydra.py Fix imports; add output filename templates --- nipreps/synthstrip/wrappers/pydra.py | 68 ++++++++++++++++++---------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/nipreps/synthstrip/wrappers/pydra.py b/nipreps/synthstrip/wrappers/pydra.py index d9b03ce..defd50b 100644 --- a/nipreps/synthstrip/wrappers/pydra.py +++ b/nipreps/synthstrip/wrappers/pydra.py @@ -1,12 +1,39 @@ -import nest_asyncio -nest_asyncio.apply() -import pydra +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# +# Copyright 2022 The NiPreps Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# We support and encourage derived works from this project, please read +# about our expectations at +# +# https://www.nipreps.org/community/licensing/ +# +"""SynthStrip interface.""" + import os import attr +from pathlib import Path +import pydra +import nest_asyncio +nest_asyncio.apply() _fs_home = os.getenv("FREESURFER_HOME", None) _default_model_path = Path(_fs_home) / "models" / "synthstrip.1.pt" if _fs_home else None +if _fs_home and not _default_model_path.exists(): + _default_model_path = Undefined _SynthStripInputSpec = pydra.specs.SpecInfo( name='SynthStripInputSpec', @@ -25,19 +52,19 @@ ( 'out_file', str, - # MAKE DEFAULT HERE BASED ON 'in_file' { 'argstr': "-o", "help_string": "Save stripped image to path", + "output_file_template": "{in_file}_desc-brain.nii.gz", }, ), ( 'out_mask', str, - # MAKE DEFAULT HERE BASED ON 'in_file' { 'argstr': "-m", "help_string": "Save binary brain mask to path", + "output_file_template": "{in_file}_desc-brain_mask.nii.gz", }, ), ( @@ -73,31 +100,24 @@ str(_default_model_path), { 'argstr': "--model", - "help_string": "file containing model's weights", + "help_string": "File containing model's weights", }, - ) - ], - bases=(pydra.specs.ShellSpec,), -) - -_SynthStripOutputSpec = pydra.specs.SpecInfo( - name='SynthStripOutputSpec', - fields=[ - ( - 'out_file', - pydra.specs.File, - 'tmp' # SET THIS TO 'out_file' of input_spec ), ( - 'out_mask', - pydra.specs.File, - 'tmp' # SET THIS TO 'out_mask' of input_spec + 'num_threads', + int, + 0, # WHAT SHOULD BE DEFAULT FOR N_THREADS? + { + 'argstr': "-n", + "help_string": "Number of threads", + }, ), ], - - bases=(pydra.specs.ShellOutSpec,), + bases=(pydra.specs.ShellSpec,), ) SynthStrip = pydra.ShellCommandTask( - name='SynthStrip', executable="nipreps-synthstrip", input_spec = _SynthStripInputSpec, output_spec=_SynthStripOutputSpec + name='SynthStrip', + executable="nipreps-synthstrip", + input_spec = _SynthStripInputSpec ) From 7242114b30a15f6433fed3f14f1ee4d10523e666 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 14:56:39 -0400 Subject: [PATCH 04/16] Update pydra.py remove n_threads default --- nipreps/synthstrip/wrappers/pydra.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nipreps/synthstrip/wrappers/pydra.py b/nipreps/synthstrip/wrappers/pydra.py index defd50b..e68b26d 100644 --- a/nipreps/synthstrip/wrappers/pydra.py +++ b/nipreps/synthstrip/wrappers/pydra.py @@ -106,7 +106,6 @@ ( 'num_threads', int, - 0, # WHAT SHOULD BE DEFAULT FOR N_THREADS? { 'argstr': "-n", "help_string": "Number of threads", From 6b7f06d443ab501fc4b8430fe339a35db59a0ec7 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 15:04:31 -0400 Subject: [PATCH 05/16] Update pydra.py --- nipreps/synthstrip/wrappers/pydra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipreps/synthstrip/wrappers/pydra.py b/nipreps/synthstrip/wrappers/pydra.py index e68b26d..5cfcec4 100644 --- a/nipreps/synthstrip/wrappers/pydra.py +++ b/nipreps/synthstrip/wrappers/pydra.py @@ -33,7 +33,7 @@ _default_model_path = Path(_fs_home) / "models" / "synthstrip.1.pt" if _fs_home else None if _fs_home and not _default_model_path.exists(): - _default_model_path = Undefined + _default_model_path = None _SynthStripInputSpec = pydra.specs.SpecInfo( name='SynthStripInputSpec', From 5e94c9fa0d3f4a139758d0b20fed7383e87a12ec Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 15:26:36 -0400 Subject: [PATCH 06/16] Update README.md --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ed9f8a..9e8e0c0 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,9 @@ pip install nipreps-synthstrip # For the nipype interface pip install nipreps-synthstrip[nipype] + +# For the pydra interface +pip install nipreps-synthstrip[pydra] ``` ### Command Line Tool @@ -24,8 +27,21 @@ $ nipreps-synthstrip from nipreps.synthstrip.wrappers.nipype import SynthStrip ``` +### Pydra Interface + +```python +import pydra +from nipreps.synthstrip.wrappers.pydra import _SynthStripInputSpec + +SynthStrip = pydra.ShellCommandTask( + name='SynthStrip', + executable="nipreps-synthstrip", + input_spec = _SynthStripInputSpec +) +``` + ## Citation > A Hoopes, JS Mora, AV Dalca, B Fischl, M Hoffmann. > SynthStrip: Skull-Stripping for Any Brain Image. -> https://arxiv.org/abs/2203.09974 \ No newline at end of file +> https://arxiv.org/abs/2203.09974 From 045e183d02190a5c3a6dc1763fda2f0131c99e49 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 15:27:09 -0400 Subject: [PATCH 07/16] Update pydra.py --- nipreps/synthstrip/wrappers/pydra.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/nipreps/synthstrip/wrappers/pydra.py b/nipreps/synthstrip/wrappers/pydra.py index 5cfcec4..dd80a92 100644 --- a/nipreps/synthstrip/wrappers/pydra.py +++ b/nipreps/synthstrip/wrappers/pydra.py @@ -114,9 +114,3 @@ ], bases=(pydra.specs.ShellSpec,), ) - -SynthStrip = pydra.ShellCommandTask( - name='SynthStrip', - executable="nipreps-synthstrip", - input_spec = _SynthStripInputSpec -) From dbca33334994dbe7e5f6ec6e20a0cfb1cd4b5e94 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 15:39:16 -0400 Subject: [PATCH 08/16] Update pyproject.toml --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7f173e2..50acc95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,9 @@ dev = [ nipype = [ "nipype", ] +pydra = [ + "pydra", +] test = [ "pytest", ] @@ -65,4 +68,4 @@ target-version = ['py310'] skip-string-normalization = true [tool.isort] -profile = 'black' \ No newline at end of file +profile = 'black' From 30fe3327f9807e792be90647f1a14999fdf6b693 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 15:43:12 -0400 Subject: [PATCH 09/16] Update pyproject.toml --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 50acc95..a468c46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,6 +45,7 @@ nipype = [ ] pydra = [ "pydra", + "nest_asyncio", ] test = [ "pytest", From e1727c07322bd2d4317b8dfdad2d3410bc10a44d Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 15:57:12 -0400 Subject: [PATCH 10/16] Update pyproject.toml remove nest-asyncio as dependency --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a468c46..50acc95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,6 @@ nipype = [ ] pydra = [ "pydra", - "nest_asyncio", ] test = [ "pytest", From a94bc6ac15e5aac41f8d7655284b8b4fb89ecfe7 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 15:57:43 -0400 Subject: [PATCH 11/16] Update pydra.py remove nest-asyncio as dependency --- nipreps/synthstrip/wrappers/pydra.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/nipreps/synthstrip/wrappers/pydra.py b/nipreps/synthstrip/wrappers/pydra.py index dd80a92..a9958a7 100644 --- a/nipreps/synthstrip/wrappers/pydra.py +++ b/nipreps/synthstrip/wrappers/pydra.py @@ -26,8 +26,6 @@ import attr from pathlib import Path import pydra -import nest_asyncio -nest_asyncio.apply() _fs_home = os.getenv("FREESURFER_HOME", None) _default_model_path = Path(_fs_home) / "models" / "synthstrip.1.pt" if _fs_home else None From c5b2b2c0653acb21ae0c17b3bc429576a8220b71 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 16:00:04 -0400 Subject: [PATCH 12/16] Update nipreps/synthstrip/wrappers/pydra.py Co-authored-by: Mathias Goncalves --- nipreps/synthstrip/wrappers/pydra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipreps/synthstrip/wrappers/pydra.py b/nipreps/synthstrip/wrappers/pydra.py index a9958a7..1b0179f 100644 --- a/nipreps/synthstrip/wrappers/pydra.py +++ b/nipreps/synthstrip/wrappers/pydra.py @@ -33,7 +33,7 @@ if _fs_home and not _default_model_path.exists(): _default_model_path = None -_SynthStripInputSpec = pydra.specs.SpecInfo( +SynthStripInputSpec = pydra.specs.SpecInfo( name='SynthStripInputSpec', fields=[ ( From 2447bb5dd892a2edbc3f16dfe20cb80900fb4f14 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 16:00:15 -0400 Subject: [PATCH 13/16] Update README.md Co-authored-by: Mathias Goncalves --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e8e0c0..81b28d1 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ from nipreps.synthstrip.wrappers.nipype import SynthStrip ```python import pydra -from nipreps.synthstrip.wrappers.pydra import _SynthStripInputSpec +from nipreps.synthstrip.wrappers.pydra import SynthStripInputSpec SynthStrip = pydra.ShellCommandTask( name='SynthStrip', From e3733b1783df36e06b1edeae1c9b72b0a9996353 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 16:00:42 -0400 Subject: [PATCH 14/16] Update README.md Co-authored-by: Mathias Goncalves --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81b28d1..4b29475 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ from nipreps.synthstrip.wrappers.pydra import SynthStripInputSpec SynthStrip = pydra.ShellCommandTask( name='SynthStrip', executable="nipreps-synthstrip", - input_spec = _SynthStripInputSpec + input_spec = SynthStripInputSpec ) ``` From d19e1886895b04ef96fd58467106cdcd848fa4f3 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 16:01:52 -0400 Subject: [PATCH 15/16] Update pydra.py --- nipreps/synthstrip/wrappers/pydra.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nipreps/synthstrip/wrappers/pydra.py b/nipreps/synthstrip/wrappers/pydra.py index 1b0179f..2109186 100644 --- a/nipreps/synthstrip/wrappers/pydra.py +++ b/nipreps/synthstrip/wrappers/pydra.py @@ -112,3 +112,8 @@ ], bases=(pydra.specs.ShellSpec,), ) + +SynthStrip = pydra.ShellCommandTask( + executable="nipreps-synthstrip", + input_spec = SynthStripInputSpec +) From 7e73674c8ffee77aeb91033b1ab057aa0084ccc3 Mon Sep 17 00:00:00 2001 From: Steven Meisler Date: Thu, 20 Jul 2023 16:04:18 -0400 Subject: [PATCH 16/16] Update README.md simplify import --- README.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/README.md b/README.md index 4b29475..cc11142 100644 --- a/README.md +++ b/README.md @@ -30,14 +30,7 @@ from nipreps.synthstrip.wrappers.nipype import SynthStrip ### Pydra Interface ```python -import pydra -from nipreps.synthstrip.wrappers.pydra import SynthStripInputSpec - -SynthStrip = pydra.ShellCommandTask( - name='SynthStrip', - executable="nipreps-synthstrip", - input_spec = SynthStripInputSpec -) +from nipreps.synthstrip.wrappers.pydra import SynthStrip ``` ## Citation