diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6aabaf9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# EditorConfig + +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.toml] +indent_size = 2 + +[*.yaml] +indent_size = 2 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..40e811e --- /dev/null +++ b/.flake8 @@ -0,0 +1,15 @@ + +[flake8] +doctests = True +exclude = + **/__init__.py + *build/ + docs/sphinxext/ + docs/tools/ + docs/conf.py + docs/source/conf.py +max-line-length = 88 +select = C,E,F,W,B,B950 +extend-ignore = E203,E501,E129,W503 +per-file-ignores = + __init__.py:F401,F403 diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..ca79ca5 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly diff --git a/.github/workflows/ci-cd.yaml b/.github/workflows/ci-cd.yaml new file mode 100644 index 0000000..94c54f8 --- /dev/null +++ b/.github/workflows/ci-cd.yaml @@ -0,0 +1,421 @@ +#This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +# For deployment, it will be necessary to create a PyPI API token and store it as a secret +# https://docs.github.com/en/actions/reference/encrypted-secrets + +name: CI/CD + +on: + push: + branches: [ master, develop ] + pull_request: + branches: [ master, develop ] + release: + types: [published] + repository_dispatch: + types: [create-post-release] + +env: + FSL_VERSION: 6.0.7.9 + FSL_HOME: ${{ github.workspace }}/fsl-install + +jobs: + + nipype-conv: + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Revert version to most recent version tag on upstream update + if: github.event_name == 'repository_dispatch' + run: git checkout $(git tag -l | grep 'v.*' | tail -n 1 | awk -F post '{print $1}') + + - name: Set up Python + uses: actions/setup-python@v5 + + - name: Install build dependencies + run: python -m pip install --upgrade pip + + - name: Install requirements + run: python -m pip install ./related-packages/fileformats -r ./nipype-auto-conv/requirements.txt + + - name: Run automatic Nipype > Pydra conversion + run: ./nipype-auto-conv/generate + + - uses: actions/upload-artifact@v4 + with: + name: converted-nipype + path: pydra/tasks/fsl/auto + + devcheck: + needs: [nipype-conv] + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.8', '3.11'] # Check oldest and newest versions + pip-flags: ['', '--editable'] + pydra: + - 'pydra' + - '--editable git+https://github.com/nipype/pydra.git#egg=pydra' + + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Revert version to most recent version tag on upstream update + if: github.event_name == 'repository_dispatch' + run: git checkout $(git tag -l | grep 'v.*' | tail -n 1 | awk -F post '{print $1}') + + - name: Download tasks converted from Nipype + uses: actions/download-artifact@v4 + with: + name: converted-nipype + path: pydra/tasks/fsl/auto + + - name: Strip auto package from gitignore so it is included in package + run: | + sed -i '/\/pydra\/tasks\/fsl\/auto/d' .gitignore + sed -i '/^_version.py/d' .gitignore + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install build dependencies + run: | + python -m pip install --upgrade pip + + - name: Install Pydra + run: | + pushd $HOME + pip install ${{ matrix.pydra }} + popd + python -c "import pydra as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" + + - name: Install task package + run: | + pip install ${{ matrix.pip-flags }} "./related-packages/fileformats[dev]" + pip install ${{ matrix.pip-flags }} "related-packages/fileformats-extras[dev]" + pip install ${{ matrix.pip-flags }} ".[dev]" + python -c "import pydra.tasks.fsl as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" + python -c "import pydra as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" + python -c "import fileformats.medimage_fsl as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" + python -c "import fileformats.extras.medimage_fsl as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" + + test: + needs: [nipype-conv] + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.8', '3.11'] + steps: + + - name: Removed unnecessary tools to free space + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install Minconda + uses: conda-incubator/setup-miniconda@v2 + with: + auto-activate-base: true + activate-environment: "" + + - name: Install fsl Packages + run: >- + conda install -c conda-forge -c https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/public/ + ciftilib cli11 elc fsl-add_module fsl-armawrap fsl-asl_mfree fsl-avwutils fsl-base + fsl-basil fsl-basisfield fsl-baycest fsl-bet2 fsl-bianca fsl-biancadata fsl-bint + fsl-cluster fsl-copain fsl-cprob fsl-cudimot fsl-data_atlases + fsl-data_atlases_xtract fsl-data_first_models_317_bin fsl-data_first_models_336_bin fsl-data_linearmni + fsl-data_omm fsl-data_possum fsl-data_standard fsl-deface fsl-discreteopt fsl-dpm fsl-dwssfp + fsl-easyfeat fsl-eddy fsl-eddy_qc fsl-fabber_core fsl-fabber_models_asl fsl-fabber_models_cest + fsl-fabber_models_dce fsl-fabber_models_dsc fsl-fabber_models_dualecho fsl-fabber_models_dwi + fsl-fabber_models_pet fsl-fabber_models_qbold fsl-fabber_models_t1 fsl-fast4 fsl-fastpdlib + fsl-fdt fsl-feat5 fsl-film fsl-filmbabe fsl-first fsl-first_lib fsl-flameo + fsl-flirt fsl-fnirt fsl-fugue fsl-get_standard fsl-giftiio fsl-gps + fsl-gui-desktop fsl-installer fsl-lesions fsl-libgdc fsl-libmeshutils fsl-libvis fsl-load_dicom fsl-mcflirt + fsl-melodic fsl-meshclass fsl-misc_c fsl-misc_scripts fsl-misc_tcl fsl-miscmaths fsl-miscvis + fsl-mist fsl-mm fsl-msm fsl-msmreglib fsl-mvdisc fsl-nets fsl-newimage + fsl-newmesh fsl-newnifti fsl-newran fsl-oxford_asl fsl-possum fsl-ptx2 fsl-pyfeeds + fsl-pyfeeds-tests fsl-qboot fsl-randomise fsl-relax fsl-shapemodel fsl-siena fsl-slicetimer + fsl-sub fsl-sub-plugin-sge fsl-sub-plugin-slurm fsl-surface fsl-susan fsl-swe fsl-tbss + fsl-topup fsl-utils fsl-vbm fsl-verbena fsl-vtkio fsl-warpfns fsl-wire fsl-xtract fsl-xtract_data + fsl-znzlib fsl_mrs fsl_sub fsl_sub_plugin_sge fsl_sub_plugin_slurm + + - name: Download tasks converted from Nipype + uses: actions/download-artifact@v4 + with: + name: converted-nipype + path: pydra/tasks/fsl/auto + + - name: Show the contents of the auto-generated tasks + run: tree pydra + + - name: Strip auto package from gitignore so it is included in package + run: | + sed -i '/\/pydra\/tasks\/fsl\/auto/d' .gitignore + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install build dependencies + run: | + python -m pip install --upgrade pip + + - name: Install task package + run: | + pip install "./related-packages/fileformats" "./related-packages/fileformats-extras" ".[test]" + python -c "import pydra.tasks.fsl as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" + python -c "import pydra as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" + + - name: Test with pytest + run: >- + pytest -sv + ./pydra/tasks/fsl + ./related-packages/fileformats + ./related-packages/fileformats-extras + --cov pydra.tasks.fsl + --cov fileformats.medimage_fsl + --cov fileformats.extras.medimage_fsl + --cov-report xml + + - name: Upload to CodeCov + uses: codecov/codecov-action@v3 + if: ${{ always() }} + with: + files: coverage.xml + name: pydra-fsl + + + deploy-fileformats: + needs: [devcheck, test] + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install build tools + run: python -m pip install build twine + + - name: Build source and wheel distributions + run: python -m build ./related-packages/fileformats + + - name: Check distributions + run: twine check ./related-packages/fileformats/dist/* + + - name: Check for PyPI token on tag + id: deployable + if: github.event_name == 'release' || github.event_name == 'repository_dispatch' + env: + PYPI_API_TOKEN: "${{ secrets.PYPI_FILEFORMATS_API_TOKEN }}" + run: if [ -n "$PYPI_API_TOKEN" ]; then echo "DEPLOY=true" >> $GITHUB_OUTPUT; fi + + - name: Upload to PyPI + if: steps.deployable.outputs.DEPLOY + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_FILEFORMATS_API_TOKEN }} + packages-dir: ./related-packages/fileformats/dist + + deploy-fileformats-extras: + needs: [deploy-fileformats] + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install build tools + run: python -m pip install build twine + + - name: Build source and wheel distributions + run: python -m build ./related-packages/fileformats-extras + + - name: Check distributions + run: twine check ./related-packages/fileformats-extras/dist/* + + - name: Check for PyPI token on tag + id: deployable + if: github.event_name == 'release' || github.event_name == 'repository_dispatch' + env: + PYPI_API_TOKEN: "${{ secrets.PYPI_FILEFORMATS_EXTRAS_API_TOKEN }}" + run: if [ -n "$PYPI_API_TOKEN" ]; then echo "DEPLOY=true" >> $GITHUB_OUTPUT; fi + + - name: Upload to PyPI + if: steps.deployable.outputs.DEPLOY + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_FILEFORMATS_EXTRAS_API_TOKEN }} + packages-dir: ./related-packages/fileformats-extras/dist + + deploy: + needs: [nipype-conv, test, deploy-fileformats, deploy-fileformats-extras] + runs-on: ubuntu-latest + steps: + + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: Set up Git user + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + + - name: Get latest version tag + id: latest_tag + run: | + git fetch --tags + echo "TAG=$(git tag -l | grep 'v.*' | tail -n 1 | awk -F post '{print $1}')" >> $GITHUB_OUTPUT + + - name: Revert to latest tag + if: github.event_name == 'repository_dispatch' + run: git checkout ${{ steps.latest_tag.outputs.TAG }} + + - name: Download tasks converted from Nipype + uses: actions/download-artifact@v4 + with: + name: converted-nipype + path: pydra/tasks/fsl/auto + + - name: Show the contents of the auto-generated tasks + run: tree pydra + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install build tools + run: python -m pip install build twine + + - name: Strip auto package from gitignore so it is included in package + run: | + sed -i '/\/pydra\/tasks\/fsl\/auto/d' .gitignore + cat .gitignore + + - name: Install task package to calculate post-release tag + run: | + pip install "./related-packages/fileformats" "./related-packages/fileformats-extras" ".[test]" + + - name: Generate post-release tag based on Nipype and Nipype2Pydra versions + id: post_release_tag + run: | + POST=$(python -c "from pydra.tasks.fsl.auto._version import *; print(post_release)") + echo "TAG=${{ steps.latest_tag.outputs.TAG }}post${POST}" >> $GITHUB_OUTPUT + + - name: Add auto directory to git repo + if: github.event_name == 'release' || github.event_name == 'repository_dispatch' + run: | + git add pydra/tasks/fsl/auto + git commit -am"added auto-generated version to make new tag for package version" + git status + + - name: Overwrite the tag of release event with latest commit (i.e. including the auto directory) + if: github.event_name == 'release' + run: | + git tag -d ${{ steps.latest_tag.outputs.TAG }}; + git tag ${{ steps.latest_tag.outputs.TAG }}; + + - name: Tag repo with the post-release + if: github.event_name == 'repository_dispatch' + run: git tag ${{ steps.post_release_tag.outputs.TAG }} + + - name: Build source and wheel distributions + run: python -m build . + + - name: Check distributions + run: twine check dist/* + + - uses: actions/upload-artifact@v4 + with: + name: distributions + path: dist/ + + - name: Check for PyPI token on tag + id: deployable + if: github.event_name == 'release' || github.event_name == 'repository_dispatch' + env: + PYPI_API_TOKEN: "${{ secrets.PYPI_API_TOKEN }}" + run: if [ -n "$PYPI_API_TOKEN" ]; then echo "DEPLOY=true" >> $GITHUB_OUTPUT; fi + + - name: Upload to PyPI + if: steps.deployable.outputs.DEPLOY + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} + + - name: Create post-release release for releases triggered by nipype2pydra dispatches + if: steps.deployable.outputs.DEPLOY && github.event_name == 'repository_dispatch' + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ steps.post_release_tag.outputs.TAG }} + release_name: Release ${{ steps.post_release_tag.outputs.TAG }} + draft: false + prerelease: false + + + # report_progress: + # needs: [deploy] + # runs-on: ubuntu-latest + # steps: + + # - name: Checkout + # uses: actions/checkout@v4 + + # - name: Generate progress report + # id: generate-report + # run: | + # tools/report_progress.py outputs/progress-report.json + # echo "progress_report=$(cat outputs/progress-report.json)" >> $GITHUB_OUTPUT + + # - name: Report progress to Nipype2Pydra repo + # if: github.event_name == 'release' || github.event_name == 'repository_dispatch' + # run: >- + # curl -XPOST -u "${{ env.REPORT_PROGRESS_PAT }}" -H "Accept: application/vnd.github.everest-preview+json" + # "https://api.github.com/repos/nipype/pydra-fsl/dispatches" + # -d '{ + # "event_type": "progress-report", + # "client_payload": ${{ steps.generate-report.output.progress_report }} + # }' + # env: + # PAT: ${{ env.REPORT_PROGRESS_PAT }} + + +# Deploy on tags if PYPI_API_TOKEN is defined in the repository secrets. +# Secrets are not accessible in the if: condition [0], so set an output variable [1] +# [0] https://github.community/t/16928 +# [1] https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml new file mode 100644 index 0000000..9ec3cc8 --- /dev/null +++ b/.github/workflows/docs.yaml @@ -0,0 +1,58 @@ +name: docs + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Install Hatch + run: pipx install hatch + - name: Build documentation + run: hatch run docs:build + - name: Upload documentation + uses: actions/upload-artifact@v4 + with: + name: docs + path: 'docs/_build/html' + retention-days: 1 + + deploy: + needs: build + if: contains('refs/heads/main', github.ref) + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Download documentation + uses: actions/download-artifact@v4 + with: + name: docs + - name: Setup GitHub Pages + uses: actions/configure-pages@v4 + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: '.' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/fsl_docker.yml b/.github/workflows/fsl_docker.yml deleted file mode 100644 index ff4265a..0000000 --- a/.github/workflows/fsl_docker.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: fsl_docker - -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - env: - DOCKER_IMAGE: djarecka/fsl_py:6.0.4 - - steps: - - uses: actions/checkout@v2 - with: - lfs: true - - name: Pull docker image - run: | - docker pull $DOCKER_IMAGE - # Have image running in background - docker run `bash <(curl -s https://codecov.io/env)` -itd --name fsl_cont -v `pwd`:/pydra_fsl $DOCKER_IMAGE - - name: Updating pydra - run: docker exec fsl_cont bash -c "pip install https://github.com/nipype/pydra/tarball/master && python -c 'import pydra; print(pydra.__version__)'" - - name: Run pytest - run: docker exec fsl_cont bash -c "pytest --color=yes -vs /pydra_fsl/pydra/tasks/fsl" - - name: removing container - run: docker rm -f fsl_cont diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..e06b07a --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,27 @@ +name: publish + +on: + release: + types: [ published ] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Build distribution + run: pipx run build + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml deleted file mode 100644 index c139864..0000000 --- a/.github/workflows/pythonpackage.yml +++ /dev/null @@ -1,119 +0,0 @@ -#This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -# For deployment, it will be necessary to create a PyPI API token and store it as a secret -# https://docs.github.com/en/actions/reference/encrypted-secrets - -name: Python package - -# Set once -env: - SUBPACKAGE: fsl - -on: - push: - branches: [ master ] - tags: [ '*' ] - pull_request: - branches: [ master ] - - -jobs: - devcheck: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: [3.7, 3.9] # Check oldest and newest versions - pip-flags: ['', '--editable'] - pydra: - - 'pydra' - - '--editable git+https://github.com/nipype/pydra.git#egg=pydra' - - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install build dependencies - run: | - python -m pip install --upgrade pip - - name: Install Pydra - run: | - pip install ${{ matrix.pydra }} - python -c "import pydra as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" - - name: Install task package - run: | - pip install ${{ matrix.pip-flags }} ".[dev]" - python -c "import pydra.tasks.$SUBPACKAGE as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" - python -c "import pydra as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" - - test: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: [3.7, 3.8, 3.9] - - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install build dependencies - run: | - python -m pip install --upgrade pip - - name: Install task package - run: | - pip install ".[test]" - python -c "import pydra.tasks.$SUBPACKAGE as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" - python -c "import pydra as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" - - name: Test with pytest - run: | - pytest -sv --doctest-modules pydra/tasks/$SUBPACKAGE \ - --cov pydra.tasks.$SUBPACKAGE --cov-report xml - - uses: codecov/codecov-action@v1 - if: ${{ always() }} - - - deploy: - needs: [devcheck, test] - runs-on: ubuntu-latest - strategy: - matrix: - python-version: [3.9] - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - fetch-depth: 0 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install build tools - run: python -m pip install --upgrade pip build twine - - name: Build source and wheel distributions - run: python -m build - - name: Check distributions - run: twine check dist/* - - uses: actions/upload-artifact@v2 - with: - name: distributions - path: dist/ - # Deploy on tags if PYPI_API_TOKEN is defined in the repository secrets. - # Secrets are not accessible in the if: condition [0], so set an output variable [1] - # [0] https://github.community/t/16928 - # [1] https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter - - name: Check for PyPI token on tag - id: deployable - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') - env: - PYPI_API_TOKEN: "${{ secrets.PYPI_API_TOKEN }}" - run: if [ -n "$PYPI_API_TOKEN" ]; then echo ::set-output name=DEPLOY::true; fi - - name: Upload to PyPI - if: steps.deployable.outputs.DEPLOY - uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 # v1.4.2 - with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..801641a --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,45 @@ +name: test + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Install Hatch + run: pipx install hatch + - name: Lint codebase + run: hatch run lint:all + + test: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + python-version: ['3.8', '3.9', '3.10', '3.11'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install Hatch + run: pipx install hatch + - name: Test codebase + run: hatch run test diff --git a/.gitignore b/.gitignore index b57b697..942699c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -.DS_Store # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -51,6 +50,7 @@ coverage.xml *.py,cover .hypothesis/ .pytest_cache/ +cover/ # Translations *.mo @@ -73,6 +73,7 @@ instance/ docs/_build/ # PyBuilder +.pybuilder/ target/ # Jupyter Notebook @@ -84,6 +85,9 @@ ipython_config.py # pyenv .python-version +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. @@ -93,6 +97,24 @@ ipython_config.py #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml +# Hatch +.hatch/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ # Celery stuff @@ -131,3 +153,31 @@ dmypy.json # Pycharm .idea + +# Vim +.*.sw[op] + +# VS Code +.vscode + +# Mac garbarge +.DS_store + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# JetBrains +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.fleet/ + +# Generated files +/pydra/tasks/fsl/_version.py +/related-packages/fileformats/fileformats/medimage_fsl/_version.py +/related-packages/fileformats-extras/fileformats/extras/medimage_fsl/_version.py +/pydra/tasks/fsl/auto diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d0b7515..6cc0006 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,6 @@ repos: - id: check-yaml - id: check-added-large-files - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 22.12.0 hooks: - id: black - exclude: (_version\.py|versioneer\.py)$ diff --git a/LICENSE b/LICENSE index b826500..261eeb9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,192 @@ - Copyright 2020-2021 Nipype developers + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..7424f8b --- /dev/null +++ b/NOTICE @@ -0,0 +1,13 @@ +Pydra-FSL +Copyright 2024 Pydra Development Team + +Portions of this software were developed by the ARAMIS Lab for the Clinica project. +Initial code for the FLIRT, ApplyXFM, ConcatXFM, ConvertXFM, FixScaleSkew, Img2ImgCoord, +Img2StdCoord, InvertXFM, Std2ImgCoord, FNIRT, ApplyWarp, ConvertWarp, FNIRTFileUtils, +InvWarp FUGUE, Prelude, PrepareFieldmap, SigLoss SUSAN FFT, ROI, ChFileType, Info, +Interleave, Merge, Orient, Reorient2Std, SelectVols, Slice, SmoothFill, Split, SwapDim, +tasks were copied from . + +The basis for the remaining task interfaces defined in this package were semi-automatically +converted from Nipype interfaces (https://github.com/nipy/nipype) using the Nipype2Pydra +tool (https://github.com/nipype/nipype2pydra). diff --git a/README.md b/README.md index 77962ed..08aa0c0 100644 --- a/README.md +++ b/README.md @@ -1,215 +1,97 @@ -# Pydra FSL Tasks +# pydra-fsl -This repository aims to be the canonical set of Pydra tasks for incorporating -[FSL](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/) tools into a Pydra workflow. +[![PyPI - Version][pypi-version]][pypi-project] +[![PyPI - Python Version][pypi-pyversions]][pypi-project] +[![PyPI - Downloads][pypi-downloads]][pypi-project] +![][status-docs] +![][status-test] -Part of this effort is to establish a (mostly) declarative language for describing tasks that -potentially have intricate rules for determining the availability and names from the choice of -inputs. See [Converter](#Converter) for this aspect of the repository. +---- + +Pydra tasks for FSL. + +[Pydra][pydra] is a dataflow engine which provides +a set of lightweight abstractions for DAG +construction, manipulation, and distributed execution. + +[FSL][fsl] is a comprehensive library of analysis tools +for FMRI, MRI and DTI brain imaging data. + +**Table of contents** + +- [Available tasks](#available-tasks) +- [Installation](#installation) +- [Development](#development) +- [License](#license) + +## Available tasks + +| Module | Tasks | +|--------|--------------------------------------------------------------------------------------------------------------------| +| bet | BET, RobustFOV | +| eddy | Eddy, ApplyTopup, Topup | +| fast | FAST | +| flirt | FLIRT, ApplyXFM, ConcatXFM, ConvertXFM, InvertXFM, FixScaleSkew, Img2ImgCoord, Img2StdCoord, Std2ImgCoord | +| fnirt | FNIRT, FNIRTFileUtils, ApplyWarp, ConvertWarp, InvWarp | +| fugue | FUGUE, PrepareFieldmap, Prelude, SigLoss | +| maths | (**experimental**) Maths, Mul | +| susan | SUSAN | +| utils | ChFileType, FFT, Info, Interleave, Merge, Orient, Reorient2Std, ROI, SelectVols, Slice, SmoothFill, Split, SwapDim | ## Installation + +```console +pip install pydra-fsl ``` -pip install /path/to/pydra-fsl/ + +A separate installation of FSL is required to use this package. +Please review the FSL [installation instructions][fsl-install] +and [licensing details][fsl-license]. + +## Development + +This project is managed with [Hatch][hatch]: + +```console +pipx install hatch ``` -### Installation for developers +To run the test suite: + +```console +hatch run test ``` -pip install -e /path/to/pydra-fsl/[dev] + +To fix linting issues: + +```console +hatch run lint:fix ``` +## License + +This project is distributed under the terms of the [Apache License, Version 2.0][license]. + +[pypi-project]: https://pypi.org/project/pydra-fsl + +[pypi-version]: https://img.shields.io/pypi/v/pydra-fsl.svg + +[pypi-pyversions]: https://img.shields.io/pypi/pyversions/pydra-fsl.svg + +[pypi-downloads]: https://static.pepy.tech/badge/pydra-fsl + +[status-docs]: https://github.com/aramis-lab/pydra-fsl/actions/workflows/docs.yaml/badge.svg -## Converter +[status-test]: https://github.com/aramis-lab/pydra-fsl/actions/workflows/test.yaml/badge.svg -`FSLConverter` class (from `tools/converter.py`) requires three parts of information: +[pydra]: https://pydra.readthedocs.io/ -- Nipype spec: converter loads nipype interface and reads `_cmd`, `input_spec` and `output_spec` -- yml file with additional spec: `specs/fsl_{module_name}_params.yml` contains additional spec that are written based -on additional functions from nipype (including `list_outputs`), each interface can have the following fields: - - inputs_metadata: additional metadata for fields from input_spec - (it will be included in `metadata` in pydra spec), - e.g., used in `specs/fsl_preprocess_params.yml` for `FAST` to set default value for `number_classes` - (it's not part of nipype's spec, but it's set in `list_output`, see [here](https://github.com/nipy/nipype/blob/f4343d6ddaee814aa16b197cc729a10d437990bf/nipype/interfaces/fsl/preprocess.py#L403)) +[fsl]: https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FSL - - output_requirements: providing required fields for the output to be created, - taken from `list_output` structure (e.g. requirements for tissue_class_files [here](https://github.com/nipy/nipype/blob/f4343d6ddaee814aa16b197cc729a10d437990bf/nipype/interfaces/fsl/preprocess.py#L418)); - it's a part of the `requires` field in metadata in pydra spec (e.g. [here](https://github.com/nipype/pydra-fsl/blob/ceae758f76bde81465e86cff029b40e334a7939a/pydra/tasks/fsl/preprocess/fast.py#L237)) +[fsl-install]: https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FslInstallation - - output_templates: providing template to create the output file name, - taken from `list_output` structure (e.g., [here](https://github.com/nipy/nipype/blob/f4343d6ddaee814aa16b197cc729a10d437990bf/nipype/interfaces/fsl/preprocess.py#L205)); - it is set as `output_file_template` in metadata (e.g. [here](https://github.com/nipype/pydra-fsl/blob/ceae758f76bde81465e86cff029b40e334a7939a/pydra/tasks/fsl/preprocess/bet.py#L204)) +[fsl-license]: https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/Licence - - output_callables: providing function name that should be used to gather output, - based on the `list_output` structure and used only for `FAST`; - it is set as `callable` in metadata (e.g. [here](https://github.com/nipype/pydra-fsl/blob/ceae758f76bde81465e86cff029b40e334a7939a/pydra/tasks/fsl/preprocess/fast.py#L237)) +[hatch]: https://hatch.pypa.io/ - - tests_inputs, tests_outputs: specification for tests, - the fields should have the same length and each element should contain - the input fields values and list of the expected output fields names - - - doctests: specification for doctest, - should include values for input fields and the expected `cmdline` - -- python file with functions used as callables to gather the outputs: -`specs/callables.py` should contain all the functions from `output_callables`; -the source code of the functions is read and written again in the pydra interface file - - -### How to use the convert - -The converter can be used by running: - - python tools/converter.py --interface_name --module_name - -The pydra task will be created and saved in `pydra/tasks/fsl/{module_name}/{interface_name}.py`. -Note, that the spec file has to be present for the specific module name in order to run the converter. -If no `interface_name` is provided, the default value `all` will be used - and the converter will be run for all interfaces from the spec file. - -Tests are written based on the fields from the yml file: -`tests_inputs` and `tests_outputs` (the lengths should be the same). -One test, `test_specs_*` checks only the correctness of the spec based -on the `test_inputs/outputs` pairs, i.e. predicts which output fields -should be created based on the list of the input fields. -The second test, `test_run_*` should run the interfaces -(TODO: this is temporary, should be removed from the final repo). -Tests can be run using `pytest`: - - pytest -vs pydra/tasks/fsl/{module_name}/tests - -## Interface progress - -Below is a list of all planned interfaces, with completed interfaces checked. The list was copied from the nipype documentation at https://nipype.readthedocs.io/en/latest/api/generated/nipype.interfaces.fsl.html. - -### Preprocess - -- [x] ApplyWarp (`applywarp`) -- [ ] ApplyXFM (`flirt`) -- [x] BET (`bet`) -- [x] FAST (`fast`) -- [x] FIRST (`first`) -- [x] FLIRT (`flirt`) -- [x] FNIRT (`fnirt`) -- [ ] FUGUE (`fugue`) -- [x] MCFLIRT (`mcflirt`) -- [x] PRELUDE (`prelude`) -- [x] SUSAN (`susan`) -- [x] SliceTimer (`slicetimer`) - -### AROMA - -- [ ] ICA_AROMA (`ICA_AROMA.py`) - -### DTI - -- [ ] BEDPOSTX / BEDPOSTX5 (`bedpostx`) -- [ ] DTIFit (`dtifit`) -- [ ] DistanceMap (`distancemap`) -- [ ] FSLXCommand (`xfibres` and `bedpost`) -- [ ] FindTheBiggest (`find_the_biggest`) -- [ ] MakeDyadicVectors (`make_dyadic_vectors`) -- [ ] ProbTrackX (`probtrackx`) -- [ ] ProbTrackX2 (`probtrackx2`) -- [ ] ProjThresh (`proj_thresh`) -- [ ] TractSkeleton (`tbss_skeleton`) -- [ ] VecReg (`vecreg`) -- [ ] XFibres / XFibres5 (`xfibres`) - -## EPI - -- [ ] ApplyTOPUP (`applytopup`) -- [ ] EPIDeWarp (`epidewarp.fsl`; depreciated) -- [ ] Eddy (`eddy_openmp`) -- [ ] EddyCorrect (`eddy_correct`; depreciated) -- [ ] EddyQuad (`eddy_quad`) -- [ ] EpiReg (`epi_reg`) -- [ ] PrepareFieldmap (`fsl_prepare_fieldmap`) -- [ ] SigLoss (`sigloss`) -- [ ] TOPUP (`topup`) - -## FIX - -- [ ] Classifier (`fix -c`) -- [ ] Cleaner (`fix -a`) -- [ ] FeatureExtractor (`fix -f`) -- [ ] Training (`fix -t`) -- [ ] TrainingSetCreator - -## Utils - -- [ ] AvScale (`avscale`) -- [ ] Complex (`fslcomplex`) -- [ ] ConvertWarp (`convertwarp`) -- [ ] ConvertXFM (`convert_xfm`) -- [ ] CopyGeom (`fslcpgeom`) -- [ ] ExtractROI (`fslroi`) -- [ ] FilterRegressor (`fsl_regfilt`) -- [ ] ImageMaths (`fslmaths`) -- [ ] ImageMeants (`fslmeants`) -- [ ] ImageStats (`fslstats`) -- [ ] InvWarp (`invwarp`) -- [ ] Merge (`fslmerge`) -- [ ] MotionOutliers (`fsl_motion_outliers`) -- [ ] Overlay (`overlay`) -- [ ] PlotMotionParams (`fsl_tsplot`) -- [ ] PlotTimeSeries (`fsl_tsplot`) -- [ ] PowerSpectrum (`fslpspec`) -- [ ] Reorient2Std (`fslreorient2std`) -- [ ] RobustFOV (`robustfov`) -- [ ] SigLoss (`sigloss`) -- [ ] Slice (`fslslice`) -- [ ] Slicer (`slicer`) -- [ ] Smooth (`fslmaths`) -- [ ] Split (`fslsplit`) -- [ ] SwapDimensions (`fslswapdim`) -- [ ] Text2Vest (`text2vest`) -- [ ] Vest2Text (`vest2text`) -- [ ] WarpPoints (`img2imgcoord`) -- [ ] WarpPointsFromStd (`std2imgcoord`) -- [ ] WarpPointsToStd (`img2stdcoord`) -- [ ] WarpUtils (`fnirtfileutils`) - -### POSSUM - -- [ ] B0Calc (`b0calc`) - -### Model - -- [ ] Cluster (`cluster`) -- [ ] ContrastMgr (`contrast_mgr`) -- [ ] DualRegression (`dual_regression`) -- [ ] FEAT (`feat`) -- [ ] FEATModel (`feat_model`) -- [ ] FEATRegister -- [ ] FILMGLS (`film_gls`) -- [ ] FLAMEO (`flameo`) -- [ ] GLM (`fsl_glm`) -- [ ] L2Model -- [ ] Level1Design -- [ ] MELODIC (`melodic`) -- [ ] MultipleRegressDesign -- [ ] Randomise (`randomise`) -- [ ] SMM (`mm --ld=logdir`) -- [ ] SmoothEstimate (`smoothest`) - -### Maths - -- [ ] AR1Image (`fslmaths`) -- [ ] ApplyMask (`fslmaths`) -- [ ] BinaryMaths (`fslmaths`) -- [ ] ChangeDataType (`fslmaths`) -- [ ] DilateImage (`fslmaths`) -- [ ] ErodeImage (`fslmaths`) -- [ ] IsotropicSmooth (`fslmaths`) -- [ ] MathsCommand (`fslmaths`) -- [ ] MaxImage (`fslmaths`) -- [ ] MaxnImage (`fslmaths`) -- [ ] MeanImage (`fslmaths`) -- [ ] MedianImage (`fslmaths`) -- [ ] MinImage (`fslmaths`) -- [ ] MultiImageMaths (`fslmaths`) -- [ ] PercentileImage (`fslmaths`) -- [ ] SpatialFilter (`fslmaths`) -- [ ] StdImage (`fslmaths`) -- [ ] TemporalFilter (`fslmaths`) -- [ ] Threshold (`fslmaths`) -- [ ] UnaryMaths (`fslmaths`) +[license]: https://spdx.org/licenses/Apache-2.0.html diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..ed18628 --- /dev/null +++ b/README.rst @@ -0,0 +1,313 @@ +========================== +Pydra task package for fsl +========================== + +.. image:: https://github.com/nipype/pydra-fsl/actions/workflows/ci-cd.yaml/badge.svg + :target: https://github.com/nipype/pydra-fsl/actions/workflows/ci-cd.yaml +.. image:: https://codecov.io/gh/nipype/pydra-fsl/branch/main/graph/badge.svg?token=UIS0OGPST7 + :target: https://codecov.io/gh/nipype/pydra-fsl +.. image:: https://img.shields.io/pypi/pyversions/pydra-fsl.svg + :target: https://pypi.python.org/pypi/pydra-fsl/ + :alt: Supported Python versions +.. image:: https://img.shields.io/pypi/v/pydra-fsl.svg + :target: https://pypi.python.org/pypi/pydra-fsl/ + :alt: Latest Version + + +This repository aims to be the canonical set of Pydra tasks for incorporating +`FSL `__ tools into a Pydra workflow. + +Part of this effort is to establish a (mostly) declarative language for describing tasks that +potentially have intricate rules for determining the availability and names from the choice of +inputs. + + +Automatically-generated vs manually-curated tasks +------------------------------------------------- + +Automatically generated tasks can be found in the `pydra.tasks.fsl.auto` package. +These packages should be treated with extreme caution as they likely do not pass testing. +Generated tasks that have been edited and pass testing are imported into one or more of the +`pydra.tasks.fsl.v*` packages, corresponding to the version of the fsl toolkit +they are designed for. + +Tests +----- + +This package comes with a battery of automatically generated test modules. To install +the necessary dependencies to run the tests + +.. code-block:: + + $ pip install -e .[test] + +Then the tests, including `doctests` `__, can be launched using + +.. code-block:: + + $ pytest --doctest-modules pydra/tasks/* + +By default, the tests are set to time-out after 10s, after which the underlying tool is +assumed to have passed the validation/initialisation phase and we assume that it will +run to completion. To disable this and run the test(s) through to completion run + +.. code-block:: + + $ pytest --doctest-modules --timeout-pass 0 pydra/tasks/* + +Continuous integration +---------------------- + +This template uses `GitHub Actions `__` to run tests and +deploy packages to PYPI. New packages are built and uploaded when releases are created on +GitHub, or new releases of Nipype or the Nipype2Pydra conversion tool are released. +Releases triggered by updates to Nipype or Nipype2Pydra are signified by the `postN` +suffix where `N = ` with the '.'s stripped, e.g. +`v0.2.3post185010` corresponds to the v0.2.3 tag of this repository with auto-generated +packages from Nipype 1.8.5 using Nipype2Pydra 0.1.0. + + +Contributing to this package +---------------------------- + +Developer installation +~~~~~~~~~~~~~~~~~~~~~~ + +Install the `fileformats `__ packages +corresponding to AFNI specific file formats + + +.. code-block:: + + $ pip install -e ./related-packages/fileformats[dev] + $ pip install -e ./related-packages/fileformats-extras[dev] + +Install repo in developer mode from the source directory and install pre-commit to +ensure consistent code-style and quality. + +.. code-block:: + + $ pip install -e .[test,dev] + $ pre-commit install + +Next install the requirements for running the auto-conversion script and generate the +Pydra task interfaces from their Nipype counterparts + +.. code-block:: + + $ pip install -r nipype-auto-conv/requirements.txt + +The run the conversion script to convert Nipype interfaces to Pydra + +.. code-block:: + + $ nipype-auto-conv/generate + +Methodology +~~~~~~~~~~~ + +The development of this package is expected to have two phases + +1. Where the corresponding Nipype interfaces are considered to be the ground truth, and + the Pydra tasks are generated from them +2. When the Pydra tasks are considered be mature and they are edited by hand + +Different tasks will probably mature at different times so there will probably be an +intermediate phase between 1 and 2. + +Auto-conversion phase +~~~~~~~~~~~~~~~~~~~~~ + +The auto-converted Pydra tasks are generated from their corresponding Nipype interface +in combination with "conversion hints" contained in YAML specs +located in `nipype-auto-conv/specs/`. The self-documented conversion specs are +to be edited by hand in order to assist the auto-converter produce valid pydra tasks. +After editing one or more conversion specs the `pydra.tasks.fsl.auto` package should +be regenerated by running + +.. code-block:: + + $ nipype-auto-conv/generate + +The tests should be run on the auto-generated tasks to see if they are valid + +.. code-block:: + + $ pytest --doctest-modules pydra/tasks/fsl/auto/tests/test_.py + +If the test passes you should then edit the `pydra/tasks/fsl/v/__init__.py` file +to import the now valid task interface to signify that it has been validated and is ready +for use, e.g. + +.. code-block::python + + from pydra.tasks.fsl.auto import + + +Typing and sample test data +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The automatically generated tests will attempt to provided the task instance to be tested +with sensible default values based on the type of the field and any constraints it has +on it. However, these will often need to be manually overridden after consulting the +underlying tool's documentation. + +For file-based data, automatically generated file-system objects will be created for +selected format types, e.g. Nifti, Dicom. Therefore, it is important to specify the +format of the file using the "mime-like" string corresponding to a +`fileformats `__ class +in the ``inputs > types`` and ``outputs > types`` dicts of the YAML spec. + +If the required file-type is not found implemented within fileformats, please see the `fileformats +docs `__ for instructions on how to define +new fileformat types, and see +`fileformats-medimage-extras `__ +for an example on how to implement methods to generate sample data for them. + + +Interface progress +================== + +Below is a list of all planned interfaces, with completed interfaces checked. The list was copied from the nipype documentation at https://nipype.readthedocs.io/en/latest/api/generated/nipype.interfaces.fsl.html. + +Preprocess +---------- + +- [x] ApplyWarp (`applywarp`) +- [ ] ApplyXFM (`flirt`) +- [x] BET (`bet`) +- [x] FAST (`fast`) +- [x] FIRST (`first`) +- [x] FLIRT (`flirt`) +- [x] FNIRT (`fnirt`) +- [ ] FUGUE (`fugue`) +- [x] MCFLIRT (`mcflirt`) +- [x] PRELUDE (`prelude`) +- [x] SUSAN (`susan`) +- [x] SliceTimer (`slicetimer`) + +AROMA +----- + +- [ ] ICA_AROMA (`ICA_AROMA.py`) + +DTI +--- + +- [ ] BEDPOSTX / BEDPOSTX5 (`bedpostx`) +- [ ] DTIFit (`dtifit`) +- [ ] DistanceMap (`distancemap`) +- [ ] FSLXCommand (`xfibres` and `bedpost`) +- [ ] FindTheBiggest (`find_the_biggest`) +- [ ] MakeDyadicVectors (`make_dyadic_vectors`) +- [ ] ProbTrackX (`probtrackx`) +- [ ] ProbTrackX2 (`probtrackx2`) +- [ ] ProjThresh (`proj_thresh`) +- [ ] TractSkeleton (`tbss_skeleton`) +- [ ] VecReg (`vecreg`) +- [ ] XFibres / XFibres5 (`xfibres`) + +EPI +--- + +- [ ] ApplyTOPUP (`applytopup`) +- [ ] EPIDeWarp (`epidewarp.fsl`; depreciated) +- [ ] Eddy (`eddy_openmp`) +- [ ] EddyCorrect (`eddy_correct`; depreciated) +- [ ] EddyQuad (`eddy_quad`) +- [ ] EpiReg (`epi_reg`) +- [ ] PrepareFieldmap (`fsl_prepare_fieldmap`) +- [ ] SigLoss (`sigloss`) +- [ ] TOPUP (`topup`) + +FIX +--- + +- [ ] Classifier (`fix -c`) +- [ ] Cleaner (`fix -a`) +- [ ] FeatureExtractor (`fix -f`) +- [ ] Training (`fix -t`) +- [ ] TrainingSetCreator + +Utils +----- + +- [ ] AvScale (`avscale`) +- [ ] Complex (`fslcomplex`) +- [ ] ConvertWarp (`convertwarp`) +- [ ] ConvertXFM (`convert_xfm`) +- [ ] CopyGeom (`fslcpgeom`) +- [ ] ExtractROI (`fslroi`) +- [ ] FilterRegressor (`fsl_regfilt`) +- [ ] ImageMaths (`fslmaths`) +- [ ] ImageMeants (`fslmeants`) +- [ ] ImageStats (`fslstats`) +- [ ] InvWarp (`invwarp`) +- [ ] Merge (`fslmerge`) +- [ ] MotionOutliers (`fsl_motion_outliers`) +- [ ] Overlay (`overlay`) +- [ ] PlotMotionParams (`fsl_tsplot`) +- [ ] PlotTimeSeries (`fsl_tsplot`) +- [ ] PowerSpectrum (`fslpspec`) +- [ ] Reorient2Std (`fslreorient2std`) +- [ ] RobustFOV (`robustfov`) +- [ ] SigLoss (`sigloss`) +- [ ] Slice (`fslslice`) +- [ ] Slicer (`slicer`) +- [ ] Smooth (`fslmaths`) +- [ ] Split (`fslsplit`) +- [ ] SwapDimensions (`fslswapdim`) +- [ ] Text2Vest (`text2vest`) +- [ ] Vest2Text (`vest2text`) +- [ ] WarpPoints (`img2imgcoord`) +- [ ] WarpPointsFromStd (`std2imgcoord`) +- [ ] WarpPointsToStd (`img2stdcoord`) +- [ ] WarpUtils (`fnirtfileutils`) + +POSSUM +------ + +- [ ] B0Calc (`b0calc`) + +### Model + +- [ ] Cluster (`cluster`) +- [ ] ContrastMgr (`contrast_mgr`) +- [ ] DualRegression (`dual_regression`) +- [ ] FEAT (`feat`) +- [ ] FEATModel (`feat_model`) +- [ ] FEATRegister +- [ ] FILMGLS (`film_gls`) +- [ ] FLAMEO (`flameo`) +- [ ] GLM (`fsl_glm`) +- [ ] L2Model +- [ ] Level1Design +- [ ] MELODIC (`melodic`) +- [ ] MultipleRegressDesign +- [ ] Randomise (`randomise`) +- [ ] SMM (`mm --ld=logdir`) +- [ ] SmoothEstimate (`smoothest`) + +Maths +----- + +- [ ] AR1Image (`fslmaths`) +- [ ] ApplyMask (`fslmaths`) +- [ ] BinaryMaths (`fslmaths`) +- [ ] ChangeDataType (`fslmaths`) +- [ ] DilateImage (`fslmaths`) +- [ ] ErodeImage (`fslmaths`) +- [ ] IsotropicSmooth (`fslmaths`) +- [ ] MathsCommand (`fslmaths`) +- [ ] MaxImage (`fslmaths`) +- [ ] MaxnImage (`fslmaths`) +- [ ] MeanImage (`fslmaths`) +- [ ] MedianImage (`fslmaths`) +- [ ] MinImage (`fslmaths`) +- [ ] MultiImageMaths (`fslmaths`) +- [ ] PercentileImage (`fslmaths`) +- [ ] SpatialFilter (`fslmaths`) +- [ ] StdImage (`fslmaths`) +- [ ] TemporalFilter (`fslmaths`) +- [ ] Threshold (`fslmaths`) +- [ ] UnaryMaths (`fslmaths`) diff --git a/codecov.yml b/codecov.yml index bbf806c..a203b50 100644 --- a/codecov.yml +++ b/codecov.yml @@ -3,8 +3,6 @@ coverage: ignore: # files and folders that will be removed during processing - "**/tests" - "**/_version.py" - - "setup.py" - - "versioneer.py" status: project: default: diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..a477980 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,7 @@ +API +=== + +.. autosummary:: + :toctree: generated + +.. automodule:: pydra.tasks.fsl diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..f57d121 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,32 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +import sys +from pathlib import Path + +from sphinx_pyproject import SphinxConfig + +config = SphinxConfig(globalns=globals()) +sys.path.insert(0, str(Path.cwd().parent / "src")) + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = config.name +author = "Pydra Development Team" +copyright = f"2022-2023, {author}" +release = config.version + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = ["sphinx.ext.autosummary", "sphinx.ext.napoleon"] +templates_path = ["_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "pydata_sphinx_theme" diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..7a85fde --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,25 @@ +About pydra-fsl +=============== + +`Pydra`_ is a dataflow engine which provides a set of lightweight abstractions for DAG construction, manipulation, and distributed execution. + +`FSL`_ is a comprehensive library of analysis tools for FMRI, MRI and DTI brain imaging data. + +pydra-fsl provides Pydra tasks for running and composing FSL commands. + +.. toctree:: + :maxdepth: 3 + :caption: Contents: + + api + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + + +.. _Pydra: https://nipype.github.io/pydra/ +.. _FSL: https://fsl.fmrib.ox.ac.uk/ diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..922152e --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/nipype-auto-conv/generate b/nipype-auto-conv/generate new file mode 100755 index 0000000..5265da9 --- /dev/null +++ b/nipype-auto-conv/generate @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +import sys +import os.path +from warnings import warn +from pathlib import Path +import shutil +from importlib import import_module +import yaml +from tqdm import tqdm +import nipype +import nipype2pydra.utils +from nipype2pydra.task import get_converter + + +SPECS_DIR = Path(__file__).parent / "specs" +PKG_ROOT = Path(__file__).parent.parent +PKG_NAME = "fsl" + +if ".dev" in nipype.__version__: + raise RuntimeError( + f"Cannot use a development version of Nipype {nipype.__version__}" + ) + +if ".dev" in nipype2pydra.__version__: + warn( + f"using development version of nipype2pydra ({nipype2pydra.__version__}), " + f"development component will be dropped in {PKG_NAME} package version" + ) + +# Insert specs dir into path so we can load callables modules +sys.path.insert(0, str(SPECS_DIR)) + +auto_init = f"# Auto-generated by {__file__}, do not edit as it will be overwritten\n\n" + +auto_dir = PKG_ROOT / "pydra" / "tasks" / PKG_NAME / "auto" +if auto_dir.exists(): + shutil.rmtree(auto_dir) + +all_interfaces = [] +for fspath in tqdm( + sorted(SPECS_DIR.glob("**/*.yaml")), "converting interfaces from Nipype to Pydra" +): + with open(fspath) as f: + spec = yaml.load(f, Loader=yaml.SafeLoader) + + rel_pkg_path = str(fspath.parent.relative_to(SPECS_DIR)).replace(os.path.sep, ".") + if rel_pkg_path == ".": + rel_pkg_path = fspath.stem + else: + rel_pkg_path += "." + fspath.stem + + callables = import_module(rel_pkg_path + "_callables") + + module_name = nipype2pydra.utils.to_snake_case(spec["task_name"]) + + converter = get_converter( + output_module=f"pydra.tasks.{PKG_NAME}.auto.{module_name}", + callables_module=callables, # type: ignore + **spec, + ) + converter.generate(PKG_ROOT) + auto_init += f"from .{module_name} import {converter.task_name}\n" + all_interfaces.append(converter.task_name) + + +with open(PKG_ROOT / "pydra" / "tasks" / PKG_NAME / "auto" / "_version.py", "w") as f: + f.write( + f"""# Auto-generated by {__file__}, do not edit as it will be overwritten + +nipype_version = "{nipype.__version__.split('.dev')[0]}" +nipype2pydra_version = "{nipype2pydra.__version__.split('.dev')[0]}" +post_release = (nipype_version + nipype2pydra_version).replace(".", "") +""" + ) + +auto_init += ( + "\n\n__all__ = [\n" + "\n".join(f' "{i}",' for i in all_interfaces) + "\n]\n" +) + +with open(PKG_ROOT / "pydra" / "tasks" / PKG_NAME / "auto" / "__init__.py", "w") as f: + f.write(auto_init) diff --git a/nipype-auto-conv/requirements.txt b/nipype-auto-conv/requirements.txt new file mode 100644 index 0000000..cb69c8a --- /dev/null +++ b/nipype-auto-conv/requirements.txt @@ -0,0 +1,12 @@ +black +attrs>=22.1.0 +nipype +tqdm +pydra +PyYAML>=6.0 +fileformats >=0.8 +fileformats-medimage >=0.4 +fileformats-datascience >= 0.1 +fileformats-medimage-fsl +traits +nipype2pydra diff --git a/nipype-auto-conv/specs/accuracy_tester.yaml b/nipype-auto-conv/specs/accuracy_tester.yaml new file mode 100644 index 0000000..b9facd6 --- /dev/null +++ b/nipype-auto-conv/specs/accuracy_tester.yaml @@ -0,0 +1,88 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.fix.AccuracyTester' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Test the accuracy of an existing training dataset on a set of hand-labelled subjects. +# Note: This may or may not be working. Couldn't presently not confirm because fix fails on this (even outside of nipype) without leaving an error msg. +# +task_name: AccuracyTester +nipype_name: AccuracyTester +nipype_module: nipype.interfaces.fsl.fix +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + trained_wts_file: generic/file + # type=file|default=: trained-weights file + mel_icas: medimage-fsl/melodic-ica+list-of + # type=inputmultiobject|default=[]: Melodic output directories + output_directory: Path + # type=directory: Path to folder in which to store the results of the accuracy test. + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + output_directory: generic/directory + # type=directory: Path to folder in which to store the results of the accuracy test. + # type=directory|default=: Path to folder in which to store the results of the accuracy test. + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + mel_icas: + # type=inputmultiobject|default=[]: Melodic output directories + trained_wts_file: + # type=file|default=: trained-weights file + output_directory: + # type=directory: Path to folder in which to store the results of the accuracy test. + # type=directory|default=: Path to folder in which to store the results of the accuracy test. + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/accuracy_tester_callables.py b/nipype-auto-conv/specs/accuracy_tester_callables.py new file mode 100644 index 0000000..d6e4893 --- /dev/null +++ b/nipype-auto-conv/specs/accuracy_tester_callables.py @@ -0,0 +1,28 @@ +"""Module to put any functions that are referred to in the "callables" section of AccuracyTester.yaml""" + +import attrs +from fileformats.generic import Directory + + +def output_directory_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["output_directory"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L251 of /interfaces/fsl/fix.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + if inputs.output_directory is not attrs.NOTHING: + outputs["output_directory"] = Directory( + exists=False, value=inputs.output_directory + ) + else: + outputs["output_directory"] = Directory(exists=False, value="accuracy_test") + return outputs diff --git a/nipype-auto-conv/specs/apply_mask.yaml b/nipype-auto-conv/specs/apply_mask.yaml new file mode 100644 index 0000000..13d115d --- /dev/null +++ b/nipype-auto-conv/specs/apply_mask.yaml @@ -0,0 +1,97 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.ApplyMask' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to apply a binary mask to another image. +task_name: ApplyMask +nipype_name: ApplyMask +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mask_file: medimage/mask+nifti-gz + # type=file|default=: binary image defining mask space + in_file: medimage/nifti-gz + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: medimage/nifti-gz + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file.nii.gz + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + mask_file: + # type=file|default=: binary image defining mask space + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/apply_mask_callables.py b/nipype-auto-conv/specs/apply_mask_callables.py new file mode 100644 index 0000000..fcd5f27 --- /dev/null +++ b/nipype-auto-conv/specs/apply_mask_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of ApplyMask.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/apply_topup.yaml b/nipype-auto-conv/specs/apply_topup.yaml new file mode 100644 index 0000000..e74a9e4 --- /dev/null +++ b/nipype-auto-conv/specs/apply_topup.yaml @@ -0,0 +1,176 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.epi.ApplyTOPUP' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Interface for FSL topup, a tool for estimating and correcting +# susceptibility induced distortions. +# `General reference +# `_ +# and `use example +# `_. +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import ApplyTOPUP +# >>> applytopup = ApplyTOPUP() +# >>> applytopup.inputs.in_files = ["epi.nii", "epi_rev.nii"] +# >>> applytopup.inputs.encoding_file = "topup_encoding.txt" +# >>> applytopup.inputs.in_topup_fieldcoef = "topup_fieldcoef.nii.gz" +# >>> applytopup.inputs.in_topup_movpar = "topup_movpar.txt" +# >>> applytopup.inputs.output_type = "NIFTI_GZ" +# >>> applytopup.cmdline # doctest: +ELLIPSIS +# 'applytopup --datain=topup_encoding.txt --imain=epi.nii,epi_rev.nii --inindex=1,2 --topup=topup --out=epi_corrected.nii.gz' +# >>> res = applytopup.run() # doctest: +SKIP +# +# +task_name: ApplyTOPUP +nipype_name: ApplyTOPUP +nipype_module: nipype.interfaces.fsl.epi +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + encoding_file: text/text-file + # type=file|default=: name of text file with PE directions/times + in_files: medimage/nifti1+list-of + # type=inputmultiobject|default=[]: name of file with images + in_topup_fieldcoef: medimage/nifti-gz + # type=file|default=: topup file containing the field coefficients + in_topup_movpar: text/text-file + # type=file|default=: topup movpar.txt file + out_corrected: Path + # type=file: name of 4D image file with unwarped images + # type=file|default=: output (warped) image + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_corrected: generic/file + # type=file: name of 4D image file with unwarped images + # type=file|default=: output (warped) image + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=inputmultiobject|default=[]: name of file with images + encoding_file: + # type=file|default=: name of text file with PE directions/times + in_index: + # type=list|default=[]: comma separated list of indices corresponding to --datain + in_topup_fieldcoef: + # type=file|default=: topup file containing the field coefficients + in_topup_movpar: + # type=file|default=: topup movpar.txt file + out_corrected: + # type=file: name of 4D image file with unwarped images + # type=file|default=: output (warped) image + method: + # type=enum|default='jac'|allowed['jac','lsr']: use jacobian modulation (jac) or least-squares resampling (lsr) + interp: + # type=enum|default='trilinear'|allowed['spline','trilinear']: interpolation method + datatype: + # type=enum|default='char'|allowed['char','double','float','int','short']: force output data type + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=inputmultiobject|default=[]: name of file with images + encoding_file: + # type=file|default=: name of text file with PE directions/times + in_topup_fieldcoef: + # type=file|default=: topup file containing the field coefficients + in_topup_movpar: + # type=file|default=: topup movpar.txt file + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: applytopup --datain=topup_encoding.txt --imain=epi.nii,epi_rev.nii --inindex=1,2 --topup=topup --out=epi_corrected.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_files: '["epi.nii", "epi_rev.nii"]' + # type=inputmultiobject|default=[]: name of file with images + encoding_file: '"topup_encoding.txt"' + # type=file|default=: name of text file with PE directions/times + in_topup_fieldcoef: '"topup_fieldcoef.nii.gz"' + # type=file|default=: topup file containing the field coefficients + in_topup_movpar: '"topup_movpar.txt"' + # type=file|default=: topup movpar.txt file + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/apply_topup_callables.py b/nipype-auto-conv/specs/apply_topup_callables.py new file mode 100644 index 0000000..6ae5fc5 --- /dev/null +++ b/nipype-auto-conv/specs/apply_topup_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of ApplyTOPUP.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_corrected_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_corrected"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/apply_warp.yaml b/nipype-auto-conv/specs/apply_warp.yaml new file mode 100644 index 0000000..f0630ac --- /dev/null +++ b/nipype-auto-conv/specs/apply_warp.yaml @@ -0,0 +1,132 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.ApplyWarp' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL's applywarp wrapper to apply the results of a FNIRT registration +# +# Examples +# -------- +# >>> from nipype.interfaces import fsl +# >>> from nipype.testing import example_data +# >>> aw = fsl.ApplyWarp() +# >>> aw.inputs.in_file = example_data('structural.nii') +# >>> aw.inputs.ref_file = example_data('mni.nii') +# >>> aw.inputs.field_file = 'my_coefficients_filed.nii' #doctest: +SKIP +# >>> res = aw.run() #doctest: +SKIP +# +# +# +task_name: ApplyWarp +nipype_name: ApplyWarp +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti-gz + # type=file|default=: image to be warped + ref_file: medimage/nifti-gz + # type=file|default=: reference image + field_file: medimage/nifti-gz + # type=file|default=: file containing warp field + premat: Path + # type=file|default=: filename for pre-transform (affine matrix) + postmat: Path + # type=file|default=: filename for post-transform (affine matrix) + mask_file: Path + # type=file|default=: filename for mask image (in reference space) + out_file: Path + # type=file: Warped output file + # type=file|default=: output filename + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: Warped output file + # type=file|default=: output filename + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: Warped output file + # type=file|default=: output filename + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: image to be warped + out_file: + # type=file: Warped output file + # type=file|default=: output filename + ref_file: + # type=file|default=: reference image + field_file: + # type=file|default=: file containing warp field + abswarp: + # type=bool|default=False: treat warp field as absolute: x' = w(x) + relwarp: + # type=bool|default=False: treat warp field as relative: x' = x + w(x) + datatype: + # type=enum|default='char'|allowed['char','double','float','int','short']: Force output data type [char short int float double]. + supersample: + # type=bool|default=False: intermediary supersampling of output, default is off + superlevel: + # type=traitcompound|default=None: level of intermediary supersampling, a for 'automatic' or integer level. Default = 2 + premat: + # type=file|default=: filename for pre-transform (affine matrix) + postmat: + # type=file|default=: filename for post-transform (affine matrix) + mask_file: + # type=file|default=: filename for mask image (in reference space) + interp: + # type=enum|default='nn'|allowed['nn','sinc','spline','trilinear']: interpolation method + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/apply_warp_callables.py b/nipype-auto-conv/specs/apply_warp_callables.py new file mode 100644 index 0000000..6d2586d --- /dev/null +++ b/nipype-auto-conv/specs/apply_warp_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of ApplyWarp.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1494 of /interfaces/fsl/preprocess.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )[name] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "applywarp" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1486 of /interfaces/fsl/preprocess.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix="_warp", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + else: + outputs["out_file"] = os.path.abspath(inputs.out_file) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/apply_xfm.yaml b/nipype-auto-conv/specs/apply_xfm.yaml new file mode 100644 index 0000000..2504b98 --- /dev/null +++ b/nipype-auto-conv/specs/apply_xfm.yaml @@ -0,0 +1,227 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.ApplyXFM' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Currently just a light wrapper around FLIRT, +# with no modifications +# +# ApplyXFM is used to apply an existing transform to an image +# +# +# Examples +# -------- +# +# >>> import nipype.interfaces.fsl as fsl +# >>> from nipype.testing import example_data +# >>> applyxfm = fsl.preprocess.ApplyXFM() +# >>> applyxfm.inputs.in_file = example_data('structural.nii') +# >>> applyxfm.inputs.in_matrix_file = example_data('trans.mat') +# >>> applyxfm.inputs.out_file = 'newfile.nii' +# >>> applyxfm.inputs.reference = example_data('mni.nii') +# >>> applyxfm.inputs.apply_xfm = True +# >>> result = applyxfm.run() # doctest: +SKIP +# +# +task_name: ApplyXFM +nipype_name: ApplyXFM +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + fieldmap: generic/file + # type=file|default=: fieldmap image in rads/s - must be already registered to the reference image + fieldmapmask: generic/file + # type=file|default=: mask for fieldmap image + in_file: generic/file + # type=file|default=: input file + in_matrix_file: generic/file + # type=file|default=: input 4x4 affine matrix + in_weight: generic/file + # type=file|default=: File for input weighting volume + out_file: Path + # type=file: path/name of registered file (if generated) + # type=file|default=: registered output file + out_log: Path + # type=file: path/name of output log (if generated) + # type=file|default=: output log + out_matrix_file: Path + # type=file: path/name of calculated affine transform (if generated) + # type=file|default=: output affine matrix in 4x4 asciii format + ref_weight: generic/file + # type=file|default=: File for reference weighting volume + reference: generic/file + # type=file|default=: reference file + schedule: generic/file + # type=file|default=: replaces default schedule + wm_seg: generic/file + # type=file|default=: white matter segmentation volume needed by BBR cost function + wmcoords: generic/file + # type=file|default=: white matter boundary coordinates for BBR cost function + wmnorms: generic/file + # type=file|default=: white matter boundary normals for BBR cost function + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: path/name of registered file (if generated) + # type=file|default=: registered output file + out_log: generic/file + # type=file: path/name of output log (if generated) + # type=file|default=: output log + out_matrix_file: generic/file + # type=file: path/name of calculated affine transform (if generated) + # type=file|default=: output affine matrix in 4x4 asciii format + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + apply_xfm: + # type=bool|default=True: apply transformation supplied by in_matrix_file or uses_qform to use the affine matrix stored in the reference header + in_file: + # type=file|default=: input file + reference: + # type=file|default=: reference file + out_file: + # type=file: path/name of registered file (if generated) + # type=file|default=: registered output file + out_matrix_file: + # type=file: path/name of calculated affine transform (if generated) + # type=file|default=: output affine matrix in 4x4 asciii format + out_log: + # type=file: path/name of output log (if generated) + # type=file|default=: output log + in_matrix_file: + # type=file|default=: input 4x4 affine matrix + apply_isoxfm: + # type=float|default=0.0: as applyxfm but forces isotropic resampling + datatype: + # type=enum|default='char'|allowed['char','double','float','int','short']: force output data type + cost: + # type=enum|default='mutualinfo'|allowed['bbr','corratio','labeldiff','leastsq','mutualinfo','normcorr','normmi']: cost function + cost_func: + # type=enum|default='mutualinfo'|allowed['bbr','corratio','labeldiff','leastsq','mutualinfo','normcorr','normmi']: cost function + uses_qform: + # type=bool|default=False: initialize using sform or qform + display_init: + # type=bool|default=False: display initial matrix + angle_rep: + # type=enum|default='quaternion'|allowed['euler','quaternion']: representation of rotation angles + interp: + # type=enum|default='trilinear'|allowed['nearestneighbour','sinc','spline','trilinear']: final interpolation method used in reslicing + sinc_width: + # type=int|default=0: full-width in voxels + sinc_window: + # type=enum|default='rectangular'|allowed['blackman','hanning','rectangular']: sinc window + bins: + # type=int|default=0: number of histogram bins + dof: + # type=int|default=0: number of transform degrees of freedom + no_resample: + # type=bool|default=False: do not change input sampling + force_scaling: + # type=bool|default=False: force rescaling even for low-res images + min_sampling: + # type=float|default=0.0: set minimum voxel dimension for sampling + padding_size: + # type=int|default=0: for applyxfm: interpolates outside image by size + searchr_x: + # type=list|default=[]: search angles along x-axis, in degrees + searchr_y: + # type=list|default=[]: search angles along y-axis, in degrees + searchr_z: + # type=list|default=[]: search angles along z-axis, in degrees + no_search: + # type=bool|default=False: set all angular searches to ranges 0 to 0 + coarse_search: + # type=int|default=0: coarse search delta angle + fine_search: + # type=int|default=0: fine search delta angle + schedule: + # type=file|default=: replaces default schedule + ref_weight: + # type=file|default=: File for reference weighting volume + in_weight: + # type=file|default=: File for input weighting volume + no_clamp: + # type=bool|default=False: do not use intensity clamping + no_resample_blur: + # type=bool|default=False: do not use blurring on downsampling + rigid2D: + # type=bool|default=False: use 2D rigid body mode - ignores dof + save_log: + # type=bool|default=False: save to log file + verbose: + # type=int|default=0: verbose mode, 0 is least + bgvalue: + # type=float|default=0: use specified background value for points outside FOV + wm_seg: + # type=file|default=: white matter segmentation volume needed by BBR cost function + wmcoords: + # type=file|default=: white matter boundary coordinates for BBR cost function + wmnorms: + # type=file|default=: white matter boundary normals for BBR cost function + fieldmap: + # type=file|default=: fieldmap image in rads/s - must be already registered to the reference image + fieldmapmask: + # type=file|default=: mask for fieldmap image + pedir: + # type=int|default=0: phase encode direction of EPI - 1/2/3=x/y/z & -1/-2/-3=-x/-y/-z + echospacing: + # type=float|default=0.0: value of EPI echo spacing - units of seconds + bbrtype: + # type=enum|default='signed'|allowed['global_abs','local_abs','signed']: type of bbr cost function: signed [default], global_abs, local_abs + bbrslope: + # type=float|default=0.0: value of bbr slope + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/apply_xfm_callables.py b/nipype-auto-conv/specs/apply_xfm_callables.py new file mode 100644 index 0000000..6b019b9 --- /dev/null +++ b/nipype-auto-conv/specs/apply_xfm_callables.py @@ -0,0 +1,352 @@ +"""Module to put any functions that are referred to in the "callables" section of ApplyXFM.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +def out_log_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_log"] + + +def out_matrix_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_matrix_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/ar1_image.yaml b/nipype-auto-conv/specs/ar1_image.yaml new file mode 100644 index 0000000..4cca722 --- /dev/null +++ b/nipype-auto-conv/specs/ar1_image.yaml @@ -0,0 +1,98 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.AR1Image' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to generate an AR1 coefficient image across a +# given dimension. (Should use -odt float and probably demean first) +# +# +task_name: AR1Image +nipype_name: AR1Image +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dimension: + # type=enum|default='T'|allowed['T','X','Y','Z']: dimension to find AR(1) coefficient across + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/ar1_image_callables.py b/nipype-auto-conv/specs/ar1_image_callables.py new file mode 100644 index 0000000..aee1108 --- /dev/null +++ b/nipype-auto-conv/specs/ar1_image_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of AR1Image.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/av_scale.yaml b/nipype-auto-conv/specs/av_scale.yaml new file mode 100644 index 0000000..02fe620 --- /dev/null +++ b/nipype-auto-conv/specs/av_scale.yaml @@ -0,0 +1,95 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.AvScale' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL avscale command to extract info from mat file output of FLIRT +# +# Examples +# -------- +# +# >>> avscale = AvScale() +# >>> avscale.inputs.mat_file = 'flirt.mat' +# >>> res = avscale.run() # doctest: +SKIP +# +# +# +task_name: AvScale +nipype_name: AvScale +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mat_file: generic/file + # type=file|default=: mat file to read + ref_file: generic/file + # type=file|default=: reference file to get center of rotation + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + average_scaling: average_scaling_callable + # type=float: Average Scaling + determinant: determinant_callable + # type=float: Determinant + left_right_orientation_preserved: left_right_orientation_preserved_callable + # type=bool: True if LR orientation preserved + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + all_param: + # type=bool|default=False: + mat_file: + # type=file|default=: mat file to read + ref_file: + # type=file|default=: reference file to get center of rotation + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/av_scale_callables.py b/nipype-auto-conv/specs/av_scale_callables.py new file mode 100644 index 0000000..a26202f --- /dev/null +++ b/nipype-auto-conv/specs/av_scale_callables.py @@ -0,0 +1,81 @@ +"""Module to put any functions that are referred to in the "callables" section of AvScale.yaml""" + + +def average_scaling_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["average_scaling"] + + +def backward_half_transform_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["backward_half_transform"] + + +def determinant_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["determinant"] + + +def forward_half_transform_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["forward_half_transform"] + + +def left_right_orientation_preserved_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["left_right_orientation_preserved"] + + +def rot_angles_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["rot_angles"] + + +def rotation_translation_matrix_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["rotation_translation_matrix"] + + +def scales_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["scales"] + + +def skews_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["skews"] + + +def translations_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["translations"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L935 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + return _results diff --git a/nipype-auto-conv/specs/b0_calc.yaml b/nipype-auto-conv/specs/b0_calc.yaml new file mode 100644 index 0000000..edd6ef7 --- /dev/null +++ b/nipype-auto-conv/specs/b0_calc.yaml @@ -0,0 +1,166 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.possum.B0Calc' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# B0 inhomogeneities occur at interfaces of materials with different magnetic susceptibilities, +# such as tissue-air interfaces. These differences lead to distortion in the local magnetic field, +# as Maxwell’s equations need to be satisfied. An example of B0 inhomogneity is the first volume +# of the 4D volume ```$FSLDIR/data/possum/b0_ppm.nii.gz```. +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import B0Calc +# >>> b0calc = B0Calc() +# >>> b0calc.inputs.in_file = 'tissue+air_map.nii' +# >>> b0calc.inputs.z_b0 = 3.0 +# >>> b0calc.inputs.output_type = "NIFTI_GZ" +# >>> b0calc.cmdline +# 'b0calc -i tissue+air_map.nii -o tissue+air_map_b0field.nii.gz --chi0=4.000000e-07 -d -9.450000e-06 --extendboundary=1.00 --b0x=0.00 --gx=0.0000 --b0y=0.00 --gy=0.0000 --b0=3.00 --gz=0.0000' +# +# +task_name: B0Calc +nipype_name: B0Calc +nipype_module: nipype.interfaces.fsl.possum +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: filename of input image (usually a tissue/air segmentation) + out_file: Path + # type=file: filename of B0 output volume + # type=file|default=: filename of B0 output volume + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: filename of B0 output volume + # type=file|default=: filename of B0 output volume + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: filename of input image (usually a tissue/air segmentation) + out_file: + # type=file: filename of B0 output volume + # type=file|default=: filename of B0 output volume + x_grad: + # type=float|default=0.0: Value for zeroth-order x-gradient field (per mm) + y_grad: + # type=float|default=0.0: Value for zeroth-order y-gradient field (per mm) + z_grad: + # type=float|default=0.0: Value for zeroth-order z-gradient field (per mm) + x_b0: + # type=float|default=0.0: Value for zeroth-order b0 field (x-component), in Tesla + y_b0: + # type=float|default=0.0: Value for zeroth-order b0 field (y-component), in Tesla + z_b0: + # type=float|default=1.0: Value for zeroth-order b0 field (z-component), in Tesla + xyz_b0: + # type=tuple|default=(0.0, 0.0, 0.0): Zeroth-order B0 field in Tesla + delta: + # type=float|default=-9.45e-06: Delta value (chi_tissue - chi_air) + chi_air: + # type=float|default=4e-07: susceptibility of air + compute_xyz: + # type=bool|default=False: calculate and save all 3 field components (i.e. x,y,z) + extendboundary: + # type=float|default=1.0: Relative proportion to extend voxels at boundary + directconv: + # type=bool|default=False: use direct (image space) convolution, not FFT + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: filename of input image (usually a tissue/air segmentation) + z_b0: '3.0' + # type=float|default=1.0: Value for zeroth-order b0 field (z-component), in Tesla + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: b0calc -i tissue+air_map.nii -o tissue+air_map_b0field.nii.gz --chi0=4.000000e-07 -d -9.450000e-06 --extendboundary=1.00 --b0x=0.00 --gx=0.0000 --b0y=0.00 --gy=0.0000 --b0=3.00 --gz=0.0000 + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"tissue+air_map.nii"' + # type=file|default=: filename of input image (usually a tissue/air segmentation) + z_b0: '3.0' + # type=float|default=1.0: Value for zeroth-order b0 field (z-component), in Tesla + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/b0_calc_callables.py b/nipype-auto-conv/specs/b0_calc_callables.py new file mode 100644 index 0000000..1a08f4f --- /dev/null +++ b/nipype-auto-conv/specs/b0_calc_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of B0Calc.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/bedpostx5.yaml b/nipype-auto-conv/specs/bedpostx5.yaml new file mode 100644 index 0000000..4ef3d5b --- /dev/null +++ b/nipype-auto-conv/specs/bedpostx5.yaml @@ -0,0 +1,231 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.BEDPOSTX5' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# BEDPOSTX stands for Bayesian Estimation of Diffusion Parameters Obtained +# using Sampling Techniques. The X stands for modelling Crossing Fibres. +# bedpostx runs Markov Chain Monte Carlo sampling to build up distributions +# on diffusion parameters at each voxel. It creates all the files necessary +# for running probabilistic tractography. For an overview of the modelling +# carried out within bedpostx see this `technical report +# `_. +# +# +# .. note:: Consider using +# :func:`niflow.nipype1.workflows.fsl.dmri.create_bedpostx_pipeline` instead. +# +# +# Example +# ------- +# +# >>> from nipype.interfaces import fsl +# >>> bedp = fsl.BEDPOSTX5(bvecs='bvecs', bvals='bvals', dwi='diffusion.nii', +# ... mask='mask.nii', n_fibres=1) +# >>> bedp.cmdline +# 'bedpostx bedpostx -b 0 --burnin_noard=0 --forcedir -n 1 -j 5000 -s 1 --updateproposalevery=40' +# +# +task_name: BEDPOSTX5 +nipype_name: BEDPOSTX5 +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + bvals: medimage/bval + # type=file|default=: b values file + bvecs: medimage/bvec + # type=file|default=: b vectors file + dwi: medimage/nifti1 + # type=file|default=: diffusion weighted image data file + grad_dev: generic/file + # type=file|default=: grad_dev file, if gradnonlin, -g is True + logdir: generic/directory + # type=directory|default=: + mask: medimage/nifti1 + # type=file|default=: bet binary mask file + out_dir: generic/directory + # type=directory|default='bedpostx': output directory + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + dyads: generic/file+list-of + # type=outputmultiobject: Mean of PDD distribution in vector form. + dyads_dispersion: generic/file+list-of + # type=outputmultiobject: Dispersion + mean_S0samples: generic/file + # type=file: Mean of distribution on T2wbaseline signal intensity S0 + mean_dsamples: generic/file + # type=file: Mean of distribution on diffusivity d + mean_fsamples: generic/file+list-of + # type=outputmultiobject: Mean of distribution on f anisotropy + mean_phsamples: generic/file+list-of + # type=outputmultiobject: Mean of distribution on phi + mean_thsamples: generic/file+list-of + # type=outputmultiobject: Mean of distribution on theta + merged_fsamples: generic/file+list-of + # type=outputmultiobject: Samples from the distribution on anisotropic volume fraction + merged_phsamples: generic/file+list-of + # type=outputmultiobject: Samples from the distribution on phi + merged_thsamples: generic/file+list-of + # type=outputmultiobject: Samples from the distribution on theta + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dwi: + # type=file|default=: diffusion weighted image data file + mask: + # type=file|default=: bet binary mask file + bvecs: + # type=file|default=: b vectors file + bvals: + # type=file|default=: b values file + logdir: + # type=directory|default=: + n_fibres: + # type=range|default=2: Maximum number of fibres to fit in each voxel + model: + # type=enum|default=1|allowed[1,2,3]: use monoexponential (1, default, required for single-shell) or multiexponential (2, multi-shell) model + fudge: + # type=int|default=0: ARD fudge factor + n_jumps: + # type=int|default=5000: Num of jumps to be made by MCMC + burn_in: + # type=range|default=0: Total num of jumps at start of MCMC to be discarded + sample_every: + # type=range|default=1: Num of jumps for each sample (MCMC) + out_dir: + # type=directory|default='bedpostx': output directory + gradnonlin: + # type=bool|default=False: consider gradient nonlinearities, default off + grad_dev: + # type=file|default=: grad_dev file, if gradnonlin, -g is True + use_gpu: + # type=bool|default=False: Use the GPU version of bedpostx + burn_in_no_ard: + # type=range|default=0: num of burnin jumps before the ard is imposed + update_proposal_every: + # type=range|default=40: Num of jumps for each update to the proposal density std (MCMC) + seed: + # type=int|default=0: seed for pseudo random number generator + no_ard: + # type=bool|default=False: Turn ARD off on all fibres + all_ard: + # type=bool|default=False: Turn ARD on on all fibres + no_spat: + # type=bool|default=False: Initialise with tensor, not spatially + non_linear: + # type=bool|default=False: Initialise with nonlinear fitting + cnlinear: + # type=bool|default=False: Initialise with constrained nonlinear fitting + rician: + # type=bool|default=False: use Rician noise modeling + f0_noard: + # type=bool|default=False: Noise floor model: add to the model an unattenuated signal compartment f0 + f0_ard: + # type=bool|default=False: Noise floor model: add to the model an unattenuated signal compartment f0 + force_dir: + # type=bool|default=True: use the actual directory name given (do not add + to make a new directory) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + bvecs: + # type=file|default=: b vectors file + bvals: + # type=file|default=: b values file + dwi: + # type=file|default=: diffusion weighted image data file + mask: + # type=file|default=: bet binary mask file + n_fibres: "1" + # type=range|default=2: Maximum number of fibres to fit in each voxel + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: + - cmdline: bedpostx bedpostx -b 0 --burnin_noard=0 --forcedir -n 1 -j 5000 -s 1 --updateproposalevery=40 + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + bvecs: '"bvecs"' + # type=file|default=: b vectors file + bvals: '"bvals"' + # type=file|default=: b values file + dwi: '"diffusion.nii"' + # type=file|default=: diffusion weighted image data file + mask: '"mask.nii"' + # type=file|default=: bet binary mask file + n_fibres: "1" + # type=range|default=2: Maximum number of fibres to fit in each voxel + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/bedpostx5_callables.py b/nipype-auto-conv/specs/bedpostx5_callables.py new file mode 100644 index 0000000..8525bc4 --- /dev/null +++ b/nipype-auto-conv/specs/bedpostx5_callables.py @@ -0,0 +1,481 @@ +"""Module to put any functions that are referred to in the "callables" section of BEDPOSTX5.yaml""" + +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def dyads_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["dyads"] + + +def dyads_dispersion_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["dyads_dispersion"] + + +def mean_S0samples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_S0samples"] + + +def mean_dsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_dsamples"] + + +def mean_fsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_fsamples"] + + +def mean_phsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_phsamples"] + + +def mean_thsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_thsamples"] + + +def merged_fsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["merged_fsamples"] + + +def merged_phsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["merged_phsamples"] + + +def merged_thsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["merged_thsamples"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "bedpostx" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L483 of /interfaces/fsl/dti.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + n_fibres = inputs.n_fibres + + multi_out = [ + "merged_thsamples", + "merged_fsamples", + "merged_phsamples", + "mean_phsamples", + "mean_thsamples", + "mean_fsamples", + "dyads_dispersion", + "dyads", + ] + + single_out = ["mean_dsamples", "mean_S0samples"] + + for k in single_out: + outputs[k] = _gen_fname( + k, + cwd=_out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + + for k in multi_out: + outputs[k] = [] + + for i in range(1, n_fibres + 1): + outputs["merged_thsamples"].append( + _gen_fname( + "merged_th%dsamples" % i, + cwd=_out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["merged_fsamples"].append( + _gen_fname( + "merged_f%dsamples" % i, + cwd=_out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["merged_phsamples"].append( + _gen_fname( + "merged_ph%dsamples" % i, + cwd=_out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["mean_thsamples"].append( + _gen_fname( + "mean_th%dsamples" % i, + cwd=_out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["mean_phsamples"].append( + _gen_fname( + "mean_ph%dsamples" % i, + cwd=_out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["mean_fsamples"].append( + _gen_fname( + "mean_f%dsamples" % i, + cwd=_out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["dyads"].append( + _gen_fname( + "dyads%d" % i, + cwd=_out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["dyads_dispersion"].append( + _gen_fname( + "dyads%d_dispersion" % i, + cwd=_out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/bet.yaml b/nipype-auto-conv/specs/bet.yaml new file mode 100644 index 0000000..40c9a43 --- /dev/null +++ b/nipype-auto-conv/specs/bet.yaml @@ -0,0 +1,204 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.BET' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL BET wrapper for skull stripping +# +# For complete details, see the `BET Documentation. +# `_ +# +# Examples +# -------- +# >>> from nipype.interfaces import fsl +# >>> btr = fsl.BET() +# >>> btr.inputs.in_file = 'structural.nii' +# >>> btr.inputs.frac = 0.7 +# >>> btr.inputs.out_file = 'brain_anat.nii' +# >>> btr.cmdline +# 'bet structural.nii brain_anat.nii -f 0.70' +# >>> res = btr.run() # doctest: +SKIP +# +# +task_name: BET +nipype_name: BET +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: input file to skull strip + out_file: Path + # type=file: path/name of skullstripped file (if generated) + # type=file|default=: name of output skull stripped image + t2_guided: generic/file + # type=file|default=: as with creating surfaces, when also feeding in non-brain-extracted T2 (includes registrations) + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + inskull_mask_file: generic/file + # type=file: path/name of inskull mask (if generated) + inskull_mesh_file: generic/file + # type=file: path/name of inskull mesh outline (if generated) + mask_file: generic/file + # type=file: path/name of binary brain mask (if generated) + meshfile: generic/file + # type=file: path/name of vtk mesh file (if generated) + out_file: medimage/nifti1 + # type=file: path/name of skullstripped file (if generated) + # type=file|default=: name of output skull stripped image + outline_file: generic/file + # type=file: path/name of outline file (if generated) + outskin_mask_file: generic/file + # type=file: path/name of outskin mask (if generated) + outskin_mesh_file: generic/file + # type=file: path/name of outskin mesh outline (if generated) + outskull_mask_file: generic/file + # type=file: path/name of outskull mask (if generated) + outskull_mesh_file: generic/file + # type=file: path/name of outskull mesh outline (if generated) + skull_file: generic/file + # type=file: path/name of skull file (if generated) + skull_mask_file: generic/file + # type=file: path/name of skull mask (if generated) + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: '"brain_anat.nii"' + # type=file: path/name of skullstripped file (if generated) + # type=file|default=: name of output skull stripped image + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file to skull strip + out_file: + # type=file: path/name of skullstripped file (if generated) + # type=file|default=: name of output skull stripped image + outline: + # type=bool|default=False: create surface outline image + mask: + # type=bool|default=False: create binary mask image + skull: + # type=bool|default=False: create skull image + no_output: + # type=bool|default=False: Don't generate segmented output + frac: + # type=float|default=0.0: fractional intensity threshold + vertical_gradient: + # type=float|default=0.0: vertical gradient in fractional intensity threshold (-1, 1) + radius: + # type=int|default=0: head radius + center: + # type=list|default=[]: center of gravity in voxels + threshold: + # type=bool|default=False: apply thresholding to segmented brain image and mask + mesh: + # type=bool|default=False: generate a vtk mesh brain surface + robust: + # type=bool|default=False: robust brain centre estimation (iterates BET several times) + padding: + # type=bool|default=False: improve BET if FOV is very small in Z (by temporarily padding end slices) + remove_eyes: + # type=bool|default=False: eye & optic nerve cleanup (can be useful in SIENA) + surfaces: + # type=bool|default=False: run bet2 and then betsurf to get additional skull and scalp surfaces (includes registrations) + t2_guided: + # type=file|default=: as with creating surfaces, when also feeding in non-brain-extracted T2 (includes registrations) + functional: + # type=bool|default=False: apply to 4D fMRI data + reduce_bias: + # type=bool|default=False: bias field and neck cleanup + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file to skull strip + frac: '0.7' + # type=float|default=0.0: fractional intensity threshold + out_file: '"brain_anat.nii"' + # type=file: path/name of skullstripped file (if generated) + # type=file|default=: name of output skull stripped image + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: bet structural.nii brain_anat.nii -f 0.70 + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"structural.nii"' + # type=file|default=: input file to skull strip + frac: '0.7' + # type=float|default=0.0: fractional intensity threshold + out_file: '"brain_anat.nii"' + # type=file: path/name of skullstripped file (if generated) + # type=file|default=: name of output skull stripped image + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/bet_callables.py b/nipype-auto-conv/specs/bet_callables.py new file mode 100644 index 0000000..1e2b1c3 --- /dev/null +++ b/nipype-auto-conv/specs/bet_callables.py @@ -0,0 +1,524 @@ +"""Module to put any functions that are referred to in the "callables" section of BET.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def inskull_mask_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["inskull_mask_file"] + + +def inskull_mesh_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["inskull_mesh_file"] + + +def mask_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mask_file"] + + +def meshfile_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["meshfile"] + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +def outline_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["outline_file"] + + +def outskin_mask_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["outskin_mask_file"] + + +def outskin_mesh_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["outskin_mesh_file"] + + +def outskull_mask_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["outskull_mask_file"] + + +def outskull_mesh_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["outskull_mesh_file"] + + +def skull_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["skull_file"] + + +def skull_mask_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["skull_mask_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L232 of /interfaces/fsl/preprocess.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _gen_outfilename( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "bet" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L176 of /interfaces/fsl/preprocess.py +def _gen_outfilename(inputs=None, stdout=None, stderr=None, output_dir=None): + out_file = inputs.out_file + # Generate default output filename if non specified. + if (out_file is attrs.NOTHING) and (inputs.in_file is not attrs.NOTHING): + out_file = _gen_fname( + inputs.in_file, + suffix="_brain", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + # Convert to relative path to prevent BET failure + # with long paths. + return op.relpath(out_file, start=output_dir) + return out_file + + +# Original source at L186 of /interfaces/fsl/preprocess.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = os.path.abspath( + _gen_outfilename( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + ) + + basename = os.path.basename(outputs["out_file"]) + cwd = os.path.dirname(outputs["out_file"]) + kwargs = {"basename": basename, "cwd": cwd} + + if ((inputs.mesh is not attrs.NOTHING) and inputs.mesh) or ( + (inputs.surfaces is not attrs.NOTHING) and inputs.surfaces + ): + outputs["meshfile"] = _gen_fname( + suffix="_mesh.vtk", + change_ext=False, + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if ((inputs.mask is not attrs.NOTHING) and inputs.mask) or ( + (inputs.reduce_bias is not attrs.NOTHING) and inputs.reduce_bias + ): + outputs["mask_file"] = _gen_fname( + suffix="_mask", + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if (inputs.outline is not attrs.NOTHING) and inputs.outline: + outputs["outline_file"] = _gen_fname( + suffix="_overlay", + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if (inputs.surfaces is not attrs.NOTHING) and inputs.surfaces: + outputs["inskull_mask_file"] = _gen_fname( + suffix="_inskull_mask", + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["inskull_mesh_file"] = _gen_fname( + suffix="_inskull_mesh", + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["outskull_mask_file"] = _gen_fname( + suffix="_outskull_mask", + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["outskull_mesh_file"] = _gen_fname( + suffix="_outskull_mesh", + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["outskin_mask_file"] = _gen_fname( + suffix="_outskin_mask", + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["outskin_mesh_file"] = _gen_fname( + suffix="_outskin_mesh", + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["skull_mask_file"] = _gen_fname( + suffix="_skull_mask", + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if (inputs.skull is not attrs.NOTHING) and inputs.skull: + outputs["skull_file"] = _gen_fname( + suffix="_skull", + **kwargs, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if (inputs.no_output is not attrs.NOTHING) and inputs.no_output: + outputs["out_file"] = attrs.NOTHING + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/binary_maths.yaml b/nipype-auto-conv/specs/binary_maths.yaml new file mode 100644 index 0000000..3c32248 --- /dev/null +++ b/nipype-auto-conv/specs/binary_maths.yaml @@ -0,0 +1,104 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.BinaryMaths' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to perform mathematical operations using a second image or +# a numeric value. +# +# +task_name: BinaryMaths +nipype_name: BinaryMaths +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + operand_file: generic/file + # type=file|default=: second image to perform operation with + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + operation: + # type=enum|default='add'|allowed['add','div','max','min','mul','rem','sub']: operation to perform + operand_file: + # type=file|default=: second image to perform operation with + operand_value: + # type=float|default=0.0: value to perform operation with + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/binary_maths_callables.py b/nipype-auto-conv/specs/binary_maths_callables.py new file mode 100644 index 0000000..ac159de --- /dev/null +++ b/nipype-auto-conv/specs/binary_maths_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of BinaryMaths.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/change_data_type.yaml b/nipype-auto-conv/specs/change_data_type.yaml new file mode 100644 index 0000000..2206fa7 --- /dev/null +++ b/nipype-auto-conv/specs/change_data_type.yaml @@ -0,0 +1,93 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.ChangeDataType' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to change the datatype of an image. +task_name: ChangeDataType +nipype_name: ChangeDataType +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: output data type + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/change_data_type_callables.py b/nipype-auto-conv/specs/change_data_type_callables.py new file mode 100644 index 0000000..3af76c1 --- /dev/null +++ b/nipype-auto-conv/specs/change_data_type_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of ChangeDataType.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/classifier.yaml b/nipype-auto-conv/specs/classifier.yaml new file mode 100644 index 0000000..99a202a --- /dev/null +++ b/nipype-auto-conv/specs/classifier.yaml @@ -0,0 +1,90 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.fix.Classifier' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Classify ICA components using a specific training dataset ( is in the range 0-100, typically 5-20). +# +task_name: Classifier +nipype_name: Classifier +nipype_module: nipype.interfaces.fsl.fix +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + artifacts_list_file: Path + # type=file: Text file listing which ICs are artifacts; can be the output from classification or can be created manually + # type=file|default=: Text file listing which ICs are artifacts; can be the output from classification or can be created manually + mel_ica: generic/directory + # type=directory|default=: Melodic output directory or directories + trained_wts_file: generic/file + # type=file|default=: trained-weights file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + artifacts_list_file: generic/file + # type=file: Text file listing which ICs are artifacts; can be the output from classification or can be created manually + # type=file|default=: Text file listing which ICs are artifacts; can be the output from classification or can be created manually + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + mel_ica: + # type=directory|default=: Melodic output directory or directories + trained_wts_file: + # type=file|default=: trained-weights file + thresh: + # type=int|default=0: Threshold for cleanup. + artifacts_list_file: + # type=file: Text file listing which ICs are artifacts; can be the output from classification or can be created manually + # type=file|default=: Text file listing which ICs are artifacts; can be the output from classification or can be created manually + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/classifier_callables.py b/nipype-auto-conv/specs/classifier_callables.py new file mode 100644 index 0000000..49a89d3 --- /dev/null +++ b/nipype-auto-conv/specs/classifier_callables.py @@ -0,0 +1,42 @@ +"""Module to put any functions that are referred to in the "callables" section of Classifier.yaml""" + +import os + + +def artifacts_list_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["artifacts_list_file"] + + +# Original source at L304 of /interfaces/fsl/fix.py +def _gen_artifacts_list_file( + mel_ica, thresh, inputs=None, stdout=None, stderr=None, output_dir=None +): + _, trained_wts_file = os.path.split(inputs.trained_wts_file) + trained_wts_filestem = trained_wts_file.split(".")[0] + filestem = "fix4melview_" + trained_wts_filestem + "_thr" + + fname = os.path.join(mel_ica, filestem + str(thresh) + ".txt") + return fname + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L312 of /interfaces/fsl/fix.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["artifacts_list_file"] = _gen_artifacts_list_file( + inputs.mel_ica, + inputs.thresh, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + + return outputs diff --git a/nipype-auto-conv/specs/cleaner.yaml b/nipype-auto-conv/specs/cleaner.yaml new file mode 100644 index 0000000..f316007 --- /dev/null +++ b/nipype-auto-conv/specs/cleaner.yaml @@ -0,0 +1,95 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.fix.Cleaner' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Extract features (for later training and/or classifying) +# +task_name: Cleaner +nipype_name: Cleaner +nipype_module: nipype.interfaces.fsl.fix +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + artifacts_list_file: generic/file + # type=file|default=: Text file listing which ICs are artifacts; can be the output from classification or can be created manually + confound_file: generic/file + # type=file|default=: Include additional confound file. + confound_file_1: generic/file + # type=file|default=: Include additional confound file. + confound_file_2: generic/file + # type=file|default=: Include additional confound file. + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + cleaned_functional_file: generic/file + # type=file: Cleaned session data + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + artifacts_list_file: + # type=file|default=: Text file listing which ICs are artifacts; can be the output from classification or can be created manually + cleanup_motion: + # type=bool|default=False: cleanup motion confounds, looks for design.fsf for highpass filter cut-off + highpass: + # type=float|default=100: cleanup motion confounds + aggressive: + # type=bool|default=False: Apply aggressive (full variance) cleanup, instead of the default less-aggressive (unique variance) cleanup. + confound_file: + # type=file|default=: Include additional confound file. + confound_file_1: + # type=file|default=: Include additional confound file. + confound_file_2: + # type=file|default=: Include additional confound file. + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/cleaner_callables.py b/nipype-auto-conv/specs/cleaner_callables.py new file mode 100644 index 0000000..8a8692c --- /dev/null +++ b/nipype-auto-conv/specs/cleaner_callables.py @@ -0,0 +1,42 @@ +"""Module to put any functions that are referred to in the "callables" section of Cleaner.yaml""" + +import os + + +def cleaned_functional_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["cleaned_functional_file"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L376 of /interfaces/fsl/fix.py +def _get_cleaned_functional_filename( + artifacts_list_filename, inputs=None, stdout=None, stderr=None, output_dir=None +): + """extract the proper filename from the first line of the artifacts file""" + artifacts_list_file = open(artifacts_list_filename, "r") + functional_filename, extension = artifacts_list_file.readline().split(".") + artifacts_list_file_path, artifacts_list_filename = os.path.split( + artifacts_list_filename + ) + + return os.path.join(artifacts_list_file_path, functional_filename + "_clean.nii.gz") + + +# Original source at L388 of /interfaces/fsl/fix.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["cleaned_functional_file"] = _get_cleaned_functional_filename( + inputs.artifacts_list_file, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return outputs diff --git a/nipype-auto-conv/specs/cluster.yaml b/nipype-auto-conv/specs/cluster.yaml new file mode 100644 index 0000000..48b618e --- /dev/null +++ b/nipype-auto-conv/specs/cluster.yaml @@ -0,0 +1,203 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.Cluster' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Uses FSL cluster to perform clustering on statistical output +# +# Examples +# -------- +# +# >>> cl = Cluster() +# >>> cl.inputs.threshold = 2.3 +# >>> cl.inputs.in_file = 'zstat1.nii.gz' +# >>> cl.inputs.out_localmax_txt_file = 'stats.txt' +# >>> cl.inputs.use_mm = True +# >>> cl.cmdline +# 'cluster --in=zstat1.nii.gz --olmax=stats.txt --thresh=2.3000000000 --mm' +task_name: Cluster +nipype_name: Cluster +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + cope_file: generic/file + # type=file|default=: cope volume + in_file: medimage/nifti-gz + # type=file|default=: input volume + std_space_file: generic/file + # type=file|default=: filename for standard-space volume + warpfield_file: generic/file + # type=file|default=: file contining warpfield + xfm_file: generic/file + # type=file|default=: filename for Linear: input->standard-space transform. Non-linear: input->highres transform + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + index_file: generic/file + # type=file: output of cluster index (in size order) + localmax_txt_file: generic/file + # type=file: local maxima text file + localmax_vol_file: generic/file + # type=file: output of local maxima volume + max_file: generic/file + # type=file: filename for output of max image + mean_file: generic/file + # type=file: filename for output of mean image + pval_file: generic/file + # type=file: filename for image output of log pvals + size_file: generic/file + # type=file: filename for output of size image + threshold_file: generic/file + # type=file: thresholded image + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input volume + threshold: + # type=float|default=0.0: threshold for input volume + out_index_file: + # type=traitcompound|default=None: output of cluster index (in size order) + out_threshold_file: + # type=traitcompound|default=None: thresholded image + out_localmax_txt_file: + # type=traitcompound|default=None: local maxima text file + out_localmax_vol_file: + # type=traitcompound|default=None: output of local maxima volume + out_size_file: + # type=traitcompound|default=None: filename for output of size image + out_max_file: + # type=traitcompound|default=None: filename for output of max image + out_mean_file: + # type=traitcompound|default=None: filename for output of mean image + out_pval_file: + # type=traitcompound|default=None: filename for image output of log pvals + pthreshold: + # type=float|default=0.0: p-threshold for clusters + peak_distance: + # type=float|default=0.0: minimum distance between local maxima/minima, in mm (default 0) + cope_file: + # type=file|default=: cope volume + volume: + # type=int|default=0: number of voxels in the mask + dlh: + # type=float|default=0.0: smoothness estimate = sqrt(det(Lambda)) + fractional: + # type=bool|default=False: interprets the threshold as a fraction of the robust range + connectivity: + # type=int|default=0: the connectivity of voxels (default 26) + use_mm: + # type=bool|default=False: use mm, not voxel, coordinates + find_min: + # type=bool|default=False: find minima instead of maxima + no_table: + # type=bool|default=False: suppresses printing of the table info + minclustersize: + # type=bool|default=False: prints out minimum significant cluster size + xfm_file: + # type=file|default=: filename for Linear: input->standard-space transform. Non-linear: input->highres transform + std_space_file: + # type=file|default=: filename for standard-space volume + num_maxima: + # type=int|default=0: no of local maxima to report + warpfield_file: + # type=file|default=: file containing warpfield + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + threshold: "2.3" + # type=float|default=0.0: threshold for input volume + in_file: + # type=file|default=: input volume + out_localmax_txt_file: '"stats.txt"' + # type=traitcompound|default=None: local maxima text file + use_mm: "True" + # type=bool|default=False: use mm, not voxel, coordinates + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: + - cmdline: cluster --in=zstat1.nii.gz --olmax=stats.txt --thresh=2.3000000000 --mm + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + threshold: "2.3" + # type=float|default=0.0: threshold for input volume + in_file: '"zstat1.nii.gz"' + # type=file|default=: input volume + out_localmax_txt_file: '"stats.txt"' + # type=traitcompound|default=None: local maxima text file + use_mm: "True" + # type=bool|default=False: use mm, not voxel, coordinates + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/cluster_callables.py b/nipype-auto-conv/specs/cluster_callables.py new file mode 100644 index 0000000..c6a7247 --- /dev/null +++ b/nipype-auto-conv/specs/cluster_callables.py @@ -0,0 +1,379 @@ +"""Module to put any functions that are referred to in the "callables" section of Cluster.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def index_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["index_file"] + + +def localmax_txt_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["localmax_txt_file"] + + +def localmax_vol_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["localmax_vol_file"] + + +def max_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["max_file"] + + +def mean_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_file"] + + +def pval_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["pval_file"] + + +def size_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["size_file"] + + +def threshold_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["threshold_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "cluster" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L2074 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + for key, suffix in list(filemap.items()): + outkey = key[4:] + inval = getattr(inputs, key) + if inval is not attrs.NOTHING: + if isinstance(inval, bool): + if inval: + change_ext = True + if suffix.endswith(".txt"): + change_ext = False + outputs[outkey] = _gen_fname( + inputs.in_file, + suffix="_" + suffix, + change_ext=change_ext, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + else: + outputs[outkey] = os.path.abspath(inval) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/complex.yaml b/nipype-auto-conv/specs/complex.yaml new file mode 100644 index 0000000..b612ec1 --- /dev/null +++ b/nipype-auto-conv/specs/complex.yaml @@ -0,0 +1,182 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.Complex' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# fslcomplex is a tool for converting complex data +# +# Examples +# -------- +# +# >>> cplx = Complex() +# >>> cplx.inputs.complex_in_file = "complex.nii" +# >>> cplx.real_polar = True +# >>> res = cplx.run() # doctest: +SKIP +# +# +# +task_name: Complex +nipype_name: Complex +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + complex_in_file: generic/file + # type=file|default=: + complex_in_file2: generic/file + # type=file|default=: + complex_out_file: Path + # type=file: + # type=file|default=: + imaginary_in_file: generic/file + # type=file|default=: + imaginary_out_file: Path + # type=file: + # type=file|default=: + magnitude_in_file: generic/file + # type=file|default=: + magnitude_out_file: Path + # type=file: + # type=file|default=: + phase_in_file: generic/file + # type=file|default=: + phase_out_file: Path + # type=file: + # type=file|default=: + real_in_file: generic/file + # type=file|default=: + real_out_file: Path + # type=file: + # type=file|default=: + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + complex_out_file: generic/file + # type=file: + # type=file|default=: + imaginary_out_file: generic/file + # type=file: + # type=file|default=: + magnitude_out_file: generic/file + # type=file: + # type=file|default=: + phase_out_file: generic/file + # type=file: + # type=file|default=: + real_out_file: generic/file + # type=file: + # type=file|default=: + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + complex_out_file: complex_out_file + # type=file: + # type=file|default=: + imaginary_out_file: imaginary_out_file + # type=file: + # type=file|default=: + magnitude_out_file: magnitude_out_file + # type=file: + # type=file|default=: + phase_out_file: phase_out_file + # type=file: + # type=file|default=: + real_out_file: real_out_file + # type=file: + # type=file|default=: + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + complex_in_file: + # type=file|default=: + complex_in_file2: + # type=file|default=: + real_in_file: + # type=file|default=: + imaginary_in_file: + # type=file|default=: + magnitude_in_file: + # type=file|default=: + phase_in_file: + # type=file|default=: + complex_out_file: + # type=file: + # type=file|default=: + magnitude_out_file: + # type=file: + # type=file|default=: + phase_out_file: + # type=file: + # type=file|default=: + real_out_file: + # type=file: + # type=file|default=: + imaginary_out_file: + # type=file: + # type=file|default=: + start_vol: + # type=int|default=0: + end_vol: + # type=int|default=0: + real_polar: + # type=bool|default=False: + real_cartesian: + # type=bool|default=False: + complex_cartesian: + # type=bool|default=False: + complex_polar: + # type=bool|default=False: + complex_split: + # type=bool|default=False: + complex_merge: + # type=bool|default=False: + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/complex_callables.py b/nipype-auto-conv/specs/complex_callables.py new file mode 100644 index 0000000..b8a505b --- /dev/null +++ b/nipype-auto-conv/specs/complex_callables.py @@ -0,0 +1,464 @@ +"""Module to put any functions that are referred to in the "callables" section of Complex.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def complex_out_file_default(inputs): + return _gen_filename("complex_out_file", inputs=inputs) + + +def imaginary_out_file_default(inputs): + return _gen_filename("imaginary_out_file", inputs=inputs) + + +def magnitude_out_file_default(inputs): + return _gen_filename("magnitude_out_file", inputs=inputs) + + +def phase_out_file_default(inputs): + return _gen_filename("phase_out_file", inputs=inputs) + + +def real_out_file_default(inputs): + return _gen_filename("real_out_file", inputs=inputs) + + +def complex_out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["complex_out_file"] + + +def imaginary_out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["imaginary_out_file"] + + +def magnitude_out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["magnitude_out_file"] + + +def phase_out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["phase_out_file"] + + +def real_out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["real_out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L2031 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "complex_out_file": + if inputs.complex_cartesian: + in_file = inputs.real_in_file + elif inputs.complex_polar: + in_file = inputs.magnitude_in_file + elif inputs.complex_split or inputs.complex_merge: + in_file = inputs.complex_in_file + else: + return None + return _gen_fname( + in_file, + suffix="_cplx", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + elif name == "magnitude_out_file": + return _gen_fname( + inputs.complex_in_file, + suffix="_mag", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + elif name == "phase_out_file": + return _gen_fname( + inputs.complex_in_file, + suffix="_phase", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + elif name == "real_out_file": + return _gen_fname( + inputs.complex_in_file, + suffix="_real", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + elif name == "imaginary_out_file": + return _gen_fname( + inputs.complex_in_file, + suffix="_imag", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslcomplex" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L2052 of /interfaces/fsl/utils.py +def _get_output(name, inputs=None, stdout=None, stderr=None, output_dir=None): + output = getattr(inputs, name) + if output is attrs.NOTHING: + output = _gen_filename( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + return os.path.abspath(output) + + +# Original source at L2058 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + if ( + inputs.complex_cartesian + or inputs.complex_polar + or inputs.complex_split + or inputs.complex_merge + ): + outputs["complex_out_file"] = _get_output( + "complex_out_file", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + elif inputs.real_cartesian: + outputs["real_out_file"] = _get_output( + "real_out_file", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["imaginary_out_file"] = _get_output( + "imaginary_out_file", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + elif inputs.real_polar: + outputs["magnitude_out_file"] = _get_output( + "magnitude_out_file", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["phase_out_file"] = _get_output( + "phase_out_file", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/contrast_mgr.yaml b/nipype-auto-conv/specs/contrast_mgr.yaml new file mode 100644 index 0000000..4d5e94d --- /dev/null +++ b/nipype-auto-conv/specs/contrast_mgr.yaml @@ -0,0 +1,118 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.ContrastMgr' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL contrast_mgr command to evaluate contrasts +# +# In interface mode this file assumes that all the required inputs are in the +# same location. This has deprecated for FSL versions 5.0.7+ as the necessary +# corrections file is no longer generated by FILMGLS. +# +task_name: ContrastMgr +nipype_name: ContrastMgr +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + corrections: generic/file + # type=file|default=: statistical corrections used within FILM modelling + dof_file: generic/file + # type=file|default=: degrees of freedom + fcon_file: generic/file + # type=file|default=: contrast file containing F-contrasts + param_estimates: generic/file+list-of + # type=inputmultiobject|default=[]: Parameter estimates for each column of the design matrix + sigmasquareds: generic/file + # type=file|default=: summary of residuals, See Woolrich, et. al., 2001 + tcon_file: generic/file + # type=file|default=: contrast file containing T-contrasts + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + copes: generic/file+list-of + # type=outputmultiobject: Contrast estimates for each contrast + fstats: generic/file+list-of + # type=outputmultiobject: f-stat file for each contrast + neffs: generic/file+list-of + # type=outputmultiobject: neff file ?? for each contrast + tstats: generic/file+list-of + # type=outputmultiobject: t-stat file for each contrast + varcopes: generic/file+list-of + # type=outputmultiobject: Variance estimates for each contrast + zfstats: generic/file+list-of + # type=outputmultiobject: z-stat file for each F contrast + zstats: generic/file+list-of + # type=outputmultiobject: z-stat file for each contrast + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + tcon_file: + # type=file|default=: contrast file containing T-contrasts + fcon_file: + # type=file|default=: contrast file containing F-contrasts + param_estimates: + # type=inputmultiobject|default=[]: Parameter estimates for each column of the design matrix + corrections: + # type=file|default=: statistical corrections used within FILM modelling + dof_file: + # type=file|default=: degrees of freedom + sigmasquareds: + # type=file|default=: summary of residuals, See Woolrich, et. al., 2001 + contrast_num: + # type=range|default=1: contrast number to start labeling copes from + suffix: + # type=str|default='': suffix to put on the end of the cope filename before the contrast number, default is nothing + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/contrast_mgr_callables.py b/nipype-auto-conv/specs/contrast_mgr_callables.py new file mode 100644 index 0000000..a2849d0 --- /dev/null +++ b/nipype-auto-conv/specs/contrast_mgr_callables.py @@ -0,0 +1,468 @@ +"""Module to put any functions that are referred to in the "callables" section of ContrastMgr.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def copes_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["copes"] + + +def fstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fstats"] + + +def neffs_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["neffs"] + + +def tstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["tstats"] + + +def varcopes_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["varcopes"] + + +def zfstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["zfstats"] + + +def zstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["zstats"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "contrast_mgr" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1301 of /interfaces/fsl/model.py +def _get_numcons(inputs=None, stdout=None, stderr=None, output_dir=None): + numtcons = 0 + numfcons = 0 + if inputs.tcon_file is not attrs.NOTHING: + fp = open(inputs.tcon_file, "rt") + for line in fp.readlines(): + if line.startswith("/NumContrasts"): + numtcons = int(line.split()[-1]) + break + fp.close() + if inputs.fcon_file is not attrs.NOTHING: + fp = open(inputs.fcon_file, "rt") + for line in fp.readlines(): + if line.startswith("/NumContrasts"): + numfcons = int(line.split()[-1]) + break + fp.close() + return numtcons, numfcons + + +# Original source at L1320 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + pth, _ = os.path.split(inputs.sigmasquareds) + numtcons, numfcons = _get_numcons( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + base_contrast = 1 + if inputs.contrast_num is not attrs.NOTHING: + base_contrast = inputs.contrast_num + copes = [] + varcopes = [] + zstats = [] + tstats = [] + neffs = [] + for i in range(numtcons): + copes.append( + _gen_fname( + "cope%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + varcopes.append( + _gen_fname( + "varcope%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + zstats.append( + _gen_fname( + "zstat%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + tstats.append( + _gen_fname( + "tstat%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + neffs.append( + _gen_fname( + "neff%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + if copes: + outputs["copes"] = copes + outputs["varcopes"] = varcopes + outputs["zstats"] = zstats + outputs["tstats"] = tstats + outputs["neffs"] = neffs + fstats = [] + zfstats = [] + for i in range(numfcons): + fstats.append( + _gen_fname( + "fstat%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + zfstats.append( + _gen_fname( + "zfstat%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + if fstats: + outputs["fstats"] = fstats + outputs["zfstats"] = zfstats + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/convert_warp.yaml b/nipype-auto-conv/specs/convert_warp.yaml new file mode 100644 index 0000000..9a3fcfe --- /dev/null +++ b/nipype-auto-conv/specs/convert_warp.yaml @@ -0,0 +1,187 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.ConvertWarp' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL `convertwarp `_ +# for combining multiple transforms into one. +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import ConvertWarp +# >>> warputils = ConvertWarp() +# >>> warputils.inputs.warp1 = "warpfield.nii" +# >>> warputils.inputs.reference = "T1.nii" +# >>> warputils.inputs.relwarp = True +# >>> warputils.inputs.output_type = "NIFTI_GZ" +# >>> warputils.cmdline # doctest: +ELLIPSIS +# 'convertwarp --ref=T1.nii --rel --warp1=warpfield.nii --out=T1_concatwarp.nii.gz' +# >>> res = warputils.run() # doctest: +SKIP +# +# +# +task_name: ConvertWarp +nipype_name: ConvertWarp +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + midmat: generic/file + # type=file|default=: Name of file containing mid-warp-affine transform + out_file: Path + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: Name of output file, containing warps that are the combination of all those given as arguments. The format of this will be a field-file (rather than spline coefficients) with any affine components included. + postmat: generic/file + # type=file|default=: Name of file containing an affine transform (applied last). It could e.g. be an affine transform that maps the MNI152-space into a better approximation to the Talairach-space (if indeed there is one). + premat: generic/file + # type=file|default=: filename for pre-transform (affine matrix) + reference: medimage/nifti1 + # type=file|default=: Name of a file in target space of the full transform. + shift_in_file: generic/file + # type=file|default=: Name of file containing a "shiftmap", a non-linear transform with displacements only in one direction (applied first, before premat). This would typically be a fieldmap that has been pre-processed using fugue that maps a subjects functional (EPI) data onto an undistorted space (i.e. a space that corresponds to his/her true anatomy). + warp1: medimage/nifti1 + # type=file|default=: Name of file containing initial warp-fields/coefficients (follows premat). This could e.g. be a fnirt-transform from a subjects structural scan to an average of a group of subjects. + warp2: generic/file + # type=file|default=: Name of file containing secondary warp-fields/coefficients (after warp1/midmat but before postmat). This could e.g. be a fnirt-transform from the average of a group of subjects to some standard space (e.g. MNI152). + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: Name of output file, containing warps that are the combination of all those given as arguments. The format of this will be a field-file (rather than spline coefficients) with any affine components included. + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + reference: + # type=file|default=: Name of a file in target space of the full transform. + out_file: + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: Name of output file, containing warps that are the combination of all those given as arguments. The format of this will be a field-file (rather than spline coefficients) with any affine components included. + premat: + # type=file|default=: filename for pre-transform (affine matrix) + warp1: + # type=file|default=: Name of file containing initial warp-fields/coefficients (follows premat). This could e.g. be a fnirt-transform from a subjects structural scan to an average of a group of subjects. + midmat: + # type=file|default=: Name of file containing mid-warp-affine transform + warp2: + # type=file|default=: Name of file containing secondary warp-fields/coefficients (after warp1/midmat but before postmat). This could e.g. be a fnirt-transform from the average of a group of subjects to some standard space (e.g. MNI152). + postmat: + # type=file|default=: Name of file containing an affine transform (applied last). It could e.g. be an affine transform that maps the MNI152-space into a better approximation to the Talairach-space (if indeed there is one). + shift_in_file: + # type=file|default=: Name of file containing a "shiftmap", a non-linear transform with displacements only in one direction (applied first, before premat). This would typically be a fieldmap that has been pre-processed using fugue that maps a subjects functional (EPI) data onto an undistorted space (i.e. a space that corresponds to his/her true anatomy). + shift_direction: + # type=enum|default='y-'|allowed['x','x-','y','y-','z','z-']: Indicates the direction that the distortions from --shiftmap goes. It depends on the direction and polarity of the phase-encoding in the EPI sequence. + cons_jacobian: + # type=bool|default=False: Constrain the Jacobian of the warpfield to lie within specified min/max limits. + jacobian_min: + # type=float|default=0.0: Minimum acceptable Jacobian value for constraint (default 0.01) + jacobian_max: + # type=float|default=0.0: Maximum acceptable Jacobian value for constraint (default 100.0) + abswarp: + # type=bool|default=False: If set it indicates that the warps in --warp1 and --warp2 should be interpreted as absolute. I.e. the values in --warp1/2 are the coordinates in the next space, rather than displacements. This flag is ignored if --warp1/2 was created by fnirt, which always creates relative displacements. + relwarp: + # type=bool|default=False: If set it indicates that the warps in --warp1/2 should be interpreted as relative. I.e. the values in --warp1/2 are displacements from the coordinates in the next space. + out_abswarp: + # type=bool|default=False: If set it indicates that the warps in --out should be absolute, i.e. the values in --out are displacements from the coordinates in --ref. + out_relwarp: + # type=bool|default=False: If set it indicates that the warps in --out should be relative, i.e. the values in --out are displacements from the coordinates in --ref. + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + warp1: + # type=file|default=: Name of file containing initial warp-fields/coefficients (follows premat). This could e.g. be a fnirt-transform from a subjects structural scan to an average of a group of subjects. + reference: + # type=file|default=: Name of a file in target space of the full transform. + relwarp: 'True' + # type=bool|default=False: If set it indicates that the warps in --warp1/2 should be interpreted as relative. I.e. the values in --warp1/2 are displacements from the coordinates in the next space. + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: convertwarp --ref=T1.nii --rel --warp1=warpfield.nii --out=T1_concatwarp.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + warp1: '"warpfield.nii"' + # type=file|default=: Name of file containing initial warp-fields/coefficients (follows premat). This could e.g. be a fnirt-transform from a subjects structural scan to an average of a group of subjects. + reference: '"T1.nii"' + # type=file|default=: Name of a file in target space of the full transform. + relwarp: 'True' + # type=bool|default=False: If set it indicates that the warps in --warp1/2 should be interpreted as relative. I.e. the values in --warp1/2 are displacements from the coordinates in the next space. + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/convert_warp_callables.py b/nipype-auto-conv/specs/convert_warp_callables.py new file mode 100644 index 0000000..bb15f5b --- /dev/null +++ b/nipype-auto-conv/specs/convert_warp_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of ConvertWarp.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/convert_xfm.yaml b/nipype-auto-conv/specs/convert_xfm.yaml new file mode 100644 index 0000000..1348dc2 --- /dev/null +++ b/nipype-auto-conv/specs/convert_xfm.yaml @@ -0,0 +1,155 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.ConvertXFM' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use the FSL utility convert_xfm to modify FLIRT transformation matrices. +# +# Examples +# -------- +# +# >>> import nipype.interfaces.fsl as fsl +# >>> invt = fsl.ConvertXFM() +# >>> invt.inputs.in_file = "flirt.mat" +# >>> invt.inputs.invert_xfm = True +# >>> invt.inputs.out_file = 'flirt_inv.mat' +# >>> invt.cmdline +# 'convert_xfm -omat flirt_inv.mat -inverse flirt.mat' +# +# +# +task_name: ConvertXFM +nipype_name: ConvertXFM +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: datascience/text-matrix + # type=file|default=: input transformation matrix + in_file2: generic/file + # type=file|default=: second input matrix (for use with fix_scale_skew or concat_xfm) + out_file: Path + # type=file: output transformation matrix + # type=file|default=: final transformation matrix + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: datascience/text-matrix + # type=file: output transformation matrix + # type=file|default=: final transformation matrix + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: '"flirt_inv.mat"' + # type=file: output transformation matrix + # type=file|default=: final transformation matrix + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input transformation matrix + in_file2: + # type=file|default=: second input matrix (for use with fix_scale_skew or concat_xfm) + invert_xfm: + # type=bool|default=False: invert input transformation + concat_xfm: + # type=bool|default=False: write joint transformation of two input matrices + fix_scale_skew: + # type=bool|default=False: use secondary matrix to fix scale and skew + out_file: + # type=file: output transformation matrix + # type=file|default=: final transformation matrix + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input transformation matrix + invert_xfm: 'True' + # type=bool|default=False: invert input transformation + out_file: '"flirt_inv.mat"' + # type=file: output transformation matrix + # type=file|default=: final transformation matrix + imports: &id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + - module: nipype.interfaces.fsl as fsl + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: convert_xfm -omat flirt_inv.mat -inverse flirt.mat + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"flirt.mat"' + # type=file|default=: input transformation matrix + invert_xfm: 'True' + # type=bool|default=False: invert input transformation + out_file: '"flirt_inv.mat"' + # type=file: output transformation matrix + # type=file|default=: final transformation matrix + imports: *id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/convert_xfm_callables.py b/nipype-auto-conv/specs/convert_xfm_callables.py new file mode 100644 index 0000000..374e76f --- /dev/null +++ b/nipype-auto-conv/specs/convert_xfm_callables.py @@ -0,0 +1,147 @@ +"""Module to put any functions that are referred to in the "callables" section of ConvertXFM.yaml""" + +import attrs +import os +import os.path as op +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +# Original source at L1592 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L1567 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outfile = inputs.out_file + if outfile is attrs.NOTHING: + _, infile1, _ = split_filename(inputs.in_file) + if inputs.invert_xfm: + outfile = fname_presuffix( + infile1, suffix="_inv.mat", newpath=output_dir, use_ext=False + ) + else: + if inputs.concat_xfm: + _, infile2, _ = split_filename(inputs.in_file2) + outfile = fname_presuffix( + "%s_%s" % (infile1, infile2), + suffix=".mat", + newpath=output_dir, + use_ext=False, + ) + else: + outfile = fname_presuffix( + infile1, suffix="_fix.mat", newpath=output_dir, use_ext=False + ) + outputs["out_file"] = os.path.abspath(outfile) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext diff --git a/nipype-auto-conv/specs/copy_geom.yaml b/nipype-auto-conv/specs/copy_geom.yaml new file mode 100644 index 0000000..296945d --- /dev/null +++ b/nipype-auto-conv/specs/copy_geom.yaml @@ -0,0 +1,90 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.CopyGeom' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslcpgeom to copy the header geometry information to another image. +# Copy certain parts of the header information (image dimensions, voxel +# dimensions, voxel dimensions units string, image orientation/origin or +# qform/sform info) from one image to another. Note that only copies from +# Analyze to Analyze or Nifti to Nifti will work properly. Copying from +# different files will result in loss of information or potentially incorrect +# settings. +# +task_name: CopyGeom +nipype_name: CopyGeom +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + dest_file: generic/file + # type=file|default=: destination image + in_file: generic/file + # type=file|default=: source image + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image with new geometry header + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: source image + dest_file: + # type=file|default=: destination image + ignore_dims: + # type=bool|default=False: Do not copy image dimensions + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/copy_geom_callables.py b/nipype-auto-conv/specs/copy_geom_callables.py new file mode 100644 index 0000000..f1ae1c9 --- /dev/null +++ b/nipype-auto-conv/specs/copy_geom_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of CopyGeom.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/dilate_image.yaml b/nipype-auto-conv/specs/dilate_image.yaml new file mode 100644 index 0000000..e4b6cc6 --- /dev/null +++ b/nipype-auto-conv/specs/dilate_image.yaml @@ -0,0 +1,103 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.DilateImage' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to perform a spatial dilation of an image. +task_name: DilateImage +nipype_name: DilateImage +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + kernel_file: generic/file + # type=file|default=: use external file for kernel + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + operation: + # type=enum|default='mean'|allowed['max','mean','modal']: filtering operation to perform in dilation + kernel_shape: + # type=enum|default='3D'|allowed['2D','3D','box','boxv','file','gauss','sphere']: kernel shape to use + kernel_size: + # type=float|default=0.0: kernel size - voxels for box/boxv, mm for sphere, mm sigma for gauss + kernel_file: + # type=file|default=: use external file for kernel + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/dilate_image_callables.py b/nipype-auto-conv/specs/dilate_image_callables.py new file mode 100644 index 0000000..db0f502 --- /dev/null +++ b/nipype-auto-conv/specs/dilate_image_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of DilateImage.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/distance_map.yaml b/nipype-auto-conv/specs/distance_map.yaml new file mode 100644 index 0000000..872a507 --- /dev/null +++ b/nipype-auto-conv/specs/distance_map.yaml @@ -0,0 +1,110 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.DistanceMap' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL's distancemap to generate a map of the distance to the nearest +# nonzero voxel. +# +# Example +# ------- +# +# >>> import nipype.interfaces.fsl as fsl +# >>> mapper = fsl.DistanceMap() +# >>> mapper.inputs.in_file = "skeleton_mask.nii.gz" +# >>> mapper.run() # doctest: +SKIP +# +# +task_name: DistanceMap +nipype_name: DistanceMap +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + distance_map: Path + # type=file: value is distance to nearest nonzero voxels + # type=file|default=: distance map to write + in_file: generic/file + # type=file|default=: image to calculate distance values for + mask_file: generic/file + # type=file|default=: binary mask to constrain calculations + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + distance_map: generic/file + # type=file: value is distance to nearest nonzero voxels + # type=file|default=: distance map to write + local_max_file: generic/file + # type=file: image of local maxima + # type=traitcompound|default=None: write an image of the local maxima + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + distance_map: distance_map + # type=file: value is distance to nearest nonzero voxels + # type=file|default=: distance map to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: image to calculate distance values for + mask_file: + # type=file|default=: binary mask to constrain calculations + invert_input: + # type=bool|default=False: invert input image + local_max_file: + # type=file: image of local maxima + # type=traitcompound|default=None: write an image of the local maxima + distance_map: + # type=file: value is distance to nearest nonzero voxels + # type=file|default=: distance map to write + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/distance_map_callables.py b/nipype-auto-conv/specs/distance_map_callables.py new file mode 100644 index 0000000..f12fbb6 --- /dev/null +++ b/nipype-auto-conv/specs/distance_map_callables.py @@ -0,0 +1,147 @@ +"""Module to put any functions that are referred to in the "callables" section of DistanceMap.yaml""" + +import attrs +import os +import os.path as op +from pathlib import Path + + +def distance_map_default(inputs): + return _gen_filename("distance_map", inputs=inputs) + + +def distance_map_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["distance_map"] + + +def local_max_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["local_max_file"] + + +# Original source at L1537 of /interfaces/fsl/dti.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "distance_map": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["distance_map"] + return None + + +# Original source at L1519 of /interfaces/fsl/dti.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + _si = inputs + outputs["distance_map"] = _si.distance_map + if _si.distance_map is attrs.NOTHING: + outputs["distance_map"] = fname_presuffix( + _si.in_file, suffix="_dstmap", use_ext=True, newpath=output_dir + ) + outputs["distance_map"] = os.path.abspath(outputs["distance_map"]) + if _si.local_max_file is not attrs.NOTHING: + outputs["local_max_file"] = _si.local_max_file + if isinstance(_si.local_max_file, bool): + outputs["local_max_file"] = fname_presuffix( + _si.in_file, suffix="_lclmax", use_ext=True, newpath=output_dir + ) + outputs["local_max_file"] = os.path.abspath(outputs["local_max_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext diff --git a/nipype-auto-conv/specs/dti_fit.yaml b/nipype-auto-conv/specs/dti_fit.yaml new file mode 100644 index 0000000..6a42635 --- /dev/null +++ b/nipype-auto-conv/specs/dti_fit.yaml @@ -0,0 +1,206 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.DTIFit' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL dtifit command for fitting a diffusion tensor model at each +# voxel +# +# Example +# ------- +# +# >>> from nipype.interfaces import fsl +# >>> dti = fsl.DTIFit() +# >>> dti.inputs.dwi = 'diffusion.nii' +# >>> dti.inputs.bvecs = 'bvecs' +# >>> dti.inputs.bvals = 'bvals' +# >>> dti.inputs.base_name = 'TP' +# >>> dti.inputs.mask = 'mask.nii' +# >>> dti.cmdline +# 'dtifit -k diffusion.nii -o TP -m mask.nii -r bvecs -b bvals' +# +# +task_name: DTIFit +nipype_name: DTIFit +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + bvals: medimage/bval + # type=file|default=: b values file + bvecs: medimage/bvec + # type=file|default=: b vectors file + cni: generic/file + # type=file|default=: input counfound regressors + dwi: medimage/nifti1 + # type=file|default=: diffusion weighted image data file + gradnonlin: generic/file + # type=file|default=: gradient non linearities + mask: medimage/nifti1 + # type=file|default=: bet binary mask file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + FA: generic/file + # type=file: path/name of file with the fractional anisotropy + L1: generic/file + # type=file: path/name of file with the 1st eigenvalue + L2: generic/file + # type=file: path/name of file with the 2nd eigenvalue + L3: generic/file + # type=file: path/name of file with the 3rd eigenvalue + MD: generic/file + # type=file: path/name of file with the mean diffusivity + MO: generic/file + # type=file: path/name of file with the mode of anisotropy + S0: generic/file + # type=file: path/name of file with the raw T2 signal with no diffusion weighting + V1: generic/file + # type=file: path/name of file with the 1st eigenvector + V2: generic/file + # type=file: path/name of file with the 2nd eigenvector + V3: generic/file + # type=file: path/name of file with the 3rd eigenvector + sse: generic/file + # type=file: path/name of file with the summed squared error + # type=bool|default=False: output sum of squared errors + tensor: generic/file + # type=file: path/name of file with the 4D tensor volume + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dwi: + # type=file|default=: diffusion weighted image data file + base_name: + # type=str|default='dtifit_': base_name that all output files will start with + mask: + # type=file|default=: bet binary mask file + bvecs: + # type=file|default=: b vectors file + bvals: + # type=file|default=: b values file + min_z: + # type=int|default=0: min z + max_z: + # type=int|default=0: max z + min_y: + # type=int|default=0: min y + max_y: + # type=int|default=0: max y + min_x: + # type=int|default=0: min x + max_x: + # type=int|default=0: max x + save_tensor: + # type=bool|default=False: save the elements of the tensor + sse: + # type=file: path/name of file with the summed squared error + # type=bool|default=False: output sum of squared errors + cni: + # type=file|default=: input counfound regressors + little_bit: + # type=bool|default=False: only process small area of brain + gradnonlin: + # type=file|default=: gradient non linearities + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dwi: + # type=file|default=: diffusion weighted image data file + bvecs: + # type=file|default=: b vectors file + bvals: + # type=file|default=: b values file + base_name: '"TP"' + # type=str|default='dtifit_': base_name that all output files will start with + mask: + # type=file|default=: bet binary mask file + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: dtifit -k diffusion.nii -o TP -m mask.nii -r bvecs -b bvals + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + dwi: '"diffusion.nii"' + # type=file|default=: diffusion weighted image data file + bvecs: '"bvecs"' + # type=file|default=: b vectors file + bvals: '"bvals"' + # type=file|default=: b values file + base_name: '"TP"' + # type=str|default='dtifit_': base_name that all output files will start with + mask: '"mask.nii"' + # type=file|default=: bet binary mask file + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/dti_fit_callables.py b/nipype-auto-conv/specs/dti_fit_callables.py new file mode 100644 index 0000000..7037322 --- /dev/null +++ b/nipype-auto-conv/specs/dti_fit_callables.py @@ -0,0 +1,407 @@ +"""Module to put any functions that are referred to in the "callables" section of DTIFit.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def FA_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["FA"] + + +def L1_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["L1"] + + +def L2_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["L2"] + + +def L3_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["L3"] + + +def MD_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["MD"] + + +def MO_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["MO"] + + +def S0_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["S0"] + + +def V1_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["V1"] + + +def V2_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["V2"] + + +def V3_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["V3"] + + +def sse_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["sse"] + + +def tensor_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["tensor"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "dtifit" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L114 of /interfaces/fsl/dti.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + keys_to_ignore = {"outputtype", "environ", "args"} + # Optional output: Map output name to input flag + opt_output = {"tensor": inputs.save_tensor, "sse": inputs.sse} + # Ignore optional output, whose corresponding input-flag is not defined + # or set to False + for output, input_flag in opt_output.items(): + if (input_flag is not attrs.NOTHING) and input_flag: + # this is wanted output, do not ignore + continue + keys_to_ignore.add(output) + + outputs = {} + for k in set(outputs.keys()) - keys_to_ignore: + outputs[k] = _gen_fname( + inputs.base_name, + suffix="_" + k, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/dual_regression.yaml b/nipype-auto-conv/specs/dual_regression.yaml new file mode 100644 index 0000000..5d90159 --- /dev/null +++ b/nipype-auto-conv/specs/dual_regression.yaml @@ -0,0 +1,176 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.DualRegression' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Wrapper Script for Dual Regression Workflow +# +# Examples +# -------- +# +# >>> dual_regression = DualRegression() +# >>> dual_regression.inputs.in_files = ["functional.nii", "functional2.nii", "functional3.nii"] +# >>> dual_regression.inputs.group_IC_maps_4D = "allFA.nii" +# >>> dual_regression.inputs.des_norm = False +# >>> dual_regression.inputs.one_sample_group_mean = True +# >>> dual_regression.inputs.n_perm = 10 +# >>> dual_regression.inputs.out_dir = "my_output_directory" +# >>> dual_regression.cmdline +# 'dual_regression allFA.nii 0 -1 10 my_output_directory functional.nii functional2.nii functional3.nii' +# >>> dual_regression.run() # doctest: +SKIP +# +# +task_name: DualRegression +nipype_name: DualRegression +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + con_file: generic/file + # type=file|default=: Design contrasts for final cross-subject modelling with randomise + design_file: generic/file + # type=file|default=: Design matrix for final cross-subject modelling with randomise + group_IC_maps_4D: medimage/nifti1 + # type=file|default=: 4D image containing spatial IC maps (melodic_IC) from the whole-group ICA analysis + in_files: medimage/nifti1+list-of + # type=inputmultiobject|default=[]: List all subjects' preprocessed, standard-space 4D datasets + out_dir: Path + # type=directory: + # type=directory|default='output': This directory will be created to hold all output and logfiles + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_dir: generic/directory + # type=directory: + # type=directory|default='output': This directory will be created to hold all output and logfiles + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_dir: '"my_output_directory"' + # type=directory: + # type=directory|default='output': This directory will be created to hold all output and logfiles + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=inputmultiobject|default=[]: List all subjects' preprocessed, standard-space 4D datasets + group_IC_maps_4D: + # type=file|default=: 4D image containing spatial IC maps (melodic_IC) from the whole-group ICA analysis + des_norm: + # type=bool|default=True: Whether to variance-normalise the timecourses used as the stage-2 regressors; True is default and recommended + one_sample_group_mean: + # type=bool|default=False: perform 1-sample group-mean test instead of generic permutation test + design_file: + # type=file|default=: Design matrix for final cross-subject modelling with randomise + con_file: + # type=file|default=: Design contrasts for final cross-subject modelling with randomise + n_perm: + # type=int|default=0: Number of permutations for randomise; set to 1 for just raw tstat output, set to 0 to not run randomise at all. + out_dir: + # type=directory: + # type=directory|default='output': This directory will be created to hold all output and logfiles + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=inputmultiobject|default=[]: List all subjects' preprocessed, standard-space 4D datasets + group_IC_maps_4D: + # type=file|default=: 4D image containing spatial IC maps (melodic_IC) from the whole-group ICA analysis + des_norm: 'False' + # type=bool|default=True: Whether to variance-normalise the timecourses used as the stage-2 regressors; True is default and recommended + one_sample_group_mean: 'True' + # type=bool|default=False: perform 1-sample group-mean test instead of generic permutation test + n_perm: '10' + # type=int|default=0: Number of permutations for randomise; set to 1 for just raw tstat output, set to 0 to not run randomise at all. + out_dir: '"my_output_directory"' + # type=directory: + # type=directory|default='output': This directory will be created to hold all output and logfiles + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: dual_regression allFA.nii 0 -1 10 my_output_directory functional.nii functional2.nii functional3.nii + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_files: '["functional.nii", "functional2.nii", "functional3.nii"]' + # type=inputmultiobject|default=[]: List all subjects' preprocessed, standard-space 4D datasets + group_IC_maps_4D: '"allFA.nii"' + # type=file|default=: 4D image containing spatial IC maps (melodic_IC) from the whole-group ICA analysis + des_norm: 'False' + # type=bool|default=True: Whether to variance-normalise the timecourses used as the stage-2 regressors; True is default and recommended + one_sample_group_mean: 'True' + # type=bool|default=False: perform 1-sample group-mean test instead of generic permutation test + n_perm: '10' + # type=int|default=0: Number of permutations for randomise; set to 1 for just raw tstat output, set to 0 to not run randomise at all. + out_dir: '"my_output_directory"' + # type=directory: + # type=directory|default='output': This directory will be created to hold all output and logfiles + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/dual_regression_callables.py b/nipype-auto-conv/specs/dual_regression_callables.py new file mode 100644 index 0000000..55ed558 --- /dev/null +++ b/nipype-auto-conv/specs/dual_regression_callables.py @@ -0,0 +1,37 @@ +"""Module to put any functions that are referred to in the "callables" section of DualRegression.yaml""" + +import attrs +import os + + +def out_dir_default(inputs): + return _gen_filename("out_dir", inputs=inputs) + + +def out_dir_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_dir"] + + +# Original source at L2198 of /interfaces/fsl/model.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_dir": + return output_dir + + +# Original source at L2190 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + if inputs.out_dir is not attrs.NOTHING: + outputs["out_dir"] = os.path.abspath(inputs.out_dir) + else: + outputs["out_dir"] = _gen_filename( + "out_dir", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return outputs diff --git a/nipype-auto-conv/specs/eddy.yaml b/nipype-auto-conv/specs/eddy.yaml new file mode 100644 index 0000000..cf7bf91 --- /dev/null +++ b/nipype-auto-conv/specs/eddy.yaml @@ -0,0 +1,378 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.epi.Eddy' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Interface for FSL eddy, a tool for estimating and correcting eddy +# currents induced distortions. `User guide +# `__ and +# `more info regarding acqp file +# `_. +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import Eddy +# +# Running eddy on a CPU using OpenMP: +# >>> eddy = Eddy() +# >>> eddy.inputs.in_file = 'epi.nii' +# >>> eddy.inputs.in_mask = 'epi_mask.nii' +# >>> eddy.inputs.in_index = 'epi_index.txt' +# >>> eddy.inputs.in_acqp = 'epi_acqp.txt' +# >>> eddy.inputs.in_bvec = 'bvecs.scheme' +# >>> eddy.inputs.in_bval = 'bvals.scheme' +# >>> eddy.cmdline # doctest: +ELLIPSIS +# 'eddy_openmp --flm=quadratic --ff=10.0 --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 --out=.../eddy_corrected --slm=none' +# +# Running eddy on an Nvidia GPU using cuda: +# >>> eddy.inputs.use_cuda = True +# >>> eddy.cmdline # doctest: +ELLIPSIS +# 'eddy_cuda --flm=quadratic --ff=10.0 --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 --out=.../eddy_corrected --slm=none' +# +# Running eddy with slice-to-volume motion correction: +# >>> eddy.inputs.mporder = 6 +# >>> eddy.inputs.slice2vol_niter = 5 +# >>> eddy.inputs.slice2vol_lambda = 1 +# >>> eddy.inputs.slice2vol_interp = 'trilinear' +# >>> eddy.inputs.slice_order = 'epi_slspec.txt' +# >>> eddy.cmdline # doctest: +ELLIPSIS +# 'eddy_cuda --flm=quadratic --ff=10.0 --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii --interp=spline --resamp=jac --mporder=6 --niter=5 --nvoxhp=1000 --out=.../eddy_corrected --s2v_interp=trilinear --s2v_lambda=1 --s2v_niter=5 --slspec=epi_slspec.txt --slm=none' +# >>> res = eddy.run() # doctest: +SKIP +# +# +task_name: Eddy +nipype_name: Eddy +nipype_module: nipype.interfaces.fsl.epi +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: File containing all the images to estimate distortions for + in_mask: generic/file + # type=file|default=: Mask to indicate brain + in_index: text/text-file + # type=file|default=: File containing indices for all volumes in --imain into --acqp and --topup + in_acqp: generic/file + # type=file|default=: File containing acquisition parameters + in_bvec: medimage/bvec + # type=file|default=: File containing the b-vectors for all volumes in --imain + in_bval: medimage/bval + # type=file|default=: File containing the b-values for all volumes in --imain + session: generic/file + # type=file|default=: File containing session indices for all volumes in --imain + in_topup_fieldcoef: generic/file + # type=file|default=: Topup results file containing the field coefficients + in_topup_movpar: generic/file + # type=file|default=: Topup results file containing the movement parameters (movpar.txt) + field: generic/file + # type=file|default=: Non-topup derived fieldmap scaled in Hz + field_mat: generic/file + # type=file|default=: Matrix specifying the relative positions of the fieldmap, --field, and the first volume of the input file, --imain + json: generic/file + # type=file|default='': Name of .json text file with information about slice timing + slice_order: text/text-file + # type=file|default='': Name of text file completely specifying slice/group acquisition + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_cnr_maps: generic/file + # type=file: path/name of file with the cnr_maps + out_corrected: generic/file + # type=file: 4D image file containing all the corrected volumes + out_movement_over_time: generic/file + # type=file: Text file containing translations (mm) and rotations (radians) for each excitation + out_movement_rms: generic/file + # type=file: Summary of the 'total movement' in each volume + out_outlier_free: generic/file + # type=file: 4D image file not corrected for susceptibility or eddy-current distortions or subject movement but with outlier slices replaced + out_outlier_map: generic/file + # type=file: Matrix where rows represent volumes and columns represent slices. "0" indicates that scan-slice is not an outlier and "1" indicates that it is + out_outlier_n_sqr_stdev_map: generic/file + # type=file: Matrix where rows represent volumes and columns represent slices. Values indicate number of standard deivations off the square root of the mean squared difference between observation and prediction is + out_outlier_n_stdev_map: generic/file + # type=file: Matrix where rows represent volumes and columns represent slices. Values indicate number of standard deviations off the mean difference between observation and prediction is + out_outlier_report: generic/file + # type=file: Text file with a plain language report on what outlier slices eddy has found + out_parameter: generic/file + # type=file: Text file with parameters defining the field and movement for each scan + out_residuals: generic/file + # type=file: path/name of file with the residuals + out_restricted_movement_rms: generic/file + # type=file: Summary of the 'total movement' in each volume disregarding translation in the PE direction + out_rotated_bvecs: generic/file + # type=file: File containing rotated b-values for all volumes + out_shell_alignment_parameters: generic/file + # type=file: Text file containing rigid body movement parameters between the different shells as estimated by a post-hoc mutual information based registration + out_shell_pe_translation_parameters: generic/file + # type=file: Text file containing translation along the PE-direction between the different shells as estimated by a post-hoc mutual information based registration + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: File containing all the images to estimate distortions for + in_mask: + # type=file|default=: Mask to indicate brain + in_index: + # type=file|default=: File containing indices for all volumes in --imain into --acqp and --topup + in_acqp: + # type=file|default=: File containing acquisition parameters + in_bvec: + # type=file|default=: File containing the b-vectors for all volumes in --imain + in_bval: + # type=file|default=: File containing the b-values for all volumes in --imain + out_base: + # type=str|default='eddy_corrected': Basename for output image + session: + # type=file|default=: File containing session indices for all volumes in --imain + in_topup_fieldcoef: + # type=file|default=: Topup results file containing the field coefficients + in_topup_movpar: + # type=file|default=: Topup results file containing the movement parameters (movpar.txt) + field: + # type=file|default=: Non-topup derived fieldmap scaled in Hz + field_mat: + # type=file|default=: Matrix specifying the relative positions of the fieldmap, --field, and the first volume of the input file, --imain + flm: + # type=enum|default='quadratic'|allowed['cubic','linear','quadratic']: First level EC model + slm: + # type=enum|default='none'|allowed['linear','none','quadratic']: Second level EC model + fep: + # type=bool|default=False: Fill empty planes in x- or y-directions + initrand: + # type=bool|default=False: Resets rand for when selecting voxels + interp: + # type=enum|default='spline'|allowed['spline','trilinear']: Interpolation model for estimation step + nvoxhp: + # type=int|default=1000: # of voxels used to estimate the hyperparameters + fudge_factor: + # type=float|default=10.0: Fudge factor for hyperparameter error variance + dont_sep_offs_move: + # type=bool|default=False: Do NOT attempt to separate field offset from subject movement + dont_peas: + # type=bool|default=False: Do NOT perform a post-eddy alignment of shells + fwhm: + # type=float|default=0.0: FWHM for conditioning filter when estimating the parameters + niter: + # type=int|default=5: Number of iterations + method: + # type=enum|default='jac'|allowed['jac','lsr']: Final resampling method (jacobian/least squares) + repol: + # type=bool|default=False: Detect and replace outlier slices + outlier_nstd: + # type=int|default=0: Number of std off to qualify as outlier + outlier_nvox: + # type=int|default=0: Min # of voxels in a slice for inclusion in outlier detection + outlier_type: + # type=enum|default='sw'|allowed['both','gw','sw']: Type of outliers, slicewise (sw), groupwise (gw) or both (both) + outlier_pos: + # type=bool|default=False: Consider both positive and negative outliers if set + outlier_sqr: + # type=bool|default=False: Consider outliers among sums-of-squared differences if set + multiband_factor: + # type=int|default=0: Multi-band factor + multiband_offset: + # type=enum|default=0|allowed[-1,0,1]: Multi-band offset (-1 if bottom slice removed, 1 if top slice removed + mporder: + # type=int|default=0: Order of slice-to-vol movement model + slice2vol_niter: + # type=int|default=0: Number of iterations for slice-to-vol + slice2vol_lambda: + # type=int|default=0: Regularisation weight for slice-to-vol movement (reasonable range 1-10) + slice2vol_interp: + # type=enum|default='trilinear'|allowed['spline','trilinear']: Slice-to-vol interpolation model for estimation step + slice_order: + # type=file|default='': Name of text file completely specifying slice/group acquisition + json: + # type=file|default='': Name of .json text file with information about slice timing + estimate_move_by_susceptibility: + # type=bool|default=False: Estimate how susceptibility field changes with subject movement + mbs_niter: + # type=int|default=0: Number of iterations for MBS estimation + mbs_lambda: + # type=int|default=0: Weighting of regularisation for MBS estimation + mbs_ksp: + # type=int|default=0: Knot-spacing for MBS field estimation + num_threads: + # type=int|default=1: Number of openmp threads to use + is_shelled: + # type=bool|default=False: Override internal check to ensure that date are acquired on a set of b-value shells + use_cuda: + # type=bool|default=False: Run eddy using cuda gpu + cnr_maps: + # type=bool|default=False: Output CNR-Maps + residuals: + # type=bool|default=False: Output Residuals + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: File containing all the images to estimate distortions for + in_index: + # type=file|default=: File containing indices for all volumes in --imain into --acqp and --topup + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + use_cuda: "True" + # type=bool|default=False: Run eddy using cuda gpu + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + mporder: "6" + # type=int|default=0: Order of slice-to-vol movement model + slice2vol_niter: "5" + # type=int|default=0: Number of iterations for slice-to-vol + slice2vol_lambda: "1" + # type=int|default=0: Regularisation weight for slice-to-vol movement (reasonable range 1-10) + slice2vol_interp: '"trilinear"' + # type=enum|default='trilinear'|allowed['spline','trilinear']: Slice-to-vol interpolation model for estimation step + slice_order: + # type=file|default='': Name of text file completely specifying slice/group acquisition + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: + - cmdline: eddy_openmp --flm=quadratic --ff=10.0 --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 --out=.../eddy_corrected --slm=none + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"epi.nii"' + # type=file|default=: File containing all the images to estimate distortions for + in_index: '"epi_index.txt"' + # type=file|default=: File containing indices for all volumes in --imain into --acqp and --topup + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS + - cmdline: eddy_cuda --flm=quadratic --ff=10.0 --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 --out=.../eddy_corrected --slm=none + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + use_cuda: "True" + # type=bool|default=False: Run eddy using cuda gpu + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS + - cmdline: eddy_cuda --flm=quadratic --ff=10.0 --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii --interp=spline --resamp=jac --mporder=6 --niter=5 --nvoxhp=1000 --out=.../eddy_corrected --s2v_interp=trilinear --s2v_lambda=1 --s2v_niter=5 --slspec=epi_slspec.txt --slm=none + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + mporder: "6" + # type=int|default=0: Order of slice-to-vol movement model + slice2vol_niter: "5" + # type=int|default=0: Number of iterations for slice-to-vol + slice2vol_lambda: "1" + # type=int|default=0: Regularisation weight for slice-to-vol movement (reasonable range 1-10) + slice2vol_interp: '"trilinear"' + # type=enum|default='trilinear'|allowed['spline','trilinear']: Slice-to-vol interpolation model for estimation step + slice_order: '"epi_slspec.txt"' + # type=file|default='': Name of text file completely specifying slice/group acquisition + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/eddy_callables.py b/nipype-auto-conv/specs/eddy_callables.py new file mode 100644 index 0000000..f1e71ba --- /dev/null +++ b/nipype-auto-conv/specs/eddy_callables.py @@ -0,0 +1,185 @@ +"""Module to put any functions that are referred to in the "callables" section of Eddy.yaml""" + +import attrs +import os + + +def out_cnr_maps_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_cnr_maps"] + + +def out_corrected_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_corrected"] + + +def out_movement_over_time_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_movement_over_time"] + + +def out_movement_rms_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_movement_rms"] + + +def out_outlier_free_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_outlier_free"] + + +def out_outlier_map_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_outlier_map"] + + +def out_outlier_n_sqr_stdev_map_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_outlier_n_sqr_stdev_map"] + + +def out_outlier_n_stdev_map_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_outlier_n_stdev_map"] + + +def out_outlier_report_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_outlier_report"] + + +def out_parameter_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_parameter"] + + +def out_residuals_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_residuals"] + + +def out_restricted_movement_rms_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_restricted_movement_rms"] + + +def out_rotated_bvecs_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_rotated_bvecs"] + + +def out_shell_alignment_parameters_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_shell_alignment_parameters"] + + +def out_shell_pe_translation_parameters_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_shell_pe_translation_parameters"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L1008 of /interfaces/fsl/epi.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_corrected"] = os.path.abspath("%s.nii.gz" % inputs.out_base) + outputs["out_parameter"] = os.path.abspath("%s.eddy_parameters" % inputs.out_base) + + # File generation might depend on the version of EDDY + out_rotated_bvecs = os.path.abspath("%s.eddy_rotated_bvecs" % inputs.out_base) + out_movement_rms = os.path.abspath("%s.eddy_movement_rms" % inputs.out_base) + out_restricted_movement_rms = os.path.abspath( + "%s.eddy_restricted_movement_rms" % inputs.out_base + ) + out_shell_alignment_parameters = os.path.abspath( + "%s.eddy_post_eddy_shell_alignment_parameters" % inputs.out_base + ) + out_shell_pe_translation_parameters = os.path.abspath( + "%s.eddy_post_eddy_shell_PE_translation_parameters" % inputs.out_base + ) + out_outlier_map = os.path.abspath("%s.eddy_outlier_map" % inputs.out_base) + out_outlier_n_stdev_map = os.path.abspath( + "%s.eddy_outlier_n_stdev_map" % inputs.out_base + ) + out_outlier_n_sqr_stdev_map = os.path.abspath( + "%s.eddy_outlier_n_sqr_stdev_map" % inputs.out_base + ) + out_outlier_report = os.path.abspath("%s.eddy_outlier_report" % inputs.out_base) + if (inputs.repol is not attrs.NOTHING) and inputs.repol: + out_outlier_free = os.path.abspath( + "%s.eddy_outlier_free_data" % inputs.out_base + ) + if os.path.exists(out_outlier_free): + outputs["out_outlier_free"] = out_outlier_free + if (inputs.mporder is not attrs.NOTHING) and inputs.mporder > 0: + out_movement_over_time = os.path.abspath( + "%s.eddy_movement_over_time" % inputs.out_base + ) + if os.path.exists(out_movement_over_time): + outputs["out_movement_over_time"] = out_movement_over_time + if (inputs.cnr_maps is not attrs.NOTHING) and inputs.cnr_maps: + out_cnr_maps = os.path.abspath("%s.eddy_cnr_maps.nii.gz" % inputs.out_base) + if os.path.exists(out_cnr_maps): + outputs["out_cnr_maps"] = out_cnr_maps + if (inputs.residuals is not attrs.NOTHING) and inputs.residuals: + out_residuals = os.path.abspath("%s.eddy_residuals.nii.gz" % inputs.out_base) + if os.path.exists(out_residuals): + outputs["out_residuals"] = out_residuals + + if os.path.exists(out_rotated_bvecs): + outputs["out_rotated_bvecs"] = out_rotated_bvecs + if os.path.exists(out_movement_rms): + outputs["out_movement_rms"] = out_movement_rms + if os.path.exists(out_restricted_movement_rms): + outputs["out_restricted_movement_rms"] = out_restricted_movement_rms + if os.path.exists(out_shell_alignment_parameters): + outputs["out_shell_alignment_parameters"] = out_shell_alignment_parameters + if os.path.exists(out_shell_pe_translation_parameters): + outputs[ + "out_shell_pe_translation_parameters" + ] = out_shell_pe_translation_parameters + if os.path.exists(out_outlier_map): + outputs["out_outlier_map"] = out_outlier_map + if os.path.exists(out_outlier_n_stdev_map): + outputs["out_outlier_n_stdev_map"] = out_outlier_n_stdev_map + if os.path.exists(out_outlier_n_sqr_stdev_map): + outputs["out_outlier_n_sqr_stdev_map"] = out_outlier_n_sqr_stdev_map + if os.path.exists(out_outlier_report): + outputs["out_outlier_report"] = out_outlier_report + + return outputs diff --git a/nipype-auto-conv/specs/eddy_correct.yaml b/nipype-auto-conv/specs/eddy_correct.yaml new file mode 100644 index 0000000..40b9f06 --- /dev/null +++ b/nipype-auto-conv/specs/eddy_correct.yaml @@ -0,0 +1,138 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.epi.EddyCorrect' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# +# .. warning:: Deprecated in FSL. Please use +# :class:`nipype.interfaces.fsl.epi.Eddy` instead +# +# Example +# ------- +# +# >>> from nipype.interfaces.fsl import EddyCorrect +# >>> eddyc = EddyCorrect(in_file='diffusion.nii', +# ... out_file="diffusion_edc.nii", ref_num=0) +# >>> eddyc.cmdline +# 'eddy_correct diffusion.nii diffusion_edc.nii 0' +# +# +task_name: EddyCorrect +nipype_name: EddyCorrect +nipype_module: nipype.interfaces.fsl.epi +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: 4D input file + out_file: Path + # type=file|default=: 4D output file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + eddy_corrected: generic/file + # type=file: path/name of 4D eddy corrected output file + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: 4D input file + out_file: + # type=file|default=: 4D output file + ref_num: + # type=int|default=0: reference number + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: 4D input file + out_file: '"diffusion_edc.nii"' + # type=file|default=: 4D output file + ref_num: '0' + # type=int|default=0: reference number + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: eddy_correct diffusion.nii diffusion_edc.nii 0 + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"diffusion.nii"' + # type=file|default=: 4D input file + out_file: '"diffusion_edc.nii"' + # type=file|default=: 4D output file + ref_num: '0' + # type=int|default=0: reference number + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/eddy_correct_callables.py b/nipype-auto-conv/specs/eddy_correct_callables.py new file mode 100644 index 0000000..209f413 --- /dev/null +++ b/nipype-auto-conv/specs/eddy_correct_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of EddyCorrect.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def eddy_corrected_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["eddy_corrected"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/eddy_quad.yaml b/nipype-auto-conv/specs/eddy_quad.yaml new file mode 100644 index 0000000..a90ca6e --- /dev/null +++ b/nipype-auto-conv/specs/eddy_quad.yaml @@ -0,0 +1,181 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.epi.EddyQuad' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Interface for FSL eddy_quad, a tool for generating single subject reports +# and storing the quality assessment indices for each subject. +# `User guide `__ +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import EddyQuad +# >>> quad = EddyQuad() +# >>> quad.inputs.base_name = 'eddy_corrected' +# >>> quad.inputs.idx_file = 'epi_index.txt' +# >>> quad.inputs.param_file = 'epi_acqp.txt' +# >>> quad.inputs.mask_file = 'epi_mask.nii' +# >>> quad.inputs.bval_file = 'bvals.scheme' +# >>> quad.inputs.bvec_file = 'bvecs.scheme' +# >>> quad.inputs.output_dir = 'eddy_corrected.qc' +# >>> quad.inputs.field = 'fieldmap_phase_fslprepared.nii' +# >>> quad.inputs.verbose = True +# >>> quad.cmdline +# 'eddy_quad eddy_corrected --bvals bvals.scheme --bvecs bvecs.scheme --field fieldmap_phase_fslprepared.nii --eddyIdx epi_index.txt --mask epi_mask.nii --output-dir eddy_corrected.qc --eddyParams epi_acqp.txt --verbose' +# >>> res = quad.run() # doctest: +SKIP +# +# +task_name: EddyQuad +nipype_name: EddyQuad +nipype_module: nipype.interfaces.fsl.epi +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + bval_file: medimage/bval + # type=file|default=: b-values file + bvec_file: medimage/bvec + # type=file|default=: b-vectors file - only used when .eddy_residuals file is present + field: generic/file + # type=file|default=: TOPUP estimated field (in Hz) + idx_file: generic/file + # type=file|default=: File containing indices for all volumes into acquisition parameters + mask_file: generic/file + # type=file|default=: Binary mask file + param_file: text/text-file + # type=file|default=: File containing acquisition parameters + slice_spec: generic/file + # type=file|default=: Text file specifying slice/group acquisition + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + avg_b0_pe_png: generic/file+list-of + # type=list: Image showing mid-sagittal, -coronal and -axial slices of each averaged pe-direction b0 volume. Generated when using the -f option. + avg_b_png: generic/file+list-of + # type=list: Image showing mid-sagittal, -coronal and -axial slices of each averaged b-shell volume. + clean_volumes: generic/file + # type=file: Text file containing a list of clean volumes, based on the eddy squared residuals. To generate a version of the pre-processed dataset without outlier volumes, use: `fslselectvols -i -o eddy_corrected_data_clean --vols=vols_no_outliers.txt` + cnr_png: generic/file+list-of + # type=list: Image showing mid-sagittal, -coronal and -axial slices of each b-shell CNR volume. Generated when CNR maps are available. + qc_json: generic/file + # type=file: Single subject database containing quality metrics and data info. + qc_pdf: generic/file + # type=file: Single subject QC report. + residuals: generic/file + # type=file: Text file containing the volume-wise mask-averaged squared residuals. Generated when residual maps are available. + vdm_png: generic/file + # type=file: Image showing mid-sagittal, -coronal and -axial slices of the voxel displacement map. Generated when using the -f option. + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + base_name: + # type=str|default='eddy_corrected': Basename (including path) for EDDY output files, i.e., corrected images and QC files + idx_file: + # type=file|default=: File containing indices for all volumes into acquisition parameters + param_file: + # type=file|default=: File containing acquisition parameters + mask_file: + # type=file|default=: Binary mask file + bval_file: + # type=file|default=: b-values file + bvec_file: + # type=file|default=: b-vectors file - only used when .eddy_residuals file is present + output_dir: + # type=str|default='': Output directory - default = '.qc' + field: + # type=file|default=: TOPUP estimated field (in Hz) + slice_spec: + # type=file|default=: Text file specifying slice/group acquisition + verbose: + # type=bool|default=False: Display debug messages + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + param_file: + # type=file|default=: File containing acquisition parameters + output_dir: '"eddy_corrected.qc"' + # type=str|default='': Output directory - default = '.qc' + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: + - cmdline: eddy_quad eddy_corrected --bvals bvals.scheme --bvecs bvecs.scheme --field fieldmap_phase_fslprepared.nii --eddyIdx epi_index.txt --mask epi_mask.nii --output-dir eddy_corrected.qc --eddyParams epi_acqp.txt --verbose + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + param_file: '"epi_acqp.txt"' + # type=file|default=: File containing acquisition parameters + output_dir: '"eddy_corrected.qc"' + # type=str|default='': Output directory - default = '.qc' + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/eddy_quad_callables.py b/nipype-auto-conv/specs/eddy_quad_callables.py new file mode 100644 index 0000000..daf563b --- /dev/null +++ b/nipype-auto-conv/specs/eddy_quad_callables.py @@ -0,0 +1,111 @@ +"""Module to put any functions that are referred to in the "callables" section of EddyQuad.yaml""" + +import attrs +import os +from glob import glob + + +def avg_b0_pe_png_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["avg_b0_pe_png"] + + +def avg_b_png_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["avg_b_png"] + + +def clean_volumes_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["clean_volumes"] + + +def cnr_png_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["cnr_png"] + + +def qc_json_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["qc_json"] + + +def qc_pdf_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["qc_pdf"] + + +def residuals_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["residuals"] + + +def vdm_png_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["vdm_png"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L1673 of /interfaces/fsl/epi.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + from glob import glob + + outputs = {} + + # If the output directory isn't defined, the interface seems to use + # the default but not set its value in `inputs.output_dir` + if inputs.output_dir is attrs.NOTHING: + out_dir = os.path.abspath(os.path.basename(inputs.base_name) + ".qc") + else: + out_dir = os.path.abspath(inputs.output_dir) + + outputs["qc_json"] = os.path.join(out_dir, "qc.json") + outputs["qc_pdf"] = os.path.join(out_dir, "qc.pdf") + + # Grab all b* files here. This will also grab the b0_pe* files + # as well, but only if the field input was provided. So we'll remove + # them later in the next conditional. + outputs["avg_b_png"] = sorted(glob(os.path.join(out_dir, "avg_b*.png"))) + + if inputs.field is not attrs.NOTHING: + outputs["avg_b0_pe_png"] = sorted(glob(os.path.join(out_dir, "avg_b0_pe*.png"))) + + # The previous glob for `avg_b_png` also grabbed the + # `avg_b0_pe_png` files so we have to remove them + # from `avg_b_png`. + for fname in outputs["avg_b0_pe_png"]: + outputs["avg_b_png"].remove(fname) + + outputs["vdm_png"] = os.path.join(out_dir, "vdm.png") + + outputs["cnr_png"] = sorted(glob(os.path.join(out_dir, "cnr*.png"))) + + residuals = os.path.join(out_dir, "eddy_msr.txt") + if os.path.isfile(residuals): + outputs["residuals"] = residuals + + clean_volumes = os.path.join(out_dir, "vols_no_outliers.txt") + if os.path.isfile(clean_volumes): + outputs["clean_volumes"] = clean_volumes + + return outputs diff --git a/nipype-auto-conv/specs/epi_de_warp.yaml b/nipype-auto-conv/specs/epi_de_warp.yaml new file mode 100644 index 0000000..55bee74 --- /dev/null +++ b/nipype-auto-conv/specs/epi_de_warp.yaml @@ -0,0 +1,188 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.epi.EPIDeWarp' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Wraps the unwarping script `epidewarp.fsl +# `_. +# +# .. warning:: deprecated in FSL, please use +# :func:`niflow.nipype1.workflows.dmri.preprocess.epi.sdc_fmb` instead. +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import EPIDeWarp +# >>> dewarp = EPIDeWarp() +# >>> dewarp.inputs.epi_file = "functional.nii" +# >>> dewarp.inputs.mag_file = "magnitude.nii" +# >>> dewarp.inputs.dph_file = "phase.nii" +# >>> dewarp.inputs.output_type = "NIFTI_GZ" +# >>> dewarp.cmdline # doctest: +ELLIPSIS +# 'epidewarp.fsl --mag magnitude.nii --dph phase.nii --epi functional.nii --esp 0.58 --exfdw .../exfdw.nii.gz --nocleanup --sigma 2 --tediff 2.46 --tmpdir .../temp --vsm .../vsm.nii.gz' +# >>> res = dewarp.run() # doctest: +SKIP +# +# +# +task_name: EPIDeWarp +nipype_name: EPIDeWarp +nipype_module: nipype.interfaces.fsl.epi +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + dph_file: medimage/nifti1 + # type=file|default=: Phase file assumed to be scaled from 0 to 4095 + epi_file: medimage/nifti1 + # type=file|default=: EPI volume to unwarp + exf_file: generic/file + # type=file|default=: example func volume (or use epi) + mag_file: medimage/nifti1 + # type=file|default=: Magnitude file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + tmpdir: tmpdir_default + # type=string|default='': tmpdir + vsm: vsm_default + # type=string|default='': voxel shift map + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + exf_mask: generic/file + # type=file: Mask from example functional volume + exfdw: generic/file + # type=file: dewarped functional volume example + # type=string|default='': dewarped example func volume + unwarped_file: generic/file + # type=file: unwarped epi file + vsm_file: generic/file + # type=file: voxel shift map + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + exfdw: exfdw + # type=file: dewarped functional volume example + # type=string|default='': dewarped example func volume + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + mag_file: + # type=file|default=: Magnitude file + dph_file: + # type=file|default=: Phase file assumed to be scaled from 0 to 4095 + exf_file: + # type=file|default=: example func volume (or use epi) + epi_file: + # type=file|default=: EPI volume to unwarp + tediff: + # type=float|default=2.46: difference in B0 field map TEs + esp: + # type=float|default=0.58: EPI echo spacing + sigma: + # type=int|default=2: 2D spatial gaussing smoothing stdev (default = 2mm) + vsm: + # type=string|default='': voxel shift map + exfdw: + # type=file: dewarped functional volume example + # type=string|default='': dewarped example func volume + epidw: + # type=string|default='': dewarped epi volume + tmpdir: + # type=string|default='': tmpdir + nocleanup: + # type=bool|default=True: no cleanup + cleanup: + # type=bool|default=False: cleanup + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + epi_file: + # type=file|default=: EPI volume to unwarp + mag_file: + # type=file|default=: Magnitude file + dph_file: + # type=file|default=: Phase file assumed to be scaled from 0 to 4095 + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: epidewarp.fsl --mag magnitude.nii --dph phase.nii --epi functional.nii --esp 0.58 --exfdw .../exfdw.nii.gz --nocleanup --sigma 2 --tediff 2.46 --tmpdir .../temp --vsm .../vsm.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + epi_file: '"functional.nii"' + # type=file|default=: EPI volume to unwarp + mag_file: '"magnitude.nii"' + # type=file|default=: Magnitude file + dph_file: '"phase.nii"' + # type=file|default=: Phase file assumed to be scaled from 0 to 4095 + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/epi_de_warp_callables.py b/nipype-auto-conv/specs/epi_de_warp_callables.py new file mode 100644 index 0000000..b121f9b --- /dev/null +++ b/nipype-auto-conv/specs/epi_de_warp_callables.py @@ -0,0 +1,424 @@ +"""Module to put any functions that are referred to in the "callables" section of EPIDeWarp.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def exfdw_default(inputs): + return _gen_filename("exfdw", inputs=inputs) + + +def tmpdir_default(inputs): + return _gen_filename("tmpdir", inputs=inputs) + + +def vsm_default(inputs): + return _gen_filename("vsm", inputs=inputs) + + +def exf_mask_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["exf_mask"] + + +def exfdw_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["exfdw"] + + +def unwarped_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["unwarped_file"] + + +def vsm_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["vsm_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1428 of /interfaces/fsl/epi.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "exfdw": + if inputs.exf_file is not attrs.NOTHING: + return _gen_fname( + inputs.exf_file, + suffix="_exfdw", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + else: + return _gen_fname( + "exfdw", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if name == "epidw": + if inputs.epi_file is not attrs.NOTHING: + return _gen_fname( + inputs.epi_file, + suffix="_epidw", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if name == "vsm": + return _gen_fname( + "vsm", inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if name == "tmpdir": + return os.path.join(output_dir, "temp") + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "epidewarp.fsl" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1443 of /interfaces/fsl/epi.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + if inputs.exfdw is attrs.NOTHING: + outputs["exfdw"] = _gen_filename( + "exfdw", inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + else: + outputs["exfdw"] = inputs.exfdw + if inputs.epi_file is not attrs.NOTHING: + if inputs.epidw is not attrs.NOTHING: + outputs["unwarped_file"] = inputs.epidw + else: + outputs["unwarped_file"] = _gen_filename( + "epidw", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if inputs.vsm is attrs.NOTHING: + outputs["vsm_file"] = _gen_filename( + "vsm", inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + else: + outputs["vsm_file"] = _gen_fname( + inputs.vsm, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if inputs.tmpdir is attrs.NOTHING: + outputs["exf_mask"] = _gen_fname( + cwd=_gen_filename("tmpdir"), + basename="maskexf", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + else: + outputs["exf_mask"] = _gen_fname( + cwd=inputs.tmpdir, + basename="maskexf", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/epi_reg.yaml b/nipype-auto-conv/specs/epi_reg.yaml new file mode 100644 index 0000000..d20b581 --- /dev/null +++ b/nipype-auto-conv/specs/epi_reg.yaml @@ -0,0 +1,232 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.epi.EpiReg' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# +# Runs FSL epi_reg script for simultaneous coregistration and fieldmap +# unwarping. +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import EpiReg +# >>> epireg = EpiReg() +# >>> epireg.inputs.epi='epi.nii' +# >>> epireg.inputs.t1_head='T1.nii' +# >>> epireg.inputs.t1_brain='T1_brain.nii' +# >>> epireg.inputs.out_base='epi2struct' +# >>> epireg.inputs.fmap='fieldmap_phase_fslprepared.nii' +# >>> epireg.inputs.fmapmag='fieldmap_mag.nii' +# >>> epireg.inputs.fmapmagbrain='fieldmap_mag_brain.nii' +# >>> epireg.inputs.echospacing=0.00067 +# >>> epireg.inputs.pedir='y' +# >>> epireg.cmdline # doctest: +ELLIPSIS +# 'epi_reg --echospacing=0.000670 --fmap=fieldmap_phase_fslprepared.nii --fmapmag=fieldmap_mag.nii --fmapmagbrain=fieldmap_mag_brain.nii --noclean --pedir=y --epi=epi.nii --t1=T1.nii --t1brain=T1_brain.nii --out=epi2struct' +# >>> epireg.run() # doctest: +SKIP +# +# +task_name: EpiReg +nipype_name: EpiReg +nipype_module: nipype.interfaces.fsl.epi +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + epi: medimage/nifti1 + # type=file|default=: EPI image + fmap: medimage/nifti1 + # type=file|default=: fieldmap image (in rad/s) + fmapmag: medimage/nifti1 + # type=file|default=: fieldmap magnitude image - wholehead + fmapmagbrain: medimage/nifti1 + # type=file|default=: fieldmap magnitude image - brain extracted + t1_brain: medimage/nifti1 + # type=file|default=: brain extracted T1 image + t1_head: medimage/nifti1 + # type=file|default=: wholehead T1 image + weight_image: generic/file + # type=file|default=: weighting image (in T1 space) + wmseg: Path + # type=file: white matter segmentation used in flirt bbr + # type=file|default=: white matter segmentation of T1 image, has to be named like the t1brain and end on _wmseg + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + epi2str_inv: generic/file + # type=file: rigid structural-to-epi transform + epi2str_mat: generic/file + # type=file: rigid epi-to-structural transform + fmap2epi_mat: generic/file + # type=file: rigid fieldmap-to-epi transform + fmap2str_mat: generic/file + # type=file: rigid fieldmap-to-structural transform + fmap_epi: generic/file + # type=file: fieldmap in epi space + fmap_str: generic/file + # type=file: fieldmap in structural space + fmapmag_str: generic/file + # type=file: fieldmap magnitude image in structural space + fullwarp: generic/file + # type=file: warpfield to unwarp epi and transform into structural space + out_1vol: generic/file + # type=file: unwarped and coregistered single volume + out_file: generic/file + # type=file: unwarped and coregistered epi input + seg: generic/file + # type=file: white matter, gray matter, csf segmentation + shiftmap: generic/file + # type=file: shiftmap in epi space + wmedge: generic/file + # type=file: white matter edges for visualization + wmseg: generic/file + # type=file: white matter segmentation used in flirt bbr + # type=file|default=: white matter segmentation of T1 image, has to be named like the t1brain and end on _wmseg + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + epi: + # type=file|default=: EPI image + t1_head: + # type=file|default=: wholehead T1 image + t1_brain: + # type=file|default=: brain extracted T1 image + out_base: + # type=string|default='epi2struct': output base name + fmap: + # type=file|default=: fieldmap image (in rad/s) + fmapmag: + # type=file|default=: fieldmap magnitude image - wholehead + fmapmagbrain: + # type=file|default=: fieldmap magnitude image - brain extracted + wmseg: + # type=file: white matter segmentation used in flirt bbr + # type=file|default=: white matter segmentation of T1 image, has to be named like the t1brain and end on _wmseg + echospacing: + # type=float|default=0.0: Effective EPI echo spacing (sometimes called dwell time) - in seconds + pedir: + # type=enum|default='x'|allowed['-x','-y','-z','x','y','z']: phase encoding direction, dir = x/y/z/-x/-y/-z + weight_image: + # type=file|default=: weighting image (in T1 space) + no_fmapreg: + # type=bool|default=False: do not perform registration of fmap to T1 (use if fmap already registered) + no_clean: + # type=bool|default=True: do not clean up intermediate files + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + epi: + # type=file|default=: EPI image + t1_head: + # type=file|default=: wholehead T1 image + t1_brain: + # type=file|default=: brain extracted T1 image + out_base: '"epi2struct"' + # type=string|default='epi2struct': output base name + fmap: + # type=file|default=: fieldmap image (in rad/s) + fmapmag: + # type=file|default=: fieldmap magnitude image - wholehead + fmapmagbrain: + # type=file|default=: fieldmap magnitude image - brain extracted + echospacing: '0.00067' + # type=float|default=0.0: Effective EPI echo spacing (sometimes called dwell time) - in seconds + pedir: '"y"' + # type=enum|default='x'|allowed['-x','-y','-z','x','y','z']: phase encoding direction, dir = x/y/z/-x/-y/-z + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: epi_reg --echospacing=0.000670 --fmap=fieldmap_phase_fslprepared.nii --fmapmag=fieldmap_mag.nii --fmapmagbrain=fieldmap_mag_brain.nii --noclean --pedir=y --epi=epi.nii --t1=T1.nii --t1brain=T1_brain.nii --out=epi2struct + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + epi: '"epi.nii"' + # type=file|default=: EPI image + t1_head: '"T1.nii"' + # type=file|default=: wholehead T1 image + t1_brain: '"T1_brain.nii"' + # type=file|default=: brain extracted T1 image + out_base: '"epi2struct"' + # type=string|default='epi2struct': output base name + fmap: '"fieldmap_phase_fslprepared.nii"' + # type=file|default=: fieldmap image (in rad/s) + fmapmag: '"fieldmap_mag.nii"' + # type=file|default=: fieldmap magnitude image - wholehead + fmapmagbrain: '"fieldmap_mag_brain.nii"' + # type=file|default=: fieldmap magnitude image - brain extracted + echospacing: '0.00067' + # type=float|default=0.0: Effective EPI echo spacing (sometimes called dwell time) - in seconds + pedir: '"y"' + # type=enum|default='x'|allowed['-x','-y','-z','x','y','z']: phase encoding direction, dir = x/y/z/-x/-y/-z + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/epi_reg_callables.py b/nipype-auto-conv/specs/epi_reg_callables.py new file mode 100644 index 0000000..9acf06e --- /dev/null +++ b/nipype-auto-conv/specs/epi_reg_callables.py @@ -0,0 +1,147 @@ +"""Module to put any functions that are referred to in the "callables" section of EpiReg.yaml""" + +import attrs +import os + + +def epi2str_inv_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["epi2str_inv"] + + +def epi2str_mat_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["epi2str_mat"] + + +def fmap2epi_mat_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fmap2epi_mat"] + + +def fmap2str_mat_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fmap2str_mat"] + + +def fmap_epi_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fmap_epi"] + + +def fmap_str_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fmap_str"] + + +def fmapmag_str_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fmapmag_str"] + + +def fullwarp_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fullwarp"] + + +def out_1vol_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_1vol"] + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +def seg_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["seg"] + + +def shiftmap_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["shiftmap"] + + +def wmedge_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["wmedge"] + + +def wmseg_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["wmseg"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L1271 of /interfaces/fsl/epi.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = os.path.join(output_dir, inputs.out_base + ".nii.gz") + if not ((inputs.no_fmapreg is not attrs.NOTHING) and inputs.no_fmapreg) and ( + inputs.fmap is not attrs.NOTHING + ): + outputs["out_1vol"] = os.path.join(output_dir, inputs.out_base + "_1vol.nii.gz") + outputs["fmap2str_mat"] = os.path.join( + output_dir, inputs.out_base + "_fieldmap2str.mat" + ) + outputs["fmap2epi_mat"] = os.path.join( + output_dir, inputs.out_base + "_fieldmaprads2epi.mat" + ) + outputs["fmap_epi"] = os.path.join( + output_dir, inputs.out_base + "_fieldmaprads2epi.nii.gz" + ) + outputs["fmap_str"] = os.path.join( + output_dir, inputs.out_base + "_fieldmaprads2str.nii.gz" + ) + outputs["fmapmag_str"] = os.path.join( + output_dir, inputs.out_base + "_fieldmap2str.nii.gz" + ) + outputs["shiftmap"] = os.path.join( + output_dir, inputs.out_base + "_fieldmaprads2epi_shift.nii.gz" + ) + outputs["fullwarp"] = os.path.join(output_dir, inputs.out_base + "_warp.nii.gz") + outputs["epi2str_inv"] = os.path.join(output_dir, inputs.out_base + "_inv.mat") + if inputs.wmseg is attrs.NOTHING: + outputs["wmedge"] = os.path.join( + output_dir, inputs.out_base + "_fast_wmedge.nii.gz" + ) + outputs["wmseg"] = os.path.join( + output_dir, inputs.out_base + "_fast_wmseg.nii.gz" + ) + outputs["seg"] = os.path.join(output_dir, inputs.out_base + "_fast_seg.nii.gz") + outputs["epi2str_mat"] = os.path.join(output_dir, inputs.out_base + ".mat") + return outputs diff --git a/nipype-auto-conv/specs/erode_image.yaml b/nipype-auto-conv/specs/erode_image.yaml new file mode 100644 index 0000000..5ae2aac --- /dev/null +++ b/nipype-auto-conv/specs/erode_image.yaml @@ -0,0 +1,103 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.ErodeImage' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to perform a spatial erosion of an image. +task_name: ErodeImage +nipype_name: ErodeImage +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + kernel_file: generic/file + # type=file|default=: use external file for kernel + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + minimum_filter: + # type=bool|default=False: if true, minimum filter rather than erosion by zeroing-out + kernel_shape: + # type=enum|default='3D'|allowed['2D','3D','box','boxv','file','gauss','sphere']: kernel shape to use + kernel_size: + # type=float|default=0.0: kernel size - voxels for box/boxv, mm for sphere, mm sigma for gauss + kernel_file: + # type=file|default=: use external file for kernel + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/erode_image_callables.py b/nipype-auto-conv/specs/erode_image_callables.py new file mode 100644 index 0000000..da319d0 --- /dev/null +++ b/nipype-auto-conv/specs/erode_image_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of ErodeImage.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/extract_roi.yaml b/nipype-auto-conv/specs/extract_roi.yaml new file mode 100644 index 0000000..ae4c2c2 --- /dev/null +++ b/nipype-auto-conv/specs/extract_roi.yaml @@ -0,0 +1,178 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.ExtractROI' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Uses FSL Fslroi command to extract region of interest (ROI) +# from an image. +# +# You can a) take a 3D ROI from a 3D data set (or if it is 4D, the +# same ROI is taken from each time point and a new 4D data set is +# created), b) extract just some time points from a 4D data set, or +# c) control time and space limits to the ROI. Note that the +# arguments are minimum index and size (not maximum index). So to +# extract voxels 10 to 12 inclusive you would specify 10 and 3 (not +# 10 and 12). +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import ExtractROI +# >>> from nipype.testing import anatfile +# >>> fslroi = ExtractROI(in_file=anatfile, roi_file='bar.nii', t_min=0, +# ... t_size=1) +# >>> fslroi.cmdline == 'fslroi %s bar.nii 0 1' % anatfile +# True +# +# +# +task_name: ExtractROI +nipype_name: ExtractROI +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: input file + roi_file: Path + # type=file: + # type=file|default=: output file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + roi_file: medimage/nifti1 + # type=file: + # type=file|default=: output file + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + roi_file: '"bar.nii"' + # type=file: + # type=file|default=: output file + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file + roi_file: + # type=file: + # type=file|default=: output file + x_min: + # type=int|default=0: + x_size: + # type=int|default=0: + y_min: + # type=int|default=0: + y_size: + # type=int|default=0: + z_min: + # type=int|default=0: + z_size: + # type=int|default=0: + t_min: + # type=int|default=0: + t_size: + # type=int|default=0: + crop_list: + # type=list|default=[]: list of two tuples specifying crop options + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file + roi_file: '"bar.nii"' + # type=file: + # type=file|default=: output file + t_min: '0' + # type=int|default=0: + t_size: '1' + # type=int|default=0: + imports: &id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + - module: nipype.testing + name: anatfile + alias: + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: anatfile + # type=file|default=: input file + roi_file: '"bar.nii"' + # type=file: + # type=file|default=: output file + t_min: '0' + # type=int|default=0: + t_size: '1' + # type=int|default=0: + imports: *id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/extract_roi_callables.py b/nipype-auto-conv/specs/extract_roi_callables.py new file mode 100644 index 0000000..7ca660e --- /dev/null +++ b/nipype-auto-conv/specs/extract_roi_callables.py @@ -0,0 +1,345 @@ +"""Module to put any functions that are referred to in the "callables" section of ExtractROI.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def roi_file_default(inputs): + return _gen_filename("roi_file", inputs=inputs) + + +def roi_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["roi_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L513 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "roi_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )[name] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslroi" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L489 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + """Create a Bunch which contains all possible files generated + by running the interface. Some files are always generated, others + depending on which ``inputs`` options are set. + + + Returns + ------- + + outputs : Bunch object + Bunch object containing all possible files generated by + interface object. + + If None, file was not generated + Else, contains path, filename of generated outputfile + + """ + outputs = {} + outputs["roi_file"] = inputs.roi_file + if outputs["roi_file"] is attrs.NOTHING: + outputs["roi_file"] = _gen_fname( + inputs.in_file, + suffix="_roi", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["roi_file"] = os.path.abspath(outputs["roi_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/fast.yaml b/nipype-auto-conv/specs/fast.yaml new file mode 100644 index 0000000..37d0d67 --- /dev/null +++ b/nipype-auto-conv/specs/fast.yaml @@ -0,0 +1,195 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.FAST' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL FAST wrapper for segmentation and bias correction +# +# For complete details, see the `FAST Documentation. +# `_ +# +# Examples +# -------- +# >>> from nipype.interfaces import fsl +# >>> fast = fsl.FAST() +# >>> fast.inputs.in_files = 'structural.nii' +# >>> fast.inputs.out_basename = 'fast_' +# >>> fast.cmdline +# 'fast -o fast_ -S 1 structural.nii' +# >>> out = fast.run() # doctest: +SKIP +# +# +task_name: FAST +nipype_name: FAST +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_files: medimage/nifti1+list-of + # type=inputmultiobject|default=[]: image, or multi-channel set of images, to be segmented + init_transform: generic/file + # type=file|default=: initialise using priors + manual_seg: generic/file + # type=file|default=: Filename containing intensities + other_priors: generic/file+list-of + # type=inputmultiobject|default=[]: alternative prior images + out_basename: Path + # type=file|default=: base name of output files + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + bias_field: generic/file+list-of + # type=outputmultiobject: + mixeltype: generic/file + # type=file: path/name of mixeltype volume file _mixeltype + partial_volume_files: generic/file+list-of + # type=outputmultiobject: + partial_volume_map: generic/file + # type=file: path/name of partial volume file _pveseg + probability_maps: generic/file+list-of + # type=outputmultiobject: + # type=bool|default=False: outputs individual probability maps + restored_image: generic/file+list-of + # type=outputmultiobject: + tissue_class_files: generic/file+list-of + # type=outputmultiobject: + tissue_class_map: generic/file + # type=file: path/name of binary segmented volume file one val for each class _seg + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=inputmultiobject|default=[]: image, or multi-channel set of images, to be segmented + out_basename: + # type=file|default=: base name of output files + number_classes: + # type=range|default=1: number of tissue-type classes + output_biasfield: + # type=bool|default=False: output estimated bias field + output_biascorrected: + # type=bool|default=False: output restored image (bias-corrected image) + img_type: + # type=enum|default=1|allowed[1,2,3]: int specifying type of image: (1 = T1, 2 = T2, 3 = PD) + bias_iters: + # type=range|default=1: number of main-loop iterations during bias-field removal + bias_lowpass: + # type=range|default=4: bias field smoothing extent (FWHM) in mm + init_seg_smooth: + # type=range|default=0.0001: initial segmentation spatial smoothness (during bias field estimation) + segments: + # type=bool|default=False: outputs a separate binary image for each tissue type + init_transform: + # type=file|default=: initialise using priors + other_priors: + # type=inputmultiobject|default=[]: alternative prior images + no_pve: + # type=bool|default=False: turn off PVE (partial volume estimation) + no_bias: + # type=bool|default=False: do not remove bias field + use_priors: + # type=bool|default=False: use priors throughout + segment_iters: + # type=range|default=1: number of segmentation-initialisation iterations + mixel_smooth: + # type=range|default=0.0: spatial smoothness for mixeltype + iters_afterbias: + # type=range|default=1: number of main-loop iterations after bias-field removal + hyper: + # type=range|default=0.0: segmentation spatial smoothness + verbose: + # type=bool|default=False: switch on diagnostic messages + manual_seg: + # type=file|default=: Filename containing intensities + probability_maps: + # type=outputmultiobject: + # type=bool|default=False: outputs individual probability maps + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=inputmultiobject|default=[]: image, or multi-channel set of images, to be segmented + out_basename: '"fast_"' + # type=file|default=: base name of output files + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fast -o fast_ -S 1 structural.nii + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_files: '"structural.nii"' + # type=inputmultiobject|default=[]: image, or multi-channel set of images, to be segmented + out_basename: '"fast_"' + # type=file|default=: base name of output files + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/fast_callables.py b/nipype-auto-conv/specs/fast_callables.py new file mode 100644 index 0000000..490163d --- /dev/null +++ b/nipype-auto-conv/specs/fast_callables.py @@ -0,0 +1,496 @@ +"""Module to put any functions that are referred to in the "callables" section of FAST.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def bias_field_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["bias_field"] + + +def mixeltype_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mixeltype"] + + +def partial_volume_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["partial_volume_files"] + + +def partial_volume_map_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["partial_volume_map"] + + +def probability_maps_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["probability_maps"] + + +def restored_image_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["restored_image"] + + +def tissue_class_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["tissue_class_files"] + + +def tissue_class_map_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["tissue_class_map"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fast" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L401 of /interfaces/fsl/preprocess.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + if inputs.number_classes is attrs.NOTHING: + nclasses = 3 + else: + nclasses = inputs.number_classes + # when using multichannel, results basename is based on last + # input filename + _gen_fname_opts = {} + if inputs.out_basename is not attrs.NOTHING: + _gen_fname_opts["basename"] = inputs.out_basename + _gen_fname_opts["cwd"] = output_dir + else: + _gen_fname_opts["basename"] = inputs.in_files[-1] + _gen_fname_opts["cwd"], _, _ = split_filename(_gen_fname_opts["basename"]) + + outputs["tissue_class_map"] = _gen_fname( + suffix="_seg", + **_gen_fname_opts, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if inputs.segments: + outputs["tissue_class_files"] = [] + for i in range(nclasses): + outputs["tissue_class_files"].append( + _gen_fname( + suffix="_seg_%d" % i, + **_gen_fname_opts, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + if inputs.output_biascorrected is not attrs.NOTHING: + outputs["restored_image"] = [] + if len(inputs.in_files) > 1: + # for multi-image segmentation there is one corrected image + # per input + for val, f in enumerate(inputs.in_files): + # image numbering is 1-based + outputs["restored_image"].append( + _gen_fname( + suffix="_restore_%d" % (val + 1), + **_gen_fname_opts, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + else: + # single image segmentation has unnumbered output image + outputs["restored_image"].append( + _gen_fname( + suffix="_restore", + **_gen_fname_opts, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + + outputs["mixeltype"] = _gen_fname( + suffix="_mixeltype", + **_gen_fname_opts, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if not inputs.no_pve: + outputs["partial_volume_map"] = _gen_fname( + suffix="_pveseg", + **_gen_fname_opts, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["partial_volume_files"] = [] + for i in range(nclasses): + outputs["partial_volume_files"].append( + _gen_fname( + suffix="_pve_%d" % i, + **_gen_fname_opts, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + if inputs.output_biasfield: + outputs["bias_field"] = [] + if len(inputs.in_files) > 1: + # for multi-image segmentation there is one bias field image + # per input + for val, f in enumerate(inputs.in_files): + # image numbering is 1-based + outputs["bias_field"].append( + _gen_fname( + suffix="_bias_%d" % (val + 1), + **_gen_fname_opts, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + else: + # single image segmentation has unnumbered output image + outputs["bias_field"].append( + _gen_fname( + suffix="_bias", + **_gen_fname_opts, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + + if inputs.probability_maps: + outputs["probability_maps"] = [] + for i in range(nclasses): + outputs["probability_maps"].append( + _gen_fname( + suffix="_prob_%d" % i, + **_gen_fname_opts, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/feat.yaml b/nipype-auto-conv/specs/feat.yaml new file mode 100644 index 0000000..042b1c0 --- /dev/null +++ b/nipype-auto-conv/specs/feat.yaml @@ -0,0 +1,77 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.FEAT' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Uses FSL feat to calculate first level stats +task_name: FEAT +nipype_name: FEAT +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + fsf_file: generic/file + # type=file|default=: File specifying the feat design spec file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + feat_dir: generic/directory + # type=directory: + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + fsf_file: + # type=file|default=: File specifying the feat design spec file + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/feat_callables.py b/nipype-auto-conv/specs/feat_callables.py new file mode 100644 index 0000000..a28955e --- /dev/null +++ b/nipype-auto-conv/specs/feat_callables.py @@ -0,0 +1,42 @@ +"""Module to put any functions that are referred to in the "callables" section of FEAT.yaml""" + +import os +from glob import glob + + +def feat_dir_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["feat_dir"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L465 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + is_ica = False + outputs["feat_dir"] = None + with open(inputs.fsf_file, "rt") as fp: + text = fp.read() + if "set fmri(inmelodic) 1" in text: + is_ica = True + for line in text.split("\n"): + if line.find("set fmri(outputdir)") > -1: + try: + outputdir_spec = line.split('"')[-2] + if os.path.exists(outputdir_spec): + outputs["feat_dir"] = outputdir_spec + + except: + pass + if not outputs["feat_dir"]: + if is_ica: + outputs["feat_dir"] = glob(os.path.join(output_dir, "*ica"))[0] + else: + outputs["feat_dir"] = glob(os.path.join(output_dir, "*feat"))[0] + return outputs diff --git a/nipype-auto-conv/specs/feat_model.yaml b/nipype-auto-conv/specs/feat_model.yaml new file mode 100644 index 0000000..bda2496 --- /dev/null +++ b/nipype-auto-conv/specs/feat_model.yaml @@ -0,0 +1,89 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.FEATModel' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Uses FSL feat_model to generate design.mat files +task_name: FEATModel +nipype_name: FEATModel +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + ev_files: generic/file+list-of + # type=list|default=[]: Event spec files generated by level1design + fsf_file: generic/file + # type=file|default=: File specifying the feat design spec file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + con_file: generic/file + # type=file: Contrast file containing contrast vectors + design_cov: generic/file + # type=file: Graphical representation of design covariance + design_file: generic/file + # type=file: Mat file containing ascii matrix for design + design_image: generic/file + # type=file: Graphical representation of design matrix + fcon_file: generic/file + # type=file: Contrast file containing contrast vectors + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + fsf_file: + # type=file|default=: File specifying the feat design spec file + ev_files: + # type=list|default=[]: Event spec files generated by level1design + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/feat_model_callables.py b/nipype-auto-conv/specs/feat_model_callables.py new file mode 100644 index 0000000..bb0a4aa --- /dev/null +++ b/nipype-auto-conv/specs/feat_model_callables.py @@ -0,0 +1,91 @@ +"""Module to put any functions that are referred to in the "callables" section of FEATModel.yaml""" + +import os +from glob import glob + + +def con_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["con_file"] + + +def design_cov_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["design_cov"] + + +def design_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["design_file"] + + +def design_image_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["design_image"] + + +def fcon_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fcon_file"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L534 of /interfaces/fsl/model.py +def _get_design_root(infile, inputs=None, stdout=None, stderr=None, output_dir=None): + _, fname = os.path.split(infile) + return fname.split(".")[0] + + +# Original source at L538 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + # TODO: figure out file names and get rid off the globs + outputs = {} + root = _get_design_root( + simplify_list(inputs.fsf_file), + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + design_file = glob(os.path.join(output_dir, "%s*.mat" % root)) + assert len(design_file) == 1, "No mat file generated by FEAT Model" + outputs["design_file"] = design_file[0] + design_image = glob(os.path.join(output_dir, "%s.png" % root)) + assert len(design_image) == 1, "No design image generated by FEAT Model" + outputs["design_image"] = design_image[0] + design_cov = glob(os.path.join(output_dir, "%s_cov.png" % root)) + assert len(design_cov) == 1, "No covariance image generated by FEAT Model" + outputs["design_cov"] = design_cov[0] + con_file = glob(os.path.join(output_dir, "%s*.con" % root)) + assert len(con_file) == 1, "No con file generated by FEAT Model" + outputs["con_file"] = con_file[0] + fcon_file = glob(os.path.join(output_dir, "%s*.fts" % root)) + if fcon_file: + assert len(fcon_file) == 1, "No fts file generated by FEAT Model" + outputs["fcon_file"] = fcon_file[0] + return outputs + + +# Original source at L530 of /utils/filemanip.py +def simplify_list(filelist): + """Returns a list if filelist is a list of length greater than 1, + otherwise returns the first element + """ + if len(filelist) > 1: + return filelist + else: + return filelist[0] diff --git a/nipype-auto-conv/specs/feature_extractor.yaml b/nipype-auto-conv/specs/feature_extractor.yaml new file mode 100644 index 0000000..d994561 --- /dev/null +++ b/nipype-auto-conv/specs/feature_extractor.yaml @@ -0,0 +1,80 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.fix.FeatureExtractor' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Extract features (for later training and/or classifying) +# +task_name: FeatureExtractor +nipype_name: FeatureExtractor +nipype_module: nipype.interfaces.fsl.fix +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mel_ica: Path + # type=directory: Melodic output directory or directories + # type=directory|default=: Melodic output directory or directories + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mel_ica: generic/directory + # type=directory: Melodic output directory or directories + # type=directory|default=: Melodic output directory or directories + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + mel_ica: + # type=directory: Melodic output directory or directories + # type=directory|default=: Melodic output directory or directories + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/feature_extractor_callables.py b/nipype-auto-conv/specs/feature_extractor_callables.py new file mode 100644 index 0000000..9a93d53 --- /dev/null +++ b/nipype-auto-conv/specs/feature_extractor_callables.py @@ -0,0 +1,20 @@ +"""Module to put any functions that are referred to in the "callables" section of FeatureExtractor.yaml""" + + +def mel_ica_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mel_ica"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L161 of /interfaces/fsl/fix.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["mel_ica"] = inputs.mel_ica + return outputs diff --git a/nipype-auto-conv/specs/filmgls.yaml b/nipype-auto-conv/specs/filmgls.yaml new file mode 100644 index 0000000..74615c3 --- /dev/null +++ b/nipype-auto-conv/specs/filmgls.yaml @@ -0,0 +1,175 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.FILMGLS' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL film_gls command to fit a design matrix to voxel timeseries +# +# Examples +# -------- +# +# Initialize with no options, assigning them when calling run: +# +# >>> from nipype.interfaces import fsl +# >>> fgls = fsl.FILMGLS() +# >>> res = fgls.run('in_file', 'design_file', 'thresh', rn='stats') #doctest: +SKIP +# +# Assign options through the ``inputs`` attribute: +# +# >>> fgls = fsl.FILMGLS() +# >>> fgls.inputs.in_file = 'functional.nii' +# >>> fgls.inputs.design_file = 'design.mat' +# >>> fgls.inputs.threshold = 10 +# >>> fgls.inputs.results_dir = 'stats' +# >>> res = fgls.run() #doctest: +SKIP +# +# Specify options when creating an instance: +# +# >>> fgls = fsl.FILMGLS(in_file='functional.nii', design_file='design.mat', threshold=10, results_dir='stats') +# >>> res = fgls.run() #doctest: +SKIP +# +# +task_name: FILMGLS +nipype_name: FILMGLS +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + design_file: generic/file + # type=file|default=: design matrix file + fcon_file: generic/file + # type=file|default=: contrast file containing F-contrasts + in_file: generic/file + # type=file|default=: input data file + results_dir: Path + # type=directory: directory storing model estimation output + # type=directory|default='results': directory to store results in + surface: generic/file + # type=file|default=: input surface for autocorr smoothing in surface-based analyses + tcon_file: generic/file + # type=file|default=: contrast file containing T-contrasts + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + copes: generic/file+list-of + # type=outputmultiobject: Contrast estimates for each contrast + dof_file: generic/file + # type=file: degrees of freedom + fstats: generic/file+list-of + # type=outputmultiobject: f-stat file for each contrast + logfile: generic/file + # type=file: FILM run logfile + param_estimates: generic/file+list-of + # type=outputmultiobject: Parameter estimates for each column of the design matrix + residual4d: generic/file + # type=file: Model fit residual mean-squared error for each time point + results_dir: generic/directory + # type=directory: directory storing model estimation output + # type=directory|default='results': directory to store results in + sigmasquareds: generic/file + # type=file: summary of residuals, See Woolrich, et. al., 2001 + thresholdac: generic/file + # type=file: The FILM autocorrelation parameters + tstats: generic/file+list-of + # type=outputmultiobject: t-stat file for each contrast + varcopes: generic/file+list-of + # type=outputmultiobject: Variance estimates for each contrast + zfstats: generic/file+list-of + # type=outputmultiobject: z-stat file for each F contrast + zstats: generic/file+list-of + # type=outputmultiobject: z-stat file for each contrast + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + threshold: + # type=float|default=-1000.0: threshold + tcon_file: + # type=file|default=: contrast file containing T-contrasts + fcon_file: + # type=file|default=: contrast file containing F-contrasts + mode: + # type=enum|default='volumetric'|allowed['surface','volumetric']: Type of analysis to be done + surface: + # type=file|default=: input surface for autocorr smoothing in surface-based analyses + in_file: + # type=file|default=: input data file + design_file: + # type=file|default=: design matrix file + smooth_autocorr: + # type=bool|default=False: Smooth auto corr estimates + mask_size: + # type=int|default=0: susan mask size + brightness_threshold: + # type=range|default=0: susan brightness threshold, otherwise it is estimated + full_data: + # type=bool|default=False: output full data + autocorr_estimate_only: + # type=bool|default=False: perform autocorrelation estimation only + fit_armodel: + # type=bool|default=False: fits autoregressive model - default is to use tukey with M=sqrt(numvols) + tukey_window: + # type=int|default=0: tukey window size to estimate autocorr + multitaper_product: + # type=int|default=0: multitapering with slepian tapers and num is the time-bandwidth product + use_pava: + # type=bool|default=False: estimates autocorr using PAVA + autocorr_noestimate: + # type=bool|default=False: do not estimate autocorrs + output_pwdata: + # type=bool|default=False: output prewhitened data and average design matrix + results_dir: + # type=directory: directory storing model estimation output + # type=directory|default='results': directory to store results in + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/filmgls_callables.py b/nipype-auto-conv/specs/filmgls_callables.py new file mode 100644 index 0000000..7d41802 --- /dev/null +++ b/nipype-auto-conv/specs/filmgls_callables.py @@ -0,0 +1,575 @@ +"""Module to put any functions that are referred to in the "callables" section of FILMGLS.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from looseversion import LooseVersion +from pathlib import Path + + +def copes_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["copes"] + + +def dof_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["dof_file"] + + +def fstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fstats"] + + +def logfile_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["logfile"] + + +def param_estimates_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["param_estimates"] + + +def residual4d_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["residual4d"] + + +def results_dir_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["results_dir"] + + +def sigmasquareds_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["sigmasquareds"] + + +def thresholdac_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["thresholdac"] + + +def tstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["tstats"] + + +def varcopes_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["varcopes"] + + +def zfstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["zfstats"] + + +def zstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["zstats"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "film_gls" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L841 of /interfaces/fsl/model.py +def _get_numcons(inputs=None, stdout=None, stderr=None, output_dir=None): + numtcons = 0 + numfcons = 0 + if inputs.tcon_file is not attrs.NOTHING: + fp = open(inputs.tcon_file, "rt") + for line in fp.readlines(): + if line.startswith("/NumContrasts"): + numtcons = int(line.split()[-1]) + break + fp.close() + if inputs.fcon_file is not attrs.NOTHING: + fp = open(inputs.fcon_file, "rt") + for line in fp.readlines(): + if line.startswith("/NumContrasts"): + numfcons = int(line.split()[-1]) + break + fp.close() + return numtcons, numfcons + + +# Original source at L827 of /interfaces/fsl/model.py +def _get_pe_files(cwd, inputs=None, stdout=None, stderr=None, output_dir=None): + files = None + if inputs.design_file is not attrs.NOTHING: + fp = open(inputs.design_file, "rt") + for line in fp.readlines(): + if line.startswith("/NumWaves"): + numpes = int(line.split()[-1]) + files = [] + for i in range(numpes): + files.append( + _gen_fname( + "pe%d.nii" % (i + 1), + cwd=cwd, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + break + fp.close() + return files + + +# Original source at L860 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + cwd = output_dir + results_dir = os.path.join(cwd, inputs.results_dir) + outputs["results_dir"] = results_dir + pe_files = _get_pe_files( + results_dir, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if pe_files: + outputs["param_estimates"] = pe_files + outputs["residual4d"] = _gen_fname( + "res4d.nii", + cwd=results_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["dof_file"] = os.path.join(results_dir, "dof") + outputs["sigmasquareds"] = _gen_fname( + "sigmasquareds.nii", + cwd=results_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["thresholdac"] = _gen_fname( + "threshac1.nii", + cwd=results_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if Info.version() and LooseVersion(Info.version()) < LooseVersion("5.0.7"): + outputs["corrections"] = _gen_fname( + "corrections.nii", + cwd=results_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["logfile"] = _gen_fname( + "logfile", + change_ext=False, + cwd=results_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + + if Info.version() and LooseVersion(Info.version()) > LooseVersion("5.0.6"): + pth = results_dir + numtcons, numfcons = _get_numcons( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + base_contrast = 1 + copes = [] + varcopes = [] + zstats = [] + tstats = [] + for i in range(numtcons): + copes.append( + _gen_fname( + "cope%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + varcopes.append( + _gen_fname( + "varcope%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + zstats.append( + _gen_fname( + "zstat%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + tstats.append( + _gen_fname( + "tstat%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + if copes: + outputs["copes"] = copes + outputs["varcopes"] = varcopes + outputs["zstats"] = zstats + outputs["tstats"] = tstats + fstats = [] + zfstats = [] + for i in range(numfcons): + fstats.append( + _gen_fname( + "fstat%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + zfstats.append( + _gen_fname( + "zfstat%d.nii" % (base_contrast + i), + cwd=pth, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + if fstats: + outputs["fstats"] = fstats + outputs["zfstats"] = zfstats + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/filter_regressor.yaml b/nipype-auto-conv/specs/filter_regressor.yaml new file mode 100644 index 0000000..74a9915 --- /dev/null +++ b/nipype-auto-conv/specs/filter_regressor.yaml @@ -0,0 +1,106 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.FilterRegressor' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Data de-noising by regressing out part of a design matrix +# +# Uses simple OLS regression on 4D images +# +task_name: FilterRegressor +nipype_name: FilterRegressor +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + design_file: generic/file + # type=file|default=: name of the matrix with time courses (e.g. GLM design or MELODIC mixing matrix) + in_file: generic/file + # type=file|default=: input file name (4D image) + mask: generic/file + # type=file|default=: mask image file name + out_file: Path + # type=file: output file name for the filtered data + # type=file|default=: output file name for the filtered data + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: output file name for the filtered data + # type=file|default=: output file name for the filtered data + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: output file name for the filtered data + # type=file|default=: output file name for the filtered data + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file name (4D image) + out_file: + # type=file: output file name for the filtered data + # type=file|default=: output file name for the filtered data + design_file: + # type=file|default=: name of the matrix with time courses (e.g. GLM design or MELODIC mixing matrix) + filter_columns: + # type=list|default=[]: (1-based) column indices to filter out of the data + filter_all: + # type=bool|default=False: use all columns in the design file in denoising + mask: + # type=file|default=: mask image file name + var_norm: + # type=bool|default=False: perform variance-normalization on data + out_vnscales: + # type=bool|default=False: output scaling factors for variance normalization + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/filter_regressor_callables.py b/nipype-auto-conv/specs/filter_regressor_callables.py new file mode 100644 index 0000000..15ef6f2 --- /dev/null +++ b/nipype-auto-conv/specs/filter_regressor_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of FilterRegressor.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L731 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )[name] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fsl_regfilt" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L721 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if outputs["out_file"] is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix="_regfilt", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/find_the_biggest.yaml b/nipype-auto-conv/specs/find_the_biggest.yaml new file mode 100644 index 0000000..a2d7e9c --- /dev/null +++ b/nipype-auto-conv/specs/find_the_biggest.yaml @@ -0,0 +1,141 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.FindTheBiggest' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Use FSL find_the_biggest for performing hard segmentation on +# the outputs of connectivity-based thresholding in probtrack. +# For complete details, see the `FDT +# Documentation. `_ +# +# Example +# ------- +# +# >>> from nipype.interfaces import fsl +# >>> ldir = ['seeds_to_M1.nii', 'seeds_to_M2.nii'] +# >>> fBig = fsl.FindTheBiggest(in_files=ldir, out_file='biggestSegmentation') +# >>> fBig.cmdline +# 'find_the_biggest seeds_to_M1.nii seeds_to_M2.nii biggestSegmentation' +# +# +task_name: FindTheBiggest +nipype_name: FindTheBiggest +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_files: generic/file+list-of + # type=list|default=[]: a list of input volumes or a singleMatrixFile + out_file: Path + # type=file: output file indexed in order of input files + # type=file|default=: file with the resulting segmentation + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: output file indexed in order of input files + # type=file|default=: file with the resulting segmentation + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: '"biggestSegmentation"' + # type=file: output file indexed in order of input files + # type=file|default=: file with the resulting segmentation + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=list|default=[]: a list of input volumes or a singleMatrixFile + out_file: + # type=file: output file indexed in order of input files + # type=file|default=: file with the resulting segmentation + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=list|default=[]: a list of input volumes or a singleMatrixFile + out_file: '"biggestSegmentation"' + # type=file: output file indexed in order of input files + # type=file|default=: file with the resulting segmentation + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: find_the_biggest seeds_to_M1.nii seeds_to_M2.nii biggestSegmentation + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_files: ldir + # type=list|default=[]: a list of input volumes or a singleMatrixFile + out_file: '"biggestSegmentation"' + # type=file: output file indexed in order of input files + # type=file|default=: file with the resulting segmentation + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/find_the_biggest_callables.py b/nipype-auto-conv/specs/find_the_biggest_callables.py new file mode 100644 index 0000000..4bc9cf0 --- /dev/null +++ b/nipype-auto-conv/specs/find_the_biggest_callables.py @@ -0,0 +1,330 @@ +"""Module to put any functions that are referred to in the "callables" section of FindTheBiggest.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1341 of /interfaces/fsl/dti.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )[name] + else: + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "find_the_biggest" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1333 of /interfaces/fsl/dti.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if outputs["out_file"] is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + "biggestSegmentation", + suffix="", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/first.yaml b/nipype-auto-conv/specs/first.yaml new file mode 100644 index 0000000..057b131 --- /dev/null +++ b/nipype-auto-conv/specs/first.yaml @@ -0,0 +1,116 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.FIRST' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL run_first_all wrapper for segmentation of subcortical volumes +# +# http://www.fmrib.ox.ac.uk/fsl/first/index.html +# +# Examples +# -------- +# +# >>> from nipype.interfaces import fsl +# >>> first = fsl.FIRST() +# >>> first.inputs.in_file = 'structural.nii' +# >>> first.inputs.out_file = 'segmented.nii' +# >>> res = first.run() #doctest: +SKIP +# +# +task_name: FIRST +nipype_name: FIRST +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + affine_file: generic/file + # type=file|default=: Affine matrix to use (e.g. img2std.mat) (does not re-run registration) + in_file: generic/file + # type=file|default=: input data file + out_file: Path + # type=file|default='segmented': output data file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + bvars: generic/file+list-of + # type=outputmultiobject: bvars for each subcortical region + original_segmentations: generic/file + # type=file: 3D image file containing the segmented regions as integer values. Uses CMA labelling + segmentation_file: generic/file + # type=file: 4D image file containing a single volume per segmented region + vtk_surfaces: generic/file+list-of + # type=outputmultiobject: VTK format meshes for each subcortical region + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input data file + out_file: + # type=file|default='segmented': output data file + verbose: + # type=bool|default=False: Use verbose logging. + brain_extracted: + # type=bool|default=False: Input structural image is already brain-extracted + no_cleanup: + # type=bool|default=False: Input structural image is already brain-extracted + method: + # type=enum|default='auto'|allowed['auto','fast','none']: Method must be one of auto, fast, none, or it can be entered using the 'method_as_numerical_threshold' input + method_as_numerical_threshold: + # type=float|default=0.0: Specify a numerical threshold value or use the 'method' input to choose auto, fast, or none + list_of_specific_structures: + # type=list|default=[]: Runs only on the specified structures (e.g. L_Hipp, R_HippL_Accu, R_Accu, L_Amyg, R_AmygL_Caud, R_Caud, L_Pall, R_PallL_Puta, R_Puta, L_Thal, R_Thal, BrStem + affine_file: + # type=file|default=: Affine matrix to use (e.g. img2std.mat) (does not re-run registration) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/first_callables.py b/nipype-auto-conv/specs/first_callables.py new file mode 100644 index 0000000..9f168a3 --- /dev/null +++ b/nipype-auto-conv/specs/first_callables.py @@ -0,0 +1,187 @@ +"""Module to put any functions that are referred to in the "callables" section of FIRST.yaml""" + +import attrs +import os.path as op + + +def bvars_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["bvars"] + + +def original_segmentations_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["original_segmentations"] + + +def segmentation_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["segmentation_file"] + + +def vtk_surfaces_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["vtk_surfaces"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L2259 of /interfaces/fsl/preprocess.py +def _gen_fname(basename, inputs=None, stdout=None, stderr=None, output_dir=None): + path, outname, ext = split_filename(inputs.out_file) + + method = "none" + if (inputs.method is not attrs.NOTHING) and inputs.method != "none": + method = "fast" + if inputs.list_of_specific_structures and inputs.method == "auto": + method = "none" + + if inputs.method_as_numerical_threshold is not attrs.NOTHING: + thres = "%.4f" % inputs.method_as_numerical_threshold + method = thres.replace(".", "") + + if basename == "original_segmentations": + return op.abspath("%s_all_%s_origsegs.nii.gz" % (outname, method)) + if basename == "segmentation_file": + return op.abspath("%s_all_%s_firstseg.nii.gz" % (outname, method)) + + return None + + +# Original source at L2279 of /interfaces/fsl/preprocess.py +def _gen_mesh_names( + name, structures, inputs=None, stdout=None, stderr=None, output_dir=None +): + path, prefix, ext = split_filename(inputs.out_file) + if name == "vtk_surfaces": + vtks = list() + for struct in structures: + vtk = prefix + "-" + struct + "_first.vtk" + vtks.append(op.abspath(vtk)) + return vtks + if name == "bvars": + bvars = list() + for struct in structures: + bvar = prefix + "-" + struct + "_first.bvars" + bvars.append(op.abspath(bvar)) + return bvars + return None + + +# Original source at L2230 of /interfaces/fsl/preprocess.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + + if inputs.list_of_specific_structures is not attrs.NOTHING: + structures = inputs.list_of_specific_structures + else: + structures = [ + "L_Hipp", + "R_Hipp", + "L_Accu", + "R_Accu", + "L_Amyg", + "R_Amyg", + "L_Caud", + "R_Caud", + "L_Pall", + "R_Pall", + "L_Puta", + "R_Puta", + "L_Thal", + "R_Thal", + "BrStem", + ] + outputs["original_segmentations"] = _gen_fname( + "original_segmentations", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["segmentation_file"] = _gen_fname( + "segmentation_file", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["vtk_surfaces"] = _gen_mesh_names( + "vtk_surfaces", + structures, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["bvars"] = _gen_mesh_names( + "bvars", + structures, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return outputs + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext diff --git a/nipype-auto-conv/specs/flameo.yaml b/nipype-auto-conv/specs/flameo.yaml new file mode 100644 index 0000000..92e69a3 --- /dev/null +++ b/nipype-auto-conv/specs/flameo.yaml @@ -0,0 +1,225 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.FLAMEO' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL flameo command to perform higher level model fits +# +# Examples +# -------- +# +# Initialize FLAMEO with no options, assigning them when calling run: +# +# >>> from nipype.interfaces import fsl +# >>> flameo = fsl.FLAMEO() +# >>> flameo.inputs.cope_file = 'cope.nii.gz' +# >>> flameo.inputs.var_cope_file = 'varcope.nii.gz' +# >>> flameo.inputs.cov_split_file = 'cov_split.mat' +# >>> flameo.inputs.design_file = 'design.mat' +# >>> flameo.inputs.t_con_file = 'design.con' +# >>> flameo.inputs.mask_file = 'mask.nii' +# >>> flameo.inputs.run_mode = 'fe' +# >>> flameo.cmdline +# 'flameo --copefile=cope.nii.gz --covsplitfile=cov_split.mat --designfile=design.mat --ld=stats --maskfile=mask.nii --runmode=fe --tcontrastsfile=design.con --varcopefile=varcope.nii.gz' +# +# +task_name: FLAMEO +nipype_name: FLAMEO +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + cope_file: medimage/nifti-gz + # type=file|default=: cope regressor data file + cov_split_file: datascience/text-matrix + # type=file|default=: ascii matrix specifying the groups the covariance is split into + design_file: datascience/text-matrix + # type=file|default=: design matrix file + dof_var_cope_file: generic/file + # type=file|default=: dof data file for varcope data + f_con_file: generic/file + # type=file|default=: ascii matrix specifying f-contrasts + log_dir: generic/directory + # type=directory|default='stats': + mask_file: medimage/nifti1 + # type=file|default=: mask file + t_con_file: medimage-fsl/con + # type=file|default=: ascii matrix specifying t-contrasts + var_cope_file: medimage/nifti-gz + # type=file|default=: varcope weightings data file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + copes: generic/file+list-of + # type=outputmultiobject: Contrast estimates for each contrast + fstats: generic/file+list-of + # type=outputmultiobject: f-stat file for each contrast + mrefvars: generic/file+list-of + # type=outputmultiobject: mean random effect variances for each contrast + pes: generic/file+list-of + # type=outputmultiobject: Parameter estimates for each column of the design matrix for each voxel + res4d: generic/file+list-of + # type=outputmultiobject: Model fit residual mean-squared error for each time point + stats_dir: generic/directory + # type=directory: directory storing model estimation output + tdof: generic/file+list-of + # type=outputmultiobject: temporal dof file for each contrast + tstats: generic/file+list-of + # type=outputmultiobject: t-stat file for each contrast + var_copes: generic/file+list-of + # type=outputmultiobject: Variance estimates for each contrast + weights: generic/file+list-of + # type=outputmultiobject: weights file for each contrast + zfstats: generic/file+list-of + # type=outputmultiobject: z stat file for each f contrast + zstats: generic/file+list-of + # type=outputmultiobject: z-stat file for each contrast + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + cope_file: + # type=file|default=: cope regressor data file + var_cope_file: + # type=file|default=: varcope weightings data file + dof_var_cope_file: + # type=file|default=: dof data file for varcope data + mask_file: + # type=file|default=: mask file + design_file: + # type=file|default=: design matrix file + t_con_file: + # type=file|default=: ascii matrix specifying t-contrasts + f_con_file: + # type=file|default=: ascii matrix specifying f-contrasts + cov_split_file: + # type=file|default=: ascii matrix specifying the groups the covariance is split into + run_mode: + # type=enum|default='fe'|allowed['fe','flame1','flame12','ols']: inference to perform + n_jumps: + # type=int|default=0: number of jumps made by mcmc + burnin: + # type=int|default=0: number of jumps at start of mcmc to be discarded + sample_every: + # type=int|default=0: number of jumps for each sample + fix_mean: + # type=bool|default=False: fix mean for tfit + infer_outliers: + # type=bool|default=False: infer outliers - not for fe + no_pe_outputs: + # type=bool|default=False: do not output pe files + sigma_dofs: + # type=int|default=0: sigma (in mm) to use for Gaussian smoothing the DOFs in FLAME 2. Default is 1mm, -1 indicates no smoothing + outlier_iter: + # type=int|default=0: Number of max iterations to use when inferring outliers. Default is 12. + log_dir: + # type=directory|default='stats': + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + cope_file: + # type=file|default=: cope regressor data file + var_cope_file: + # type=file|default=: varcope weightings data file + cov_split_file: + # type=file|default=: ascii matrix specifying the groups the covariance is split into + design_file: + # type=file|default=: design matrix file + t_con_file: + # type=file|default=: ascii matrix specifying t-contrasts + mask_file: + # type=file|default=: mask file + run_mode: '"fe"' + # type=enum|default='fe'|allowed['fe','flame1','flame12','ols']: inference to perform + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: flameo --copefile=cope.nii.gz --covsplitfile=cov_split.mat --designfile=design.mat --ld=stats --maskfile=mask.nii --runmode=fe --tcontrastsfile=design.con --varcopefile=varcope.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + cope_file: '"cope.nii.gz"' + # type=file|default=: cope regressor data file + var_cope_file: '"varcope.nii.gz"' + # type=file|default=: varcope weightings data file + cov_split_file: '"cov_split.mat"' + # type=file|default=: ascii matrix specifying the groups the covariance is split into + design_file: '"design.mat"' + # type=file|default=: design matrix file + t_con_file: '"design.con"' + # type=file|default=: ascii matrix specifying t-contrasts + mask_file: '"mask.nii"' + # type=file|default=: mask file + run_mode: '"fe"' + # type=enum|default='fe'|allowed['fe','flame1','flame12','ols']: inference to perform + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/flameo_callables.py b/nipype-auto-conv/specs/flameo_callables.py new file mode 100644 index 0000000..734d1ea --- /dev/null +++ b/nipype-auto-conv/specs/flameo_callables.py @@ -0,0 +1,167 @@ +"""Module to put any functions that are referred to in the "callables" section of FLAMEO.yaml""" + +import attrs +import os +import re +from glob import glob + + +def copes_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["copes"] + + +def fstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fstats"] + + +def mrefvars_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mrefvars"] + + +def pes_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["pes"] + + +def res4d_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["res4d"] + + +def stats_dir_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["stats_dir"] + + +def tdof_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["tdof"] + + +def tstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["tstats"] + + +def var_copes_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["var_copes"] + + +def weights_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["weights"] + + +def zfstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["zfstats"] + + +def zstats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["zstats"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L1143 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + pth = os.path.join(output_dir, inputs.log_dir) + + pes = human_order_sorted(glob(os.path.join(pth, "pe[0-9]*.*"))) + assert len(pes) >= 1, "No pe volumes generated by FSL Estimate" + outputs["pes"] = pes + + res4d = human_order_sorted(glob(os.path.join(pth, "res4d.*"))) + assert len(res4d) == 1, "No residual volume generated by FSL Estimate" + outputs["res4d"] = res4d[0] + + copes = human_order_sorted(glob(os.path.join(pth, "cope[0-9]*.*"))) + assert len(copes) >= 1, "No cope volumes generated by FSL CEstimate" + outputs["copes"] = copes + + var_copes = human_order_sorted(glob(os.path.join(pth, "varcope[0-9]*.*"))) + assert len(var_copes) >= 1, "No varcope volumes generated by FSL CEstimate" + outputs["var_copes"] = var_copes + + zstats = human_order_sorted(glob(os.path.join(pth, "zstat[0-9]*.*"))) + assert len(zstats) >= 1, "No zstat volumes generated by FSL CEstimate" + outputs["zstats"] = zstats + + if inputs.f_con_file is not attrs.NOTHING: + zfstats = human_order_sorted(glob(os.path.join(pth, "zfstat[0-9]*.*"))) + assert len(zfstats) >= 1, "No zfstat volumes generated by FSL CEstimate" + outputs["zfstats"] = zfstats + + fstats = human_order_sorted(glob(os.path.join(pth, "fstat[0-9]*.*"))) + assert len(fstats) >= 1, "No fstat volumes generated by FSL CEstimate" + outputs["fstats"] = fstats + + tstats = human_order_sorted(glob(os.path.join(pth, "tstat[0-9]*.*"))) + assert len(tstats) >= 1, "No tstat volumes generated by FSL CEstimate" + outputs["tstats"] = tstats + + mrefs = human_order_sorted( + glob(os.path.join(pth, "mean_random_effects_var[0-9]*.*")) + ) + assert len(mrefs) >= 1, "No mean random effects volumes generated by FLAMEO" + outputs["mrefvars"] = mrefs + + tdof = human_order_sorted(glob(os.path.join(pth, "tdof_t[0-9]*.*"))) + assert len(tdof) >= 1, "No T dof volumes generated by FLAMEO" + outputs["tdof"] = tdof + + weights = human_order_sorted(glob(os.path.join(pth, "weights[0-9]*.*"))) + assert len(weights) >= 1, "No weight volumes generated by FLAMEO" + outputs["weights"] = weights + + outputs["stats_dir"] = pth + + return outputs + + +# Original source at L19 of /utils/misc.py +def human_order_sorted(l): + """Sorts string in human order (i.e. 'stat10' will go after 'stat2')""" + + def atoi(text): + return int(text) if text.isdigit() else text + + def natural_keys(text): + if isinstance(text, tuple): + text = text[0] + return [atoi(c) for c in re.split(r"(\d+)", text)] + + return sorted(l, key=natural_keys) diff --git a/nipype-auto-conv/specs/flirt.yaml b/nipype-auto-conv/specs/flirt.yaml new file mode 100644 index 0000000..f079021 --- /dev/null +++ b/nipype-auto-conv/specs/flirt.yaml @@ -0,0 +1,280 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.FLIRT' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL FLIRT wrapper for coregistration +# +# For complete details, see the `FLIRT Documentation. +# `_ +# +# To print out the command line help, use: +# fsl.FLIRT().inputs_help() +# +# Examples +# -------- +# >>> from nipype.interfaces import fsl +# >>> from nipype.testing import example_data +# >>> flt = fsl.FLIRT(bins=640, cost_func='mutualinfo') +# >>> flt.inputs.in_file = 'structural.nii' +# >>> flt.inputs.reference = 'mni.nii' +# >>> flt.inputs.output_type = "NIFTI_GZ" +# >>> flt.cmdline # doctest: +ELLIPSIS +# 'flirt -in structural.nii -ref mni.nii -out structural_flirt.nii.gz -omat structural_flirt.mat -bins 640 -searchcost mutualinfo' +# >>> res = flt.run() #doctest: +SKIP +# +# +task_name: FLIRT +nipype_name: FLIRT +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + fieldmap: generic/file + # type=file|default=: fieldmap image in rads/s - must be already registered to the reference image + fieldmapmask: generic/file + # type=file|default=: mask for fieldmap image + in_file: medimage/nifti1 + # type=file|default=: input file + in_matrix_file: generic/file + # type=file|default=: input 4x4 affine matrix + in_weight: generic/file + # type=file|default=: File for input weighting volume + out_file: Path + # type=file: path/name of registered file (if generated) + # type=file|default=: registered output file + out_log: Path + # type=file: path/name of output log (if generated) + # type=file|default=: output log + out_matrix_file: Path + # type=file: path/name of calculated affine transform (if generated) + # type=file|default=: output affine matrix in 4x4 asciii format + ref_weight: generic/file + # type=file|default=: File for reference weighting volume + reference: medimage/nifti1 + # type=file|default=: reference file + schedule: generic/file + # type=file|default=: replaces default schedule + wm_seg: generic/file + # type=file|default=: white matter segmentation volume needed by BBR cost function + wmcoords: generic/file + # type=file|default=: white matter boundary coordinates for BBR cost function + wmnorms: generic/file + # type=file|default=: white matter boundary normals for BBR cost function + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: path/name of registered file (if generated) + # type=file|default=: registered output file + out_log: generic/file + # type=file: path/name of output log (if generated) + # type=file|default=: output log + out_matrix_file: generic/file + # type=file: path/name of calculated affine transform (if generated) + # type=file|default=: output affine matrix in 4x4 asciii format + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file + reference: + # type=file|default=: reference file + out_file: + # type=file: path/name of registered file (if generated) + # type=file|default=: registered output file + out_matrix_file: + # type=file: path/name of calculated affine transform (if generated) + # type=file|default=: output affine matrix in 4x4 asciii format + out_log: + # type=file: path/name of output log (if generated) + # type=file|default=: output log + in_matrix_file: + # type=file|default=: input 4x4 affine matrix + apply_xfm: + # type=bool|default=False: apply transformation supplied by in_matrix_file or uses_qform to use the affine matrix stored in the reference header + apply_isoxfm: + # type=float|default=0.0: as applyxfm but forces isotropic resampling + datatype: + # type=enum|default='char'|allowed['char','double','float','int','short']: force output data type + cost: + # type=enum|default='mutualinfo'|allowed['bbr','corratio','labeldiff','leastsq','mutualinfo','normcorr','normmi']: cost function + cost_func: + # type=enum|default='mutualinfo'|allowed['bbr','corratio','labeldiff','leastsq','mutualinfo','normcorr','normmi']: cost function + uses_qform: + # type=bool|default=False: initialize using sform or qform + display_init: + # type=bool|default=False: display initial matrix + angle_rep: + # type=enum|default='quaternion'|allowed['euler','quaternion']: representation of rotation angles + interp: + # type=enum|default='trilinear'|allowed['nearestneighbour','sinc','spline','trilinear']: final interpolation method used in reslicing + sinc_width: + # type=int|default=0: full-width in voxels + sinc_window: + # type=enum|default='rectangular'|allowed['blackman','hanning','rectangular']: sinc window + bins: + # type=int|default=0: number of histogram bins + dof: + # type=int|default=0: number of transform degrees of freedom + no_resample: + # type=bool|default=False: do not change input sampling + force_scaling: + # type=bool|default=False: force rescaling even for low-res images + min_sampling: + # type=float|default=0.0: set minimum voxel dimension for sampling + padding_size: + # type=int|default=0: for applyxfm: interpolates outside image by size + searchr_x: + # type=list|default=[]: search angles along x-axis, in degrees + searchr_y: + # type=list|default=[]: search angles along y-axis, in degrees + searchr_z: + # type=list|default=[]: search angles along z-axis, in degrees + no_search: + # type=bool|default=False: set all angular searches to ranges 0 to 0 + coarse_search: + # type=int|default=0: coarse search delta angle + fine_search: + # type=int|default=0: fine search delta angle + schedule: + # type=file|default=: replaces default schedule + ref_weight: + # type=file|default=: File for reference weighting volume + in_weight: + # type=file|default=: File for input weighting volume + no_clamp: + # type=bool|default=False: do not use intensity clamping + no_resample_blur: + # type=bool|default=False: do not use blurring on downsampling + rigid2D: + # type=bool|default=False: use 2D rigid body mode - ignores dof + save_log: + # type=bool|default=False: save to log file + verbose: + # type=int|default=0: verbose mode, 0 is least + bgvalue: + # type=float|default=0: use specified background value for points outside FOV + wm_seg: + # type=file|default=: white matter segmentation volume needed by BBR cost function + wmcoords: + # type=file|default=: white matter boundary coordinates for BBR cost function + wmnorms: + # type=file|default=: white matter boundary normals for BBR cost function + fieldmap: + # type=file|default=: fieldmap image in rads/s - must be already registered to the reference image + fieldmapmask: + # type=file|default=: mask for fieldmap image + pedir: + # type=int|default=0: phase encode direction of EPI - 1/2/3=x/y/z & -1/-2/-3=-x/-y/-z + echospacing: + # type=float|default=0.0: value of EPI echo spacing - units of seconds + bbrtype: + # type=enum|default='signed'|allowed['global_abs','local_abs','signed']: type of bbr cost function: signed [default], global_abs, local_abs + bbrslope: + # type=float|default=0.0: value of bbr slope + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file + reference: + # type=file|default=: reference file + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + bins: '640' + # type=int|default=0: number of histogram bins + cost_func: '"mutualinfo"' + # type=enum|default='mutualinfo'|allowed['bbr','corratio','labeldiff','leastsq','mutualinfo','normcorr','normmi']: cost function + imports: &id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + - module: nipype.testing + name: example_data + alias: + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: flirt -in structural.nii -ref mni.nii -out structural_flirt.nii.gz -omat structural_flirt.mat -bins 640 -searchcost mutualinfo + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"structural.nii"' + # type=file|default=: input file + reference: '"mni.nii"' + # type=file|default=: reference file + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + bins: '640' + # type=int|default=0: number of histogram bins + cost_func: '"mutualinfo"' + # type=enum|default='mutualinfo'|allowed['bbr','corratio','labeldiff','leastsq','mutualinfo','normcorr','normmi']: cost function + imports: *id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/flirt_callables.py b/nipype-auto-conv/specs/flirt_callables.py new file mode 100644 index 0000000..cf6386c --- /dev/null +++ b/nipype-auto-conv/specs/flirt_callables.py @@ -0,0 +1,352 @@ +"""Module to put any functions that are referred to in the "callables" section of FLIRT.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +def out_log_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_log"] + + +def out_matrix_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_matrix_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/fnirt.yaml b/nipype-auto-conv/specs/fnirt.yaml new file mode 100644 index 0000000..d434bec --- /dev/null +++ b/nipype-auto-conv/specs/fnirt.yaml @@ -0,0 +1,278 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.FNIRT' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL FNIRT wrapper for non-linear registration +# +# For complete details, see the `FNIRT Documentation. +# `_ +# +# Examples +# -------- +# >>> from nipype.interfaces import fsl +# >>> from nipype.testing import example_data +# >>> fnt = fsl.FNIRT(affine_file=example_data('trans.mat')) +# >>> res = fnt.run(ref_file=example_data('mni.nii', in_file=example_data('structural.nii')) #doctest: +SKIP +# +# T1 -> Mni153 +# +# >>> from nipype.interfaces import fsl +# >>> fnirt_mprage = fsl.FNIRT() +# >>> fnirt_mprage.inputs.in_fwhm = [8, 4, 2, 2] +# >>> fnirt_mprage.inputs.subsampling_scheme = [4, 2, 1, 1] +# +# Specify the resolution of the warps +# +# >>> fnirt_mprage.inputs.warp_resolution = (6, 6, 6) +# >>> res = fnirt_mprage.run(in_file='structural.nii', ref_file='mni.nii', warped_file='warped.nii', fieldcoeff_file='fieldcoeff.nii')#doctest: +SKIP +# +# We can check the command line and confirm that it's what we expect. +# +# >>> fnirt_mprage.cmdline #doctest: +SKIP +# 'fnirt --cout=fieldcoeff.nii --in=structural.nii --infwhm=8,4,2,2 --ref=mni.nii --subsamp=4,2,1,1 --warpres=6,6,6 --iout=warped.nii' +# +# +task_name: FNIRT +nipype_name: FNIRT +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + affine_file: generic/file + # type=file|default=: name of file containing affine transform + in_file: generic/file + # type=file|default=: name of input image + in_intensitymap_file: generic/file+list-of + # type=list|default=[]: name of file/files containing initial intensity mapping usually generated by previous fnirt run + inmask_file: generic/file + # type=file|default=: name of file with mask in input image space + inwarp_file: generic/file + # type=file|default=: name of file containing initial non-linear warps + log_file: Path + # type=file: Name of log-file + # type=file|default=: Name of log-file + ref_file: generic/file + # type=file|default=: name of reference image + refmask_file: generic/file + # type=file|default=: name of file with mask in reference space + warped_file: Path + # type=file: warped image + # type=file|default=: name of output image + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + field_file: generic/file + # type=file: file with warp field + # type=traitcompound|default=None: name of output file with field or true + fieldcoeff_file: generic/file + # type=file: file with field coefficients + # type=traitcompound|default=None: name of output file with field coefficients or true + jacobian_file: generic/file + # type=file: file containing Jacobian of the field + # type=traitcompound|default=None: name of file for writing out the Jacobian of the field (for diagnostic or VBM purposes) + log_file: generic/file + # type=file: Name of log-file + # type=file|default=: Name of log-file + modulatedref_file: generic/file + # type=file: file containing intensity modulated --ref + # type=traitcompound|default=None: name of file for writing out intensity modulated --ref (for diagnostic purposes) + out_intensitymap_file: generic/file+list-of + # type=list: files containing info pertaining to intensity mapping + # type=traitcompound|default=None: name of files for writing information pertaining to intensity mapping + warped_file: generic/file + # type=file: warped image + # type=file|default=: name of output image + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + log_file: log_file + # type=file: Name of log-file + # type=file|default=: Name of log-file + warped_file: warped_file + # type=file: warped image + # type=file|default=: name of output image + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + ref_file: + # type=file|default=: name of reference image + in_file: + # type=file|default=: name of input image + affine_file: + # type=file|default=: name of file containing affine transform + inwarp_file: + # type=file|default=: name of file containing initial non-linear warps + in_intensitymap_file: + # type=list|default=[]: name of file/files containing initial intensity mapping usually generated by previous fnirt run + fieldcoeff_file: + # type=file: file with field coefficients + # type=traitcompound|default=None: name of output file with field coefficients or true + warped_file: + # type=file: warped image + # type=file|default=: name of output image + field_file: + # type=file: file with warp field + # type=traitcompound|default=None: name of output file with field or true + jacobian_file: + # type=file: file containing Jacobian of the field + # type=traitcompound|default=None: name of file for writing out the Jacobian of the field (for diagnostic or VBM purposes) + modulatedref_file: + # type=file: file containing intensity modulated --ref + # type=traitcompound|default=None: name of file for writing out intensity modulated --ref (for diagnostic purposes) + out_intensitymap_file: + # type=list: files containing info pertaining to intensity mapping + # type=traitcompound|default=None: name of files for writing information pertaining to intensity mapping + log_file: + # type=file: Name of log-file + # type=file|default=: Name of log-file + config_file: + # type=traitcompound|default=None: Name of config file specifying command line arguments + refmask_file: + # type=file|default=: name of file with mask in reference space + inmask_file: + # type=file|default=: name of file with mask in input image space + skip_refmask: + # type=bool|default=False: Skip specified refmask if set, default false + skip_inmask: + # type=bool|default=False: skip specified inmask if set, default false + apply_refmask: + # type=list|default=[]: list of iterations to use reference mask on (1 to use, 0 to skip) + apply_inmask: + # type=list|default=[]: list of iterations to use input mask on (1 to use, 0 to skip) + skip_implicit_ref_masking: + # type=bool|default=False: skip implicit masking based on value in --ref image. Default = 0 + skip_implicit_in_masking: + # type=bool|default=False: skip implicit masking based on value in --in image. Default = 0 + refmask_val: + # type=float|default=0.0: Value to mask out in --ref image. Default =0.0 + inmask_val: + # type=float|default=0.0: Value to mask out in --in image. Default =0.0 + max_nonlin_iter: + # type=list|default=[]: Max # of non-linear iterations list, default [5, 5, 5, 5] + subsampling_scheme: + # type=list|default=[]: sub-sampling scheme, list, default [4, 2, 1, 1] + warp_resolution: + # type=tuple|default=(0, 0, 0): (approximate) resolution (in mm) of warp basis in x-, y- and z-direction, default 10, 10, 10 + spline_order: + # type=int|default=0: Order of spline, 2->Qadratic spline, 3->Cubic spline. Default=3 + in_fwhm: + # type=list|default=[]: FWHM (in mm) of gaussian smoothing kernel for input volume, default [6, 4, 2, 2] + ref_fwhm: + # type=list|default=[]: FWHM (in mm) of gaussian smoothing kernel for ref volume, default [4, 2, 0, 0] + regularization_model: + # type=enum|default='membrane_energy'|allowed['bending_energy','membrane_energy']: Model for regularisation of warp-field [membrane_energy bending_energy], default bending_energy + regularization_lambda: + # type=list|default=[]: Weight of regularisation, default depending on --ssqlambda and --regmod switches. See user documentation. + skip_lambda_ssq: + # type=bool|default=False: If true, lambda is not weighted by current ssq, default false + jacobian_range: + # type=tuple|default=(0.0, 0.0): Allowed range of Jacobian determinants, default 0.01, 100.0 + derive_from_ref: + # type=bool|default=False: If true, ref image is used to calculate derivatives. Default false + intensity_mapping_model: + # type=enum|default='none'|allowed['global_linear','global_non_linear','global_non_linear_with_bias','local_linear','local_non_linear','none']: Model for intensity-mapping + intensity_mapping_order: + # type=int|default=0: Order of poynomial for mapping intensities, default 5 + biasfield_resolution: + # type=tuple|default=(0, 0, 0): Resolution (in mm) of bias-field modelling local intensities, default 50, 50, 50 + bias_regularization_lambda: + # type=float|default=0.0: Weight of regularisation for bias-field, default 10000 + skip_intensity_mapping: + # type=bool|default=False: Skip estimate intensity-mapping default false + apply_intensity_mapping: + # type=list|default=[]: List of subsampling levels to apply intensity mapping for (0 to skip, 1 to apply) + hessian_precision: + # type=enum|default='double'|allowed['double','float']: Precision for representing Hessian, double or float. Default double + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_fwhm: '[8, 4, 2, 2]' + # type=list|default=[]: FWHM (in mm) of gaussian smoothing kernel for input volume, default [6, 4, 2, 2] + subsampling_scheme: '[4, 2, 1, 1]' + # type=list|default=[]: sub-sampling scheme, list, default [4, 2, 1, 1] + warp_resolution: (6, 6, 6) + # type=tuple|default=(0, 0, 0): (approximate) resolution (in mm) of warp basis in x-, y- and z-direction, default 10, 10, 10 + imports: &id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + - module: nipype.testing + name: example_data + alias: + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_fwhm: '[8, 4, 2, 2]' + # type=list|default=[]: FWHM (in mm) of gaussian smoothing kernel for input volume, default [6, 4, 2, 2] + subsampling_scheme: '[4, 2, 1, 1] Specify the resolution of the warps >>> fnirt_mprage.inputs.warp_resolution = (6, 6, 6)' + # type=list|default=[]: sub-sampling scheme, list, default [4, 2, 1, 1] + imports: *id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/fnirt_callables.py b/nipype-auto-conv/specs/fnirt_callables.py new file mode 100644 index 0000000..3d121a2 --- /dev/null +++ b/nipype-auto-conv/specs/fnirt_callables.py @@ -0,0 +1,420 @@ +"""Module to put any functions that are referred to in the "callables" section of FNIRT.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def log_file_default(inputs): + return _gen_filename("log_file", inputs=inputs) + + +def warped_file_default(inputs): + return _gen_filename("warped_file", inputs=inputs) + + +def field_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["field_file"] + + +def fieldcoeff_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fieldcoeff_file"] + + +def jacobian_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["jacobian_file"] + + +def log_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["log_file"] + + +def modulatedref_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["modulatedref_file"] + + +def out_intensitymap_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_intensitymap_file"] + + +def warped_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["warped_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1341 of /interfaces/fsl/preprocess.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name in ["warped_file", "log_file"]: + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )[name] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fnirt" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1298 of /interfaces/fsl/preprocess.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + for key, suffix in list(filemap.items()): + inval = getattr(inputs, key) + change_ext = True + if key in ["warped_file", "log_file"]: + if suffix.endswith(".txt"): + change_ext = False + if inval is not attrs.NOTHING: + outputs[key] = os.path.abspath(inval) + else: + outputs[key] = _gen_fname( + inputs.in_file, + suffix="_" + suffix, + change_ext=change_ext, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + elif inval is not attrs.NOTHING: + if isinstance(inval, bool): + if inval: + outputs[key] = _gen_fname( + inputs.in_file, + suffix="_" + suffix, + change_ext=change_ext, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + else: + outputs[key] = os.path.abspath(inval) + + if key == "out_intensitymap_file" and (outputs[key] is not attrs.NOTHING): + basename = intensitymap_file_basename( + outputs[key], + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs[key] = [outputs[key], "%s.txt" % basename] + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L1364 of /interfaces/fsl/preprocess.py +def intensitymap_file_basename( + f, inputs=None, stdout=None, stderr=None, output_dir=None +): + """Removes valid intensitymap extensions from `f`, returning a basename + that can refer to both intensitymap files. + """ + for ext in list(Info.ftypes.values()) + [".txt"]: + if f.endswith(ext): + return f[: -len(ext)] + # TODO consider warning for this case + return f + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/fugue.yaml b/nipype-auto-conv/specs/fugue.yaml new file mode 100644 index 0000000..cf5bd47 --- /dev/null +++ b/nipype-auto-conv/specs/fugue.yaml @@ -0,0 +1,390 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.FUGUE' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL FUGUE set of tools for EPI distortion correction +# +# `FUGUE `_ is, most generally, +# a set of tools for EPI distortion correction. +# +# Distortions may be corrected for +# 1. improving registration with non-distorted images (e.g. structurals), +# or +# 2. dealing with motion-dependent changes. +# +# FUGUE is designed to deal only with the first case - +# improving registration. +# +# +# Examples +# -------- +# +# +# Unwarping an input image (shift map is known): +# +# >>> from nipype.interfaces.fsl.preprocess import FUGUE +# >>> fugue = FUGUE() +# >>> fugue.inputs.in_file = 'epi.nii' +# >>> fugue.inputs.mask_file = 'epi_mask.nii' +# >>> fugue.inputs.shift_in_file = 'vsm.nii' # Previously computed with fugue as well +# >>> fugue.inputs.unwarp_direction = 'y' +# >>> fugue.inputs.output_type = "NIFTI_GZ" +# >>> fugue.cmdline # doctest: +ELLIPSIS +# 'fugue --in=epi.nii --mask=epi_mask.nii --loadshift=vsm.nii --unwarpdir=y --unwarp=epi_unwarped.nii.gz' +# >>> fugue.run() #doctest: +SKIP +# +# +# Warping an input image (shift map is known): +# +# >>> from nipype.interfaces.fsl.preprocess import FUGUE +# >>> fugue = FUGUE() +# >>> fugue.inputs.in_file = 'epi.nii' +# >>> fugue.inputs.forward_warping = True +# >>> fugue.inputs.mask_file = 'epi_mask.nii' +# >>> fugue.inputs.shift_in_file = 'vsm.nii' # Previously computed with fugue as well +# >>> fugue.inputs.unwarp_direction = 'y' +# >>> fugue.inputs.output_type = "NIFTI_GZ" +# >>> fugue.cmdline # doctest: +ELLIPSIS +# 'fugue --in=epi.nii --mask=epi_mask.nii --loadshift=vsm.nii --unwarpdir=y --warp=epi_warped.nii.gz' +# >>> fugue.run() #doctest: +SKIP +# +# +# Computing the vsm (unwrapped phase map is known): +# +# >>> from nipype.interfaces.fsl.preprocess import FUGUE +# >>> fugue = FUGUE() +# >>> fugue.inputs.phasemap_in_file = 'epi_phasediff.nii' +# >>> fugue.inputs.mask_file = 'epi_mask.nii' +# >>> fugue.inputs.dwell_to_asym_ratio = (0.77e-3 * 3) / 2.46e-3 +# >>> fugue.inputs.unwarp_direction = 'y' +# >>> fugue.inputs.save_shift = True +# >>> fugue.inputs.output_type = "NIFTI_GZ" +# >>> fugue.cmdline # doctest: +ELLIPSIS +# 'fugue --dwelltoasym=0.9390243902 --mask=epi_mask.nii --phasemap=epi_phasediff.nii --saveshift=epi_phasediff_vsm.nii.gz --unwarpdir=y' +# >>> fugue.run() #doctest: +SKIP +# +# +# +task_name: FUGUE +nipype_name: FUGUE +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + fmap_in_file: generic/file + # type=file|default=: filename for loading fieldmap (rad/s) + fmap_out_file: Path + # type=file: fieldmap file + # type=file|default=: filename for saving fieldmap (rad/s) + in_file: medimage/nifti1 + # type=file|default=: filename of input volume + mask_file: medimage/nifti1 + # type=file|default=: filename for loading valid mask + phasemap_in_file: medimage/nifti1 + # type=file|default=: filename for input phase image + shift_in_file: medimage/nifti1 + # type=file|default=: filename for reading pixel shift volume + shift_out_file: Path + # type=file: voxel shift map file + # type=file|default=: filename for saving pixel shift volume + unwarped_file: Path + # type=file: unwarped file + # type=file|default=: apply unwarping and save as filename + warped_file: Path + # type=file: forward warped file + # type=file|default=: apply forward warping and save as filename + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + fmap_out_file: generic/file + # type=file: fieldmap file + # type=file|default=: filename for saving fieldmap (rad/s) + shift_out_file: generic/file + # type=file: voxel shift map file + # type=file|default=: filename for saving pixel shift volume + unwarped_file: generic/file + # type=file: unwarped file + # type=file|default=: apply unwarping and save as filename + warped_file: generic/file + # type=file: forward warped file + # type=file|default=: apply forward warping and save as filename + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: filename of input volume + shift_in_file: + # type=file|default=: filename for reading pixel shift volume + phasemap_in_file: + # type=file|default=: filename for input phase image + fmap_in_file: + # type=file|default=: filename for loading fieldmap (rad/s) + unwarped_file: + # type=file: unwarped file + # type=file|default=: apply unwarping and save as filename + warped_file: + # type=file: forward warped file + # type=file|default=: apply forward warping and save as filename + forward_warping: + # type=bool|default=False: apply forward warping instead of unwarping + dwell_to_asym_ratio: + # type=float|default=0.0: set the dwell to asym time ratio + dwell_time: + # type=float|default=0.0: set the EPI dwell time per phase-encode line - same as echo spacing - (sec) + asym_se_time: + # type=float|default=0.0: set the fieldmap asymmetric spin echo time (sec) + median_2dfilter: + # type=bool|default=False: apply 2D median filtering + despike_2dfilter: + # type=bool|default=False: apply a 2D de-spiking filter + no_gap_fill: + # type=bool|default=False: do not apply gap-filling measure to the fieldmap + no_extend: + # type=bool|default=False: do not apply rigid-body extrapolation to the fieldmap + smooth2d: + # type=float|default=0.0: apply 2D Gaussian smoothing of sigma N (in mm) + smooth3d: + # type=float|default=0.0: apply 3D Gaussian smoothing of sigma N (in mm) + poly_order: + # type=int|default=0: apply polynomial fitting of order N + fourier_order: + # type=int|default=0: apply Fourier (sinusoidal) fitting of order N + pava: + # type=bool|default=False: apply monotonic enforcement via PAVA + despike_threshold: + # type=float|default=0.0: specify the threshold for de-spiking (default=3.0) + unwarp_direction: + # type=enum|default='x'|allowed['x','x-','y','y-','z','z-']: specifies direction of warping (default y) + phase_conjugate: + # type=bool|default=False: apply phase conjugate method of unwarping + icorr: + # type=bool|default=False: apply intensity correction to unwarping (pixel shift method only) + icorr_only: + # type=bool|default=False: apply intensity correction only + mask_file: + # type=file|default=: filename for loading valid mask + nokspace: + # type=bool|default=False: do not use k-space forward warping + save_shift: + # type=bool|default=False: write pixel shift volume + shift_out_file: + # type=file: voxel shift map file + # type=file|default=: filename for saving pixel shift volume + save_unmasked_shift: + # type=bool|default=False: saves the unmasked shiftmap when using --saveshift + save_fmap: + # type=bool|default=False: write field map volume + fmap_out_file: + # type=file: fieldmap file + # type=file|default=: filename for saving fieldmap (rad/s) + save_unmasked_fmap: + # type=bool|default=False: saves the unmasked fieldmap when using --savefmap + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: filename of input volume + mask_file: + # type=file|default=: filename for loading valid mask + shift_in_file: + # type=file|default=: filename for reading pixel shift volume + unwarp_direction: '"y"' + # type=enum|default='x'|allowed['x','x-','y','y-','z','z-']: specifies direction of warping (default y) + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: filename of input volume + forward_warping: 'True' + # type=bool|default=False: apply forward warping instead of unwarping + mask_file: + # type=file|default=: filename for loading valid mask + shift_in_file: + # type=file|default=: filename for reading pixel shift volume + unwarp_direction: '"y"' + # type=enum|default='x'|allowed['x','x-','y','y-','z','z-']: specifies direction of warping (default y) + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + phasemap_in_file: + # type=file|default=: filename for input phase image + mask_file: + # type=file|default=: filename for loading valid mask + dwell_to_asym_ratio: (0.77e-3 * 3) / 2.46e-3 + # type=float|default=0.0: set the dwell to asym time ratio + unwarp_direction: '"y"' + # type=enum|default='x'|allowed['x','x-','y','y-','z','z-']: specifies direction of warping (default y) + save_shift: 'True' + # type=bool|default=False: write pixel shift volume + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fugue --in=epi.nii --mask=epi_mask.nii --loadshift=vsm.nii --unwarpdir=y --unwarp=epi_unwarped.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"epi.nii"' + # type=file|default=: filename of input volume + mask_file: '"epi_mask.nii"' + # type=file|default=: filename for loading valid mask + shift_in_file: '"vsm.nii" # Previously computed with fugue as well' + # type=file|default=: filename for reading pixel shift volume + unwarp_direction: '"y"' + # type=enum|default='x'|allowed['x','x-','y','y-','z','z-']: specifies direction of warping (default y) + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS +- cmdline: fugue --in=epi.nii --mask=epi_mask.nii --loadshift=vsm.nii --unwarpdir=y --warp=epi_warped.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"epi.nii"' + # type=file|default=: filename of input volume + forward_warping: 'True' + # type=bool|default=False: apply forward warping instead of unwarping + mask_file: '"epi_mask.nii"' + # type=file|default=: filename for loading valid mask + shift_in_file: '"vsm.nii" # Previously computed with fugue as well' + # type=file|default=: filename for reading pixel shift volume + unwarp_direction: '"y"' + # type=enum|default='x'|allowed['x','x-','y','y-','z','z-']: specifies direction of warping (default y) + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS +- cmdline: fugue --dwelltoasym=0.9390243902 --mask=epi_mask.nii --phasemap=epi_phasediff.nii --saveshift=epi_phasediff_vsm.nii.gz --unwarpdir=y + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + phasemap_in_file: '"epi_phasediff.nii"' + # type=file|default=: filename for input phase image + mask_file: '"epi_mask.nii"' + # type=file|default=: filename for loading valid mask + dwell_to_asym_ratio: (0.77e-3 * 3) / 2.46e-3 + # type=float|default=0.0: set the dwell to asym time ratio + unwarp_direction: '"y"' + # type=enum|default='x'|allowed['x','x-','y','y-','z','z-']: specifies direction of warping (default y) + save_shift: 'True' + # type=bool|default=False: write pixel shift volume + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/fugue_callables.py b/nipype-auto-conv/specs/fugue_callables.py new file mode 100644 index 0000000..befea95 --- /dev/null +++ b/nipype-auto-conv/specs/fugue_callables.py @@ -0,0 +1,359 @@ +"""Module to put any functions that are referred to in the "callables" section of FUGUE.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def fmap_out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fmap_out_file"] + + +def shift_out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["shift_out_file"] + + +def unwarped_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["unwarped_file"] + + +def warped_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["warped_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/glm.yaml b/nipype-auto-conv/specs/glm.yaml new file mode 100644 index 0000000..3668994 --- /dev/null +++ b/nipype-auto-conv/specs/glm.yaml @@ -0,0 +1,227 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.GLM' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# FSL GLM: +# +# Example +# ------- +# >>> import nipype.interfaces.fsl as fsl +# >>> glm = fsl.GLM(in_file='functional.nii', design='maps.nii', output_type='NIFTI') +# >>> glm.cmdline +# 'fsl_glm -i functional.nii -d maps.nii -o functional_glm.nii' +# +# +task_name: GLM +nipype_name: GLM +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + contrasts: generic/file + # type=file|default=: matrix of t-statics contrasts + design: medimage/nifti1 + # type=file|default=: file name of the GLM design matrix (text time courses for temporal regression or an image file for spatial regression) + in_file: medimage/nifti1 + # type=file|default=: input file name (text matrix or 3D/4D image file) + mask: generic/file + # type=file|default=: mask image file name if input is image + out_cope: Path + # type=outputmultiobject: output file name for COPEs (either as text file or image) + # type=file|default=: output file name for COPE (either as txt or image + out_data_name: Path + # type=file|default=: output file name for pre-processed data + out_f_name: Path + # type=file|default=: output file name for F-value of full model fit + out_file: Path + # type=file: file name of GLM parameters (if generated) + # type=file|default=: filename for GLM parameter estimates (GLM betas) + out_p_name: Path + # type=file|default=: output file name for p-values of Z-stats (either as text file or image) + out_pf_name: Path + # type=file|default=: output file name for p-value for full model fit + out_res_name: Path + # type=file|default=: output file name for residuals + out_sigsq_name: Path + # type=file|default=: output file name for residual noise variance sigma-square + out_t_name: Path + # type=file|default=: output file name for t-stats (either as txt or image + out_varcb_name: Path + # type=file|default=: output file name for variance of COPEs + out_vnscales_name: Path + # type=file|default=: output file name for scaling factors for variance normalisation + out_z_name: Path + # type=file|default=: output file name for Z-stats (either as txt or image + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_cope: generic/file+list-of + # type=outputmultiobject: output file name for COPEs (either as text file or image) + # type=file|default=: output file name for COPE (either as txt or image + out_data: generic/file+list-of + # type=outputmultiobject: output file for preprocessed data + out_f: generic/file+list-of + # type=outputmultiobject: output file name for F-value of full model fit + out_file: generic/file + # type=file: file name of GLM parameters (if generated) + # type=file|default=: filename for GLM parameter estimates (GLM betas) + out_p: generic/file+list-of + # type=outputmultiobject: output file name for p-values of Z-stats (either as text file or image) + out_pf: generic/file+list-of + # type=outputmultiobject: output file name for p-value for full model fit + out_res: generic/file+list-of + # type=outputmultiobject: output file name for residuals + out_sigsq: generic/file+list-of + # type=outputmultiobject: output file name for residual noise variance sigma-square + out_t: generic/file+list-of + # type=outputmultiobject: output file name for t-stats (either as text file or image) + out_varcb: generic/file+list-of + # type=outputmultiobject: output file name for variance of COPEs + out_vnscales: generic/file+list-of + # type=outputmultiobject: output file name for scaling factors for variance normalisation + out_z: generic/file+list-of + # type=outputmultiobject: output file name for COPEs (either as text file or image) + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file name (text matrix or 3D/4D image file) + out_file: + # type=file: file name of GLM parameters (if generated) + # type=file|default=: filename for GLM parameter estimates (GLM betas) + design: + # type=file|default=: file name of the GLM design matrix (text time courses for temporal regression or an image file for spatial regression) + contrasts: + # type=file|default=: matrix of t-statics contrasts + mask: + # type=file|default=: mask image file name if input is image + dof: + # type=int|default=0: set degrees of freedom explicitly + des_norm: + # type=bool|default=False: switch on normalization of the design matrix columns to unit std deviation + dat_norm: + # type=bool|default=False: switch on normalization of the data time series to unit std deviation + var_norm: + # type=bool|default=False: perform MELODIC variance-normalisation on data + demean: + # type=bool|default=False: switch on demeaining of design and data + out_cope: + # type=outputmultiobject: output file name for COPEs (either as text file or image) + # type=file|default=: output file name for COPE (either as txt or image + out_z_name: + # type=file|default=: output file name for Z-stats (either as txt or image + out_t_name: + # type=file|default=: output file name for t-stats (either as txt or image + out_p_name: + # type=file|default=: output file name for p-values of Z-stats (either as text file or image) + out_f_name: + # type=file|default=: output file name for F-value of full model fit + out_pf_name: + # type=file|default=: output file name for p-value for full model fit + out_res_name: + # type=file|default=: output file name for residuals + out_varcb_name: + # type=file|default=: output file name for variance of COPEs + out_sigsq_name: + # type=file|default=: output file name for residual noise variance sigma-square + out_data_name: + # type=file|default=: output file name for pre-processed data + out_vnscales_name: + # type=file|default=: output file name for scaling factors for variance normalisation + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file name (text matrix or 3D/4D image file) + design: + # type=file|default=: file name of the GLM design matrix (text time courses for temporal regression or an image file for spatial regression) + output_type: '"NIFTI"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: &id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + - module: nipype.interfaces.fsl as fsl + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fsl_glm -i functional.nii -d maps.nii -o functional_glm.nii + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"functional.nii"' + # type=file|default=: input file name (text matrix or 3D/4D image file) + design: '"maps.nii"' + # type=file|default=: file name of the GLM design matrix (text time courses for temporal regression or an image file for spatial regression) + output_type: '"NIFTI"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: *id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/glm_callables.py b/nipype-auto-conv/specs/glm_callables.py new file mode 100644 index 0000000..3f35c49 --- /dev/null +++ b/nipype-auto-conv/specs/glm_callables.py @@ -0,0 +1,457 @@ +"""Module to put any functions that are referred to in the "callables" section of GLM.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_cope_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_cope"] + + +def out_data_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_data"] + + +def out_f_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_f"] + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +def out_p_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_p"] + + +def out_pf_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_pf"] + + +def out_res_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_res"] + + +def out_sigsq_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_sigsq"] + + +def out_t_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_t"] + + +def out_varcb_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_varcb"] + + +def out_vnscales_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_vnscales"] + + +def out_z_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_z"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L2511 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = nipype_interfaces_fsl__FSLCommand___list_outputs() + + if inputs.out_cope is not attrs.NOTHING: + outputs["out_cope"] = os.path.abspath(inputs.out_cope) + + if inputs.out_z_name is not attrs.NOTHING: + outputs["out_z"] = os.path.abspath(inputs.out_z_name) + + if inputs.out_t_name is not attrs.NOTHING: + outputs["out_t"] = os.path.abspath(inputs.out_t_name) + + if inputs.out_p_name is not attrs.NOTHING: + outputs["out_p"] = os.path.abspath(inputs.out_p_name) + + if inputs.out_f_name is not attrs.NOTHING: + outputs["out_f"] = os.path.abspath(inputs.out_f_name) + + if inputs.out_pf_name is not attrs.NOTHING: + outputs["out_pf"] = os.path.abspath(inputs.out_pf_name) + + if inputs.out_res_name is not attrs.NOTHING: + outputs["out_res"] = os.path.abspath(inputs.out_res_name) + + if inputs.out_varcb_name is not attrs.NOTHING: + outputs["out_varcb"] = os.path.abspath(inputs.out_varcb_name) + + if inputs.out_sigsq_name is not attrs.NOTHING: + outputs["out_sigsq"] = os.path.abspath(inputs.out_sigsq_name) + + if inputs.out_data_name is not attrs.NOTHING: + outputs["out_data"] = os.path.abspath(inputs.out_data_name) + + if inputs.out_vnscales_name is not attrs.NOTHING: + outputs["out_vnscales"] = os.path.abspath(inputs.out_vnscales_name) + + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L891 of /interfaces/base/core.py +def nipype_interfaces_fsl__FSLCommand___list_outputs( + inputs=None, stdout=None, stderr=None, output_dir=None +): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/ica__aroma.yaml b/nipype-auto-conv/specs/ica__aroma.yaml new file mode 100644 index 0000000..bd97c5f --- /dev/null +++ b/nipype-auto-conv/specs/ica__aroma.yaml @@ -0,0 +1,204 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.aroma.ICA_AROMA' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Interface for the ICA_AROMA.py script. +# +# ICA-AROMA (i.e. 'ICA-based Automatic Removal Of Motion Artifacts') concerns +# a data-driven method to identify and remove motion-related independent +# components from fMRI data. To that end it exploits a small, but robust +# set of theoretically motivated features, preventing the need for classifier +# re-training and therefore providing direct and easy applicability. +# +# See link for further documentation: https://github.com/rhr-pruim/ICA-AROMA +# +# Example +# ------- +# +# >>> from nipype.interfaces.fsl import ICA_AROMA +# >>> from nipype.testing import example_data +# >>> AROMA_obj = ICA_AROMA() +# >>> AROMA_obj.inputs.in_file = 'functional.nii' +# >>> AROMA_obj.inputs.mat_file = 'func_to_struct.mat' +# >>> AROMA_obj.inputs.fnirt_warp_file = 'warpfield.nii' +# >>> AROMA_obj.inputs.motion_parameters = 'fsl_mcflirt_movpar.txt' +# >>> AROMA_obj.inputs.mask = 'mask.nii.gz' +# >>> AROMA_obj.inputs.denoise_type = 'both' +# >>> AROMA_obj.inputs.out_dir = 'ICA_testout' +# >>> AROMA_obj.cmdline # doctest: +ELLIPSIS +# 'ICA_AROMA.py -den both -warp warpfield.nii -i functional.nii -m mask.nii.gz -affmat func_to_struct.mat -mc fsl_mcflirt_movpar.txt -o .../ICA_testout' +# +task_name: ICA_AROMA +nipype_name: ICA_AROMA +nipype_module: nipype.interfaces.fsl.aroma +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + feat_dir: generic/directory + # type=directory|default=: If a feat directory exists and temporal filtering has not been run yet, ICA_AROMA can use the files in this directory. + fnirt_warp_file: medimage/nifti1 + # type=file|default=: File name of the warp-file describing the non-linear registration (e.g. FSL FNIRT) of the structural data to MNI152 space (.nii.gz) + in_file: medimage/nifti1 + # type=file|default=: volume to be denoised + mask: medimage/nifti-gz + # type=file|default=: path/name volume mask + mat_file: datascience/text-matrix + # type=file|default=: path/name of the mat-file describing the affine registration (e.g. FSL FLIRT) of the functional data to structural space (.mat file) + melodic_dir: generic/directory + # type=directory|default=: path to MELODIC directory if MELODIC has already been run + motion_parameters: text/text-file + # type=file|default=: motion parameters file + out_dir: Path + # type=directory: directory contains (in addition to the denoised files): melodic.ica + classified_motion_components + classification_overview + feature_scores + melodic_ic_mni) + # type=directory|default='out': output directory + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + aggr_denoised_file: generic/file + # type=file: if generated: aggressively denoised volume + nonaggr_denoised_file: generic/file + # type=file: if generated: non aggressively denoised volume + out_dir: generic/directory + # type=directory: directory contains (in addition to the denoised files): melodic.ica + classified_motion_components + classification_overview + feature_scores + melodic_ic_mni) + # type=directory|default='out': output directory + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + feat_dir: + # type=directory|default=: If a feat directory exists and temporal filtering has not been run yet, ICA_AROMA can use the files in this directory. + in_file: + # type=file|default=: volume to be denoised + out_dir: + # type=directory: directory contains (in addition to the denoised files): melodic.ica + classified_motion_components + classification_overview + feature_scores + melodic_ic_mni) + # type=directory|default='out': output directory + mask: + # type=file|default=: path/name volume mask + dim: + # type=int|default=0: Dimensionality reduction when running MELODIC (default is automatic estimation) + TR: + # type=float|default=0.0: TR in seconds. If this is not specified the TR will be extracted from the header of the fMRI nifti file. + melodic_dir: + # type=directory|default=: path to MELODIC directory if MELODIC has already been run + mat_file: + # type=file|default=: path/name of the mat-file describing the affine registration (e.g. FSL FLIRT) of the functional data to structural space (.mat file) + fnirt_warp_file: + # type=file|default=: File name of the warp-file describing the non-linear registration (e.g. FSL FNIRT) of the structural data to MNI152 space (.nii.gz) + motion_parameters: + # type=file|default=: motion parameters file + denoise_type: + # type=enum|default='nonaggr'|allowed['aggr','both','no','nonaggr']: Type of denoising strategy: -no: only classification, no denoising -nonaggr (default): non-aggresssive denoising, i.e. partial component regression -aggr: aggressive denoising, i.e. full component regression -both: both aggressive and non-aggressive denoising (two outputs) + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: volume to be denoised + mat_file: + # type=file|default=: path/name of the mat-file describing the affine registration (e.g. FSL FLIRT) of the functional data to structural space (.mat file) + fnirt_warp_file: + # type=file|default=: File name of the warp-file describing the non-linear registration (e.g. FSL FNIRT) of the structural data to MNI152 space (.nii.gz) + motion_parameters: + # type=file|default=: motion parameters file + mask: + # type=file|default=: path/name volume mask + denoise_type: '"both"' + # type=enum|default='nonaggr'|allowed['aggr','both','no','nonaggr']: Type of denoising strategy: -no: only classification, no denoising -nonaggr (default): non-aggresssive denoising, i.e. partial component regression -aggr: aggressive denoising, i.e. full component regression -both: both aggressive and non-aggressive denoising (two outputs) + out_dir: '"ICA_testout"' + # type=directory: directory contains (in addition to the denoised files): melodic.ica + classified_motion_components + classification_overview + feature_scores + melodic_ic_mni) + # type=directory|default='out': output directory + imports: &id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + - module: nipype.testing + name: example_data + alias: + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: ICA_AROMA.py -den both -warp warpfield.nii -i functional.nii -m mask.nii.gz -affmat func_to_struct.mat -mc fsl_mcflirt_movpar.txt -o .../ICA_testout + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"functional.nii"' + # type=file|default=: volume to be denoised + mat_file: '"func_to_struct.mat"' + # type=file|default=: path/name of the mat-file describing the affine registration (e.g. FSL FLIRT) of the functional data to structural space (.mat file) + fnirt_warp_file: '"warpfield.nii"' + # type=file|default=: File name of the warp-file describing the non-linear registration (e.g. FSL FNIRT) of the structural data to MNI152 space (.nii.gz) + motion_parameters: '"fsl_mcflirt_movpar.txt"' + # type=file|default=: motion parameters file + mask: '"mask.nii.gz"' + # type=file|default=: path/name volume mask + denoise_type: '"both"' + # type=enum|default='nonaggr'|allowed['aggr','both','no','nonaggr']: Type of denoising strategy: -no: only classification, no denoising -nonaggr (default): non-aggresssive denoising, i.e. partial component regression -aggr: aggressive denoising, i.e. full component regression -both: both aggressive and non-aggressive denoising (two outputs) + out_dir: '"ICA_testout"' + # type=directory: directory contains (in addition to the denoised files): melodic.ica + classified_motion_components + classification_overview + feature_scores + melodic_ic_mni) + # type=directory|default='out': output directory + imports: *id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/ica__aroma_callables.py b/nipype-auto-conv/specs/ica__aroma_callables.py new file mode 100644 index 0000000..2c25633 --- /dev/null +++ b/nipype-auto-conv/specs/ica__aroma_callables.py @@ -0,0 +1,46 @@ +"""Module to put any functions that are referred to in the "callables" section of ICA_AROMA.yaml""" + +import os + + +def aggr_denoised_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["aggr_denoised_file"] + + +def nonaggr_denoised_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["nonaggr_denoised_file"] + + +def out_dir_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_dir"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L151 of /interfaces/fsl/aroma.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_dir"] = os.path.abspath(inputs.out_dir) + out_dir = outputs["out_dir"] + + if inputs.denoise_type in ("aggr", "both"): + outputs["aggr_denoised_file"] = os.path.join( + out_dir, "denoised_func_data_aggr.nii.gz" + ) + if inputs.denoise_type in ("nonaggr", "both"): + outputs["nonaggr_denoised_file"] = os.path.join( + out_dir, "denoised_func_data_nonaggr.nii.gz" + ) + return outputs diff --git a/nipype-auto-conv/specs/image_maths.yaml b/nipype-auto-conv/specs/image_maths.yaml new file mode 100644 index 0000000..c0cb2c5 --- /dev/null +++ b/nipype-auto-conv/specs/image_maths.yaml @@ -0,0 +1,162 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.ImageMaths' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL fslmaths command to allow mathematical manipulation of images +# `FSL info `_ +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces import fsl +# >>> from nipype.testing import anatfile +# >>> maths = fsl.ImageMaths(in_file=anatfile, op_string= '-add 5', +# ... out_file='foo_maths.nii') +# >>> maths.cmdline == 'fslmaths %s -add 5 foo_maths.nii' % anatfile +# True +# +# +# +task_name: ImageMaths +nipype_name: ImageMaths +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: + in_file2: generic/file + # type=file|default=: + mask_file: generic/file + # type=file|default=: use (following image>0) to mask current image + out_file: Path + # type=file: + # type=file|default=: + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: medimage/nifti1 + # type=file: + # type=file|default=: + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: '"foo_maths.nii"' + # type=file: + # type=file|default=: + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: + in_file2: + # type=file|default=: + mask_file: + # type=file|default=: use (following image>0) to mask current image + out_file: + # type=file: + # type=file|default=: + op_string: + # type=str|default='': string defining the operation, i. e. -add + suffix: + # type=str|default='': out_file suffix + out_data_type: + # type=enum|default='char'|allowed['char','double','float','input','int','short']: output datatype, one of (char, short, int, float, double, input) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: + op_string: '"-add 5"' + # type=str|default='': string defining the operation, i. e. -add + out_file: '"foo_maths.nii"' + # type=file: + # type=file|default=: + imports: &id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + - module: nipype.testing + name: anatfile + alias: + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: anatfile + # type=file|default=: + op_string: '"-add 5"' + # type=str|default='': string defining the operation, i. e. -add + out_file: '"foo_maths.nii"' + # type=file: + # type=file|default=: + imports: *id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/image_maths_callables.py b/nipype-auto-conv/specs/image_maths_callables.py new file mode 100644 index 0000000..0689a1c --- /dev/null +++ b/nipype-auto-conv/specs/image_maths_callables.py @@ -0,0 +1,332 @@ +"""Module to put any functions that are referred to in the "callables" section of ImageMaths.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L627 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )[name] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L635 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + suffix = "_maths" # ohinds: build suffix + if inputs.suffix is not attrs.NOTHING: + suffix = inputs.suffix + outputs = {} + outputs["out_file"] = inputs.out_file + if outputs["out_file"] is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/image_meants.yaml b/nipype-auto-conv/specs/image_meants.yaml new file mode 100644 index 0000000..c677a44 --- /dev/null +++ b/nipype-auto-conv/specs/image_meants.yaml @@ -0,0 +1,109 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.ImageMeants' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmeants for printing the average timeseries (intensities) to +# the screen (or saves to a file). The average is taken over all voxels +# in the mask (or all voxels in the image if no mask is specified) +# +# +task_name: ImageMeants +nipype_name: ImageMeants +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: input file for computing the average timeseries + mask: generic/file + # type=file|default=: input 3D mask + out_file: Path + # type=file: path/name of output text matrix + # type=file|default=: name of output text matrix + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: path/name of output text matrix + # type=file|default=: name of output text matrix + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: path/name of output text matrix + # type=file|default=: name of output text matrix + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file for computing the average timeseries + out_file: + # type=file: path/name of output text matrix + # type=file|default=: name of output text matrix + mask: + # type=file|default=: input 3D mask + spatial_coord: + # type=list|default=[]: requested spatial coordinate (instead of mask) + use_mm: + # type=bool|default=False: use mm instead of voxel coordinates (for -c option) + show_all: + # type=bool|default=False: show all voxel time series (within mask) instead of averaging + eig: + # type=bool|default=False: calculate Eigenvariate(s) instead of mean (output will have 0 mean) + order: + # type=int|default=1: select number of Eigenvariates + nobin: + # type=bool|default=False: do not binarise the mask for calculation of Eigenvariates + transpose: + # type=bool|default=False: output results in transpose format (one row per voxel/mean) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/image_meants_callables.py b/nipype-auto-conv/specs/image_meants_callables.py new file mode 100644 index 0000000..b7eb8a5 --- /dev/null +++ b/nipype-auto-conv/specs/image_meants_callables.py @@ -0,0 +1,331 @@ +"""Module to put any functions that are referred to in the "callables" section of ImageMeants.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L184 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )[name] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmeants" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L174 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if outputs["out_file"] is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix="_ts", + ext=".txt", + change_ext=True, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/image_stats.yaml b/nipype-auto-conv/specs/image_stats.yaml new file mode 100644 index 0000000..b390726 --- /dev/null +++ b/nipype-auto-conv/specs/image_stats.yaml @@ -0,0 +1,144 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.ImageStats' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL fslstats command to calculate stats from images +# `FSL info +# `_ +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import ImageStats +# >>> from nipype.testing import funcfile +# >>> stats = ImageStats(in_file=funcfile, op_string= '-M') +# >>> stats.cmdline == 'fslstats %s -M'%funcfile +# True +# +# +# +task_name: ImageStats +nipype_name: ImageStats +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: input file to generate stats of + index_mask_file: generic/file + # type=file|default=: generate separate n submasks from indexMask, for indexvalues 1..n where n is the maximum index value in indexMask, and generate statistics for each submask + mask_file: generic/file + # type=file|default=: mask file used for option -k %s + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + out_stat: out_stat_callable + # type=any: stats output + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + split_4d: + # type=bool|default=False: give a separate output line for each 3D volume of a 4D timeseries + in_file: + # type=file|default=: input file to generate stats of + op_string: + # type=str|default='': string defining the operation, options are applied in order, e.g. -M -l 10 -M will report the non-zero mean, apply a threshold and then report the new nonzero mean + mask_file: + # type=file|default=: mask file used for option -k %s + index_mask_file: + # type=file|default=: generate separate n submasks from indexMask, for indexvalues 1..n where n is the maximum index value in indexMask, and generate statistics for each submask + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input file to generate stats of + op_string: '"-M"' + # type=str|default='': string defining the operation, options are applied in order, e.g. -M -l 10 -M will report the non-zero mean, apply a threshold and then report the new nonzero mean + imports: &id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + - module: nipype.testing + name: funcfile + alias: + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: funcfile + # type=file|default=: input file to generate stats of + op_string: '"-M"' + # type=str|default='': string defining the operation, options are applied in order, e.g. -M -l 10 -M will report the non-zero mean, apply a threshold and then report the new nonzero mean + imports: *id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/image_stats_callables.py b/nipype-auto-conv/specs/image_stats_callables.py new file mode 100644 index 0000000..691ce5b --- /dev/null +++ b/nipype-auto-conv/specs/image_stats_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of ImageStats.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_stat_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_stat"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/inv_warp.yaml b/nipype-auto-conv/specs/inv_warp.yaml new file mode 100644 index 0000000..a34cde0 --- /dev/null +++ b/nipype-auto-conv/specs/inv_warp.yaml @@ -0,0 +1,160 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.InvWarp' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Use FSL Invwarp to invert a FNIRT warp +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import InvWarp +# >>> invwarp = InvWarp() +# >>> invwarp.inputs.warp = "struct2mni.nii" +# >>> invwarp.inputs.reference = "anatomical.nii" +# >>> invwarp.inputs.output_type = "NIFTI_GZ" +# >>> invwarp.cmdline +# 'invwarp --out=struct2mni_inverse.nii.gz --ref=anatomical.nii --warp=struct2mni.nii' +# >>> res = invwarp.run() # doctest: +SKIP +# +# +# +task_name: InvWarp +nipype_name: InvWarp +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + inverse_warp: Path + # type=file: Name of output file, containing warps that are the "reverse" of those in --warp. + # type=file|default=: Name of output file, containing warps that are the "reverse" of those in --warp. This will be a field-file (rather than a file of spline coefficients), and it will have any affine component included as part of the displacements. + reference: medimage/nifti1 + # type=file|default=: Name of a file in target space. Note that the target space is now different from the target space that was used to create the --warp file. It would typically be the file that was specified with the --in argument when running fnirt. + warp: medimage/nifti1 + # type=file|default=: Name of file containing warp-coefficients/fields. This would typically be the output from the --cout switch of fnirt (but can also use fields, like the output from --fout). + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + inverse_warp: generic/file + # type=file: Name of output file, containing warps that are the "reverse" of those in --warp. + # type=file|default=: Name of output file, containing warps that are the "reverse" of those in --warp. This will be a field-file (rather than a file of spline coefficients), and it will have any affine component included as part of the displacements. + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + warp: + # type=file|default=: Name of file containing warp-coefficients/fields. This would typically be the output from the --cout switch of fnirt (but can also use fields, like the output from --fout). + reference: + # type=file|default=: Name of a file in target space. Note that the target space is now different from the target space that was used to create the --warp file. It would typically be the file that was specified with the --in argument when running fnirt. + inverse_warp: + # type=file: Name of output file, containing warps that are the "reverse" of those in --warp. + # type=file|default=: Name of output file, containing warps that are the "reverse" of those in --warp. This will be a field-file (rather than a file of spline coefficients), and it will have any affine component included as part of the displacements. + absolute: + # type=bool|default=False: If set it indicates that the warps in --warp should be interpreted as absolute, provided that it is not created by fnirt (which always uses relative warps). If set it also indicates that the output --out should be absolute. + relative: + # type=bool|default=False: If set it indicates that the warps in --warp should be interpreted as relative. I.e. the values in --warp are displacements from the coordinates in the --ref space. If set it also indicates that the output --out should be relative. + niter: + # type=int|default=0: Determines how many iterations of the gradient-descent search that should be run. + regularise: + # type=float|default=0.0: Regularization strength (default=1.0). + noconstraint: + # type=bool|default=False: Do not apply Jacobian constraint + jacobian_min: + # type=float|default=0.0: Minimum acceptable Jacobian value for constraint (default 0.01) + jacobian_max: + # type=float|default=0.0: Maximum acceptable Jacobian value for constraint (default 100.0) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + warp: + # type=file|default=: Name of file containing warp-coefficients/fields. This would typically be the output from the --cout switch of fnirt (but can also use fields, like the output from --fout). + reference: + # type=file|default=: Name of a file in target space. Note that the target space is now different from the target space that was used to create the --warp file. It would typically be the file that was specified with the --in argument when running fnirt. + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: invwarp --out=struct2mni_inverse.nii.gz --ref=anatomical.nii --warp=struct2mni.nii + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + warp: '"struct2mni.nii"' + # type=file|default=: Name of file containing warp-coefficients/fields. This would typically be the output from the --cout switch of fnirt (but can also use fields, like the output from --fout). + reference: '"anatomical.nii"' + # type=file|default=: Name of a file in target space. Note that the target space is now different from the target space that was used to create the --warp file. It would typically be the file that was specified with the --in argument when running fnirt. + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/inv_warp_callables.py b/nipype-auto-conv/specs/inv_warp_callables.py new file mode 100644 index 0000000..f9af045 --- /dev/null +++ b/nipype-auto-conv/specs/inv_warp_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of InvWarp.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def inverse_warp_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["inverse_warp"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/isotropic_smooth.yaml b/nipype-auto-conv/specs/isotropic_smooth.yaml new file mode 100644 index 0000000..51d44a9 --- /dev/null +++ b/nipype-auto-conv/specs/isotropic_smooth.yaml @@ -0,0 +1,97 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.IsotropicSmooth' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to spatially smooth an image with a gaussian kernel. +task_name: IsotropicSmooth +nipype_name: IsotropicSmooth +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + fwhm: + # type=float|default=0.0: fwhm of smoothing kernel [mm] + sigma: + # type=float|default=0.0: sigma of smoothing kernel [mm] + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/isotropic_smooth_callables.py b/nipype-auto-conv/specs/isotropic_smooth_callables.py new file mode 100644 index 0000000..214d374 --- /dev/null +++ b/nipype-auto-conv/specs/isotropic_smooth_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of IsotropicSmooth.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/l2_model.yaml b/nipype-auto-conv/specs/l2_model.yaml new file mode 100644 index 0000000..fdfd1e2 --- /dev/null +++ b/nipype-auto-conv/specs/l2_model.yaml @@ -0,0 +1,81 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.L2Model' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Generate subject specific second level model +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import L2Model +# >>> model = L2Model(num_copes=3) # 3 sessions +# +# +task_name: L2Model +nipype_name: L2Model +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + design_con: generic/file + # type=file: design contrast file + design_grp: generic/file + # type=file: design group file + design_mat: generic/file + # type=file: design matrix file + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + num_copes: + # type=range|default=1: number of copes to be combined + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/l2_model_callables.py b/nipype-auto-conv/specs/l2_model_callables.py new file mode 100644 index 0000000..faac4e1 --- /dev/null +++ b/nipype-auto-conv/specs/l2_model_callables.py @@ -0,0 +1,32 @@ +"""Module to put any functions that are referred to in the "callables" section of L2Model.yaml""" + +import os + + +def design_con_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["design_con"] + + +def design_grp_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["design_grp"] + + +def design_mat_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["design_mat"] + + +# Original source at L1431 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + for field in list(outputs.keys()): + outputs[field] = os.path.join(output_dir, field.replace("_", ".")) + return outputs diff --git a/nipype-auto-conv/specs/level_1_design.yaml b/nipype-auto-conv/specs/level_1_design.yaml new file mode 100644 index 0000000..4c3d611 --- /dev/null +++ b/nipype-auto-conv/specs/level_1_design.yaml @@ -0,0 +1,90 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.Level1Design' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Generate FEAT specific files +# +# Examples +# -------- +# +# >>> level1design = Level1Design() +# >>> level1design.inputs.interscan_interval = 2.5 +# >>> level1design.inputs.bases = {'dgamma':{'derivs': False}} +# >>> level1design.inputs.session_info = 'session_info.npz' +# >>> level1design.run() # doctest: +SKIP +# +# +task_name: Level1Design +nipype_name: Level1Design +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + fsf_files: generic/file+list-of + # type=outputmultiobject: FSL feat specification files + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + interscan_interval: + # type=float|default=0.0: Interscan interval (in secs) + session_info: + # type=any|default=None: Session specific information generated by ``modelgen.SpecifyModel`` + bases: + # type=traitcompound|default=None: name of basis function and options e.g., {'dgamma': {'derivs': True}} + orthogonalization: + # type=dict|default={}: which regressors to make orthogonal e.g., {1: {0:0,1:0,2:0}, 2: {0:1,1:1,2:0}} to make the second regressor in a 2-regressor model orthogonal to the first. + model_serial_correlations: + # type=bool|default=False: Option to model serial correlations using an autoregressive estimator (order 1). Setting this option is only useful in the context of the fsf file. If you set this to False, you need to repeat this option for FILMGLS by setting autocorr_noestimate to True + contrasts: + # type=list|default=[]: List of contrasts with each contrast being a list of the form - [('name', 'stat', [condition list], [weight list], [session list])]. if session list is None or not provided, all sessions are used. For F contrasts, the condition list should contain previously defined T-contrasts. + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/level_1_design_callables.py b/nipype-auto-conv/specs/level_1_design_callables.py new file mode 100644 index 0000000..ed9f720 --- /dev/null +++ b/nipype-auto-conv/specs/level_1_design_callables.py @@ -0,0 +1,63 @@ +"""Module to put any functions that are referred to in the "callables" section of Level1Design.yaml""" + +import os + + +def ev_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["ev_files"] + + +def fsf_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fsf_files"] + + +# Original source at L343 of /interfaces/fsl/model.py +def _format_session_info( + session_info, inputs=None, stdout=None, stderr=None, output_dir=None +): + if isinstance(session_info, dict): + session_info = [session_info] + return session_info + + +# Original source at L414 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + cwd = output_dir + outputs["fsf_files"] = [] + outputs["ev_files"] = [] + basis_key = list(inputs.bases.keys())[0] + ev_parameters = dict(inputs.bases[basis_key]) + for runno, runinfo in enumerate( + _format_session_info( + inputs.session_info, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ): + outputs["fsf_files"].append(os.path.join(cwd, "run%d.fsf" % runno)) + outputs["ev_files"].insert(runno, []) + evname = [] + for field in ["cond", "regress"]: + for i, cond in enumerate(runinfo[field]): + name = cond["name"] + evname.append(name) + evfname = os.path.join( + cwd, "ev_%s_%d_%d.txt" % (name, runno, len(evname)) + ) + if field == "cond": + ev_parameters["temporalderiv"] = int( + bool(ev_parameters.get("derivs", False)) + ) + if ev_parameters["temporalderiv"]: + evname.append(name + "TD") + outputs["ev_files"][runno].append(os.path.join(cwd, evfname)) + return outputs diff --git a/nipype-auto-conv/specs/make_dyadic_vectors.yaml b/nipype-auto-conv/specs/make_dyadic_vectors.yaml new file mode 100644 index 0000000..0ad7027 --- /dev/null +++ b/nipype-auto-conv/specs/make_dyadic_vectors.yaml @@ -0,0 +1,94 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.MakeDyadicVectors' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Create vector volume representing mean principal diffusion direction +# and its uncertainty (dispersion) +task_name: MakeDyadicVectors +nipype_name: MakeDyadicVectors +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mask: generic/file + # type=file|default=: + output: generic/file + # type=file|default='dyads': + phi_vol: generic/file + # type=file|default=: + theta_vol: generic/file + # type=file|default=: + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + dispersion: generic/file + # type=file: + dyads: generic/file + # type=file: + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + theta_vol: + # type=file|default=: + phi_vol: + # type=file|default=: + mask: + # type=file|default=: + output: + # type=file|default='dyads': + perc: + # type=float|default=0.0: the {perc}% angle of the output cone of uncertainty (output will be in degrees) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/make_dyadic_vectors_callables.py b/nipype-auto-conv/specs/make_dyadic_vectors_callables.py new file mode 100644 index 0000000..8851bde --- /dev/null +++ b/nipype-auto-conv/specs/make_dyadic_vectors_callables.py @@ -0,0 +1,332 @@ +"""Module to put any functions that are referred to in the "callables" section of MakeDyadicVectors.yaml""" + +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def dispersion_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["dispersion"] + + +def dyads_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["dyads"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "make_dyadic_vectors" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1571 of /interfaces/fsl/dti.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["dyads"] = _gen_fname( + inputs.output, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["dispersion"] = _gen_fname( + inputs.output, + suffix="_dispersion", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/maths_command.yaml b/nipype-auto-conv/specs/maths_command.yaml new file mode 100644 index 0000000..9b8e624 --- /dev/null +++ b/nipype-auto-conv/specs/maths_command.yaml @@ -0,0 +1,93 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.MathsCommand' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +task_name: MathsCommand +nipype_name: MathsCommand +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/maths_command_callables.py b/nipype-auto-conv/specs/maths_command_callables.py new file mode 100644 index 0000000..c11baf2 --- /dev/null +++ b/nipype-auto-conv/specs/maths_command_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of MathsCommand.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/max_image.yaml b/nipype-auto-conv/specs/max_image.yaml new file mode 100644 index 0000000..3e56aed --- /dev/null +++ b/nipype-auto-conv/specs/max_image.yaml @@ -0,0 +1,139 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.MaxImage' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to generate a max image across a given dimension. +# +# Examples +# -------- +# >>> from nipype.interfaces.fsl.maths import MaxImage +# >>> maxer = MaxImage() +# >>> maxer.inputs.in_file = "functional.nii" # doctest: +SKIP +# >>> maxer.dimension = "T" +# >>> maxer.cmdline # doctest: +SKIP +# 'fslmaths functional.nii -Tmax functional_max.nii' +# +# +task_name: MaxImage +nipype_name: MaxImage +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dimension: + # type=enum|default='T'|allowed['T','X','Y','Z']: dimension to max across + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: image to operate on + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fslmaths functional.nii -Tmax functional_max.nii + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"functional.nii" # doctest: +SKIP' + # type=file|default=: image to operate on + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/max_image_callables.py b/nipype-auto-conv/specs/max_image_callables.py new file mode 100644 index 0000000..61b6ae6 --- /dev/null +++ b/nipype-auto-conv/specs/max_image_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of MaxImage.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/maxn_image.yaml b/nipype-auto-conv/specs/maxn_image.yaml new file mode 100644 index 0000000..c60f028 --- /dev/null +++ b/nipype-auto-conv/specs/maxn_image.yaml @@ -0,0 +1,98 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.MaxnImage' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to generate an image of index of max across +# a given dimension. +# +# +task_name: MaxnImage +nipype_name: MaxnImage +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dimension: + # type=enum|default='T'|allowed['T','X','Y','Z']: dimension to index max across + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/maxn_image_callables.py b/nipype-auto-conv/specs/maxn_image_callables.py new file mode 100644 index 0000000..87f0b52 --- /dev/null +++ b/nipype-auto-conv/specs/maxn_image_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of MaxnImage.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/mcflirt.yaml b/nipype-auto-conv/specs/mcflirt.yaml new file mode 100644 index 0000000..5db6ff0 --- /dev/null +++ b/nipype-auto-conv/specs/mcflirt.yaml @@ -0,0 +1,198 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.MCFLIRT' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL MCFLIRT wrapper for within-modality motion correction +# +# For complete details, see the `MCFLIRT Documentation. +# `_ +# +# Examples +# -------- +# >>> from nipype.interfaces import fsl +# >>> mcflt = fsl.MCFLIRT() +# >>> mcflt.inputs.in_file = 'functional.nii' +# >>> mcflt.inputs.cost = 'mutualinfo' +# >>> mcflt.inputs.out_file = 'moco.nii' +# >>> mcflt.cmdline +# 'mcflirt -in functional.nii -cost mutualinfo -out moco.nii' +# >>> res = mcflt.run() # doctest: +SKIP +# +# +task_name: MCFLIRT +nipype_name: MCFLIRT +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: timeseries to motion-correct + init: generic/file + # type=file|default=: initial transformation matrix + out_file: Path + # type=file: motion-corrected timeseries + # type=file|default=: file to write + ref_file: generic/file + # type=file|default=: target image for motion correction + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mat_file: generic/file+list-of + # type=outputmultiobject: transformation matrices + mean_img: generic/file + # type=file: mean timeseries image (if mean_vol=True) + out_file: medimage/nifti1 + # type=file: motion-corrected timeseries + # type=file|default=: file to write + par_file: generic/file + # type=file: text-file with motion parameters + rms_files: generic/file+list-of + # type=outputmultiobject: absolute and relative displacement parameters + std_img: generic/file + # type=file: standard deviation image + variance_img: generic/file + # type=file: variance image + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: '"moco.nii"' + # type=file: motion-corrected timeseries + # type=file|default=: file to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: timeseries to motion-correct + out_file: + # type=file: motion-corrected timeseries + # type=file|default=: file to write + cost: + # type=enum|default='mutualinfo'|allowed['corratio','leastsquares','mutualinfo','normcorr','normmi','woods']: cost function to optimize + bins: + # type=int|default=0: number of histogram bins + dof: + # type=int|default=0: degrees of freedom for the transformation + ref_vol: + # type=int|default=0: volume to align frames to + scaling: + # type=float|default=0.0: scaling factor to use + smooth: + # type=float|default=0.0: smoothing factor for the cost function + rotation: + # type=int|default=0: scaling factor for rotation tolerances + stages: + # type=int|default=0: stages (if 4, perform final search with sinc interpolation + init: + # type=file|default=: initial transformation matrix + interpolation: + # type=enum|default='spline'|allowed['nn','sinc','spline']: interpolation method for transformation + use_gradient: + # type=bool|default=False: run search on gradient images + use_contour: + # type=bool|default=False: run search on contour images + mean_vol: + # type=bool|default=False: register to mean volume + stats_imgs: + # type=bool|default=False: produce variance and std. dev. images + save_mats: + # type=bool|default=False: save transformation matrices + save_plots: + # type=bool|default=False: save transformation parameters + save_rms: + # type=bool|default=False: save rms displacement parameters + ref_file: + # type=file|default=: target image for motion correction + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: timeseries to motion-correct + cost: '"mutualinfo"' + # type=enum|default='mutualinfo'|allowed['corratio','leastsquares','mutualinfo','normcorr','normmi','woods']: cost function to optimize + out_file: '"moco.nii"' + # type=file: motion-corrected timeseries + # type=file|default=: file to write + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: mcflirt -in functional.nii -cost mutualinfo -out moco.nii + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"functional.nii"' + # type=file|default=: timeseries to motion-correct + cost: '"mutualinfo"' + # type=enum|default='mutualinfo'|allowed['corratio','leastsquares','mutualinfo','normcorr','normmi','woods']: cost function to optimize + out_file: '"moco.nii"' + # type=file: motion-corrected timeseries + # type=file|default=: file to write + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/mcflirt_callables.py b/nipype-auto-conv/specs/mcflirt_callables.py new file mode 100644 index 0000000..d6bc0a6 --- /dev/null +++ b/nipype-auto-conv/specs/mcflirt_callables.py @@ -0,0 +1,466 @@ +"""Module to put any functions that are referred to in the "callables" section of MCFLIRT.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from looseversion import LooseVersion +from nibabel import load +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def mat_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mat_file"] + + +def mean_img_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_img"] + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +def par_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["par_file"] + + +def rms_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["rms_files"] + + +def std_img_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["std_img"] + + +def variance_img_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["variance_img"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L962 of /interfaces/fsl/preprocess.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _gen_outfilename( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "mcflirt" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L967 of /interfaces/fsl/preprocess.py +def _gen_outfilename(inputs=None, stdout=None, stderr=None, output_dir=None): + out_file = inputs.out_file + if out_file is not attrs.NOTHING: + out_file = os.path.realpath(out_file) + if (out_file is attrs.NOTHING) and (inputs.in_file is not attrs.NOTHING): + out_file = _gen_fname( + inputs.in_file, + suffix="_mcf", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return os.path.abspath(out_file) + + +# Original source at L906 of /interfaces/fsl/preprocess.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + + outputs["out_file"] = _gen_outfilename( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + output_dir = os.path.dirname(outputs["out_file"]) + + if (inputs.stats_imgs is not attrs.NOTHING) and inputs.stats_imgs: + if LooseVersion(Info.version()) < LooseVersion("6.0.0"): + # FSL <6.0 outputs have .nii.gz_variance.nii.gz as extension + outputs["variance_img"] = _gen_fname( + outputs["out_file"] + "_variance.ext", + cwd=output_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["std_img"] = _gen_fname( + outputs["out_file"] + "_sigma.ext", + cwd=output_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + else: + outputs["variance_img"] = _gen_fname( + outputs["out_file"], + suffix="_variance", + cwd=output_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["std_img"] = _gen_fname( + outputs["out_file"], + suffix="_sigma", + cwd=output_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + + # The mean image created if -stats option is specified ('meanvol') + # is missing the top and bottom slices. Therefore we only expose the + # mean image created by -meanvol option ('mean_reg') which isn't + # corrupted. + # Note that the same problem holds for the std and variance image. + + if (inputs.mean_vol is not attrs.NOTHING) and inputs.mean_vol: + if LooseVersion(Info.version()) < LooseVersion("6.0.0"): + # FSL <6.0 outputs have .nii.gz_mean_img.nii.gz as extension + outputs["mean_img"] = _gen_fname( + outputs["out_file"] + "_mean_reg.ext", + cwd=output_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + else: + outputs["mean_img"] = _gen_fname( + outputs["out_file"], + suffix="_mean_reg", + cwd=output_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + + if (inputs.save_mats is not attrs.NOTHING) and inputs.save_mats: + _, filename = os.path.split(outputs["out_file"]) + matpathname = os.path.join(output_dir, filename + ".mat") + _, _, _, timepoints = load(inputs.in_file).shape + outputs["mat_file"] = [] + for t in range(timepoints): + outputs["mat_file"].append(os.path.join(matpathname, "MAT_%04d" % t)) + if (inputs.save_plots is not attrs.NOTHING) and inputs.save_plots: + # Note - if e.g. out_file has .nii.gz, you get .nii.gz.par, + # which is what mcflirt does! + outputs["par_file"] = outputs["out_file"] + ".par" + if (inputs.save_rms is not attrs.NOTHING) and inputs.save_rms: + outfile = outputs["out_file"] + outputs["rms_files"] = [outfile + "_abs.rms", outfile + "_rel.rms"] + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/mean_image.yaml b/nipype-auto-conv/specs/mean_image.yaml new file mode 100644 index 0000000..78394bf --- /dev/null +++ b/nipype-auto-conv/specs/mean_image.yaml @@ -0,0 +1,95 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.MeanImage' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to generate a mean image across a given dimension. +task_name: MeanImage +nipype_name: MeanImage +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dimension: + # type=enum|default='T'|allowed['T','X','Y','Z']: dimension to mean across + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/mean_image_callables.py b/nipype-auto-conv/specs/mean_image_callables.py new file mode 100644 index 0000000..5943cf3 --- /dev/null +++ b/nipype-auto-conv/specs/mean_image_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of MeanImage.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/median_image.yaml b/nipype-auto-conv/specs/median_image.yaml new file mode 100644 index 0000000..e297a4a --- /dev/null +++ b/nipype-auto-conv/specs/median_image.yaml @@ -0,0 +1,95 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.MedianImage' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to generate a median image across a given dimension. +task_name: MedianImage +nipype_name: MedianImage +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dimension: + # type=enum|default='T'|allowed['T','X','Y','Z']: dimension to median across + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/median_image_callables.py b/nipype-auto-conv/specs/median_image_callables.py new file mode 100644 index 0000000..ac60356 --- /dev/null +++ b/nipype-auto-conv/specs/median_image_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of MedianImage.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/melodic.yaml b/nipype-auto-conv/specs/melodic.yaml new file mode 100644 index 0000000..e6c7c27 --- /dev/null +++ b/nipype-auto-conv/specs/melodic.yaml @@ -0,0 +1,297 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.MELODIC' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Multivariate Exploratory Linear Optimised Decomposition into Independent +# Components +# +# Examples +# -------- +# +# >>> melodic_setup = MELODIC() +# >>> melodic_setup.inputs.approach = 'tica' +# >>> melodic_setup.inputs.in_files = ['functional.nii', 'functional2.nii', 'functional3.nii'] +# >>> melodic_setup.inputs.no_bet = True +# >>> melodic_setup.inputs.bg_threshold = 10 +# >>> melodic_setup.inputs.tr_sec = 1.5 +# >>> melodic_setup.inputs.mm_thresh = 0.5 +# >>> melodic_setup.inputs.out_stats = True +# >>> melodic_setup.inputs.t_des = 'timeDesign.mat' +# >>> melodic_setup.inputs.t_con = 'timeDesign.con' +# >>> melodic_setup.inputs.s_des = 'subjectDesign.mat' +# >>> melodic_setup.inputs.s_con = 'subjectDesign.con' +# >>> melodic_setup.inputs.out_dir = 'groupICA.out' +# >>> melodic_setup.cmdline +# 'melodic -i functional.nii,functional2.nii,functional3.nii -a tica --bgthreshold=10.000000 --mmthresh=0.500000 --nobet -o groupICA.out --Ostats --Scon=subjectDesign.con --Sdes=subjectDesign.mat --Tcon=timeDesign.con --Tdes=timeDesign.mat --tr=1.500000' +# >>> melodic_setup.run() # doctest: +SKIP +# +# +# +task_name: MELODIC +nipype_name: MELODIC +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + ICs: generic/file + # type=file|default=: filename of the IC components file for mixture modelling + bg_image: generic/file + # type=file|default=: specify background image for report (default: mean image) + in_files: medimage/nifti1+list-of + # type=inputmultiobject|default=[]: input file names (either single file name or a list) + mask: generic/file + # type=file|default=: file name of mask for thresholding + mix: generic/file + # type=file|default=: mixing matrix for mixture modelling / filtering + out_dir: Path + # type=directory: + # type=directory|default=: output directory name + s_con: medimage-fsl/con + # type=file|default=: t-contrast matrix across subject-domain + s_des: datascience/text-matrix + # type=file|default=: design matrix across subject-domain + smode: generic/file + # type=file|default=: matrix of session modes for report generation + t_con: medimage-fsl/con + # type=file|default=: t-contrast matrix across time-domain + t_des: datascience/text-matrix + # type=file|default=: design matrix across time-domain + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_dir: '"groupICA.out"' + # type=directory: + # type=directory|default=: output directory name + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=inputmultiobject|default=[]: input file names (either single file name or a list) + out_dir: + # type=directory: + # type=directory|default=: output directory name + mask: + # type=file|default=: file name of mask for thresholding + no_mask: + # type=bool|default=False: switch off masking + update_mask: + # type=bool|default=False: switch off mask updating + no_bet: + # type=bool|default=False: switch off BET + bg_threshold: + # type=float|default=0.0: brain/non-brain threshold used to mask non-brain voxels, as a percentage (only if --nobet selected) + dim: + # type=int|default=0: dimensionality reduction into #num dimensions (default: automatic estimation) + dim_est: + # type=str|default='': use specific dim. estimation technique: lap, bic, mdl, aic, mean (default: lap) + sep_whiten: + # type=bool|default=False: switch on separate whitening + sep_vn: + # type=bool|default=False: switch off joined variance normalization + migp: + # type=bool|default=False: switch on MIGP data reduction + migpN: + # type=int|default=0: number of internal Eigenmaps + migp_shuffle: + # type=bool|default=False: randomise MIGP file order (default: TRUE) + migp_factor: + # type=int|default=0: Internal Factor of mem-threshold relative to number of Eigenmaps (default: 2) + num_ICs: + # type=int|default=0: number of IC's to extract (for deflation approach) + approach: + # type=str|default='': approach for decomposition, 2D: defl, symm (default), 3D: tica (default), concat + non_linearity: + # type=str|default='': nonlinearity: gauss, tanh, pow3, pow4 + var_norm: + # type=bool|default=False: switch off variance normalization + pbsc: + # type=bool|default=False: switch off conversion to percent BOLD signal change + cov_weight: + # type=float|default=0.0: voxel-wise weights for the covariance matrix (e.g. segmentation information) + epsilon: + # type=float|default=0.0: minimum error change + epsilonS: + # type=float|default=0.0: minimum error change for rank-1 approximation in TICA + maxit: + # type=int|default=0: maximum number of iterations before restart + max_restart: + # type=int|default=0: maximum number of restarts + mm_thresh: + # type=float|default=0.0: threshold for Mixture Model based inference + no_mm: + # type=bool|default=False: switch off mixture modelling on IC maps + ICs: + # type=file|default=: filename of the IC components file for mixture modelling + mix: + # type=file|default=: mixing matrix for mixture modelling / filtering + smode: + # type=file|default=: matrix of session modes for report generation + rem_cmp: + # type=list|default=[]: component numbers to remove + report: + # type=bool|default=False: generate Melodic web report + bg_image: + # type=file|default=: specify background image for report (default: mean image) + tr_sec: + # type=float|default=0.0: TR in seconds + log_power: + # type=bool|default=False: calculate log of power for frequency spectrum + t_des: + # type=file|default=: design matrix across time-domain + t_con: + # type=file|default=: t-contrast matrix across time-domain + s_des: + # type=file|default=: design matrix across subject-domain + s_con: + # type=file|default=: t-contrast matrix across subject-domain + out_all: + # type=bool|default=False: output everything + out_unmix: + # type=bool|default=False: output unmixing matrix + out_stats: + # type=bool|default=False: output thresholded maps and probability maps + out_pca: + # type=bool|default=False: output PCA results + out_white: + # type=bool|default=False: output whitening/dewhitening matrices + out_orig: + # type=bool|default=False: output the original ICs + out_mean: + # type=bool|default=False: output mean volume + report_maps: + # type=str|default='': control string for spatial map images (see slicer) + remove_deriv: + # type=bool|default=False: removes every second entry in paradigm file (EV derivatives) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + approach: '"tica"' + # type=str|default='': approach for decomposition, 2D: defl, symm (default), 3D: tica (default), concat + in_files: + # type=inputmultiobject|default=[]: input file names (either single file name or a list) + no_bet: 'True' + # type=bool|default=False: switch off BET + bg_threshold: '10' + # type=float|default=0.0: brain/non-brain threshold used to mask non-brain voxels, as a percentage (only if --nobet selected) + tr_sec: '1.5' + # type=float|default=0.0: TR in seconds + mm_thresh: '0.5' + # type=float|default=0.0: threshold for Mixture Model based inference + out_stats: 'True' + # type=bool|default=False: output thresholded maps and probability maps + t_des: + # type=file|default=: design matrix across time-domain + t_con: + # type=file|default=: t-contrast matrix across time-domain + s_des: + # type=file|default=: design matrix across subject-domain + s_con: + # type=file|default=: t-contrast matrix across subject-domain + out_dir: '"groupICA.out"' + # type=directory: + # type=directory|default=: output directory name + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: melodic -i functional.nii,functional2.nii,functional3.nii -a tica --bgthreshold=10.000000 --mmthresh=0.500000 --nobet -o groupICA.out --Ostats --Scon=subjectDesign.con --Sdes=subjectDesign.mat --Tcon=timeDesign.con --Tdes=timeDesign.mat --tr=1.500000 + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + approach: '"tica"' + # type=str|default='': approach for decomposition, 2D: defl, symm (default), 3D: tica (default), concat + in_files: '["functional.nii", "functional2.nii", "functional3.nii"]' + # type=inputmultiobject|default=[]: input file names (either single file name or a list) + no_bet: 'True' + # type=bool|default=False: switch off BET + bg_threshold: '10' + # type=float|default=0.0: brain/non-brain threshold used to mask non-brain voxels, as a percentage (only if --nobet selected) + tr_sec: '1.5' + # type=float|default=0.0: TR in seconds + mm_thresh: '0.5' + # type=float|default=0.0: threshold for Mixture Model based inference + out_stats: 'True' + # type=bool|default=False: output thresholded maps and probability maps + t_des: '"timeDesign.mat"' + # type=file|default=: design matrix across time-domain + t_con: '"timeDesign.con"' + # type=file|default=: t-contrast matrix across time-domain + s_des: '"subjectDesign.mat"' + # type=file|default=: design matrix across subject-domain + s_con: '"subjectDesign.con"' + # type=file|default=: t-contrast matrix across subject-domain + out_dir: '"groupICA.out"' + # type=directory: + # type=directory|default=: output directory name + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/melodic_callables.py b/nipype-auto-conv/specs/melodic_callables.py new file mode 100644 index 0000000..9ab73a8 --- /dev/null +++ b/nipype-auto-conv/specs/melodic_callables.py @@ -0,0 +1,46 @@ +"""Module to put any functions that are referred to in the "callables" section of MELODIC.yaml""" + +import attrs +import os + + +def out_dir_default(inputs): + return _gen_filename("out_dir", inputs=inputs) + + +def out_dir_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_dir"] + + +def report_dir_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["report_dir"] + + +# Original source at L1858 of /interfaces/fsl/model.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_dir": + return output_dir + + +# Original source at L1848 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + if inputs.out_dir is not attrs.NOTHING: + outputs["out_dir"] = os.path.abspath(inputs.out_dir) + else: + outputs["out_dir"] = _gen_filename( + "out_dir", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if (inputs.report is not attrs.NOTHING) and inputs.report: + outputs["report_dir"] = os.path.join(outputs["out_dir"], "report") + return outputs diff --git a/nipype-auto-conv/specs/merge.yaml b/nipype-auto-conv/specs/merge.yaml new file mode 100644 index 0000000..6dd97e4 --- /dev/null +++ b/nipype-auto-conv/specs/merge.yaml @@ -0,0 +1,157 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.Merge' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmerge to concatenate images +# +# Images can be concatenated across time, x, y, or z dimensions. Across the +# time (t) dimension the TR is set by default to 1 sec. +# +# Note: to set the TR to a different value, specify 't' for dimension and +# specify the TR value in seconds for the tr input. The dimension will be +# automatically updated to 'tr'. +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import Merge +# >>> merger = Merge() +# >>> merger.inputs.in_files = ['functional2.nii', 'functional3.nii'] +# >>> merger.inputs.dimension = 't' +# >>> merger.inputs.output_type = 'NIFTI_GZ' +# >>> merger.cmdline +# 'fslmerge -t functional2_merged.nii.gz functional2.nii functional3.nii' +# >>> merger.inputs.tr = 2.25 +# >>> merger.cmdline +# 'fslmerge -tr functional2_merged.nii.gz functional2.nii functional3.nii 2.25' +# +# +# +task_name: Merge +nipype_name: Merge +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_files: medimage/nifti1+list-of + # type=list|default=[]: + merged_file: Path + # type=file: + # type=file|default=: + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + merged_file: generic/file + # type=file: + # type=file|default=: + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=list|default=[]: + dimension: + # type=enum|default='t'|allowed['a','t','x','y','z']: dimension along which to merge, optionally set tr input when dimension is t + tr: + # type=float|default=0.0: use to specify TR in seconds (default is 1.00 sec), overrides dimension and sets it to tr + merged_file: + # type=file: + # type=file|default=: + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=list|default=[]: + dimension: '"t"' + # type=enum|default='t'|allowed['a','t','x','y','z']: dimension along which to merge, optionally set tr input when dimension is t + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + tr: '2.25' + # type=float|default=0.0: use to specify TR in seconds (default is 1.00 sec), overrides dimension and sets it to tr + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fslmerge -tr functional2_merged.nii.gz functional2.nii functional3.nii 2.25 + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_files: '["functional2.nii", "functional3.nii"]' + # type=list|default=[]: + dimension: '"t"' + # type=enum|default='t'|allowed['a','t','x','y','z']: dimension along which to merge, optionally set tr input when dimension is t + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + tr: '2.25' + # type=float|default=0.0: use to specify TR in seconds (default is 1.00 sec), overrides dimension and sets it to tr + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/merge_callables.py b/nipype-auto-conv/specs/merge_callables.py new file mode 100644 index 0000000..efab957 --- /dev/null +++ b/nipype-auto-conv/specs/merge_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of Merge.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def merged_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["merged_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/min_image.yaml b/nipype-auto-conv/specs/min_image.yaml new file mode 100644 index 0000000..3b50baa --- /dev/null +++ b/nipype-auto-conv/specs/min_image.yaml @@ -0,0 +1,95 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.MinImage' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to generate a minimum image across a given dimension. +task_name: MinImage +nipype_name: MinImage +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dimension: + # type=enum|default='T'|allowed['T','X','Y','Z']: dimension to min across + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/min_image_callables.py b/nipype-auto-conv/specs/min_image_callables.py new file mode 100644 index 0000000..9cde1b9 --- /dev/null +++ b/nipype-auto-conv/specs/min_image_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of MinImage.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/motion_outliers.yaml b/nipype-auto-conv/specs/motion_outliers.yaml new file mode 100644 index 0000000..0c8650c --- /dev/null +++ b/nipype-auto-conv/specs/motion_outliers.yaml @@ -0,0 +1,157 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.MotionOutliers' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Use FSL fsl_motion_outliers`http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FSLMotionOutliers`_ to find outliers in timeseries (4d) data. +# Examples +# -------- +# >>> from nipype.interfaces.fsl import MotionOutliers +# >>> mo = MotionOutliers() +# >>> mo.inputs.in_file = "epi.nii" +# >>> mo.cmdline # doctest: +ELLIPSIS +# 'fsl_motion_outliers -i epi.nii -o epi_outliers.txt -p epi_metrics.png -s epi_metrics.txt' +# >>> res = mo.run() # doctest: +SKIP +# +task_name: MotionOutliers +nipype_name: MotionOutliers +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: unfiltered 4D image + mask: generic/file + # type=file|default=: mask image for calculating metric + out_file: Path + # type=file: + # type=file|default=: output outlier file name + out_metric_plot: Path + # type=file: + # type=file|default=: output metric values plot (DVARS etc.) file name + out_metric_values: Path + # type=file: + # type=file|default=: output metric values (DVARS etc.) file name + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: + # type=file|default=: output outlier file name + out_metric_plot: generic/file + # type=file: + # type=file|default=: output metric values plot (DVARS etc.) file name + out_metric_values: generic/file + # type=file: + # type=file|default=: output metric values (DVARS etc.) file name + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: unfiltered 4D image + out_file: + # type=file: + # type=file|default=: output outlier file name + mask: + # type=file|default=: mask image for calculating metric + metric: + # type=enum|default='refrms'|allowed['dvars','fd','fdrms','refmse','refrms']: metrics: refrms - RMS intensity difference to reference volume as metric [default metric], refmse - Mean Square Error version of refrms (used in original version of fsl_motion_outliers), dvars - DVARS, fd - frame displacement, fdrms - FD with RMS matrix calculation + threshold: + # type=float|default=0.0: specify absolute threshold value (otherwise use box-plot cutoff = P75 + 1.5*IQR) + no_motion_correction: + # type=bool|default=False: do not run motion correction (assumed already done) + dummy: + # type=int|default=0: number of dummy scans to delete (before running anything and creating EVs) + out_metric_values: + # type=file: + # type=file|default=: output metric values (DVARS etc.) file name + out_metric_plot: + # type=file: + # type=file|default=: output metric values plot (DVARS etc.) file name + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: unfiltered 4D image + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fsl_motion_outliers -i epi.nii -o epi_outliers.txt -p epi_metrics.png -s epi_metrics.txt + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"epi.nii"' + # type=file|default=: unfiltered 4D image + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/motion_outliers_callables.py b/nipype-auto-conv/specs/motion_outliers_callables.py new file mode 100644 index 0000000..09bc820 --- /dev/null +++ b/nipype-auto-conv/specs/motion_outliers_callables.py @@ -0,0 +1,352 @@ +"""Module to put any functions that are referred to in the "callables" section of MotionOutliers.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +def out_metric_plot_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_metric_plot"] + + +def out_metric_values_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_metric_values"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/multi_image_maths.yaml b/nipype-auto-conv/specs/multi_image_maths.yaml new file mode 100644 index 0000000..17e28ce --- /dev/null +++ b/nipype-auto-conv/specs/multi_image_maths.yaml @@ -0,0 +1,159 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.MultiImageMaths' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to perform a sequence of mathematical operations. +# +# Examples +# -------- +# >>> from nipype.interfaces.fsl import MultiImageMaths +# >>> maths = MultiImageMaths() +# >>> maths.inputs.in_file = "functional.nii" +# >>> maths.inputs.op_string = "-add %s -mul -1 -div %s" +# >>> maths.inputs.operand_files = ["functional2.nii", "functional3.nii"] +# >>> maths.inputs.out_file = "functional4.nii" +# >>> maths.cmdline +# 'fslmaths functional.nii -add functional2.nii -mul -1 -div functional3.nii functional4.nii' +# +# +task_name: MultiImageMaths +nipype_name: MultiImageMaths +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: image to operate on + operand_files: medimage/nifti1+list-of + # type=inputmultiobject|default=[]: list of file names to plug into op string + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: medimage/nifti1 + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: '"functional4.nii"' + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + op_string: + # type=string|default='': python formatted string of operations to perform + operand_files: + # type=inputmultiobject|default=[]: list of file names to plug into op string + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: image to operate on + op_string: '"-add %s -mul -1 -div %s"' + # type=string|default='': python formatted string of operations to perform + operand_files: + # type=inputmultiobject|default=[]: list of file names to plug into op string + out_file: '"functional4.nii"' + # type=file: image written after calculations + # type=file|default=: image to write + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fslmaths functional.nii -add functional2.nii -mul -1 -div functional3.nii functional4.nii + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"functional.nii"' + # type=file|default=: image to operate on + op_string: '"-add %s -mul -1 -div %s"' + # type=string|default='': python formatted string of operations to perform + operand_files: '["functional2.nii", "functional3.nii"]' + # type=inputmultiobject|default=[]: list of file names to plug into op string + out_file: '"functional4.nii"' + # type=file: image written after calculations + # type=file|default=: image to write + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/multi_image_maths_callables.py b/nipype-auto-conv/specs/multi_image_maths_callables.py new file mode 100644 index 0000000..9b5eedb --- /dev/null +++ b/nipype-auto-conv/specs/multi_image_maths_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of MultiImageMaths.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/multiple_regress_design.yaml b/nipype-auto-conv/specs/multiple_regress_design.yaml new file mode 100644 index 0000000..38e5a82 --- /dev/null +++ b/nipype-auto-conv/specs/multiple_regress_design.yaml @@ -0,0 +1,97 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.MultipleRegressDesign' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Generate multiple regression design +# +# .. note:: +# FSL does not demean columns for higher level analysis. +# +# Please see `FSL documentation +# `_ +# for more details on model specification for higher level analysis. +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import MultipleRegressDesign +# >>> model = MultipleRegressDesign() +# >>> model.inputs.contrasts = [['group mean', 'T',['reg1'],[1]]] +# >>> model.inputs.regressors = dict(reg1=[1, 1, 1], reg2=[2.,-4, 3]) +# >>> model.run() # doctest: +SKIP +# +# +task_name: MultipleRegressDesign +nipype_name: MultipleRegressDesign +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + design_con: generic/file + # type=file: design t-contrast file + design_fts: generic/file + # type=file: design f-contrast file + design_grp: generic/file + # type=file: design group file + design_mat: generic/file + # type=file: design matrix file + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + contrasts: + # type=list|default=[]: List of contrasts with each contrast being a list of the form - [('name', 'stat', [condition list], [weight list])]. if session list is None or not provided, all sessions are used. For F contrasts, the condition list should contain previously defined T-contrasts without any weight list. + regressors: + # type=dict|default={}: dictionary containing named lists of regressors + groups: + # type=list|default=[]: list of group identifiers (defaults to single group) + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/multiple_regress_design_callables.py b/nipype-auto-conv/specs/multiple_regress_design_callables.py new file mode 100644 index 0000000..a295709 --- /dev/null +++ b/nipype-auto-conv/specs/multiple_regress_design_callables.py @@ -0,0 +1,42 @@ +"""Module to put any functions that are referred to in the "callables" section of MultipleRegressDesign.yaml""" + +import os + + +def design_con_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["design_con"] + + +def design_fts_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["design_fts"] + + +def design_grp_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["design_grp"] + + +def design_mat_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["design_mat"] + + +# Original source at L1600 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + nfcons = sum([1 for con in inputs.contrasts if con[1] == "F"]) + for field in list(outputs.keys()): + if ("fts" in field) and (nfcons == 0): + continue + outputs[field] = os.path.join(output_dir, field.replace("_", ".")) + return outputs diff --git a/nipype-auto-conv/specs/overlay.yaml b/nipype-auto-conv/specs/overlay.yaml new file mode 100644 index 0000000..6ffac87 --- /dev/null +++ b/nipype-auto-conv/specs/overlay.yaml @@ -0,0 +1,130 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.Overlay' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL's overlay command to combine background and statistical images +# into one volume +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces import fsl +# >>> combine = fsl.Overlay() +# >>> combine.inputs.background_image = 'mean_func.nii.gz' +# >>> combine.inputs.auto_thresh_bg = True +# >>> combine.inputs.stat_image = 'zstat1.nii.gz' +# >>> combine.inputs.stat_thresh = (3.5, 10) +# >>> combine.inputs.show_negative_stats = True +# >>> res = combine.run() #doctest: +SKIP +# +# +# +task_name: Overlay +nipype_name: Overlay +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + background_image: generic/file + # type=file|default=: image to use as background + out_file: Path + # type=file: combined image volume + # type=file|default=: combined image volume + stat_image: generic/file + # type=file|default=: statistical image to overlay in color + stat_image2: generic/file + # type=file|default=: second statistical image to overlay in color + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: combined image volume + # type=file|default=: combined image volume + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: combined image volume + # type=file|default=: combined image volume + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + transparency: + # type=bool|default=True: make overlay colors semi-transparent + out_type: + # type=enum|default='float'|allowed['float','int']: write output with float or int + use_checkerboard: + # type=bool|default=False: use checkerboard mask for overlay + background_image: + # type=file|default=: image to use as background + auto_thresh_bg: + # type=bool|default=False: automatically threshold the background image + full_bg_range: + # type=bool|default=False: use full range of background image + bg_thresh: + # type=tuple|default=(0.0, 0.0): min and max values for background intensity + stat_image: + # type=file|default=: statistical image to overlay in color + stat_thresh: + # type=tuple|default=(0.0, 0.0): min and max values for the statistical overlay + show_negative_stats: + # type=bool|default=False: display negative statistics in overlay + stat_image2: + # type=file|default=: second statistical image to overlay in color + stat_thresh2: + # type=tuple|default=(0.0, 0.0): min and max values for second statistical overlay + out_file: + # type=file: combined image volume + # type=file|default=: combined image volume + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/overlay_callables.py b/nipype-auto-conv/specs/overlay_callables.py new file mode 100644 index 0000000..a56187c --- /dev/null +++ b/nipype-auto-conv/specs/overlay_callables.py @@ -0,0 +1,339 @@ +"""Module to put any functions that are referred to in the "callables" section of Overlay.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1098 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "overlay" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1080 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + out_file = inputs.out_file + if out_file is attrs.NOTHING: + if (inputs.stat_image2 is not attrs.NOTHING) and ( + (inputs.show_negative_stats is attrs.NOTHING) + or not inputs.show_negative_stats + ): + stem = "%s_and_%s" % ( + split_filename(inputs.stat_image)[1], + split_filename(inputs.stat_image2)[1], + ) + else: + stem = split_filename(inputs.stat_image)[1] + out_file = _gen_fname( + stem, + suffix="_overlay", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(out_file) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/percentile_image.yaml b/nipype-auto-conv/specs/percentile_image.yaml new file mode 100644 index 0000000..d57bf3b --- /dev/null +++ b/nipype-auto-conv/specs/percentile_image.yaml @@ -0,0 +1,142 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.PercentileImage' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to generate a percentile image across a given dimension. +# +# Examples +# -------- +# >>> from nipype.interfaces.fsl.maths import MaxImage +# >>> percer = PercentileImage() +# >>> percer.inputs.in_file = "functional.nii" # doctest: +SKIP +# >>> percer.dimension = "T" +# >>> percer.perc = 90 +# >>> percer.cmdline # doctest: +SKIP +# 'fslmaths functional.nii -Tperc 90 functional_perc.nii' +# +# +task_name: PercentileImage +nipype_name: PercentileImage +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dimension: + # type=enum|default='T'|allowed['T','X','Y','Z']: dimension to percentile across + perc: + # type=range|default=0: nth percentile (0-100) of FULL RANGE across dimension + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: image to operate on + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fslmaths functional.nii -Tperc 90 functional_perc.nii + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"functional.nii" # doctest: +SKIP' + # type=file|default=: image to operate on + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/percentile_image_callables.py b/nipype-auto-conv/specs/percentile_image_callables.py new file mode 100644 index 0000000..a86a925 --- /dev/null +++ b/nipype-auto-conv/specs/percentile_image_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of PercentileImage.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/plot_motion_params.yaml b/nipype-auto-conv/specs/plot_motion_params.yaml new file mode 100644 index 0000000..c375af6 --- /dev/null +++ b/nipype-auto-conv/specs/plot_motion_params.yaml @@ -0,0 +1,116 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.PlotMotionParams' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fsl_tsplot to plot the estimated motion parameters from a +# realignment program. +# +# +# Examples +# -------- +# +# >>> import nipype.interfaces.fsl as fsl +# >>> plotter = fsl.PlotMotionParams() +# >>> plotter.inputs.in_file = 'functional.par' +# >>> plotter.inputs.in_source = 'fsl' +# >>> plotter.inputs.plot_type = 'rotations' +# >>> res = plotter.run() #doctest: +SKIP +# +# +# Notes +# ----- +# +# The 'in_source' attribute determines the order of columns that are expected +# in the source file. FSL prints motion parameters in the order rotations, +# translations, while SPM prints them in the opposite order. This interface +# should be able to plot timecourses of motion parameters generated from +# other sources as long as they fall under one of these two patterns. For +# more flexibility, see the :class:`fsl.PlotTimeSeries` interface. +# +# +task_name: PlotMotionParams +nipype_name: PlotMotionParams +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: Path + # type=file: image to write + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image to write + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image to write + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=traitcompound|default=None: file with motion parameters + in_source: + # type=enum|default='spm'|allowed['fsl','spm']: which program generated the motion parameter file - fsl, spm + plot_type: + # type=enum|default='rotations'|allowed['displacement','rotations','translations']: which motion type to plot - rotations, translations, displacement + plot_size: + # type=tuple|default=(0, 0): plot image height and width + out_file: + # type=file: image to write + # type=file|default=: image to write + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/plot_motion_params_callables.py b/nipype-auto-conv/specs/plot_motion_params_callables.py new file mode 100644 index 0000000..d632bf6 --- /dev/null +++ b/nipype-auto-conv/specs/plot_motion_params_callables.py @@ -0,0 +1,135 @@ +"""Module to put any functions that are referred to in the "callables" section of PlotMotionParams.yaml""" + +import attrs +import os +import os.path as op +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +# Original source at L1495 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L1478 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + out_file = inputs.out_file + if out_file is attrs.NOTHING: + if isinstance(inputs.in_file, list): + infile = inputs.in_file[0] + else: + infile = inputs.in_file + plttype = dict(rot="rot", tra="trans", dis="disp")[inputs.plot_type[:3]] + out_file = fname_presuffix(infile, suffix="_%s.png" % plttype, use_ext=False) + outputs["out_file"] = os.path.abspath(out_file) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext diff --git a/nipype-auto-conv/specs/plot_time_series.yaml b/nipype-auto-conv/specs/plot_time_series.yaml new file mode 100644 index 0000000..17abf1a --- /dev/null +++ b/nipype-auto-conv/specs/plot_time_series.yaml @@ -0,0 +1,126 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.PlotTimeSeries' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fsl_tsplot to create images of time course plots. +# +# Examples +# -------- +# +# >>> import nipype.interfaces.fsl as fsl +# >>> plotter = fsl.PlotTimeSeries() +# >>> plotter.inputs.in_file = 'functional.par' +# >>> plotter.inputs.title = 'Functional timeseries' +# >>> plotter.inputs.labels = ['run1', 'run2'] +# >>> plotter.run() #doctest: +SKIP +# +# +# +task_name: PlotTimeSeries +nipype_name: PlotTimeSeries +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + legend_file: generic/file + # type=file|default=: legend file + out_file: Path + # type=file: image to write + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image to write + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image to write + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=traitcompound|default=None: file or list of files with columns of timecourse information + plot_start: + # type=int|default=0: first column from in-file to plot + plot_finish: + # type=int|default=0: final column from in-file to plot + plot_range: + # type=tuple|default=(0, 0): first and last columns from the in-file to plot + title: + # type=str|default='': plot title + legend_file: + # type=file|default=: legend file + labels: + # type=traitcompound|default=None: label or list of labels + y_min: + # type=float|default=0.0: minimum y value + y_max: + # type=float|default=0.0: maximum y value + y_range: + # type=tuple|default=(0.0, 0.0): min and max y axis values + x_units: + # type=int|default=1: scaling units for x-axis (between 1 and length of in file) + plot_size: + # type=tuple|default=(0, 0): plot image height and width + x_precision: + # type=int|default=0: precision of x-axis labels + sci_notation: + # type=bool|default=False: switch on scientific notation + out_file: + # type=file: image to write + # type=file|default=: image to write + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/plot_time_series_callables.py b/nipype-auto-conv/specs/plot_time_series_callables.py new file mode 100644 index 0000000..bd4ce1e --- /dev/null +++ b/nipype-auto-conv/specs/plot_time_series_callables.py @@ -0,0 +1,333 @@ +"""Module to put any functions that are referred to in the "callables" section of PlotTimeSeries.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1367 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fsl_tsplot" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1355 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + out_file = inputs.out_file + if out_file is attrs.NOTHING: + if isinstance(inputs.in_file, list): + infile = inputs.in_file[0] + else: + infile = inputs.in_file + out_file = _gen_fname( + infile, + ext=".png", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(out_file) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/power_spectrum.yaml b/nipype-auto-conv/specs/power_spectrum.yaml new file mode 100644 index 0000000..8375cfe --- /dev/null +++ b/nipype-auto-conv/specs/power_spectrum.yaml @@ -0,0 +1,98 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.PowerSpectrum' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL PowerSpectrum command for power spectrum estimation. +# +# Examples +# -------- +# +# >>> from nipype.interfaces import fsl +# >>> pspec = fsl.PowerSpectrum() +# >>> pspec.inputs.in_file = 'functional.nii' +# >>> res = pspec.run() # doctest: +SKIP +# +# +# +task_name: PowerSpectrum +nipype_name: PowerSpectrum +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: input 4D file to estimate the power spectrum + out_file: Path + # type=file: path/name of the output 4D power spectrum file + # type=file|default=: name of output 4D file for power spectrum + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: path/name of the output 4D power spectrum file + # type=file|default=: name of output 4D file for power spectrum + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: path/name of the output 4D power spectrum file + # type=file|default=: name of output 4D file for power spectrum + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input 4D file to estimate the power spectrum + out_file: + # type=file: path/name of the output 4D power spectrum file + # type=file|default=: name of output 4D file for power spectrum + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/power_spectrum_callables.py b/nipype-auto-conv/specs/power_spectrum_callables.py new file mode 100644 index 0000000..126f6e6 --- /dev/null +++ b/nipype-auto-conv/specs/power_spectrum_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of PowerSpectrum.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1700 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _gen_outfilename( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslpspec" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1689 of /interfaces/fsl/utils.py +def _gen_outfilename(inputs=None, stdout=None, stderr=None, output_dir=None): + out_file = inputs.out_file + if (out_file is attrs.NOTHING) and (inputs.in_file is not attrs.NOTHING): + out_file = _gen_fname( + inputs.in_file, + suffix="_ps", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return out_file + + +# Original source at L1695 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = os.path.abspath( + _gen_outfilename( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/prelude.yaml b/nipype-auto-conv/specs/prelude.yaml new file mode 100644 index 0000000..e4148fc --- /dev/null +++ b/nipype-auto-conv/specs/prelude.yaml @@ -0,0 +1,134 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.PRELUDE' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL prelude wrapper for phase unwrapping +# +# Examples +# -------- +# +# Please insert examples for use of this command +# +# +task_name: PRELUDE +nipype_name: PRELUDE +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + complex_phase_file: generic/file + # type=file|default=: complex phase input volume + label_file: generic/file + # type=file|default=: saving the area labels output + magnitude_file: generic/file + # type=file|default=: file containing magnitude image + mask_file: generic/file + # type=file|default=: filename of mask input volume + phase_file: generic/file + # type=file|default=: raw phase file + rawphase_file: generic/file + # type=file|default=: saving the raw phase output + savemask_file: generic/file + # type=file|default=: saving the mask volume + unwrapped_phase_file: Path + # type=file: unwrapped phase file + # type=file|default=: file containing unwrapepd phase + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + unwrapped_phase_file: generic/file + # type=file: unwrapped phase file + # type=file|default=: file containing unwrapepd phase + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + unwrapped_phase_file: unwrapped_phase_file + # type=file: unwrapped phase file + # type=file|default=: file containing unwrapepd phase + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + complex_phase_file: + # type=file|default=: complex phase input volume + magnitude_file: + # type=file|default=: file containing magnitude image + phase_file: + # type=file|default=: raw phase file + unwrapped_phase_file: + # type=file: unwrapped phase file + # type=file|default=: file containing unwrapepd phase + num_partitions: + # type=int|default=0: number of phase partitions to use + labelprocess2d: + # type=bool|default=False: does label processing in 2D (slice at a time) + process2d: + # type=bool|default=False: does all processing in 2D (slice at a time) + process3d: + # type=bool|default=False: forces all processing to be full 3D + threshold: + # type=float|default=0.0: intensity threshold for masking + mask_file: + # type=file|default=: filename of mask input volume + start: + # type=int|default=0: first image number to process (default 0) + end: + # type=int|default=0: final image number to process (default Inf) + savemask_file: + # type=file|default=: saving the mask volume + rawphase_file: + # type=file|default=: saving the raw phase output + label_file: + # type=file|default=: saving the area labels output + removeramps: + # type=bool|default=False: remove phase ramps during unwrapping + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/prelude_callables.py b/nipype-auto-conv/specs/prelude_callables.py new file mode 100644 index 0000000..3104d4a --- /dev/null +++ b/nipype-auto-conv/specs/prelude_callables.py @@ -0,0 +1,339 @@ +"""Module to put any functions that are referred to in the "callables" section of PRELUDE.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def unwrapped_phase_file_default(inputs): + return _gen_filename("unwrapped_phase_file", inputs=inputs) + + +def unwrapped_phase_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["unwrapped_phase_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L2115 of /interfaces/fsl/preprocess.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "unwrapped_phase_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["unwrapped_phase_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "prelude" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L2102 of /interfaces/fsl/preprocess.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + out_file = inputs.unwrapped_phase_file + if out_file is attrs.NOTHING: + if inputs.phase_file is not attrs.NOTHING: + out_file = _gen_fname( + inputs.phase_file, + suffix="_unwrapped", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + elif inputs.complex_phase_file is not attrs.NOTHING: + out_file = _gen_fname( + inputs.complex_phase_file, + suffix="_phase_unwrapped", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["unwrapped_phase_file"] = os.path.abspath(out_file) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/prepare_fieldmap.yaml b/nipype-auto-conv/specs/prepare_fieldmap.yaml new file mode 100644 index 0000000..bcd7324 --- /dev/null +++ b/nipype-auto-conv/specs/prepare_fieldmap.yaml @@ -0,0 +1,156 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.epi.PrepareFieldmap' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Interface for the fsl_prepare_fieldmap script (FSL 5.0) +# +# Prepares a fieldmap suitable for FEAT from SIEMENS data - saves output in +# rad/s format (e.g. ```fsl_prepare_fieldmap SIEMENS +# images_3_gre_field_mapping images_4_gre_field_mapping fmap_rads 2.65```). +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import PrepareFieldmap +# >>> prepare = PrepareFieldmap() +# >>> prepare.inputs.in_phase = "phase.nii" +# >>> prepare.inputs.in_magnitude = "magnitude.nii" +# >>> prepare.inputs.output_type = "NIFTI_GZ" +# >>> prepare.cmdline # doctest: +ELLIPSIS +# 'fsl_prepare_fieldmap SIEMENS phase.nii magnitude.nii .../phase_fslprepared.nii.gz 2.460000' +# >>> res = prepare.run() # doctest: +SKIP +# +# +# +task_name: PrepareFieldmap +nipype_name: PrepareFieldmap +nipype_module: nipype.interfaces.fsl.epi +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_magnitude: medimage/nifti1 + # type=file|default=: Magnitude difference map, brain extracted + in_phase: medimage/nifti1 + # type=file|default=: Phase difference map, in SIEMENS format range from 0-4096 or 0-8192) + out_fieldmap: Path + # type=file: output name for prepared fieldmap + # type=file|default=: output name for prepared fieldmap + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_fieldmap: generic/file + # type=file: output name for prepared fieldmap + # type=file|default=: output name for prepared fieldmap + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + scanner: + # type=string|default='SIEMENS': must be SIEMENS + in_phase: + # type=file|default=: Phase difference map, in SIEMENS format range from 0-4096 or 0-8192) + in_magnitude: + # type=file|default=: Magnitude difference map, brain extracted + delta_TE: + # type=float|default=2.46: echo time difference of the fieldmap sequence in ms. (usually 2.46ms in Siemens) + nocheck: + # type=bool|default=False: do not perform sanity checks for image size/range/dimensions + out_fieldmap: + # type=file: output name for prepared fieldmap + # type=file|default=: output name for prepared fieldmap + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_phase: + # type=file|default=: Phase difference map, in SIEMENS format range from 0-4096 or 0-8192) + in_magnitude: + # type=file|default=: Magnitude difference map, brain extracted + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fsl_prepare_fieldmap SIEMENS phase.nii magnitude.nii .../phase_fslprepared.nii.gz 2.460000 + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_phase: '"phase.nii"' + # type=file|default=: Phase difference map, in SIEMENS format range from 0-4096 or 0-8192) + in_magnitude: '"magnitude.nii"' + # type=file|default=: Magnitude difference map, brain extracted + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/prepare_fieldmap_callables.py b/nipype-auto-conv/specs/prepare_fieldmap_callables.py new file mode 100644 index 0000000..9b4e146 --- /dev/null +++ b/nipype-auto-conv/specs/prepare_fieldmap_callables.py @@ -0,0 +1,20 @@ +"""Module to put any functions that are referred to in the "callables" section of PrepareFieldmap.yaml""" + + +def out_fieldmap_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_fieldmap"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L110 of /interfaces/fsl/epi.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_fieldmap"] = inputs.out_fieldmap + return outputs diff --git a/nipype-auto-conv/specs/prob_track_x.yaml b/nipype-auto-conv/specs/prob_track_x.yaml new file mode 100644 index 0000000..f03ab34 --- /dev/null +++ b/nipype-auto-conv/specs/prob_track_x.yaml @@ -0,0 +1,284 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.ProbTrackX' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL probtrackx for tractography on bedpostx results +# +# Examples +# -------- +# +# >>> from nipype.interfaces import fsl +# >>> pbx = fsl.ProbTrackX(samples_base_name='merged', mask='mask.nii', seed='MASK_average_thal_right.nii', mode='seedmask', xfm='trans.mat', n_samples=3, n_steps=10, force_dir=True, opd=True, os2t=True, target_masks = ['targets_MASK1.nii', 'targets_MASK2.nii'], thsamples='merged_thsamples.nii', fsamples='merged_fsamples.nii', phsamples='merged_phsamples.nii', out_dir='.') +# >>> pbx.cmdline +# 'probtrackx --forcedir -m mask.nii --mode=seedmask --nsamples=3 --nsteps=10 --opd --os2t --dir=. --samples=merged --seed=MASK_average_thal_right.nii --targetmasks=targets.txt --xfm=trans.mat' +# +# +task_name: ProbTrackX +nipype_name: ProbTrackX +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + avoid_mp: generic/file + # type=file|default=: reject pathways passing through locations given by this mask + fsamples: medimage/nifti1+list-of + # type=inputmultiobject|default=[]: + inv_xfm: generic/file + # type=file|default=: transformation matrix taking DTI space to seed space (compulsory when using a warp_field for seeds_to_dti) + mask: medimage/nifti1 + # type=file|default=: bet binary mask file in diffusion space + mask2: generic/file + # type=file|default=: second bet binary mask (in diffusion space) in twomask_symm mode + mesh: generic/file + # type=file|default=: Freesurfer-type surface descriptor (in ascii format) + out_dir: Path + # type=directory|default=: directory to put the final volumes in + phsamples: medimage/nifti1+list-of + # type=inputmultiobject|default=[]: + seed_ref: generic/file + # type=file|default=: reference vol to define seed space in simple mode - diffusion space assumed if absent + stop_mask: generic/file + # type=file|default=: stop tracking at locations given by this mask file + target_masks: medimage/nifti1+list-of + # type=inputmultiobject|default=[]: list of target masks - required for seeds_to_targets classification + thsamples: medimage/nifti1+list-of + # type=inputmultiobject|default=[]: + waypoints: generic/file + # type=file|default=: waypoint mask or ascii list of waypoint masks - only keep paths going through ALL the masks + xfm: datascience/text-matrix + # type=file|default=: transformation matrix taking seed space to DTI space (either FLIRT matrix or FNIRT warp_field) - default is identity + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + mode: mode_default + # type=enum|default='simple'|allowed['seedmask','simple','two_mask_symm']: options: simple (single seed voxel), seedmask (mask of seed voxels), twomask_symm (two bet binary masks) + out_dir: out_dir_default + # type=directory|default=: directory to put the final volumes in + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + fdt_paths: generic/file+list-of + # type=outputmultiobject: path/name of a 3D image file containing the output connectivity distribution to the seed mask + log: generic/file + # type=file: path/name of a text record of the command that was run + particle_files: generic/file+list-of + # type=list: Files describing all of the tract samples. Generated only if verbose is set to 2 + targets: generic/file+list-of + # type=list: a list with all generated seeds_to_target files + way_total: generic/file + # type=file: path/name of a text file containing a single number corresponding to the total number of generated tracts that have not been rejected by inclusion/exclusion mask criteria + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + mode: + # type=enum|default='simple'|allowed['seedmask','simple','two_mask_symm']: options: simple (single seed voxel), seedmask (mask of seed voxels), twomask_symm (two bet binary masks) + mask2: + # type=file|default=: second bet binary mask (in diffusion space) in twomask_symm mode + mesh: + # type=file|default=: Freesurfer-type surface descriptor (in ascii format) + thsamples: + # type=inputmultiobject|default=[]: + phsamples: + # type=inputmultiobject|default=[]: + fsamples: + # type=inputmultiobject|default=[]: + samples_base_name: + # type=str|default='merged': the rootname/base_name for samples files + mask: + # type=file|default=: bet binary mask file in diffusion space + seed: + # type=traitcompound|default=None: seed volume(s), or voxel(s) or freesurfer label file + target_masks: + # type=inputmultiobject|default=[]: list of target masks - required for seeds_to_targets classification + waypoints: + # type=file|default=: waypoint mask or ascii list of waypoint masks - only keep paths going through ALL the masks + network: + # type=bool|default=False: activate network mode - only keep paths going through at least one seed mask (required if multiple seed masks) + seed_ref: + # type=file|default=: reference vol to define seed space in simple mode - diffusion space assumed if absent + out_dir: + # type=directory|default=: directory to put the final volumes in + force_dir: + # type=bool|default=True: use the actual directory name given - i.e. do not add + to make a new directory + opd: + # type=bool|default=True: outputs path distributions + correct_path_distribution: + # type=bool|default=False: correct path distribution for the length of the pathways + os2t: + # type=bool|default=False: Outputs seeds to targets + avoid_mp: + # type=file|default=: reject pathways passing through locations given by this mask + stop_mask: + # type=file|default=: stop tracking at locations given by this mask file + xfm: + # type=file|default=: transformation matrix taking seed space to DTI space (either FLIRT matrix or FNIRT warp_field) - default is identity + inv_xfm: + # type=file|default=: transformation matrix taking DTI space to seed space (compulsory when using a warp_field for seeds_to_dti) + n_samples: + # type=int|default=5000: number of samples - default=5000 + n_steps: + # type=int|default=0: number of steps per sample - default=2000 + dist_thresh: + # type=float|default=0.0: discards samples shorter than this threshold (in mm - default=0) + c_thresh: + # type=float|default=0.0: curvature threshold - default=0.2 + sample_random_points: + # type=float|default=0.0: sample random points within seed voxels + step_length: + # type=float|default=0.0: step_length in mm - default=0.5 + loop_check: + # type=bool|default=False: perform loop_checks on paths - slower, but allows lower curvature threshold + use_anisotropy: + # type=bool|default=False: use anisotropy to constrain tracking + rand_fib: + # type=enum|default=0|allowed[0,1,2,3]: options: 0 - default, 1 - to randomly sample initial fibres (with f > fibthresh), 2 - to sample in proportion fibres (with f>fibthresh) to f, 3 - to sample ALL populations at random (even if f: bet binary mask file in diffusion space + seed: '"MASK_average_thal_right.nii"' + # type=traitcompound|default=None: seed volume(s), or voxel(s) or freesurfer label file + mode: '"seedmask"' + # type=enum|default='simple'|allowed['seedmask','simple','two_mask_symm']: options: simple (single seed voxel), seedmask (mask of seed voxels), twomask_symm (two bet binary masks) + xfm: + # type=file|default=: transformation matrix taking seed space to DTI space (either FLIRT matrix or FNIRT warp_field) - default is identity + n_samples: '3' + # type=int|default=5000: number of samples - default=5000 + n_steps: '10' + # type=int|default=0: number of steps per sample - default=2000 + force_dir: 'True' + # type=bool|default=True: use the actual directory name given - i.e. do not add + to make a new directory + opd: 'True' + # type=bool|default=True: outputs path distributions + os2t: 'True' + # type=bool|default=False: Outputs seeds to targets + target_masks: + # type=inputmultiobject|default=[]: list of target masks - required for seeds_to_targets classification + thsamples: + # type=inputmultiobject|default=[]: + fsamples: + # type=inputmultiobject|default=[]: + phsamples: + # type=inputmultiobject|default=[]: + out_dir: '"."' + # type=directory|default=: directory to put the final volumes in + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: probtrackx --forcedir -m mask.nii --mode=seedmask --nsamples=3 --nsteps=10 --opd --os2t --dir=. --samples=merged --seed=MASK_average_thal_right.nii --targetmasks=targets.txt --xfm=trans.mat + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + samples_base_name: '"merged"' + # type=str|default='merged': the rootname/base_name for samples files + mask: '"mask.nii"' + # type=file|default=: bet binary mask file in diffusion space + seed: '"MASK_average_thal_right.nii"' + # type=traitcompound|default=None: seed volume(s), or voxel(s) or freesurfer label file + mode: '"seedmask"' + # type=enum|default='simple'|allowed['seedmask','simple','two_mask_symm']: options: simple (single seed voxel), seedmask (mask of seed voxels), twomask_symm (two bet binary masks) + xfm: '"trans.mat"' + # type=file|default=: transformation matrix taking seed space to DTI space (either FLIRT matrix or FNIRT warp_field) - default is identity + n_samples: '3' + # type=int|default=5000: number of samples - default=5000 + n_steps: '10' + # type=int|default=0: number of steps per sample - default=2000 + force_dir: 'True' + # type=bool|default=True: use the actual directory name given - i.e. do not add + to make a new directory + opd: 'True' + # type=bool|default=True: outputs path distributions + os2t: 'True' + # type=bool|default=False: Outputs seeds to targets + target_masks: '["targets_MASK1.nii", "targets_MASK2.nii"]' + # type=inputmultiobject|default=[]: list of target masks - required for seeds_to_targets classification + thsamples: '"merged_thsamples.nii"' + # type=inputmultiobject|default=[]: + fsamples: '"merged_fsamples.nii"' + # type=inputmultiobject|default=[]: + phsamples: '"merged_phsamples.nii"' + # type=inputmultiobject|default=[]: + out_dir: '"."' + # type=directory|default=: directory to put the final volumes in + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/prob_track_x2.yaml b/nipype-auto-conv/specs/prob_track_x2.yaml new file mode 100644 index 0000000..736c84e --- /dev/null +++ b/nipype-auto-conv/specs/prob_track_x2.yaml @@ -0,0 +1,307 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.ProbTrackX2' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL probtrackx2 for tractography on bedpostx results +# +# Examples +# -------- +# +# >>> from nipype.interfaces import fsl +# >>> pbx2 = fsl.ProbTrackX2() +# >>> pbx2.inputs.seed = 'seed_source.nii.gz' +# >>> pbx2.inputs.thsamples = 'merged_th1samples.nii.gz' +# >>> pbx2.inputs.fsamples = 'merged_f1samples.nii.gz' +# >>> pbx2.inputs.phsamples = 'merged_ph1samples.nii.gz' +# >>> pbx2.inputs.mask = 'nodif_brain_mask.nii.gz' +# >>> pbx2.inputs.out_dir = '.' +# >>> pbx2.inputs.n_samples = 3 +# >>> pbx2.inputs.n_steps = 10 +# >>> pbx2.cmdline +# 'probtrackx2 --forcedir -m nodif_brain_mask.nii.gz --nsamples=3 --nsteps=10 --opd --dir=. --samples=merged --seed=seed_source.nii.gz' +# +task_name: ProbTrackX2 +nipype_name: ProbTrackX2 +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + avoid_mp: generic/file + # type=file|default=: reject pathways passing through locations given by this mask + colmask4: generic/file + # type=file|default=: Mask for columns of matrix4 (default=seed mask) + fopd: generic/file + # type=file|default=: Other mask for binning tract distribution + fsamples: medimage/nifti-gz+list-of + # type=inputmultiobject|default=[]: + inv_xfm: generic/file + # type=file|default=: transformation matrix taking DTI space to seed space (compulsory when using a warp_field for seeds_to_dti) + lrtarget3: generic/file + # type=file|default=: Column-space mask used for Nxn connectivity matrix + mask: medimage/nifti-gz + # type=file|default=: bet binary mask file in diffusion space + out_dir: Path + # type=directory|default=: directory to put the final volumes in + phsamples: medimage/nifti-gz+list-of + # type=inputmultiobject|default=[]: + seed_ref: generic/file + # type=file|default=: reference vol to define seed space in simple mode - diffusion space assumed if absent + stop_mask: generic/file + # type=file|default=: stop tracking at locations given by this mask file + target2: generic/file + # type=file|default=: Low resolution binary brain mask for storing connectivity distribution in matrix2 mode + target3: generic/file + # type=file|default=: Mask used for NxN connectivity matrix (or Nxn if lrtarget3 is set) + target4: generic/file + # type=file|default=: Brain mask in DTI space + target_masks: generic/file+list-of + # type=inputmultiobject|default=[]: list of target masks - required for seeds_to_targets classification + thsamples: medimage/nifti-gz+list-of + # type=inputmultiobject|default=[]: + waypoints: generic/file + # type=file|default=: waypoint mask or ascii list of waypoint masks - only keep paths going through ALL the masks + xfm: generic/file + # type=file|default=: transformation matrix taking seed space to DTI space (either FLIRT matrix or FNIRT warp_field) - default is identity + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + out_dir: out_dir_default + # type=directory|default=: directory to put the final volumes in + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + fdt_paths: generic/file+list-of + # type=outputmultiobject: path/name of a 3D image file containing the output connectivity distribution to the seed mask + log: generic/file + # type=file: path/name of a text record of the command that was run + lookup_tractspace: generic/file + # type=file: lookup_tractspace generated by --omatrix2 option + matrix1_dot: generic/file + # type=file: Output matrix1.dot - SeedToSeed Connectivity + matrix2_dot: generic/file + # type=file: Output matrix2.dot - SeedToLowResMask + matrix3_dot: generic/file + # type=file: Output matrix3 - NxN connectivity matrix + network_matrix: generic/file + # type=file: the network matrix generated by --omatrix1 option + particle_files: generic/file+list-of + # type=list: Files describing all of the tract samples. Generated only if verbose is set to 2 + targets: generic/file+list-of + # type=list: a list with all generated seeds_to_target files + way_total: generic/file + # type=file: path/name of a text file containing a single number corresponding to the total number of generated tracts that have not been rejected by inclusion/exclusion mask criteria + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + simple: + # type=bool|default=False: rack from a list of voxels (seed must be a ASCII list of coordinates) + fopd: + # type=file|default=: Other mask for binning tract distribution + waycond: + # type=enum|default='OR'|allowed['AND','OR']: Waypoint condition. Either "AND" (default) or "OR" + wayorder: + # type=bool|default=False: Reject streamlines that do not hit waypoints in given order. Only valid if waycond=AND + onewaycondition: + # type=bool|default=False: Apply waypoint conditions to each half tract separately + omatrix1: + # type=bool|default=False: Output matrix1 - SeedToSeed Connectivity + distthresh1: + # type=float|default=0.0: Discards samples (in matrix1) shorter than this threshold (in mm - default=0) + omatrix2: + # type=bool|default=False: Output matrix2 - SeedToLowResMask + target2: + # type=file|default=: Low resolution binary brain mask for storing connectivity distribution in matrix2 mode + omatrix3: + # type=bool|default=False: Output matrix3 (NxN connectivity matrix) + target3: + # type=file|default=: Mask used for NxN connectivity matrix (or Nxn if lrtarget3 is set) + lrtarget3: + # type=file|default=: Column-space mask used for Nxn connectivity matrix + distthresh3: + # type=float|default=0.0: Discards samples (in matrix3) shorter than this threshold (in mm - default=0) + omatrix4: + # type=bool|default=False: Output matrix4 - DtiMaskToSeed (special Oxford Sparse Format) + colmask4: + # type=file|default=: Mask for columns of matrix4 (default=seed mask) + target4: + # type=file|default=: Brain mask in DTI space + meshspace: + # type=enum|default='caret'|allowed['caret','first','freesurfer','vox']: Mesh reference space - either "caret" (default) or "freesurfer" or "first" or "vox" + thsamples: + # type=inputmultiobject|default=[]: + phsamples: + # type=inputmultiobject|default=[]: + fsamples: + # type=inputmultiobject|default=[]: + samples_base_name: + # type=str|default='merged': the rootname/base_name for samples files + mask: + # type=file|default=: bet binary mask file in diffusion space + seed: + # type=traitcompound|default=None: seed volume(s), or voxel(s) or freesurfer label file + target_masks: + # type=inputmultiobject|default=[]: list of target masks - required for seeds_to_targets classification + waypoints: + # type=file|default=: waypoint mask or ascii list of waypoint masks - only keep paths going through ALL the masks + network: + # type=bool|default=False: activate network mode - only keep paths going through at least one seed mask (required if multiple seed masks) + seed_ref: + # type=file|default=: reference vol to define seed space in simple mode - diffusion space assumed if absent + out_dir: + # type=directory|default=: directory to put the final volumes in + force_dir: + # type=bool|default=True: use the actual directory name given - i.e. do not add + to make a new directory + opd: + # type=bool|default=True: outputs path distributions + correct_path_distribution: + # type=bool|default=False: correct path distribution for the length of the pathways + os2t: + # type=bool|default=False: Outputs seeds to targets + avoid_mp: + # type=file|default=: reject pathways passing through locations given by this mask + stop_mask: + # type=file|default=: stop tracking at locations given by this mask file + xfm: + # type=file|default=: transformation matrix taking seed space to DTI space (either FLIRT matrix or FNIRT warp_field) - default is identity + inv_xfm: + # type=file|default=: transformation matrix taking DTI space to seed space (compulsory when using a warp_field for seeds_to_dti) + n_samples: + # type=int|default=5000: number of samples - default=5000 + n_steps: + # type=int|default=0: number of steps per sample - default=2000 + dist_thresh: + # type=float|default=0.0: discards samples shorter than this threshold (in mm - default=0) + c_thresh: + # type=float|default=0.0: curvature threshold - default=0.2 + sample_random_points: + # type=float|default=0.0: sample random points within seed voxels + step_length: + # type=float|default=0.0: step_length in mm - default=0.5 + loop_check: + # type=bool|default=False: perform loop_checks on paths - slower, but allows lower curvature threshold + use_anisotropy: + # type=bool|default=False: use anisotropy to constrain tracking + rand_fib: + # type=enum|default=0|allowed[0,1,2,3]: options: 0 - default, 1 - to randomly sample initial fibres (with f > fibthresh), 2 - to sample in proportion fibres (with f>fibthresh) to f, 3 - to sample ALL populations at random (even if f: bet binary mask file in diffusion space + out_dir: '"."' + # type=directory|default=: directory to put the final volumes in + n_samples: '3' + # type=int|default=5000: number of samples - default=5000 + n_steps: '10' + # type=int|default=0: number of steps per sample - default=2000 + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: probtrackx2 --forcedir -m nodif_brain_mask.nii.gz --nsamples=3 --nsteps=10 --opd --dir=. --samples=merged --seed=seed_source.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + seed: '"seed_source.nii.gz"' + # type=traitcompound|default=None: seed volume(s), or voxel(s) or freesurfer label file + thsamples: '"merged_th1samples.nii.gz"' + # type=inputmultiobject|default=[]: + fsamples: '"merged_f1samples.nii.gz"' + # type=inputmultiobject|default=[]: + phsamples: '"merged_ph1samples.nii.gz"' + # type=inputmultiobject|default=[]: + mask: '"nodif_brain_mask.nii.gz"' + # type=file|default=: bet binary mask file in diffusion space + out_dir: '"."' + # type=directory|default=: directory to put the final volumes in + n_samples: '3' + # type=int|default=5000: number of samples - default=5000 + n_steps: '10' + # type=int|default=0: number of steps per sample - default=2000 + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/prob_track_x2_callables.py b/nipype-auto-conv/specs/prob_track_x2_callables.py new file mode 100644 index 0000000..8d008b4 --- /dev/null +++ b/nipype-auto-conv/specs/prob_track_x2_callables.py @@ -0,0 +1,485 @@ +"""Module to put any functions that are referred to in the "callables" section of ProbTrackX2.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_dir_default(inputs): + return _gen_filename("out_dir", inputs=inputs) + + +def fdt_paths_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fdt_paths"] + + +def log_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["log"] + + +def lookup_tractspace_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["lookup_tractspace"] + + +def matrix1_dot_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["matrix1_dot"] + + +def matrix2_dot_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["matrix2_dot"] + + +def matrix3_dot_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["matrix3_dot"] + + +def network_matrix_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["network_matrix"] + + +def particle_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["particle_files"] + + +def targets_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["targets"] + + +def way_total_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["way_total"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L921 of /interfaces/fsl/dti.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_dir": + return output_dir + elif name == "mode": + if isinstance(inputs.seed, list) and isinstance(inputs.seed[0], list): + return "simple" + else: + return "seedmask" + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "probtrackx2" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1070 of /interfaces/fsl/dti.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = nipype_interfaces_fsl_dti__ProbTrackX___list_outputs() + + if inputs.out_dir is attrs.NOTHING: + out_dir = output_dir + else: + out_dir = inputs.out_dir + + outputs["way_total"] = os.path.abspath(os.path.join(out_dir, "waytotal")) + + if inputs.omatrix1 is not attrs.NOTHING: + outputs["network_matrix"] = os.path.abspath( + os.path.join(out_dir, "matrix_seeds_to_all_targets") + ) + outputs["matrix1_dot"] = os.path.abspath( + os.path.join(out_dir, "fdt_matrix1.dot") + ) + + if inputs.omatrix2 is not attrs.NOTHING: + outputs["lookup_tractspace"] = os.path.abspath( + os.path.join(out_dir, "lookup_tractspace_fdt_matrix2.nii.gz") + ) + outputs["matrix2_dot"] = os.path.abspath( + os.path.join(out_dir, "fdt_matrix2.dot") + ) + + if inputs.omatrix3 is not attrs.NOTHING: + outputs["matrix3_dot"] = os.path.abspath( + os.path.join(out_dir, "fdt_matrix3.dot") + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L871 of /interfaces/fsl/dti.py +def nipype_interfaces_fsl_dti__ProbTrackX___list_outputs( + inputs=None, stdout=None, stderr=None, output_dir=None +): + outputs = {} + if inputs.out_dir is attrs.NOTHING: + out_dir = _gen_filename( + "out_dir", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + else: + out_dir = inputs.out_dir + + outputs["log"] = os.path.abspath(os.path.join(out_dir, "probtrackx.log")) + # outputs['way_total'] = os.path.abspath(os.path.join(out_dir, + # 'waytotal')) + if inputs.opd is True is not attrs.NOTHING: + if isinstance(inputs.seed, list) and isinstance(inputs.seed[0], list): + outputs["fdt_paths"] = [] + for seed in inputs.seed: + outputs["fdt_paths"].append( + os.path.abspath( + _gen_fname( + ("fdt_paths_%s" % ("_".join([str(s) for s in seed]))), + cwd=out_dir, + suffix="", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + ) + else: + outputs["fdt_paths"] = os.path.abspath( + _gen_fname( + "fdt_paths", + cwd=out_dir, + suffix="", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + + # handle seeds-to-target output files + if inputs.target_masks is not attrs.NOTHING: + outputs["targets"] = [] + for target in inputs.target_masks: + outputs["targets"].append( + os.path.abspath( + _gen_fname( + "seeds_to_" + os.path.split(target)[1], + cwd=out_dir, + suffix="", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + ) + if (inputs.verbose is not attrs.NOTHING) and inputs.verbose == 2: + outputs["particle_files"] = [ + os.path.abspath(os.path.join(out_dir, "particle%d" % i)) + for i in range(inputs.n_samples) + ] + return outputs + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/prob_track_x_callables.py b/nipype-auto-conv/specs/prob_track_x_callables.py new file mode 100644 index 0000000..7c8c61f --- /dev/null +++ b/nipype-auto-conv/specs/prob_track_x_callables.py @@ -0,0 +1,418 @@ +"""Module to put any functions that are referred to in the "callables" section of ProbTrackX.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def mode_default(inputs): + return _gen_filename("mode", inputs=inputs) + + +def out_dir_default(inputs): + return _gen_filename("out_dir", inputs=inputs) + + +def fdt_paths_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fdt_paths"] + + +def log_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["log"] + + +def particle_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["particle_files"] + + +def targets_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["targets"] + + +def way_total_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["way_total"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L921 of /interfaces/fsl/dti.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_dir": + return output_dir + elif name == "mode": + if isinstance(inputs.seed, list) and isinstance(inputs.seed[0], list): + return "simple" + else: + return "seedmask" + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "probtrackx" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L871 of /interfaces/fsl/dti.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + if inputs.out_dir is attrs.NOTHING: + out_dir = _gen_filename( + "out_dir", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + else: + out_dir = inputs.out_dir + + outputs["log"] = os.path.abspath(os.path.join(out_dir, "probtrackx.log")) + # outputs['way_total'] = os.path.abspath(os.path.join(out_dir, + # 'waytotal')) + if inputs.opd is True is not attrs.NOTHING: + if isinstance(inputs.seed, list) and isinstance(inputs.seed[0], list): + outputs["fdt_paths"] = [] + for seed in inputs.seed: + outputs["fdt_paths"].append( + os.path.abspath( + _gen_fname( + ("fdt_paths_%s" % ("_".join([str(s) for s in seed]))), + cwd=out_dir, + suffix="", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + ) + else: + outputs["fdt_paths"] = os.path.abspath( + _gen_fname( + "fdt_paths", + cwd=out_dir, + suffix="", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + + # handle seeds-to-target output files + if inputs.target_masks is not attrs.NOTHING: + outputs["targets"] = [] + for target in inputs.target_masks: + outputs["targets"].append( + os.path.abspath( + _gen_fname( + "seeds_to_" + os.path.split(target)[1], + cwd=out_dir, + suffix="", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + ) + if (inputs.verbose is not attrs.NOTHING) and inputs.verbose == 2: + outputs["particle_files"] = [ + os.path.abspath(os.path.join(out_dir, "particle%d" % i)) + for i in range(inputs.n_samples) + ] + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/proj_thresh.yaml b/nipype-auto-conv/specs/proj_thresh.yaml new file mode 100644 index 0000000..c111a93 --- /dev/null +++ b/nipype-auto-conv/specs/proj_thresh.yaml @@ -0,0 +1,129 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.ProjThresh' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL proj_thresh for thresholding some outputs of probtrack +# For complete details, see the FDT Documentation +# +# +# Example +# ------- +# +# >>> from nipype.interfaces import fsl +# >>> ldir = ['seeds_to_M1.nii', 'seeds_to_M2.nii'] +# >>> pThresh = fsl.ProjThresh(in_files=ldir, threshold=3) +# >>> pThresh.cmdline +# 'proj_thresh seeds_to_M1.nii seeds_to_M2.nii 3' +# +# +task_name: ProjThresh +nipype_name: ProjThresh +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_files: generic/file+list-of + # type=list|default=[]: a list of input volumes + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_files: generic/file+list-of + # type=list: path/name of output volume after thresholding + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=list|default=[]: a list of input volumes + threshold: + # type=int|default=0: threshold indicating minimum number of seed voxels entering this mask region + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_files: + # type=list|default=[]: a list of input volumes + threshold: '3' + # type=int|default=0: threshold indicating minimum number of seed voxels entering this mask region + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: proj_thresh seeds_to_M1.nii seeds_to_M2.nii 3 + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_files: ldir + # type=list|default=[]: a list of input volumes + threshold: '3' + # type=int|default=0: threshold indicating minimum number of seed voxels entering this mask region + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/proj_thresh_callables.py b/nipype-auto-conv/specs/proj_thresh_callables.py new file mode 100644 index 0000000..40ea989 --- /dev/null +++ b/nipype-auto-conv/specs/proj_thresh_callables.py @@ -0,0 +1,323 @@ +"""Module to put any functions that are referred to in the "callables" section of ProjThresh.yaml""" + +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_files"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "proj_thresh" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1268 of /interfaces/fsl/dti.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_files"] = [] + for name in inputs.in_files: + cwd, base_name = os.path.split(name) + outputs["out_files"].append( + _gen_fname( + base_name, + cwd=cwd, + suffix="_proj_seg_thr_{}".format(inputs.threshold), + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/randomise.yaml b/nipype-auto-conv/specs/randomise.yaml new file mode 100644 index 0000000..df78e2e --- /dev/null +++ b/nipype-auto-conv/specs/randomise.yaml @@ -0,0 +1,206 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.Randomise' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL Randomise: feeds the 4D projected FA data into GLM +# modelling and thresholding +# in order to find voxels which correlate with your model +# +# Example +# ------- +# >>> import nipype.interfaces.fsl as fsl +# >>> rand = fsl.Randomise(in_file='allFA.nii', mask = 'mask.nii', tcon='design.con', design_mat='design.mat') +# >>> rand.cmdline +# 'randomise -i allFA.nii -o "randomise" -d design.mat -t design.con -m mask.nii' +# +# +task_name: Randomise +nipype_name: Randomise +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + design_mat: datascience/text-matrix + # type=file|default=: design matrix file + fcon: generic/file + # type=file|default=: f contrasts file + in_file: medimage/nifti1 + # type=file|default=: 4D input file + mask: medimage/nifti1 + # type=file|default=: mask image + tcon: medimage-fsl/con + # type=file|default=: t contrasts file + x_block_labels: generic/file + # type=file|default=: exchangeability block labels file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + f_corrected_p_files: generic/file+list-of + # type=list: f contrast FWE (Family-wise error) corrected p values files + f_p_files: generic/file+list-of + # type=list: f contrast uncorrected p values files + fstat_files: generic/file+list-of + # type=list: f contrast raw statistic + t_corrected_p_files: generic/file+list-of + # type=list: t contrast FWE (Family-wise error) corrected p values files + t_p_files: generic/file+list-of + # type=list: f contrast uncorrected p values files + tstat_files: generic/file+list-of + # type=list: t contrast raw statistic + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: 4D input file + base_name: + # type=str|default='randomise': the rootname that all generated files will have + design_mat: + # type=file|default=: design matrix file + tcon: + # type=file|default=: t contrasts file + fcon: + # type=file|default=: f contrasts file + mask: + # type=file|default=: mask image + x_block_labels: + # type=file|default=: exchangeability block labels file + demean: + # type=bool|default=False: demean data temporally before model fitting + one_sample_group_mean: + # type=bool|default=False: perform 1-sample group-mean test instead of generic permutation test + show_total_perms: + # type=bool|default=False: print out how many unique permutations would be generated and exit + show_info_parallel_mode: + # type=bool|default=False: print out information required for parallel mode and exit + vox_p_values: + # type=bool|default=False: output voxelwise (corrected and uncorrected) p-value images + tfce: + # type=bool|default=False: carry out Threshold-Free Cluster Enhancement + tfce2D: + # type=bool|default=False: carry out Threshold-Free Cluster Enhancement with 2D optimisation + f_only: + # type=bool|default=False: calculate f-statistics only + raw_stats_imgs: + # type=bool|default=False: output raw ( unpermuted ) statistic images + p_vec_n_dist_files: + # type=bool|default=False: output permutation vector and null distribution text files + num_perm: + # type=int|default=0: number of permutations (default 5000, set to 0 for exhaustive) + seed: + # type=int|default=0: specific integer seed for random number generator + var_smooth: + # type=int|default=0: use variance smoothing (std is in mm) + c_thresh: + # type=float|default=0.0: carry out cluster-based thresholding + cm_thresh: + # type=float|default=0.0: carry out cluster-mass-based thresholding + f_c_thresh: + # type=float|default=0.0: carry out f cluster thresholding + f_cm_thresh: + # type=float|default=0.0: carry out f cluster-mass thresholding + tfce_H: + # type=float|default=0.0: TFCE height parameter (default=2) + tfce_E: + # type=float|default=0.0: TFCE extent parameter (default=0.5) + tfce_C: + # type=float|default=0.0: TFCE connectivity (6 or 26; default=6) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: 4D input file + mask: + # type=file|default=: mask image + tcon: + # type=file|default=: t contrasts file + design_mat: + # type=file|default=: design matrix file + imports: &id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + - module: nipype.interfaces.fsl as fsl + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: randomise -i allFA.nii -o "randomise" -d design.mat -t design.con -m mask.nii + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"allFA.nii"' + # type=file|default=: 4D input file + mask: '"mask.nii"' + # type=file|default=: mask image + tcon: '"design.con"' + # type=file|default=: t contrasts file + design_mat: '"design.mat"' + # type=file|default=: design matrix file + imports: *id001 + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/randomise_callables.py b/nipype-auto-conv/specs/randomise_callables.py new file mode 100644 index 0000000..635bd2c --- /dev/null +++ b/nipype-auto-conv/specs/randomise_callables.py @@ -0,0 +1,409 @@ +"""Module to put any functions that are referred to in the "callables" section of Randomise.yaml""" + +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def f_corrected_p_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["f_corrected_p_files"] + + +def f_p_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["f_p_files"] + + +def fstat_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fstat_files"] + + +def t_corrected_p_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["t_corrected_p_files"] + + +def t_p_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["t_p_files"] + + +def tstat_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["tstat_files"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "randomise" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L2322 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["tstat_files"] = glob( + _gen_fname( + "%s_tstat*.nii" % inputs.base_name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["fstat_files"] = glob( + _gen_fname( + "%s_fstat*.nii" % inputs.base_name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + prefix = False + if inputs.tfce or inputs.tfce2D: + prefix = "tfce" + elif inputs.vox_p_values: + prefix = "vox" + elif inputs.c_thresh or inputs.f_c_thresh: + prefix = "clustere" + elif inputs.cm_thresh or inputs.f_cm_thresh: + prefix = "clusterm" + if prefix: + outputs["t_p_files"] = glob( + _gen_fname( + "%s_%s_p_tstat*" % (inputs.base_name, prefix), + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["t_corrected_p_files"] = glob( + _gen_fname( + "%s_%s_corrp_tstat*.nii" % (inputs.base_name, prefix), + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + + outputs["f_p_files"] = glob( + _gen_fname( + "%s_%s_p_fstat*.nii" % (inputs.base_name, prefix), + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["f_corrected_p_files"] = glob( + _gen_fname( + "%s_%s_corrp_fstat*.nii" % (inputs.base_name, prefix), + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/reorient_2_std.yaml b/nipype-auto-conv/specs/reorient_2_std.yaml new file mode 100644 index 0000000..a0ab8b6 --- /dev/null +++ b/nipype-auto-conv/specs/reorient_2_std.yaml @@ -0,0 +1,99 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.Reorient2Std' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# fslreorient2std is a tool for reorienting the image to match the +# approximate orientation of the standard template images (MNI152). +# +# +# Examples +# -------- +# +# >>> reorient = Reorient2Std() +# >>> reorient.inputs.in_file = "functional.nii" +# >>> res = reorient.run() # doctest: +SKIP +# +# +# +task_name: Reorient2Std +nipype_name: Reorient2Std +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: + out_file: Path + # type=file: + # type=file|default=: + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: + # type=file|default=: + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: + # type=file|default=: + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: + out_file: + # type=file: + # type=file|default=: + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/reorient_2_std_callables.py b/nipype-auto-conv/specs/reorient_2_std_callables.py new file mode 100644 index 0000000..dcfa528 --- /dev/null +++ b/nipype-auto-conv/specs/reorient_2_std_callables.py @@ -0,0 +1,333 @@ +"""Module to put any functions that are referred to in the "callables" section of Reorient2Std.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1784 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _gen_fname( + inputs.in_file, + suffix="_reoriented", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslreorient2std" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1789 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_filename( + "out_file", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + else: + outputs["out_file"] = os.path.abspath(inputs.out_file) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/robust_fov.yaml b/nipype-auto-conv/specs/robust_fov.yaml new file mode 100644 index 0000000..31eed5b --- /dev/null +++ b/nipype-auto-conv/specs/robust_fov.yaml @@ -0,0 +1,99 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.RobustFOV' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Automatically crops an image removing lower head and neck. +# +# Interface is stable 5.0.0 to 5.0.9, but default brainsize changed from +# 150mm to 170mm. +# +task_name: RobustFOV +nipype_name: RobustFOV +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: input filename + out_roi: Path + # type=file: ROI volume output name + # type=file|default=: ROI volume output name + out_transform: Path + # type=file: Transformation matrix in_file to out_roi output name + # type=file|default=: Transformation matrix in_file to out_roi output name + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_roi: generic/file + # type=file: ROI volume output name + # type=file|default=: ROI volume output name + out_transform: generic/file + # type=file: Transformation matrix in_file to out_roi output name + # type=file|default=: Transformation matrix in_file to out_roi output name + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input filename + out_roi: + # type=file: ROI volume output name + # type=file|default=: ROI volume output name + brainsize: + # type=int|default=0: size of brain in z-dimension (default 170mm/150mm) + out_transform: + # type=file: Transformation matrix in_file to out_roi output name + # type=file|default=: Transformation matrix in_file to out_roi output name + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/robust_fov_callables.py b/nipype-auto-conv/specs/robust_fov_callables.py new file mode 100644 index 0000000..f9cce33 --- /dev/null +++ b/nipype-auto-conv/specs/robust_fov_callables.py @@ -0,0 +1,345 @@ +"""Module to put any functions that are referred to in the "callables" section of RobustFOV.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_roi_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_roi"] + + +def out_transform_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_transform"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/sig_loss.yaml b/nipype-auto-conv/specs/sig_loss.yaml new file mode 100644 index 0000000..adf86db --- /dev/null +++ b/nipype-auto-conv/specs/sig_loss.yaml @@ -0,0 +1,106 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.SigLoss' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Estimates signal loss from a field map (in rad/s) +# +# Examples +# -------- +# +# >>> sigloss = SigLoss() +# >>> sigloss.inputs.in_file = "phase.nii" +# >>> sigloss.inputs.echo_time = 0.03 +# >>> res = sigloss.run() # doctest: +SKIP +# +# +# +task_name: SigLoss +nipype_name: SigLoss +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: b0 fieldmap file + mask_file: generic/file + # type=file|default=: brain mask file + out_file: Path + # type=file: signal loss estimate file + # type=file|default=: output signal loss estimate file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: signal loss estimate file + # type=file|default=: output signal loss estimate file + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: signal loss estimate file + # type=file|default=: output signal loss estimate file + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: b0 fieldmap file + out_file: + # type=file: signal loss estimate file + # type=file|default=: output signal loss estimate file + mask_file: + # type=file|default=: brain mask file + echo_time: + # type=float|default=0.0: echo time in seconds + slice_direction: + # type=enum|default='x'|allowed['x','y','z']: slicing direction + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/sig_loss_callables.py b/nipype-auto-conv/specs/sig_loss_callables.py new file mode 100644 index 0000000..18d0a40 --- /dev/null +++ b/nipype-auto-conv/specs/sig_loss_callables.py @@ -0,0 +1,328 @@ +"""Module to put any functions that are referred to in the "callables" section of SigLoss.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1750 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "sigloss" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1741 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if (outputs["out_file"] is attrs.NOTHING) and (inputs.in_file is not attrs.NOTHING): + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix="_sigloss", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/slice.yaml b/nipype-auto-conv/specs/slice.yaml new file mode 100644 index 0000000..6ff12e7 --- /dev/null +++ b/nipype-auto-conv/specs/slice.yaml @@ -0,0 +1,130 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.Slice' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslslice to split a 3D file into lots of 2D files (along z-axis). +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import Slice +# >>> slice = Slice() +# >>> slice.inputs.in_file = 'functional.nii' +# >>> slice.inputs.out_base_name = 'sl' +# >>> slice.cmdline +# 'fslslice functional.nii sl' +# +# +# +task_name: Slice +nipype_name: Slice +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: input filename + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_files: generic/file+list-of + # type=outputmultiobject: + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input filename + out_base_name: + # type=str|default='': outputs prefix + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input filename + out_base_name: '"sl"' + # type=str|default='': outputs prefix + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fslslice functional.nii sl + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"functional.nii"' + # type=file|default=: input filename + out_base_name: '"sl"' + # type=str|default='': outputs prefix + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/slice_callables.py b/nipype-auto-conv/specs/slice_callables.py new file mode 100644 index 0000000..d6fc97a --- /dev/null +++ b/nipype-auto-conv/specs/slice_callables.py @@ -0,0 +1,278 @@ +"""Module to put any functions that are referred to in the "callables" section of Slice.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_files"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L305 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + """Create a Bunch which contains all possible files generated + by running the interface. Some files are always generated, others + depending on which ``inputs`` options are set. + + Returns + ------- + + outputs : Bunch object + Bunch object containing all possible files generated by + interface object. + + If None, file was not generated + Else, contains path, filename of generated outputfile + + """ + outputs = {} + ext = Info.output_type_to_ext(inputs.output_type) + suffix = "_slice_*" + ext + if inputs.out_base_name is not attrs.NOTHING: + fname_template = os.path.abspath(inputs.out_base_name + suffix) + else: + fname_template = fname_presuffix(inputs.in_file, suffix=suffix, use_ext=False) + + outputs["out_files"] = sorted(glob(fname_template)) + + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/slice_timer.yaml b/nipype-auto-conv/specs/slice_timer.yaml new file mode 100644 index 0000000..5bef559 --- /dev/null +++ b/nipype-auto-conv/specs/slice_timer.yaml @@ -0,0 +1,112 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.SliceTimer' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL slicetimer wrapper to perform slice timing correction +# +# Examples +# -------- +# >>> from nipype.interfaces import fsl +# >>> from nipype.testing import example_data +# >>> st = fsl.SliceTimer() +# >>> st.inputs.in_file = example_data('functional.nii') +# >>> st.inputs.interleaved = True +# >>> result = st.run() #doctest: +SKIP +# +# +task_name: SliceTimer +nipype_name: SliceTimer +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + custom_order: generic/file + # type=file|default=: filename of single-column custom interleave order file (first slice is referred to as 1 not 0) + custom_timings: generic/file + # type=file|default=: slice timings, in fractions of TR, range 0:1 (default is 0.5 = no shift) + in_file: generic/file + # type=file|default=: filename of input timeseries + out_file: Path + # type=file|default=: filename of output timeseries + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + out_file: out_file_default + # type=file|default=: filename of output timeseries + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + slice_time_corrected_file: generic/file + # type=file: slice time corrected file + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: filename of input timeseries + out_file: + # type=file|default=: filename of output timeseries + index_dir: + # type=bool|default=False: slice indexing from top to bottom + time_repetition: + # type=float|default=0.0: Specify TR of data - default is 3s + slice_direction: + # type=enum|default=1|allowed[1,2,3]: direction of slice acquisition (x=1, y=2, z=3) - default is z + interleaved: + # type=bool|default=False: use interleaved acquisition + custom_timings: + # type=file|default=: slice timings, in fractions of TR, range 0:1 (default is 0.5 = no shift) + global_shift: + # type=float|default=0.0: shift in fraction of TR, range 0:1 (default is 0.5 = no shift) + custom_order: + # type=file|default=: filename of single-column custom interleave order file (first slice is referred to as 1 not 0) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/slice_timer_callables.py b/nipype-auto-conv/specs/slice_timer_callables.py new file mode 100644 index 0000000..4e3d44c --- /dev/null +++ b/nipype-auto-conv/specs/slice_timer_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of SliceTimer.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def slice_time_corrected_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["slice_time_corrected_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1578 of /interfaces/fsl/preprocess.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["slice_time_corrected_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "slicetimer" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1570 of /interfaces/fsl/preprocess.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + out_file = inputs.out_file + if out_file is attrs.NOTHING: + out_file = _gen_fname( + inputs.in_file, + suffix="_st", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["slice_time_corrected_file"] = os.path.abspath(out_file) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/slicer.yaml b/nipype-auto-conv/specs/slicer.yaml new file mode 100644 index 0000000..3652534 --- /dev/null +++ b/nipype-auto-conv/specs/slicer.yaml @@ -0,0 +1,136 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.Slicer' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL's slicer command to output a png image from a volume. +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces import fsl +# >>> from nipype.testing import example_data +# >>> slice = fsl.Slicer() +# >>> slice.inputs.in_file = example_data('functional.nii') +# >>> slice.inputs.all_axial = True +# >>> slice.inputs.image_width = 750 +# >>> res = slice.run() #doctest: +SKIP +# +# +# +task_name: Slicer +nipype_name: Slicer +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + colour_map: generic/file + # type=file|default=: use different colour map from that stored in nifti header + image_edges: generic/file + # type=file|default=: volume to display edge overlay for (useful for checking registration + in_file: generic/file + # type=file|default=: input volume + out_file: Path + # type=file: picture to write + # type=file|default=: picture to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: picture to write + # type=file|default=: picture to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: picture to write + # type=file|default=: picture to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input volume + image_edges: + # type=file|default=: volume to display edge overlay for (useful for checking registration + label_slices: + # type=bool|default=True: display slice number + colour_map: + # type=file|default=: use different colour map from that stored in nifti header + intensity_range: + # type=tuple|default=(0.0, 0.0): min and max intensities to display + threshold_edges: + # type=float|default=0.0: use threshold for edges + dither_edges: + # type=bool|default=False: produce semi-transparent (dithered) edges + nearest_neighbour: + # type=bool|default=False: use nearest neighbor interpolation for output + show_orientation: + # type=bool|default=True: label left-right orientation + single_slice: + # type=enum|default='x'|allowed['x','y','z']: output picture of single slice in the x, y, or z plane + slice_number: + # type=int|default=0: slice number to save in picture + middle_slices: + # type=bool|default=False: output picture of mid-sagittal, axial, and coronal slices + all_axial: + # type=bool|default=False: output all axial slices into one picture + sample_axial: + # type=int|default=0: output every n axial slices into one picture + image_width: + # type=int|default=0: max picture width + out_file: + # type=file: picture to write + # type=file|default=: picture to write + scaling: + # type=float|default=0.0: image scale + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/slicer_callables.py b/nipype-auto-conv/specs/slicer_callables.py new file mode 100644 index 0000000..f7ee3c2 --- /dev/null +++ b/nipype-auto-conv/specs/slicer_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of Slicer.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1246 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "slicer" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1238 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + out_file = inputs.out_file + if out_file is attrs.NOTHING: + out_file = _gen_fname( + inputs.in_file, + ext=".png", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(out_file) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/smm.yaml b/nipype-auto-conv/specs/smm.yaml new file mode 100644 index 0000000..2f1b196 --- /dev/null +++ b/nipype-auto-conv/specs/smm.yaml @@ -0,0 +1,92 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.SMM' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Spatial Mixture Modelling. For more detail on the spatial mixture modelling +# see Mixture Models with Adaptive Spatial Regularisation for Segmentation +# with an Application to FMRI Data; Woolrich, M., Behrens, T., Beckmann, C., +# and Smith, S.; IEEE Trans. Medical Imaging, 24(1):1-11, 2005. +# +task_name: SMM +nipype_name: SMM +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mask: generic/file + # type=file|default=: mask file + spatial_data_file: generic/file + # type=file|default=: statistics spatial map + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + activation_p_map: generic/file + # type=file: + deactivation_p_map: generic/file + # type=file: + null_p_map: generic/file + # type=file: + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + spatial_data_file: + # type=file|default=: statistics spatial map + mask: + # type=file|default=: mask file + no_deactivation_class: + # type=bool|default=False: enforces no deactivation class + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/smm_callables.py b/nipype-auto-conv/specs/smm_callables.py new file mode 100644 index 0000000..c3df01d --- /dev/null +++ b/nipype-auto-conv/specs/smm_callables.py @@ -0,0 +1,352 @@ +"""Module to put any functions that are referred to in the "callables" section of SMM.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def activation_p_map_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["activation_p_map"] + + +def deactivation_p_map_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["deactivation_p_map"] + + +def null_p_map_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["null_p_map"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "mm --ld=logdir" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1650 of /interfaces/fsl/model.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + # TODO get the true logdir from the stdout + outputs["null_p_map"] = _gen_fname( + basename="w1_mean", + cwd="logdir", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["activation_p_map"] = _gen_fname( + basename="w2_mean", + cwd="logdir", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if ( + inputs.no_deactivation_class is attrs.NOTHING + ) or not inputs.no_deactivation_class: + outputs["deactivation_p_map"] = _gen_fname( + basename="w3_mean", + cwd="logdir", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/smooth.yaml b/nipype-auto-conv/specs/smooth.yaml new file mode 100644 index 0000000..afc1c3e --- /dev/null +++ b/nipype-auto-conv/specs/smooth.yaml @@ -0,0 +1,242 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.Smooth' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Use fslmaths to smooth the image +# +# Examples +# -------- +# +# Setting the kernel width using sigma: +# +# >>> sm = Smooth() +# >>> sm.inputs.output_type = 'NIFTI_GZ' +# >>> sm.inputs.in_file = 'functional2.nii' +# >>> sm.inputs.sigma = 8.0 +# >>> sm.cmdline # doctest: +ELLIPSIS +# 'fslmaths functional2.nii -kernel gauss 8.000 -fmean functional2_smooth.nii.gz' +# +# Setting the kernel width using fwhm: +# +# >>> sm = Smooth() +# >>> sm.inputs.output_type = 'NIFTI_GZ' +# >>> sm.inputs.in_file = 'functional2.nii' +# >>> sm.inputs.fwhm = 8.0 +# >>> sm.cmdline # doctest: +ELLIPSIS +# 'fslmaths functional2.nii -kernel gauss 3.397 -fmean functional2_smooth.nii.gz' +# +# One of sigma or fwhm must be set: +# +# >>> from nipype.interfaces.fsl import Smooth +# >>> sm = Smooth() +# >>> sm.inputs.output_type = 'NIFTI_GZ' +# >>> sm.inputs.in_file = 'functional2.nii' +# >>> sm.cmdline #doctest: +ELLIPSIS +# Traceback (most recent call last): +# ... +# ValueError: Smooth requires a value for one of the inputs ... +# +# +task_name: Smooth +nipype_name: Smooth +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: + smoothed_file: Path + # type=file: + # type=file|default=: + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + smoothed_file: generic/file + # type=file: + # type=file|default=: + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: + sigma: + # type=float|default=0.0: gaussian kernel sigma in mm (not voxels) + fwhm: + # type=float|default=0.0: gaussian kernel fwhm, will be converted to sigma in mm (not voxels) + smoothed_file: + # type=file: + # type=file|default=: + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + in_file: + # type=file|default=: + sigma: '8.0' + # type=float|default=0.0: gaussian kernel sigma in mm (not voxels) + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + in_file: + # type=file|default=: + fwhm: '8.0' + # type=float|default=0.0: gaussian kernel fwhm, will be converted to sigma in mm (not voxels) + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + in_file: + # type=file|default=: + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fslmaths functional2.nii -kernel gauss 8.000 -fmean functional2_smooth.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + in_file: '"functional2.nii"' + # type=file|default=: + sigma: '8.0' + # type=float|default=0.0: gaussian kernel sigma in mm (not voxels) + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS +- cmdline: fslmaths functional2.nii -kernel gauss 3.397 -fmean functional2_smooth.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + in_file: '"functional2.nii"' + # type=file|default=: + fwhm: '8.0' + # type=float|default=0.0: gaussian kernel fwhm, will be converted to sigma in mm (not voxels) + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS +- cmdline: + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + in_file: '"functional2.nii"' + # type=file|default=: + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/smooth_callables.py b/nipype-auto-conv/specs/smooth_callables.py new file mode 100644 index 0000000..6854c24 --- /dev/null +++ b/nipype-auto-conv/specs/smooth_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of Smooth.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def smoothed_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["smoothed_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/smooth_estimate.yaml b/nipype-auto-conv/specs/smooth_estimate.yaml new file mode 100644 index 0000000..1da7862 --- /dev/null +++ b/nipype-auto-conv/specs/smooth_estimate.yaml @@ -0,0 +1,139 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.model.SmoothEstimate' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Estimates the smoothness of an image +# +# Examples +# -------- +# +# >>> est = SmoothEstimate() +# >>> est.inputs.zstat_file = 'zstat1.nii.gz' +# >>> est.inputs.mask_file = 'mask.nii' +# >>> est.cmdline +# 'smoothest --mask=mask.nii --zstat=zstat1.nii.gz' +# +# +task_name: SmoothEstimate +nipype_name: SmoothEstimate +nipype_module: nipype.interfaces.fsl.model +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mask_file: medimage/nifti1 + # type=file|default=: brain mask volume + residual_fit_file: generic/file + # type=file|default=: residual-fit image file + zstat_file: medimage/nifti-gz + # type=file|default=: zstat image file + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + dlh: dlh_callable + # type=float: smoothness estimate sqrt(det(Lambda)) + resels: resels_callable + # type=float: volume of resel, in voxels, defined as FWHM_x * FWHM_y * FWHM_z + volume: volume_callable + # type=int: number of voxels in mask + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dof: + # type=int|default=0: number of degrees of freedom + mask_file: + # type=file|default=: brain mask volume + residual_fit_file: + # type=file|default=: residual-fit image file + zstat_file: + # type=file|default=: zstat image file + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + zstat_file: + # type=file|default=: zstat image file + mask_file: + # type=file|default=: brain mask volume + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: smoothest --mask=mask.nii --zstat=zstat1.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + zstat_file: '"zstat1.nii.gz"' + # type=file|default=: zstat image file + mask_file: '"mask.nii"' + # type=file|default=: brain mask volume + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/smooth_estimate_callables.py b/nipype-auto-conv/specs/smooth_estimate_callables.py new file mode 100644 index 0000000..967d160 --- /dev/null +++ b/nipype-auto-conv/specs/smooth_estimate_callables.py @@ -0,0 +1,352 @@ +"""Module to put any functions that are referred to in the "callables" section of SmoothEstimate.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def dlh_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["dlh"] + + +def resels_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["resels"] + + +def volume_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["volume"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/spatial_filter.yaml b/nipype-auto-conv/specs/spatial_filter.yaml new file mode 100644 index 0000000..8956e06 --- /dev/null +++ b/nipype-auto-conv/specs/spatial_filter.yaml @@ -0,0 +1,103 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.SpatialFilter' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to spatially filter an image. +task_name: SpatialFilter +nipype_name: SpatialFilter +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + kernel_file: generic/file + # type=file|default=: use external file for kernel + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + operation: + # type=enum|default='mean'|allowed['mean','meanu','median']: operation to filter with + kernel_shape: + # type=enum|default='3D'|allowed['2D','3D','box','boxv','file','gauss','sphere']: kernel shape to use + kernel_size: + # type=float|default=0.0: kernel size - voxels for box/boxv, mm for sphere, mm sigma for gauss + kernel_file: + # type=file|default=: use external file for kernel + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/spatial_filter_callables.py b/nipype-auto-conv/specs/spatial_filter_callables.py new file mode 100644 index 0000000..8799501 --- /dev/null +++ b/nipype-auto-conv/specs/spatial_filter_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of SpatialFilter.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/split.yaml b/nipype-auto-conv/specs/split.yaml new file mode 100644 index 0000000..a27bd79 --- /dev/null +++ b/nipype-auto-conv/specs/split.yaml @@ -0,0 +1,83 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.Split' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Uses FSL Fslsplit command to separate a volume into images in +# time, x, y or z dimension. +# +task_name: Split +nipype_name: Split +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: input filename + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_files: generic/file+list-of + # type=outputmultiobject: + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input filename + out_base_name: + # type=str|default='': outputs prefix + dimension: + # type=enum|default='t'|allowed['t','x','y','z']: dimension along which the file will be split + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/split_callables.py b/nipype-auto-conv/specs/split_callables.py new file mode 100644 index 0000000..28b9397 --- /dev/null +++ b/nipype-auto-conv/specs/split_callables.py @@ -0,0 +1,178 @@ +"""Module to put any functions that are referred to in the "callables" section of Split.yaml""" + +import attrs +import logging +import os +from glob import glob + + +def out_files_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_files"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L549 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + """Create a Bunch which contains all possible files generated + by running the interface. Some files are always generated, others + depending on which ``inputs`` options are set. + + Returns + ------- + + outputs : Bunch object + Bunch object containing all possible files generated by + interface object. + + If None, file was not generated + Else, contains path, filename of generated outputfile + + """ + outputs = {} + ext = Info.output_type_to_ext(inputs.output_type) + outbase = "vol[0-9]*" + if inputs.out_base_name is not attrs.NOTHING: + outbase = "%s[0-9]*" % inputs.out_base_name + outputs["out_files"] = sorted(glob(os.path.join(output_dir, outbase + ext))) + return outputs + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/std_image.yaml b/nipype-auto-conv/specs/std_image.yaml new file mode 100644 index 0000000..bbdb636 --- /dev/null +++ b/nipype-auto-conv/specs/std_image.yaml @@ -0,0 +1,97 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.StdImage' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to generate a standard deviation in an image across a given +# dimension. +# +task_name: StdImage +nipype_name: StdImage +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + dimension: + # type=enum|default='T'|allowed['T','X','Y','Z']: dimension to standard deviate across + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/std_image_callables.py b/nipype-auto-conv/specs/std_image_callables.py new file mode 100644 index 0000000..d9e0072 --- /dev/null +++ b/nipype-auto-conv/specs/std_image_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of StdImage.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/susan.yaml b/nipype-auto-conv/specs/susan.yaml new file mode 100644 index 0000000..ebe726c --- /dev/null +++ b/nipype-auto-conv/specs/susan.yaml @@ -0,0 +1,110 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.preprocess.SUSAN' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# FSL SUSAN wrapper to perform smoothing +# +# For complete details, see the `SUSAN Documentation. +# `_ +# +# Examples +# -------- +# +# >>> from nipype.interfaces import fsl +# >>> from nipype.testing import example_data +# >>> anatfile # doctest: +SKIP +# anatomical.nii # doctest: +SKIP +# >>> sus = fsl.SUSAN() +# >>> sus.inputs.in_file = example_data('structural.nii') +# >>> sus.inputs.brightness_threshold = 2000.0 +# >>> sus.inputs.fwhm = 8.0 +# >>> result = sus.run() # doctest: +SKIP +# +task_name: SUSAN +nipype_name: SUSAN +nipype_module: nipype.interfaces.fsl.preprocess +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: filename of input timeseries + out_file: Path + # type=file|default=: output file name + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + out_file: out_file_default + # type=file|default=: output file name + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + smoothed_file: generic/file + # type=file: smoothed output file + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: filename of input timeseries + brightness_threshold: + # type=float|default=0.0: brightness threshold and should be greater than noise level and less than contrast of edges to be preserved. + fwhm: + # type=float|default=0.0: fwhm of smoothing, in mm, gets converted using sqrt(8*log(2)) + dimension: + # type=enum|default=3|allowed[2,3]: within-plane (2) or fully 3D (3) + use_median: + # type=enum|default=1|allowed[0,1]: whether to use a local median filter in the cases where single-point noise is detected + usans: + # type=list|default=[]: determines whether the smoothing area (USAN) is to be found from secondary images (0, 1 or 2). A negative value for any brightness threshold will auto-set the threshold at 10% of the robust range + out_file: + # type=file|default=: output file name + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/susan_callables.py b/nipype-auto-conv/specs/susan_callables.py new file mode 100644 index 0000000..859ed75 --- /dev/null +++ b/nipype-auto-conv/specs/susan_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of SUSAN.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def smoothed_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["smoothed_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1694 of /interfaces/fsl/preprocess.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["smoothed_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "susan" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1686 of /interfaces/fsl/preprocess.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + out_file = inputs.out_file + if out_file is attrs.NOTHING: + out_file = _gen_fname( + inputs.in_file, + suffix="_smooth", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["smoothed_file"] = os.path.abspath(out_file) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/swap_dimensions.yaml b/nipype-auto-conv/specs/swap_dimensions.yaml new file mode 100644 index 0000000..c2fb752 --- /dev/null +++ b/nipype-auto-conv/specs/swap_dimensions.yaml @@ -0,0 +1,96 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.SwapDimensions' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslswapdim to alter the orientation of an image. +# +# This interface accepts a three-tuple corresponding to the new +# orientation. You may either provide dimension ids in the form of +# (-)x, (-)y, or (-z), or nifti-syle dimension codes +# (RL, LR, AP, PA, IS, SI). +# +# +task_name: SwapDimensions +nipype_name: SwapDimensions +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: input image + out_file: Path + # type=file: image with new dimensions + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image with new dimensions + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image with new dimensions + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input image + new_dims: + # type=tuple|default=('x', 'x', 'x'): 3-tuple of new dimension order + out_file: + # type=file: image with new dimensions + # type=file|default=: image to write + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/swap_dimensions_callables.py b/nipype-auto-conv/specs/swap_dimensions_callables.py new file mode 100644 index 0000000..055aff1 --- /dev/null +++ b/nipype-auto-conv/specs/swap_dimensions_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of SwapDimensions.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1642 of /interfaces/fsl/utils.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslswapdim" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1632 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix="_newdims", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/temporal_filter.yaml b/nipype-auto-conv/specs/temporal_filter.yaml new file mode 100644 index 0000000..7f7667a --- /dev/null +++ b/nipype-auto-conv/specs/temporal_filter.yaml @@ -0,0 +1,100 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.TemporalFilter' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to apply a low, high, or bandpass temporal filter to a +# timeseries. +# +# +task_name: TemporalFilter +nipype_name: TemporalFilter +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + lowpass_sigma: + # type=float|default=-1: lowpass filter sigma (in volumes) + highpass_sigma: + # type=float|default=-1: highpass filter sigma (in volumes) + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/temporal_filter_callables.py b/nipype-auto-conv/specs/temporal_filter_callables.py new file mode 100644 index 0000000..8da590f --- /dev/null +++ b/nipype-auto-conv/specs/temporal_filter_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of TemporalFilter.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/text_2_vest.yaml b/nipype-auto-conv/specs/text_2_vest.yaml new file mode 100644 index 0000000..7c7ec5d --- /dev/null +++ b/nipype-auto-conv/specs/text_2_vest.yaml @@ -0,0 +1,136 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.Text2Vest' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Use FSL Text2Vest`https://web.mit.edu/fsl_v5.0.10/fsl/doc/wiki/GLM(2f)CreatingDesignMatricesByHand.html`_ +# to convert your plain text design matrix data into the format used by the FSL tools. +# +# Examples +# -------- +# >>> from nipype.interfaces.fsl import Text2Vest +# >>> t2v = Text2Vest() +# >>> t2v.inputs.in_file = "design.txt" +# >>> t2v.inputs.out_file = "design.mat" +# >>> t2v.cmdline +# 'Text2Vest design.txt design.mat' +# >>> res = t2v.run() # doctest: +SKIP +# +task_name: Text2Vest +nipype_name: Text2Vest +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: text/text-file + # type=file|default=: plain text file representing your design, contrast, or f-test matrix + out_file: Path + # type=file: matrix data in the format used by FSL tools + # type=file|default=: file name to store matrix data in the format used by FSL tools (e.g., design.mat, design.con design.fts) + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: datascience/text-matrix + # type=file: matrix data in the format used by FSL tools + # type=file|default=: file name to store matrix data in the format used by FSL tools (e.g., design.mat, design.con design.fts) + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: plain text file representing your design, contrast, or f-test matrix + out_file: + # type=file: matrix data in the format used by FSL tools + # type=file|default=: file name to store matrix data in the format used by FSL tools (e.g., design.mat, design.con design.fts) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: plain text file representing your design, contrast, or f-test matrix + out_file: '"design.mat"' + # type=file: matrix data in the format used by FSL tools + # type=file|default=: file name to store matrix data in the format used by FSL tools (e.g., design.mat, design.con design.fts) + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: Text2Vest design.txt design.mat + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"design.txt"' + # type=file|default=: plain text file representing your design, contrast, or f-test matrix + out_file: '"design.mat"' + # type=file: matrix data in the format used by FSL tools + # type=file|default=: file name to store matrix data in the format used by FSL tools (e.g., design.mat, design.con design.fts) + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/text_2_vest_callables.py b/nipype-auto-conv/specs/text_2_vest_callables.py new file mode 100644 index 0000000..f8c73e2 --- /dev/null +++ b/nipype-auto-conv/specs/text_2_vest_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of Text2Vest.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/threshold.yaml b/nipype-auto-conv/specs/threshold.yaml new file mode 100644 index 0000000..3b898b7 --- /dev/null +++ b/nipype-auto-conv/specs/threshold.yaml @@ -0,0 +1,101 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.Threshold' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to apply a threshold to an image in a variety of ways. +task_name: Threshold +nipype_name: Threshold +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + thresh: + # type=float|default=0.0: threshold value + direction: + # type=enum|default='below'|allowed['above','below']: zero-out either below or above thresh value + use_robust_range: + # type=bool|default=False: interpret thresh as percentage (0-100) of robust range + use_nonzero_voxels: + # type=bool|default=False: use nonzero voxels to calculate robust range + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/threshold_callables.py b/nipype-auto-conv/specs/threshold_callables.py new file mode 100644 index 0000000..5f6a848 --- /dev/null +++ b/nipype-auto-conv/specs/threshold_callables.py @@ -0,0 +1,329 @@ +"""Module to put any functions that are referred to in the "callables" section of Threshold.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L51 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/topup.yaml b/nipype-auto-conv/specs/topup.yaml new file mode 100644 index 0000000..cd2b5cb --- /dev/null +++ b/nipype-auto-conv/specs/topup.yaml @@ -0,0 +1,237 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.epi.TOPUP' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Interface for FSL topup, a tool for estimating and correcting +# susceptibility induced distortions. See FSL documentation for +# `reference `_, +# `usage examples +# `_, +# and `exemplary config files +# `_. +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import TOPUP +# >>> topup = TOPUP() +# >>> topup.inputs.in_file = "b0_b0rev.nii" +# >>> topup.inputs.encoding_file = "topup_encoding.txt" +# >>> topup.inputs.output_type = "NIFTI_GZ" +# >>> topup.cmdline # doctest: +ELLIPSIS +# 'topup --config=b02b0.cnf --datain=topup_encoding.txt --imain=b0_b0rev.nii --out=b0_b0rev_base --iout=b0_b0rev_corrected.nii.gz --fout=b0_b0rev_field.nii.gz --jacout=jac --logout=b0_b0rev_topup.log --rbmout=xfm --dfout=warpfield' +# >>> res = topup.run() # doctest: +SKIP +# +# +task_name: TOPUP +nipype_name: TOPUP +nipype_module: nipype.interfaces.fsl.epi +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + encoding_file: text/text-file + # type=file|default=: name of text file with PE directions/times + in_file: medimage/nifti1 + # type=file|default=: name of 4D file with images + out_base: Path + # type=file|default=: base-name of output files (spline coefficients (Hz) and movement parameters) + readout_times: generic/file+list-of + # type=inputmultiobject|default=[]: readout times (dwell times by # phase-encode steps minus 1) + out_corrected: Path + # type=file: name of 4D image file with unwarped images + # type=file|default=: name of 4D image file with unwarped images + out_field: Path + # type=file: name of image file with field (Hz) + out_logfile: Path + # type=file: name of log-file + # type=file|default=: name of log-file + warp_res: typing.List[float] + subsamp: typing.List[int] + fwhm: typing.List[float] + reg_lambda: typing.List[float] + regmod: str + estmov: typing.List[int] + minmet: typing.List[int] + splineorder: int + interp: str + scale: bool + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + scale: + argstr: "--scale {int(scale)}" + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_corrected: generic/file + # type=file: name of 4D image file with unwarped images + # type=file|default=: name of 4D image file with unwarped images + out_enc_file: generic/file + # type=file: encoding directions file output for applytopup + out_field: generic/file + # type=file: name of image file with field (Hz) + # type=file|default=: name of image file with field (Hz) + out_fieldcoef: generic/file + # type=file: file containing the field coefficients + out_jacs: generic/file+list-of + # type=list: Jacobian images + out_logfile: generic/file + # type=file: name of log-file + # type=file|default=: name of log-file + out_mats: generic/file+list-of + # type=list: realignment matrices + out_movpar: generic/file + # type=file: movpar.txt output file + out_warps: generic/file+list-of + # type=list: warpfield images + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: name of 4D file with images + encoding_file: + # type=file|default=: name of text file with PE directions/times + encoding_direction: + # type=list|default=[]: encoding direction for automatic generation of encoding_file + readout_times: + # type=inputmultiobject|default=[]: readout times (dwell times by # phase-encode steps minus 1) + out_base: + # type=file|default=: base-name of output files (spline coefficients (Hz) and movement parameters) + out_field: + # type=file: name of image file with field (Hz) + # type=file|default=: name of image file with field (Hz) + out_warp_prefix: + # type=str|default='warpfield': prefix for the warpfield images (in mm) + out_mat_prefix: + # type=str|default='xfm': prefix for the realignment matrices + out_jac_prefix: + # type=str|default='jac': prefix for the warpfield images + out_corrected: + # type=file: name of 4D image file with unwarped images + # type=file|default=: name of 4D image file with unwarped images + out_logfile: + # type=file: name of log-file + # type=file|default=: name of log-file + warp_res: + # type=float|default=0.0: (approximate) resolution (in mm) of warp basis for the different sub-sampling levels + subsamp: + # type=int|default=0: sub-sampling scheme + fwhm: + # type=float|default=0.0: FWHM (in mm) of gaussian smoothing kernel + config: + # type=string|default='b02b0.cnf': Name of config file specifying command line arguments + max_iter: + # type=int|default=0: max # of non-linear iterations + reg_lambda: + # type=float|default=0.0: Weight of regularisation, default depending on --ssqlambda and --regmod switches. + ssqlambda: + # type=enum|default=1|allowed[0,1]: Weight lambda by the current value of the ssd. If used (=1), the effective weight of regularisation term becomes higher for the initial iterations, therefore initial steps are a little smoother than they would without weighting. This reduces the risk of finding a local minimum. + regmod: + # type=enum|default='bending_energy'|allowed['bending_energy','membrane_energy']: Regularisation term implementation. Defaults to bending_energy. Note that the two functions have vastly different scales. The membrane energy is based on the first derivatives and the bending energy on the second derivatives. The second derivatives will typically be much smaller than the first derivatives, so input lambda will have to be larger for bending_energy to yield approximately the same level of regularisation. + estmov: + # type=enum|default=1|allowed[0,1]: estimate movements if set + minmet: + # type=enum|default=0|allowed[0,1]: Minimisation method 0=Levenberg-Marquardt, 1=Scaled Conjugate Gradient + splineorder: + # type=int|default=0: order of spline, 2->Qadratic spline, 3->Cubic spline + numprec: + # type=enum|default='double'|allowed['double','float']: Precision for representing Hessian, double or float. + interp: + # type=enum|default='spline'|allowed['linear','spline']: Image interpolation model, linear or spline. + scale: + # type=enum|default=0|allowed[0,1]: If set (=1), the images are individually scaled to a common mean + regrid: + # type=enum|default=1|allowed[0,1]: If set (=1), the calculations are done in a different grid + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: name of 4D file with images + encoding_file: + # type=file|default=: name of text file with PE directions/times + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: + - cmdline: topup --config=b02b0.cnf --datain=topup_encoding.txt --imain=b0_b0rev.nii --out=b0_b0rev_base --iout=b0_b0rev_corrected.nii.gz --fout=b0_b0rev_field.nii.gz --jacout=jac --logout=b0_b0rev_topup.log --rbmout=xfm --dfout=warpfield + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"b0_b0rev.nii"' + # type=file|default=: name of 4D file with images + encoding_file: '"topup_encoding.txt"' + # type=file|default=: name of text file with PE directions/times + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/topup_callables.py b/nipype-auto-conv/specs/topup_callables.py new file mode 100644 index 0000000..93a2073 --- /dev/null +++ b/nipype-auto-conv/specs/topup_callables.py @@ -0,0 +1,565 @@ +"""Module to put any functions that are referred to in the "callables" section of TOPUP.yaml""" + +import attrs +import logging +import nibabel as nb +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_corrected_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_corrected"] + + +def out_enc_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_enc_file"] + + +def out_field_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_field"] + + +def out_fieldcoef_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_fieldcoef"] + + +def out_jacs_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_jacs"] + + +def out_logfile_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_logfile"] + + +def out_mats_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_mats"] + + +def out_movpar_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_movpar"] + + +def out_warps_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_warps"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = nipype_interfaces_fsl__FSLCommand___overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "topup" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L398 of /interfaces/fsl/epi.py +def _get_encfilename(inputs=None, stdout=None, stderr=None, output_dir=None): + out_file = os.path.join( + output_dir, ("%s_encfile.txt" % split_filename(inputs.in_file)[1]) + ) + return out_file + + +# Original source at L361 of /interfaces/fsl/epi.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = nipype_interfaces_fsl__FSLCommand___list_outputs() + del outputs["out_base"] + base_path = None + if inputs.out_base is not attrs.NOTHING: + base_path, base, _ = split_filename(inputs.out_base) + if base_path == "": + base_path = None + else: + base = split_filename(inputs.in_file)[1] + "_base" + outputs["out_fieldcoef"] = _gen_fname( + base, + suffix="_fieldcoef", + cwd=base_path, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_movpar"] = _gen_fname( + base, + suffix="_movpar", + ext=".txt", + cwd=base_path, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + + n_vols = nb.load(inputs.in_file).shape[-1] + ext = Info.output_type_to_ext(inputs.output_type) + fmt = os.path.abspath("{prefix}_{i:02d}{ext}").format + outputs["out_warps"] = [ + fmt(prefix=inputs.out_warp_prefix, i=i, ext=ext) for i in range(1, n_vols + 1) + ] + outputs["out_jacs"] = [ + fmt(prefix=inputs.out_jac_prefix, i=i, ext=ext) for i in range(1, n_vols + 1) + ] + outputs["out_mats"] = [ + fmt(prefix=inputs.out_mat_prefix, i=i, ext=".mat") for i in range(1, n_vols + 1) + ] + + if inputs.encoding_direction is not attrs.NOTHING: + outputs["out_enc_file"] = _get_encfilename( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + return outputs + + +# Original source at L430 of /interfaces/fsl/epi.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if name == "out_base": + return value + return nipype_interfaces_fsl__FSLCommand___overload_extension(value, name) + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L891 of /interfaces/base/core.py +def nipype_interfaces_fsl__FSLCommand___list_outputs( + inputs=None, stdout=None, stderr=None, output_dir=None +): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def nipype_interfaces_fsl__FSLCommand___overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/tract_skeleton.yaml b/nipype-auto-conv/specs/tract_skeleton.yaml new file mode 100644 index 0000000..bf7687c --- /dev/null +++ b/nipype-auto-conv/specs/tract_skeleton.yaml @@ -0,0 +1,138 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.TractSkeleton' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL's tbss_skeleton to skeletonise an FA image or project arbitrary +# values onto a skeleton. +# +# There are two ways to use this interface. To create a skeleton from an FA +# image, just supply the ``in_file`` and set ``skeleton_file`` to True (or +# specify a skeleton filename. To project values onto a skeleton, you must +# set ``project_data`` to True, and then also supply values for +# ``threshold``, ``distance_map``, and ``data_file``. The +# ``search_mask_file`` and ``use_cingulum_mask`` inputs are also used in data +# projection, but ``use_cingulum_mask`` is set to True by default. This mask +# controls where the projection algorithm searches within a circular space +# around a tract, rather than in a single perpendicular direction. +# +# Example +# ------- +# +# >>> import nipype.interfaces.fsl as fsl +# >>> skeletor = fsl.TractSkeleton() +# >>> skeletor.inputs.in_file = "all_FA.nii.gz" +# >>> skeletor.inputs.skeleton_file = True +# >>> skeletor.run() # doctest: +SKIP +# +# +task_name: TractSkeleton +nipype_name: TractSkeleton +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + alt_data_file: generic/file + # type=file|default=: 4D non-FA data to project onto skeleton + alt_skeleton: generic/file + # type=file|default=: alternate skeleton to use + data_file: generic/file + # type=file|default=: 4D data to project onto skeleton (usually FA) + distance_map: generic/file + # type=file|default=: distance map image + in_file: generic/file + # type=file|default=: input image (typically mean FA volume) + projected_data: Path + # type=file: input data projected onto skeleton + # type=file|default=: input data projected onto skeleton + search_mask_file: generic/file + # type=file|default=: mask in which to use alternate search rule + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + projected_data: generic/file + # type=file: input data projected onto skeleton + # type=file|default=: input data projected onto skeleton + skeleton_file: generic/file + # type=file: tract skeleton image + # type=traitcompound|default=None: write out skeleton image + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: input image (typically mean FA volume) + project_data: + # type=bool|default=False: project data onto skeleton + threshold: + # type=float|default=0.0: skeleton threshold value + distance_map: + # type=file|default=: distance map image + search_mask_file: + # type=file|default=: mask in which to use alternate search rule + use_cingulum_mask: + # type=bool|default=True: perform alternate search using built-in cingulum mask + data_file: + # type=file|default=: 4D data to project onto skeleton (usually FA) + alt_data_file: + # type=file|default=: 4D non-FA data to project onto skeleton + alt_skeleton: + # type=file|default=: alternate skeleton to use + projected_data: + # type=file: input data projected onto skeleton + # type=file|default=: input data projected onto skeleton + skeleton_file: + # type=file: tract skeleton image + # type=traitcompound|default=None: write out skeleton image + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/tract_skeleton_callables.py b/nipype-auto-conv/specs/tract_skeleton_callables.py new file mode 100644 index 0000000..9833726 --- /dev/null +++ b/nipype-auto-conv/specs/tract_skeleton_callables.py @@ -0,0 +1,141 @@ +"""Module to put any functions that are referred to in the "callables" section of TractSkeleton.yaml""" + +import attrs +import os.path as op +from pathlib import Path + + +def projected_data_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["projected_data"] + + +def skeleton_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["skeleton_file"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L1445 of /interfaces/fsl/dti.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + _si = inputs + if (_si.project_data is not attrs.NOTHING) and _si.project_data: + proj_data = _si.projected_data + outputs["projected_data"] = proj_data + if proj_data is attrs.NOTHING: + stem = _si.data_file + if _si.alt_data_file is not attrs.NOTHING: + stem = _si.alt_data_file + outputs["projected_data"] = fname_presuffix( + stem, suffix="_skeletonised", newpath=output_dir, use_ext=True + ) + if (_si.skeleton_file is not attrs.NOTHING) and _si.skeleton_file: + outputs["skeleton_file"] = _si.skeleton_file + if isinstance(_si.skeleton_file, bool): + outputs["skeleton_file"] = fname_presuffix( + _si.in_file, suffix="_skeleton", newpath=output_dir, use_ext=True + ) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext diff --git a/nipype-auto-conv/specs/training.yaml b/nipype-auto-conv/specs/training.yaml new file mode 100644 index 0000000..fde680a --- /dev/null +++ b/nipype-auto-conv/specs/training.yaml @@ -0,0 +1,81 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.fix.Training' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Train the classifier based on your own FEAT/MELODIC output directory. +# +task_name: Training +nipype_name: Training +nipype_module: nipype.interfaces.fsl.fix +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mel_icas: generic/file+list-of + # type=inputmultiobject|default=[]: Melodic output directories + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + trained_wts_file: generic/file + # type=file: Trained-weights file + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + mel_icas: + # type=inputmultiobject|default=[]: Melodic output directories + trained_wts_filestem: + # type=str|default='': trained-weights filestem, used for trained_wts_file and output directories + loo: + # type=bool|default=False: full leave-one-out test with classifier training + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/training_callables.py b/nipype-auto-conv/specs/training_callables.py new file mode 100644 index 0000000..b162530 --- /dev/null +++ b/nipype-auto-conv/specs/training_callables.py @@ -0,0 +1,28 @@ +"""Module to put any functions that are referred to in the "callables" section of Training.yaml""" + +import attrs +import os + + +def trained_wts_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["trained_wts_file"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L200 of /interfaces/fsl/fix.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + if inputs.trained_wts_filestem is not attrs.NOTHING: + outputs["trained_wts_file"] = os.path.abspath( + inputs.trained_wts_filestem + ".RData" + ) + else: + outputs["trained_wts_file"] = os.path.abspath("trained_wts_file.RData") + return outputs diff --git a/nipype-auto-conv/specs/training_set_creator.yaml b/nipype-auto-conv/specs/training_set_creator.yaml new file mode 100644 index 0000000..69429c7 --- /dev/null +++ b/nipype-auto-conv/specs/training_set_creator.yaml @@ -0,0 +1,78 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.fix.TrainingSetCreator' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Goes through set of provided melodic output directories, to find all +# the ones that have a hand_labels_noise.txt file in them. +# +# This is outsourced as a separate class, so that the pipeline is +# rerun every time a handlabeled file has been changed, or a new one +# created. +# +# +task_name: TrainingSetCreator +nipype_name: TrainingSetCreator +nipype_module: nipype.interfaces.fsl.fix +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mel_icas_in: generic/directory+list-of + # type=inputmultiobject|default=[]: Melodic output directories + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + mel_icas_out: generic/directory+list-of + # type=outputmultiobject: Hand labels for noise vs signal + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + mel_icas_in: + # type=inputmultiobject|default=[]: Melodic output directories + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/training_set_creator_callables.py b/nipype-auto-conv/specs/training_set_creator_callables.py new file mode 100644 index 0000000..02bfada --- /dev/null +++ b/nipype-auto-conv/specs/training_set_creator_callables.py @@ -0,0 +1,21 @@ +"""Module to put any functions that are referred to in the "callables" section of TrainingSetCreator.yaml""" + +import os + + +def mel_icas_out_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mel_icas_out"] + + +# Original source at L122 of /interfaces/fsl/fix.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + mel_icas = [] + for item in inputs.mel_icas_in: + if os.path.exists(os.path.join(item, "hand_labels_noise.txt")): + mel_icas.append(item) + outputs = {} + outputs["mel_icas_out"] = mel_icas + return outputs diff --git a/nipype-auto-conv/specs/unary_maths.yaml b/nipype-auto-conv/specs/unary_maths.yaml new file mode 100644 index 0000000..7666385 --- /dev/null +++ b/nipype-auto-conv/specs/unary_maths.yaml @@ -0,0 +1,95 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.maths.UnaryMaths' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use fslmaths to perorm a variety of mathematical operations on an image. +task_name: UnaryMaths +nipype_name: UnaryMaths +nipype_module: nipype.interfaces.fsl.maths +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: generic/file + # type=file|default=: image to operate on + out_file: Path + # type=file: image written after calculations + # type=file|default=: image to write + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: image written after calculations + # type=file|default=: image to write + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: out_file + # type=file: image written after calculations + # type=file|default=: image to write + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + operation: + # type=enum|default='exp'|allowed['abs','acos','asin','atan','bin','binv','cos','edge','exp','fillh','fillh26','index','log','nan','nanm','rand','randn','range','recip','sin','sqr','sqrt','tan']: operation to perform + in_file: + # type=file|default=: image to operate on + out_file: + # type=file: image written after calculations + # type=file|default=: image to write + internal_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for calculations (default is float) + output_datatype: + # type=enum|default='float'|allowed['char','double','float','input','int','short']: datatype to use for output (default uses input type) + nan2zeros: + # type=bool|default=False: change NaNs to zeros before doing anything + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/unary_maths_callables.py b/nipype-auto-conv/specs/unary_maths_callables.py new file mode 100644 index 0000000..62b82c1 --- /dev/null +++ b/nipype-auto-conv/specs/unary_maths_callables.py @@ -0,0 +1,337 @@ +"""Module to put any functions that are referred to in the "callables" section of UnaryMaths.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L61 of /interfaces/fsl/maths.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return nipype_interfaces_fsl_maths__MathsCommand___list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )["out_file"] + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "fslmaths" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L502 of /interfaces/fsl/maths.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + _suffix = "_" + inputs.operation + return nipype_interfaces_fsl_maths__MathsCommand___list_outputs() + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L51 of /interfaces/fsl/maths.py +def nipype_interfaces_fsl_maths__MathsCommand___list_outputs( + inputs=None, stdout=None, stderr=None, output_dir=None +): + outputs = {} + outputs["out_file"] = inputs.out_file + if inputs.out_file is attrs.NOTHING: + outputs["out_file"] = _gen_fname( + inputs.in_file, + suffix=_suffix, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/vec_reg.yaml b/nipype-auto-conv/specs/vec_reg.yaml new file mode 100644 index 0000000..d8908a0 --- /dev/null +++ b/nipype-auto-conv/specs/vec_reg.yaml @@ -0,0 +1,176 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.VecReg' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL vecreg for registering vector data +# For complete details, see the FDT Documentation +# +# +# Example +# ------- +# +# >>> from nipype.interfaces import fsl +# >>> vreg = fsl.VecReg(in_file='diffusion.nii', affine_mat='trans.mat', ref_vol='mni.nii', out_file='diffusion_vreg.nii') +# >>> vreg.cmdline +# 'vecreg -t trans.mat -i diffusion.nii -o diffusion_vreg.nii -r mni.nii' +# +# +task_name: VecReg +nipype_name: VecReg +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + affine_mat: datascience/text-matrix + # type=file|default=: filename for affine transformation matrix + in_file: medimage/nifti1 + # type=file|default=: filename for input vector or tensor field + mask: generic/file + # type=file|default=: brain mask in input space + out_file: Path + # type=file: path/name of filename for the registered vector or tensor field + # type=file|default=: filename for output registered vector or tensor field + ref_mask: generic/file + # type=file|default=: brain mask in output space (useful for speed up of nonlinear reg) + ref_vol: medimage/nifti1 + # type=file|default=: filename for reference (target) volume + rotation_mat: generic/file + # type=file|default=: filename for secondary affine matrix if set, this will be used for the rotation of the vector/tensor field + rotation_warp: generic/file + # type=file|default=: filename for secondary warp field if set, this will be used for the rotation of the vector/tensor field + warp_field: generic/file + # type=file|default=: filename for 4D warp field for nonlinear registration + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: medimage/nifti1 + # type=file: path/name of filename for the registered vector or tensor field + # type=file|default=: filename for output registered vector or tensor field + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + out_file: '"diffusion_vreg.nii"' + # type=file: path/name of filename for the registered vector or tensor field + # type=file|default=: filename for output registered vector or tensor field + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: filename for input vector or tensor field + out_file: + # type=file: path/name of filename for the registered vector or tensor field + # type=file|default=: filename for output registered vector or tensor field + ref_vol: + # type=file|default=: filename for reference (target) volume + affine_mat: + # type=file|default=: filename for affine transformation matrix + warp_field: + # type=file|default=: filename for 4D warp field for nonlinear registration + rotation_mat: + # type=file|default=: filename for secondary affine matrix if set, this will be used for the rotation of the vector/tensor field + rotation_warp: + # type=file|default=: filename for secondary warp field if set, this will be used for the rotation of the vector/tensor field + interpolation: + # type=enum|default='nearestneighbour'|allowed['nearestneighbour','sinc','spline','trilinear']: interpolation method : nearestneighbour, trilinear (default), sinc or spline + mask: + # type=file|default=: brain mask in input space + ref_mask: + # type=file|default=: brain mask in output space (useful for speed up of nonlinear reg) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: filename for input vector or tensor field + affine_mat: + # type=file|default=: filename for affine transformation matrix + ref_vol: + # type=file|default=: filename for reference (target) volume + out_file: '"diffusion_vreg.nii"' + # type=file: path/name of filename for the registered vector or tensor field + # type=file|default=: filename for output registered vector or tensor field + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: vecreg -t trans.mat -i diffusion.nii -o diffusion_vreg.nii -r mni.nii + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"diffusion.nii"' + # type=file|default=: filename for input vector or tensor field + affine_mat: '"trans.mat"' + # type=file|default=: filename for affine transformation matrix + ref_vol: '"mni.nii"' + # type=file|default=: filename for reference (target) volume + out_file: '"diffusion_vreg.nii"' + # type=file: path/name of filename for the registered vector or tensor field + # type=file|default=: filename for output registered vector or tensor field + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/vec_reg_callables.py b/nipype-auto-conv/specs/vec_reg_callables.py new file mode 100644 index 0000000..1a7b200 --- /dev/null +++ b/nipype-auto-conv/specs/vec_reg_callables.py @@ -0,0 +1,332 @@ +"""Module to put any functions that are referred to in the "callables" section of VecReg.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def out_file_default(inputs): + return _gen_filename("out_file", inputs=inputs) + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L1216 of /interfaces/fsl/dti.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + if name == "out_file": + return _list_outputs( + inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + )[name] + else: + return None + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "vecreg" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L1205 of /interfaces/fsl/dti.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = inputs.out_file + if (outputs["out_file"] is attrs.NOTHING) and (inputs.in_file is not attrs.NOTHING): + pth, base_name = os.path.split(inputs.in_file) + outputs["out_file"] = _gen_fname( + base_name, + cwd=os.path.abspath(pth), + suffix="_vreg", + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + outputs["out_file"] = os.path.abspath(outputs["out_file"]) + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/nipype-auto-conv/specs/vest_2_text.yaml b/nipype-auto-conv/specs/vest_2_text.yaml new file mode 100644 index 0000000..b4dbeb3 --- /dev/null +++ b/nipype-auto-conv/specs/vest_2_text.yaml @@ -0,0 +1,129 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.Vest2Text' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Use FSL Vest2Text`https://web.mit.edu/fsl_v5.0.10/fsl/doc/wiki/GLM(2f)CreatingDesignMatricesByHand.html`_ +# to convert your design.mat design.con and design.fts files into plain text. +# +# Examples +# -------- +# >>> from nipype.interfaces.fsl import Vest2Text +# >>> v2t = Vest2Text() +# >>> v2t.inputs.in_file = "design.mat" +# >>> v2t.cmdline +# 'Vest2Text design.mat design.txt' +# >>> res = v2t.run() # doctest: +SKIP +# +task_name: Vest2Text +nipype_name: Vest2Text +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: datascience/text-matrix + # type=file|default=: matrix data stored in the format used by FSL tools + out_file: Path + # type=file: plain text representation of FSL matrix + # type=file|default='design.txt': file name to store text output from matrix + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: plain text representation of FSL matrix + # type=file|default='design.txt': file name to store text output from matrix + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: matrix data stored in the format used by FSL tools + out_file: + # type=file: plain text representation of FSL matrix + # type=file|default='design.txt': file name to store text output from matrix + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: matrix data stored in the format used by FSL tools + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: Vest2Text design.mat design.txt + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"design.mat"' + # type=file|default=: matrix data stored in the format used by FSL tools + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/vest_2_text_callables.py b/nipype-auto-conv/specs/vest_2_text_callables.py new file mode 100644 index 0000000..2b60243 --- /dev/null +++ b/nipype-auto-conv/specs/vest_2_text_callables.py @@ -0,0 +1,338 @@ +"""Module to put any functions that are referred to in the "callables" section of Vest2Text.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/warp_points.yaml b/nipype-auto-conv/specs/warp_points.yaml new file mode 100644 index 0000000..4acaa41 --- /dev/null +++ b/nipype-auto-conv/specs/warp_points.yaml @@ -0,0 +1,172 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.WarpPoints' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL `img2imgcoord `_ +# to transform point sets. Accepts plain text files and vtk files. +# +# .. Note:: transformation of TrackVis trk files is not yet implemented +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import WarpPoints +# >>> warppoints = WarpPoints() +# >>> warppoints.inputs.in_coords = 'surf.txt' +# >>> warppoints.inputs.src_file = 'epi.nii' +# >>> warppoints.inputs.dest_file = 'T1.nii' +# >>> warppoints.inputs.warp_file = 'warpfield.nii' +# >>> warppoints.inputs.coord_mm = True +# >>> warppoints.cmdline # doctest: +ELLIPSIS +# 'img2imgcoord -mm -dest T1.nii -src epi.nii -warp warpfield.nii surf.txt' +# >>> res = warppoints.run() # doctest: +SKIP +# +# +# +task_name: WarpPoints +nipype_name: WarpPoints +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + dest_file: medimage/nifti1 + # type=file|default=: filename of destination image + in_coords: text/text-file + # type=file|default=: filename of file containing coordinates + out_file: Path + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: output file name + src_file: medimage/nifti1 + # type=file|default=: filename of source image + warp_file: medimage/nifti1 + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + xfm_file: generic/file + # type=file|default=: filename of affine transform (e.g. source2dest.mat) + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: output file name + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + src_file: + # type=file|default=: filename of source image + dest_file: + # type=file|default=: filename of destination image + in_coords: + # type=file|default=: filename of file containing coordinates + xfm_file: + # type=file|default=: filename of affine transform (e.g. source2dest.mat) + warp_file: + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + coord_vox: + # type=bool|default=True: all coordinates in voxels - default + coord_mm: + # type=bool|default=False: all coordinates in mm + out_file: + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: output file name + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_coords: + # type=file|default=: filename of file containing coordinates + src_file: + # type=file|default=: filename of source image + dest_file: + # type=file|default=: filename of destination image + warp_file: + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + coord_mm: 'True' + # type=bool|default=False: all coordinates in mm + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: img2imgcoord -mm -dest T1.nii -src epi.nii -warp warpfield.nii surf.txt + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_coords: '"surf.txt"' + # type=file|default=: filename of file containing coordinates + src_file: '"epi.nii"' + # type=file|default=: filename of source image + dest_file: '"T1.nii"' + # type=file|default=: filename of destination image + warp_file: '"warpfield.nii"' + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + coord_mm: 'True' + # type=bool|default=False: all coordinates in mm + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/warp_points_callables.py b/nipype-auto-conv/specs/warp_points_callables.py new file mode 100644 index 0000000..1962865 --- /dev/null +++ b/nipype-auto-conv/specs/warp_points_callables.py @@ -0,0 +1,204 @@ +"""Module to put any functions that are referred to in the "callables" section of WarpPoints.yaml""" + +import attrs +import logging +import os +import os.path as op + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L2585 of /interfaces/fsl/utils.py +def _overload_extension( + value, name, inputs=None, stdout=None, stderr=None, output_dir=None +): + if name == "out_file": + return "%s.%s" % (value, getattr(self, "_outformat")) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/warp_points_from_std.yaml b/nipype-auto-conv/specs/warp_points_from_std.yaml new file mode 100644 index 0000000..7320302 --- /dev/null +++ b/nipype-auto-conv/specs/warp_points_from_std.yaml @@ -0,0 +1,165 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.WarpPointsFromStd' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Use FSL `std2imgcoord `_ +# to transform point sets to standard space coordinates. Accepts plain text coordinates +# files. +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import WarpPointsFromStd +# >>> warppoints = WarpPointsFromStd() +# >>> warppoints.inputs.in_coords = 'surf.txt' +# >>> warppoints.inputs.img_file = 'T1.nii' +# >>> warppoints.inputs.std_file = 'mni.nii' +# >>> warppoints.inputs.warp_file = 'warpfield.nii' +# >>> warppoints.inputs.coord_mm = True +# >>> warppoints.cmdline # doctest: +ELLIPSIS +# 'std2imgcoord -mm -img T1.nii -std mni.nii -warp warpfield.nii surf.txt' +# >>> res = warppoints.run() # doctest: +SKIP +# +# +# +task_name: WarpPointsFromStd +nipype_name: WarpPointsFromStd +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + img_file: medimage/nifti1 + # type=file|default=: filename of a destination image + in_coords: text/text-file + # type=file|default=: filename of file containing coordinates + std_file: medimage/nifti1 + # type=file|default=: filename of the image in standard space + warp_file: medimage/nifti1 + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + xfm_file: generic/file + # type=file|default=: filename of affine transform (e.g. source2dest.mat) + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: Name of output file, containing the warp as field or coefficients. + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + img_file: + # type=file|default=: filename of a destination image + std_file: + # type=file|default=: filename of the image in standard space + in_coords: + # type=file|default=: filename of file containing coordinates + xfm_file: + # type=file|default=: filename of affine transform (e.g. source2dest.mat) + warp_file: + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + coord_vox: + # type=bool|default=True: all coordinates in voxels - default + coord_mm: + # type=bool|default=False: all coordinates in mm + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_coords: + # type=file|default=: filename of file containing coordinates + img_file: + # type=file|default=: filename of a destination image + std_file: + # type=file|default=: filename of the image in standard space + warp_file: + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + coord_mm: 'True' + # type=bool|default=False: all coordinates in mm + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: std2imgcoord -mm -img T1.nii -std mni.nii -warp warpfield.nii surf.txt + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_coords: '"surf.txt"' + # type=file|default=: filename of file containing coordinates + img_file: '"T1.nii"' + # type=file|default=: filename of a destination image + std_file: '"mni.nii"' + # type=file|default=: filename of the image in standard space + warp_file: '"warpfield.nii"' + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + coord_mm: 'True' + # type=bool|default=False: all coordinates in mm + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/warp_points_from_std_callables.py b/nipype-auto-conv/specs/warp_points_from_std_callables.py new file mode 100644 index 0000000..0bd158b --- /dev/null +++ b/nipype-auto-conv/specs/warp_points_from_std_callables.py @@ -0,0 +1,22 @@ +"""Module to put any functions that are referred to in the "callables" section of WarpPointsFromStd.yaml""" + +import os.path as op + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L2744 of /interfaces/fsl/utils.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + outputs["out_file"] = op.abspath("stdout.nipype") + return outputs diff --git a/nipype-auto-conv/specs/warp_points_to_std.yaml b/nipype-auto-conv/specs/warp_points_to_std.yaml new file mode 100644 index 0000000..0cfbe88 --- /dev/null +++ b/nipype-auto-conv/specs/warp_points_to_std.yaml @@ -0,0 +1,178 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.WarpPointsToStd' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Use FSL `img2stdcoord `_ +# to transform point sets to standard space coordinates. Accepts plain text +# files and vtk files. +# +# .. Note:: transformation of TrackVis trk files is not yet implemented +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import WarpPointsToStd +# >>> warppoints = WarpPointsToStd() +# >>> warppoints.inputs.in_coords = 'surf.txt' +# >>> warppoints.inputs.img_file = 'T1.nii' +# >>> warppoints.inputs.std_file = 'mni.nii' +# >>> warppoints.inputs.warp_file = 'warpfield.nii' +# >>> warppoints.inputs.coord_mm = True +# >>> warppoints.cmdline # doctest: +ELLIPSIS +# 'img2stdcoord -mm -img T1.nii -std mni.nii -warp warpfield.nii surf.txt' +# >>> res = warppoints.run() # doctest: +SKIP +# +# +# +task_name: WarpPointsToStd +nipype_name: WarpPointsToStd +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + img_file: medimage/nifti1 + # type=file|default=: filename of input image + in_coords: text/text-file + # type=file|default=: filename of file containing coordinates + out_file: Path + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: output file name + premat_file: generic/file + # type=file|default=: filename of pre-warp affine transform (e.g. example_func2highres.mat) + std_file: medimage/nifti1 + # type=file|default=: filename of destination image + warp_file: medimage/nifti1 + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + xfm_file: generic/file + # type=file|default=: filename of affine transform (e.g. source2dest.mat) + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: output file name + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + img_file: + # type=file|default=: filename of input image + std_file: + # type=file|default=: filename of destination image + premat_file: + # type=file|default=: filename of pre-warp affine transform (e.g. example_func2highres.mat) + in_coords: + # type=file|default=: filename of file containing coordinates + xfm_file: + # type=file|default=: filename of affine transform (e.g. source2dest.mat) + warp_file: + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + coord_vox: + # type=bool|default=True: all coordinates in voxels - default + coord_mm: + # type=bool|default=False: all coordinates in mm + out_file: + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: output file name + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_coords: + # type=file|default=: filename of file containing coordinates + img_file: + # type=file|default=: filename of input image + std_file: + # type=file|default=: filename of destination image + warp_file: + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + coord_mm: 'True' + # type=bool|default=False: all coordinates in mm + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: img2stdcoord -mm -img T1.nii -std mni.nii -warp warpfield.nii surf.txt + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_coords: '"surf.txt"' + # type=file|default=: filename of file containing coordinates + img_file: '"T1.nii"' + # type=file|default=: filename of input image + std_file: '"mni.nii"' + # type=file|default=: filename of destination image + warp_file: '"warpfield.nii"' + # type=file|default=: filename of warpfield (e.g. intermediate2dest_warp.nii.gz) + coord_mm: 'True' + # type=bool|default=False: all coordinates in mm + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/warp_points_to_std_callables.py b/nipype-auto-conv/specs/warp_points_to_std_callables.py new file mode 100644 index 0000000..078867b --- /dev/null +++ b/nipype-auto-conv/specs/warp_points_to_std_callables.py @@ -0,0 +1,204 @@ +"""Module to put any functions that are referred to in the "callables" section of WarpPointsToStd.yaml""" + +import attrs +import logging +import os +import os.path as op + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L2585 of /interfaces/fsl/utils.py +def _overload_extension( + value, name, inputs=None, stdout=None, stderr=None, output_dir=None +): + if name == "out_file": + return "%s.%s" % (value, getattr(self, "_outformat")) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/warp_utils.yaml b/nipype-auto-conv/specs/warp_utils.yaml new file mode 100644 index 0000000..0210a25 --- /dev/null +++ b/nipype-auto-conv/specs/warp_utils.yaml @@ -0,0 +1,175 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.utils.WarpUtils' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# Use FSL `fnirtfileutils `_ +# to convert field->coefficients, coefficients->field, coefficients->other_coefficients etc +# +# +# Examples +# -------- +# +# >>> from nipype.interfaces.fsl import WarpUtils +# >>> warputils = WarpUtils() +# >>> warputils.inputs.in_file = "warpfield.nii" +# >>> warputils.inputs.reference = "T1.nii" +# >>> warputils.inputs.out_format = 'spline' +# >>> warputils.inputs.warp_resolution = (10,10,10) +# >>> warputils.inputs.output_type = "NIFTI_GZ" +# >>> warputils.cmdline # doctest: +ELLIPSIS +# 'fnirtfileutils --in=warpfield.nii --outformat=spline --ref=T1.nii --warpres=10.0000,10.0000,10.0000 --out=warpfield_coeffs.nii.gz' +# >>> res = invwarp.run() # doctest: +SKIP +# +# +# +task_name: WarpUtils +nipype_name: WarpUtils +nipype_module: nipype.interfaces.fsl.utils +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + in_file: medimage/nifti1 + # type=file|default=: Name of file containing warp-coefficients/fields. This would typically be the output from the --cout switch of fnirt (but can also use fields, like the output from --fout). + out_file: Path + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: Name of output file. The format of the output depends on what other parameters are set. The default format is a (4D) field-file. If the --outformat is set to spline the format will be a (4D) file of spline coefficients. + out_jacobian: Path + # type=file: Name of output file, containing the map of the determinant of the Jacobian + # type=file|default=: Specifies that a (3D) file of Jacobian determinants corresponding to --in should be produced and written to filename. + reference: medimage/nifti1 + # type=file|default=: Name of a file in target space. Note that the target space is now different from the target space that was used to create the --warp file. It would typically be the file that was specified with the --in argument when running fnirt. + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + out_file: generic/file + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: Name of output file. The format of the output depends on what other parameters are set. The default format is a (4D) field-file. If the --outformat is set to spline the format will be a (4D) file of spline coefficients. + out_jacobian: generic/file + # type=file: Name of output file, containing the map of the determinant of the Jacobian + # type=file|default=: Specifies that a (3D) file of Jacobian determinants corresponding to --in should be produced and written to filename. + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: Name of file containing warp-coefficients/fields. This would typically be the output from the --cout switch of fnirt (but can also use fields, like the output from --fout). + reference: + # type=file|default=: Name of a file in target space. Note that the target space is now different from the target space that was used to create the --warp file. It would typically be the file that was specified with the --in argument when running fnirt. + out_format: + # type=enum|default='spline'|allowed['field','spline']: Specifies the output format. If set to field (default) the output will be a (4D) field-file. If set to spline the format will be a (4D) file of spline coefficients. + warp_resolution: + # type=tuple|default=(0.0, 0.0, 0.0): Specifies the resolution/knot-spacing of the splines pertaining to the coefficients in the --out file. This parameter is only relevant if --outformat is set to spline. It should be noted that if the --in file has a higher resolution, the resulting coefficients will pertain to the closest (in a least-squares sense) file in the space of fields with the --warpres resolution. It should also be noted that the resolution will always be an integer multiple of the voxel size. + knot_space: + # type=tuple|default=(0, 0, 0): Alternative (to --warpres) specification of the resolution of the output spline-field. + out_file: + # type=file: Name of output file, containing the warp as field or coefficients. + # type=file|default=: Name of output file. The format of the output depends on what other parameters are set. The default format is a (4D) field-file. If the --outformat is set to spline the format will be a (4D) file of spline coefficients. + write_jacobian: + # type=bool|default=False: Switch on --jac flag with automatically generated filename + out_jacobian: + # type=file: Name of output file, containing the map of the determinant of the Jacobian + # type=file|default=: Specifies that a (3D) file of Jacobian determinants corresponding to --in should be produced and written to filename. + with_affine: + # type=bool|default=False: Specifies that the affine transform (i.e. that which was specified for the --aff parameter in fnirt) should be included as displacements in the --out file. That can be useful for interfacing with software that cannot decode FSL/fnirt coefficient-files (where the affine transform is stored separately from the displacements). + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +- inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + in_file: + # type=file|default=: Name of file containing warp-coefficients/fields. This would typically be the output from the --cout switch of fnirt (but can also use fields, like the output from --fout). + reference: + # type=file|default=: Name of a file in target space. Note that the target space is now different from the target space that was used to create the --warp file. It would typically be the file that was specified with the --in argument when running fnirt. + out_format: '"spline"' + # type=enum|default='spline'|allowed['field','spline']: Specifies the output format. If set to field (default) the output will be a (4D) field-file. If set to spline the format will be a (4D) file of spline coefficients. + warp_resolution: (10,10,10) + # type=tuple|default=(0.0, 0.0, 0.0): Specifies the resolution/knot-spacing of the splines pertaining to the coefficients in the --out file. This parameter is only relevant if --outformat is set to spline. It should be noted that if the --in file has a higher resolution, the resulting coefficients will pertain to the closest (in a least-squares sense) file in the space of fields with the --warpres resolution. It should also be noted that the resolution will always be an integer multiple of the voxel size. + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: +- cmdline: fnirtfileutils --in=warpfield.nii --outformat=spline --ref=T1.nii --warpres=10.0000,10.0000,10.0000 --out=warpfield_coeffs.nii.gz + # str - the expected cmdline output + inputs: + # dict[str, str] - name-value pairs for inputs to be provided to the doctest. + # If the field is of file-format type and the value is None, then the + # '.mock()' method of the corresponding class is used instead. + in_file: '"warpfield.nii"' + # type=file|default=: Name of file containing warp-coefficients/fields. This would typically be the output from the --cout switch of fnirt (but can also use fields, like the output from --fout). + reference: '"T1.nii"' + # type=file|default=: Name of a file in target space. Note that the target space is now different from the target space that was used to create the --warp file. It would typically be the file that was specified with the --in argument when running fnirt. + out_format: '"spline"' + # type=enum|default='spline'|allowed['field','spline']: Specifies the output format. If set to field (default) the output will be a (4D) field-file. If set to spline the format will be a (4D) file of spline coefficients. + warp_resolution: (10,10,10) + # type=tuple|default=(0.0, 0.0, 0.0): Specifies the resolution/knot-spacing of the splines pertaining to the coefficients in the --out file. This parameter is only relevant if --outformat is set to spline. It should be noted that if the --in file has a higher resolution, the resulting coefficients will pertain to the closest (in a least-squares sense) file in the space of fields with the --warpres resolution. It should also be noted that the resolution will always be an integer multiple of the voxel size. + output_type: '"NIFTI_GZ"' + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + directive: + # str - any doctest directive to place on the cmdline call, e.g. # doctest: +ELLIPSIS diff --git a/nipype-auto-conv/specs/warp_utils_callables.py b/nipype-auto-conv/specs/warp_utils_callables.py new file mode 100644 index 0000000..25df087 --- /dev/null +++ b/nipype-auto-conv/specs/warp_utils_callables.py @@ -0,0 +1,345 @@ +"""Module to put any functions that are referred to in the "callables" section of WarpUtils.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob + + +def out_file_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_file"] + + +def out_jacobian_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["out_jacobian"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +iflogger = logging.getLogger("nipype.interface") + + +# Original source at L809 of /interfaces/base/core.py +def _filename_from_source( + name, chain=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + if chain is None: + chain = [] + + trait_spec = inputs.trait(name) + retval = getattr(inputs, name) + source_ext = None + if (retval is attrs.NOTHING) or "%s" in retval: + if not trait_spec.name_source: + return retval + + # Do not generate filename when excluded by other inputs + if any( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.xor or () + ): + return retval + + # Do not generate filename when required fields are missing + if not all( + (getattr(inputs, field) is not attrs.NOTHING) + for field in trait_spec.requires or () + ): + return retval + + if (retval is not attrs.NOTHING) and "%s" in retval: + name_template = retval + else: + name_template = trait_spec.name_template + if not name_template: + name_template = "%s_generated" + + ns = trait_spec.name_source + while isinstance(ns, (list, tuple)): + if len(ns) > 1: + iflogger.warning("Only one name_source per trait is allowed") + ns = ns[0] + + if not isinstance(ns, (str, bytes)): + raise ValueError( + "name_source of '{}' trait should be an input trait " + "name, but a type {} object was found".format(name, type(ns)) + ) + + if getattr(inputs, ns) is not attrs.NOTHING: + name_source = ns + source = getattr(inputs, name_source) + while isinstance(source, list): + source = source[0] + + # special treatment for files + try: + _, base, source_ext = split_filename(source) + except (AttributeError, TypeError): + base = source + else: + if name in chain: + raise NipypeInterfaceError("Mutually pointing name_sources") + + chain.append(name) + base = _filename_from_source( + ns, + chain, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + if base is not attrs.NOTHING: + _, _, source_ext = split_filename(base) + else: + # Do not generate filename when required fields are missing + return retval + + chain = None + retval = name_template % base + _, _, ext = split_filename(retval) + if trait_spec.keep_extension and (ext or source_ext): + if (ext is None or not ext) and source_ext: + retval = retval + source_ext + else: + retval = _overload_extension( + retval, + name, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + return retval + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L891 of /interfaces/base/core.py +def _list_outputs(inputs=None, stdout=None, stderr=None, output_dir=None): + metadata = dict(name_source=lambda t: t is not None) + traits = inputs.traits(**metadata) + if traits: + outputs = {} + for name, trait_spec in list(traits.items()): + out_name = name + if trait_spec.output_name is not None: + out_name = trait_spec.output_name + fname = _filename_from_source( + name, inputs=inputs, stdout=stdout, stderr=stderr, output_dir=output_dir + ) + if fname is not attrs.NOTHING: + outputs[out_name] = os.path.abspath(fname) + return outputs + + +# Original source at L249 of /interfaces/fsl/base.py +def _overload_extension( + value, name=None, inputs=None, stdout=None, stderr=None, output_dir=None +): + return value + Info.output_type_to_ext(inputs.output_type) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) + + +# Original source at L125 of /interfaces/base/support.py +class NipypeInterfaceError(Exception): + """Custom error for interfaces""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "{}".format(self.value) diff --git a/nipype-auto-conv/specs/x_fibres_5.yaml b/nipype-auto-conv/specs/x_fibres_5.yaml new file mode 100644 index 0000000..95887a8 --- /dev/null +++ b/nipype-auto-conv/specs/x_fibres_5.yaml @@ -0,0 +1,150 @@ +# This file is used to manually specify the semi-automatic conversion of +# 'nipype.interfaces.fsl.dti.XFibres5' from Nipype to Pydra. +# +# Please fill-in/edit the fields below where appropriate +# +# Docs +# ---- +# +# Perform model parameters estimation for local (voxelwise) diffusion +# parameters +# +task_name: XFibres5 +nipype_name: XFibres5 +nipype_module: nipype.interfaces.fsl.dti +inputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + bvals: generic/file + # type=file|default=: b values file + bvecs: generic/file + # type=file|default=: b vectors file + dwi: generic/file + # type=file|default=: diffusion weighted image data file + gradnonlin: generic/file + # type=file|default=: gradient file corresponding to slice + logdir: generic/directory + # type=directory|default='.': + mask: generic/file + # type=file|default=: brain binary mask file (i.e. from BET) + callable_defaults: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set as the `default` method of input fields + metadata: + # dict[str, dict[str, any]] - additional metadata to set on any of the input fields (e.g. out_file: position: 1) +outputs: + omit: + # list[str] - fields to omit from the Pydra interface + rename: + # dict[str, str] - fields to rename in the Pydra interface + types: + # dict[str, type] - override inferred types (use "mime-like" string for file-format types, + # e.g. 'medimage/nifti-gz'). For most fields the type will be correctly inferred + # from the nipype interface, but you may want to be more specific, particularly + # for file types, where specifying the format also specifies the file that will be + # passed to the field in the automatically generated unittests. + dyads: generic/file+list-of + # type=outputmultiobject: Mean of PDD distribution in vector form. + fsamples: generic/file+list-of + # type=outputmultiobject: Samples from the distribution on f anisotropy + mean_S0samples: generic/file + # type=file: Mean of distribution on T2wbaseline signal intensity S0 + mean_dsamples: generic/file + # type=file: Mean of distribution on diffusivity d + mean_fsamples: generic/file+list-of + # type=outputmultiobject: Mean of distribution on f anisotropy + mean_tausamples: generic/file + # type=file: Mean of distribution on tau samples (only with rician noise) + phsamples: generic/file+list-of + # type=outputmultiobject: phi samples, per fiber + thsamples: generic/file+list-of + # type=outputmultiobject: theta samples, per fiber + callables: + # dict[str, str] - names of methods/callable classes defined in the adjacent `*_callables.py` + # to set to the `callable` attribute of output fields + templates: + # dict[str, str] - `output_file_template` values to be provided to output fields + requirements: + # dict[str, list[str]] - input fields that are required to be provided for the output field to be present +tests: + - inputs: + # dict[str, str] - values to provide to inputs fields in the task initialisation + # (if not specified, will try to choose a sensible value) + gradnonlin: + # type=file|default=: gradient file corresponding to slice + dwi: + # type=file|default=: diffusion weighted image data file + mask: + # type=file|default=: brain binary mask file (i.e. from BET) + bvecs: + # type=file|default=: b vectors file + bvals: + # type=file|default=: b values file + logdir: + # type=directory|default='.': + n_fibres: + # type=range|default=2: Maximum number of fibres to fit in each voxel + model: + # type=enum|default=1|allowed[1,2,3]: use monoexponential (1, default, required for single-shell) or multiexponential (2, multi-shell) model + fudge: + # type=int|default=0: ARD fudge factor + n_jumps: + # type=int|default=5000: Num of jumps to be made by MCMC + burn_in: + # type=range|default=0: Total num of jumps at start of MCMC to be discarded + burn_in_no_ard: + # type=range|default=0: num of burnin jumps before the ard is imposed + sample_every: + # type=range|default=1: Num of jumps for each sample (MCMC) + update_proposal_every: + # type=range|default=40: Num of jumps for each update to the proposal density std (MCMC) + seed: + # type=int|default=0: seed for pseudo random number generator + no_ard: + # type=bool|default=False: Turn ARD off on all fibres + all_ard: + # type=bool|default=False: Turn ARD on on all fibres + no_spat: + # type=bool|default=False: Initialise with tensor, not spatially + non_linear: + # type=bool|default=False: Initialise with nonlinear fitting + cnlinear: + # type=bool|default=False: Initialise with constrained nonlinear fitting + rician: + # type=bool|default=False: use Rician noise modeling + f0_noard: + # type=bool|default=False: Noise floor model: add to the model an unattenuated signal compartment f0 + f0_ard: + # type=bool|default=False: Noise floor model: add to the model an unattenuated signal compartment f0 + force_dir: + # type=bool|default=True: use the actual directory name given (do not add + to make a new directory) + output_type: + # type=enum|default='NIFTI'|allowed['NIFTI','NIFTI_GZ','NIFTI_PAIR','NIFTI_PAIR_GZ']: FSL output type + args: + # type=str|default='': Additional parameters to the command + environ: + # type=dict|default={}: Environment variables + imports: + # list[nipype2pydra.task.base.importstatement] - list import statements required by the test, with each list item + # consisting of 'module', 'name', and optionally 'alias' keys + expected_outputs: + # dict[str, str] - expected values for selected outputs, noting that tests will typically + # be terminated before they complete for time-saving reasons, and therefore + # these values will be ignored, when running in CI + timeout: 10 + # int - the value to set for the timeout in the generated test, + # after which the test will be considered to have been initialised + # successfully. Set to 0 to disable the timeout (warning, this could + # lead to the unittests taking a very long time to complete) + xfail: true + # bool - whether the unittest is expected to fail or not. Set to false + # when you are satisfied with the edits you have made to this file +doctests: [] diff --git a/nipype-auto-conv/specs/x_fibres_5_callables.py b/nipype-auto-conv/specs/x_fibres_5_callables.py new file mode 100644 index 0000000..8b82c68 --- /dev/null +++ b/nipype-auto-conv/specs/x_fibres_5_callables.py @@ -0,0 +1,446 @@ +"""Module to put any functions that are referred to in the "callables" section of XFibres5.yaml""" + +import attrs +import logging +import os +import os.path as op +from glob import glob +from pathlib import Path + + +def dyads_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["dyads"] + + +def fsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["fsamples"] + + +def mean_S0samples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_S0samples"] + + +def mean_dsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_dsamples"] + + +def mean_fsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_fsamples"] + + +def mean_tausamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["mean_tausamples"] + + +def phsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["phsamples"] + + +def thsamples_callable(output_dir, inputs, stdout, stderr): + outputs = _list_outputs( + output_dir=output_dir, inputs=inputs, stdout=stdout, stderr=stderr + ) + return outputs["thsamples"] + + +IFLOGGER = logging.getLogger("nipype.interface") + + +# Original source at L885 of /interfaces/base/core.py +def _gen_filename(name, inputs=None, stdout=None, stderr=None, output_dir=None): + raise NotImplementedError + + +# Original source at L205 of /interfaces/fsl/base.py +def _gen_fname( + basename, + cwd=None, + suffix=None, + change_ext=True, + ext=None, + inputs=None, + stdout=None, + stderr=None, + output_dir=None, +): + """Generate a filename based on the given parameters. + + The filename will take the form: cwd/basename. + If change_ext is True, it will use the extensions specified in + inputs.output_type. + + Parameters + ---------- + basename : str + Filename to base the new filename on. + cwd : str + Path to prefix to the new filename. (default is output_dir) + suffix : str + Suffix to add to the `basename`. (defaults is '' ) + change_ext : bool + Flag to change the filename extension to the FSL output type. + (default True) + + Returns + ------- + fname : str + New filename based on given parameters. + + """ + + if basename == "": + msg = "Unable to generate filename for command %s. " % "xfibres" + msg += "basename is not set!" + raise ValueError(msg) + if cwd is None: + cwd = output_dir + if ext is None: + ext = Info.output_type_to_ext(inputs.output_type) + if change_ext: + if suffix: + suffix = "".join((suffix, ext)) + else: + suffix = ext + if suffix is None: + suffix = "" + fname = fname_presuffix(basename, suffix=suffix, use_ext=False, newpath=cwd) + return fname + + +# Original source at L298 of /interfaces/fsl/dti.py +def _list_outputs(out_dir=None, inputs=None, stdout=None, stderr=None, output_dir=None): + outputs = {} + n_fibres = inputs.n_fibres + if not out_dir: + if inputs.logdir is not attrs.NOTHING: + out_dir = os.path.abspath(inputs.logdir) + else: + out_dir = os.path.abspath("logdir") + + multi_out = ["dyads", "fsamples", "mean_fsamples", "phsamples", "thsamples"] + single_out = ["mean_dsamples", "mean_S0samples"] + + for k in single_out: + outputs[k] = _gen_fname( + k, + cwd=out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + + if (inputs.rician is not attrs.NOTHING) and inputs.rician: + outputs["mean_tausamples"] = _gen_fname( + "mean_tausamples", + cwd=out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + + for k in multi_out: + outputs[k] = [] + + for i in range(1, n_fibres + 1): + outputs["fsamples"].append( + _gen_fname( + "f%dsamples" % i, + cwd=out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["mean_fsamples"].append( + _gen_fname( + "mean_f%dsamples" % i, + cwd=out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + + for i in range(1, n_fibres + 1): + outputs["dyads"].append( + _gen_fname( + "dyads%d" % i, + cwd=out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["phsamples"].append( + _gen_fname( + "ph%dsamples" % i, + cwd=out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + outputs["thsamples"].append( + _gen_fname( + "th%dsamples" % i, + cwd=out_dir, + inputs=inputs, + stdout=stdout, + stderr=stderr, + output_dir=output_dir, + ) + ) + + return outputs + + +# Original source at L108 of /utils/filemanip.py +def fname_presuffix(fname, prefix="", suffix="", newpath=None, use_ext=True): + """Manipulates path and name of input filename + + Parameters + ---------- + fname : string + A filename (may or may not include path) + prefix : string + Characters to prepend to the filename + suffix : string + Characters to append to the filename + newpath : string + Path to replace the path of the input fname + use_ext : boolean + If True (default), appends the extension of the original file + to the output name. + + Returns + ------- + Absolute path of the modified filename + + >>> from nipype.utils.filemanip import fname_presuffix + >>> fname = 'foo.nii.gz' + >>> fname_presuffix(fname,'pre','post','/tmp') + '/tmp/prefoopost.nii.gz' + + >>> from nipype.interfaces.base import attrs.NOTHING + >>> fname_presuffix(fname, 'pre', 'post', attrs.NOTHING) == \ + fname_presuffix(fname, 'pre', 'post') + True + + """ + pth, fname, ext = split_filename(fname) + if not use_ext: + ext = "" + + # No need for : bool(attrs.NOTHING is not attrs.NOTHING) evaluates to False + if newpath: + pth = op.abspath(newpath) + return op.join(pth, prefix + fname + suffix + ext) + + +# Original source at L58 of /utils/filemanip.py +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : str + file or path name + + Returns + ------- + pth : str + base path from fname + fname : str + filename from fname, without extension + ext : str + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + + """ + + special_extensions = [".nii.gz", ".tar.gz", ".niml.dset"] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext + + +# Original source at L1069 of /interfaces/base/core.py +class PackageInfo(object): + _version = None + version_cmd = None + version_file = None + + @classmethod + def version(klass): + if klass._version is None: + if klass.version_cmd is not None: + try: + clout = CommandLine( + command=klass.version_cmd, + resource_monitor=False, + terminal_output="allatonce", + ).run() + except IOError: + return None + + raw_info = clout.runtime.stdout + elif klass.version_file is not None: + try: + with open(klass.version_file, "rt") as fobj: + raw_info = fobj.read() + except OSError: + return None + else: + return None + + klass._version = klass.parse_version(raw_info) + + return klass._version + + @staticmethod + def parse_version(raw_info): + raise NotImplementedError + + +# Original source at L40 of /interfaces/fsl/base.py +class Info(PackageInfo): + """ + Handle FSL ``output_type`` and version information. + + output type refers to the type of file fsl defaults to writing + eg, NIFTI, NIFTI_GZ + + Examples + -------- + + >>> from nipype.interfaces.fsl import Info + >>> Info.version() # doctest: +SKIP + >>> Info.output_type() # doctest: +SKIP + + """ + + ftypes = { + "NIFTI": ".nii", + "NIFTI_PAIR": ".img", + "NIFTI_GZ": ".nii.gz", + "NIFTI_PAIR_GZ": ".img.gz", + } + + if os.getenv("FSLDIR"): + version_file = os.path.join(os.getenv("FSLDIR"), "etc", "fslversion") + + @staticmethod + def parse_version(raw_info): + return raw_info.splitlines()[0] + + @classmethod + def output_type_to_ext(cls, output_type): + """Get the file extension for the given output type. + + Parameters + ---------- + output_type : {'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ'} + String specifying the output type. + + Returns + ------- + extension : str + The file extension for the output type. + """ + + try: + return cls.ftypes[output_type] + except KeyError: + msg = "Invalid FSLOUTPUTTYPE: ", output_type + raise KeyError(msg) + + @classmethod + def output_type(cls): + """Get the global FSL output file type FSLOUTPUTTYPE. + + This returns the value of the environment variable + FSLOUTPUTTYPE. An exception is raised if it is not defined. + + Returns + ------- + fsl_ftype : string + Represents the current environment setting of FSLOUTPUTTYPE + """ + try: + return os.environ["FSLOUTPUTTYPE"] + except KeyError: + IFLOGGER.warning( + "FSLOUTPUTTYPE environment variable is not set. " + "Setting FSLOUTPUTTYPE=NIFTI" + ) + return "NIFTI" + + @staticmethod + def standard_image(img_name=None): + """Grab an image from the standard location. + + Returns a list of standard images if called without arguments. + + Could be made more fancy to allow for more relocatability""" + try: + fsldir = os.environ["FSLDIR"] + except KeyError: + raise Exception("FSL environment variables not set") + stdpath = os.path.join(fsldir, "data", "standard") + if img_name is None: + return [ + filename.replace(stdpath + "/", "") + for filename in glob(os.path.join(stdpath, "*nii*")) + ] + return os.path.join(stdpath, img_name) diff --git a/pydra/tasks/fsl/__init__.py b/pydra/tasks/fsl/__init__.py index ad1ccb6..dc03b8a 100644 --- a/pydra/tasks/fsl/__init__.py +++ b/pydra/tasks/fsl/__init__.py @@ -1,12 +1,38 @@ """ -To use the tasks in this package, import from ``pydra.tasks.fsl``:: - - >>> import pydra.engine - >>> import pydra.tasks.fsl +This is a basic doctest demonstrating that the package and pydra can both be successfully +imported. +>>> import pydra.engine +>>> import pydra.tasks.fsl """ +from warnings import warn +from pathlib import Path + +pkg_path = Path(__file__).parent.parent + try: from ._version import __version__ except ImportError: - pass + raise RuntimeError( + "pydra-fsl has not been properly installed, please run " + f"`pip install -e {str(pkg_path)}` to install a development version" + ) +if "nipype" not in __version__: + try: + from .auto._version import nipype_version, nipype2pydra_version + except ImportError: + warn( + "Nipype interfaces haven't been automatically converted from their specs in " + f"`nipype-auto-conv`. Please run `{str(pkg_path / 'nipype-auto-conv' / 'generate')}` " + "to generated the converted Nipype interfaces in pydra.tasks.fsl.auto" + ) + else: + n_ver = nipype_version.replace(".", "_") + n2p_ver = nipype2pydra_version.replace(".", "_") + __version__ += ( + "_" if "+" in __version__ else "+" + ) + f"nipype{n_ver}_nipype2pydra{n2p_ver}" + + +__all__ = ["__version__"] diff --git a/pydra/tasks/fsl/_version.py b/pydra/tasks/fsl/_version.py deleted file mode 100644 index c519089..0000000 --- a/pydra/tasks/fsl/_version.py +++ /dev/null @@ -1,4 +0,0 @@ -# file generated by setuptools_scm -# don't change, don't track in version control -__version__ = version = '0.1.dev123+gd6b46a1.d20230502' -__version_tuple__ = version_tuple = (0, 1, 'dev123', 'gd6b46a1.d20230502') diff --git a/pydra/tasks/fsl/conftest.py b/pydra/tasks/fsl/conftest.py deleted file mode 100644 index ba9f4d8..0000000 --- a/pydra/tasks/fsl/conftest.py +++ /dev/null @@ -1,48 +0,0 @@ -import os -import shutil -from tempfile import mkdtemp -import pytest - -# import numpy -import py.path as pp - -NIPYPE_DATADIR = os.path.realpath(os.path.join(os.path.dirname(__file__), "tests/data")) -temp_folder = mkdtemp() -data_dir = os.path.join(temp_folder, "data") -shutil.copytree(NIPYPE_DATADIR, data_dir) - - -@pytest.fixture(autouse=True) -def add_np(doctest_namespace): - # doctest_namespace["np"] = numpy - doctest_namespace["os"] = os - doctest_namespace["pytest"] = pytest - doctest_namespace["datadir"] = data_dir - - -@pytest.fixture(autouse=True) -def _docdir(request): - """Grabbed from https://stackoverflow.com/a/46991331""" - # Trigger ONLY for the doctests. - doctest_plugin = request.config.pluginmanager.getplugin("doctest") - if isinstance(request.node, doctest_plugin.DoctestItem): - # Get the fixture dynamically by its name. - tmpdir = pp.local(data_dir) - - # Chdir only for the duration of the test. - with tmpdir.as_cwd(): - yield - - else: - # For normal tests, we have to yield, since this is a yield-fixture. - yield - - -@pytest.fixture() -def test_data(): - return NIPYPE_DATADIR - - -def pytest_unconfigure(config): - # Delete temp folder after session is finished - shutil.rmtree(temp_folder) diff --git a/pydra/tasks/fsl/latest.py b/pydra/tasks/fsl/latest.py new file mode 100644 index 0000000..edb8f37 --- /dev/null +++ b/pydra/tasks/fsl/latest.py @@ -0,0 +1,3 @@ +PACKAGE_VERSION = "v6_0" + +from .v6_0 import * # noqa diff --git a/pydra/tasks/fsl/model/__init__.py b/pydra/tasks/fsl/model/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/model/cluster.py b/pydra/tasks/fsl/model/cluster.py deleted file mode 100644 index e45f144..0000000 --- a/pydra/tasks/fsl/model/cluster.py +++ /dev/null @@ -1,242 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def Cluster_output(inputs): - import os, attr - from pydra.engine.helpers_file import split_filename - - in_file = inputs.in_file - pth, fname, ext = split_filename(in_file) - - return os.path.join(pth, f"{fname}_localmax.txt") - - -input_fields = [ - ( - "in_file", - specs.File, - {"help_string": "input volume", "argstr": "--in={in_file}", "mandatory": True}, - ), - ( - "threshold", - float, - { - "help_string": "threshold for input volume", - "argstr": "--thresh={threshold:.10f}", - "mandatory": True, - }, - ), - ( - "out_index_file", - ty.Union[bool, str], - False, - { - "help_string": "output of cluster index (in size order)", - "argstr": "--oindex={out_index_file}", - "output_file_template": "{in_file}_index", - }, - ), - ( - "out_threshold_file", - ty.Union[bool, str], - False, - { - "help_string": "thresholded image", - "argstr": "--othresh={out_threshold_file}", - "output_file_template": "{in_file}_threshold", - }, - ), - ( - "out_localmax_txt_file", - ty.Union[bool, str], - False, - { - "help_string": "local maxima text file", - "argstr": "--olmax={out_localmax_txt_file}", - "output_file_template": Cluster_output, - }, - ), - ( - "out_localmax_vol_file", - ty.Union[bool, str], - False, - { - "help_string": "output of local maxima volume", - "argstr": "--olmaxim={out_localmax_vol_file}", - "output_file_template": "{in_file}_localmax", - }, - ), - ( - "out_size_file", - ty.Union[bool, str], - False, - { - "help_string": "filename for output of size image", - "argstr": "--osize={out_size_file}", - "output_file_template": "{in_file}_size", - }, - ), - ( - "out_max_file", - ty.Union[bool, str], - False, - { - "help_string": "filename for output of max image", - "argstr": "--omax={out_max_file}", - "output_file_template": "{in_file}_max", - }, - ), - ( - "out_mean_file", - ty.Union[bool, str], - False, - { - "help_string": "filename for output of mean image", - "argstr": "--omean={out_mean_file}", - "output_file_template": "{in_file}_mean", - }, - ), - ( - "out_pval_file", - ty.Union[bool, str], - False, - { - "help_string": "filename for image output of log pvals", - "argstr": "--opvals={out_pval_file}", - "output_file_template": "{in_file}_pval", - }, - ), - ( - "pthreshold", - float, - { - "help_string": "p-threshold for clusters", - "argstr": "--pthresh={pthreshold:.10f}", - "requires": ["dlh", "volume"], - }, - ), - ( - "peak_distance", - float, - { - "help_string": "minimum distance between local maxima/minima, in mm (default 0)", - "argstr": "--peakdist={peak_distance:.10f}", - }, - ), - ("cope_file", str, {"help_string": "cope volume", "argstr": "--cope={cope_file}"}), - ( - "volume", - int, - {"help_string": "number of voxels in the mask", "argstr": "--volume={volume}"}, - ), - ( - "dlh", - float, - { - "help_string": "smoothness estimate = sqrt(det(Lambda))", - "argstr": "--dlh={dlh:.10f}", - }, - ), - ( - "fractional", - bool, - False, - { - "help_string": "interprets the threshold as a fraction of the robust range", - "argstr": "--fractional", - }, - ), - ( - "connectivity", - int, - { - "help_string": "the connectivity of voxels (default 26)", - "argstr": "--connectivity={connectivity}", - }, - ), - ( - "use_mm", - bool, - False, - {"help_string": "use mm, not voxel, coordinates", "argstr": "--mm"}, - ), - ( - "find_min", - bool, - False, - {"help_string": "find minima instead of maxima", "argstr": "--min"}, - ), - ( - "no_table", - bool, - False, - { - "help_string": "suppresses printing of the table info", - "argstr": "--no_table", - }, - ), - ( - "minclustersize", - bool, - False, - { - "help_string": "prints out minimum significant cluster size", - "argstr": "--minclustersize", - }, - ), - ( - "xfm_file", - str, - { - "help_string": "filename for Linear: input->standard-space transform. Non-linear: input->highres transform", - "argstr": "--xfm={xfm_file}", - }, - ), - ( - "std_space_file", - str, - { - "help_string": "filename for standard-space volume", - "argstr": "--stdvol={std_space_file}", - }, - ), - ( - "num_maxima", - int, - {"help_string": "no of local maxima to report", "argstr": "--num={num_maxima}"}, - ), - ( - "warpfield_file", - str, - { - "help_string": "file contining warpfield", - "argstr": "--warpvol={warpfield_file}", - }, - ), -] -Cluster_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -Cluster_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class Cluster(ShellCommandTask): - """ - Example - ------- - >>> task = Cluster() - >>> task.inputs.in_file = "zstat1.nii.gz" - >>> task.inputs.out_localmax_txt_file = True - >>> task.inputs.threshold = 2.3 - >>> task.inputs.use_mm = True - >>> task.cmdline # doctest: +ELLIPSIS - 'cluster --in=zstat1.nii.gz --thresh=2.3000000000 --olmax=.../zstat1_localmax.txt --mm' - """ - - input_spec = Cluster_input_spec - output_spec = Cluster_output_spec - executable = "cluster" diff --git a/pydra/tasks/fsl/model/feat.py b/pydra/tasks/fsl/model/feat.py deleted file mode 100644 index 8f171d3..0000000 --- a/pydra/tasks/fsl/model/feat.py +++ /dev/null @@ -1,62 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def FEAT_output(fsf_file): - is_ica = False - with open(fsf_file, "rt") as fp: - text = fp.read() - if "set fmri(inmelodic) 1" in text: - is_ica = True - for line in text.split("\n"): - if line.find("set fmri(outputdir)") > -1: - try: - outputdir_spec = line.split('"')[-2] - if os.path.exists(outputdir_spec): - outputs = outputdir_spec - except: - pass - - if not outputs: - if is_ica: - outputs = glob(os.path.join(os.getcwd(), "*ica"))[0] - else: - outputs = glob(os.path.join(os.getcwd(), "*feat"))[0] - print("Outputs from FEATmodel:", outputs) - return outputs - - -input_fields = [ - ( - "fsf_file", - specs.File, - { - "help_string": "File specifying the feat design spec file", - "argstr": "{fsf_file}", - "mandatory": True, - "position": 0, - }, - ) -] -FEAT_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ("feat_dir", specs.Directory, {"requires": ["fsf_file"], "callable": FEAT_output}) -] -FEAT_output_spec = specs.SpecInfo(name="Output", fields=output_fields, bases=(specs.ShellOutSpec,)) - - -class FEAT(ShellCommandTask): - """ - Example - ------- - >>> task = FEAT() - >>> task.inputs.fsf_file = "test.fsf" - >>> task.cmdline - 'feat test.fsf' - """ - - input_spec = FEAT_input_spec - output_spec = FEAT_output_spec - executable = "feat" diff --git a/pydra/tasks/fsl/model/featmodel.py b/pydra/tasks/fsl/model/featmodel.py deleted file mode 100644 index 47663c6..0000000 --- a/pydra/tasks/fsl/model/featmodel.py +++ /dev/null @@ -1,119 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def FEATModel_output(field, fsf_file): - import os - - # TODO: figure out file names and get rid off the globs - outputs = {} - _, fname = os.path.split(fsf_file) - root = fname.split(".")[0] - name = field.name - if name == "design_file": - design_file = glob(os.path.join(os.getcwd(), "%s*.mat" % root)) - assert len(design_file) == 1, "No mat file generated by FEAT Model" - outputs = design_file[0] - elif name == "design_image": - design_image = glob(os.path.join(os.getcwd(), "%s.png" % root)) - assert len(design_image) == 1, "No design image generated by FEAT Model" - outputs = design_image[0] - elif name == "design_cov": - design_cov = glob(os.path.join(os.getcwd(), "%s_cov.png" % root)) - assert len(design_cov) == 1, "No covariance image generated by FEAT Model" - outputs = design_cov[0] - elif name == "con_file": - con_file = glob(os.path.join(os.getcwd(), "%s*.con" % root)) - assert len(con_file) == 1, "No con file generated by FEAT Model" - outputs = con_file[0] - elif name == "fcon_file": - fcon_file = glob(os.path.join(os.getcwd(), "%s*.fts" % root)) - if fcon_file: - assert len(fcon_file) == 1, "No fts file generated by FEAT Model" - outputs = fcon_file[0] - else: - raise Exception( - f"this function should be run only for design_file, design_image" - f"design_cov, con_file, or fcon_file, not for {name}" - ) - return outputs - - -input_fields = [ - ( - "fsf_file", - specs.File, - { - "help_string": "File specifying the feat design spec file", - "argstr": "{fsf_file}", - "copyfile": False, - "mandatory": True, - "position": 0, - }, - ), - ( - "ev_files", - specs.MultiInputFile, - { - "help_string": "Event spec files generated by level1design", - "argstr": "{ev_files}", - "copyfile": False, - "mandatory": True, - "position": 1, - }, - ), -] -FEATModel_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "design_file", - specs.File, - { - "help_string": "Mat file containing ascii matrix for design", - "callable": FEATModel_output, - }, - ), - ( - "design_image", - specs.File, - { - "help_string": "Graphical representation of design matrix", - "callable": FEATModel_output, - }, - ), - ( - "design_cov", - specs.File, - { - "help_string": "Graphical representation of design covariance", - "callable": FEATModel_output, - }, - ), - ( - "con_file", - specs.File, - { - "help_string": "Contrast file containing contrast vectors", - "callable": FEATModel_output, - }, - ), - ( - "fcon_file", - specs.File, - { - "help_string": "Contrast file containing contrast vectors", - "callable": FEATModel_output, - }, - ), -] -FEATModel_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class FEATModel(ShellCommandTask): - input_spec = FEATModel_input_spec - output_spec = FEATModel_output_spec - executable = "feat_model" diff --git a/pydra/tasks/fsl/model/filmgls.py b/pydra/tasks/fsl/model/filmgls.py deleted file mode 100644 index 75c0e19..0000000 --- a/pydra/tasks/fsl/model/filmgls.py +++ /dev/null @@ -1,396 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def FILMGLS_output(field, inputs): - import os, attr - - def _get_pe_files(design_file, pth): - files = None - if design_file not in [None, attr.NOTHING]: - fp = open(design_file, "rt") - for line in fp.readlines(): - if line.startswith("/NumWaves"): - numpes = int(line.split()[-1]) - files = [] - for i in range(numpes): - files.append(os.path.join(pth, ("pe%d.nii.gz" % (i + 1)))) - break - fp.close() - return files - - def _get_numcons(inputs): - numtcons = 0 - numfcons = 0 - if inputs.tcon_file not in [None, attr.NOTHING]: - fp = open(inputs.tcon_file, "rt") - for line in fp.readlines(): - if line.startswith("/NumContrasts"): - numtcons = int(line.split()[-1]) - break - fp.close() - if inputs.fcon_file not in [None, attr.NOTHING]: - fp = open(inputs.fcon_file, "rt") - for line in fp.readlines(): - if line.startswith("/NumContrasts"): - numfcons = int(line.split()[-1]) - break - fp.close() - return numtcons, numfcons - - name = field.name - pth = inputs.results_dir - if name == "results_dir": - return pth - elif name == "param_estimates": - design_file = inputs.design_file - pe_files = _get_pe_files(design_file, pth) - if pe_files: - return pe_files - elif name == "residual4d": - return os.path.join(pth, "res4d.nii.gz") - elif name == "dof_file": - return os.path.join(pth, "dof") - elif name == "sigmasquareds": - return os.path.join(pth, "sigmasquareds.nii.gz") - elif name == "thresholdac": - return os.path.join(pth, "threshac1.nii.gz") - elif name == "logfile": - return os.path.join(pth, "logfile") - - numtcons, numfcons = _get_numcons(inputs) - base_contrast = 1 - copes = [] - varcopes = [] - zstats = [] - tstats = [] - for i in range(numtcons): - copes.append(os.path.join(pth, ("cope%d.nii.gz" % (base_contrast + i)))) - varcopes.append(os.path.join(pth, ("varcope%d.nii.gz" % (base_contrast + i)))) - zstats.append(os.path.join(pth, ("zstat%d.nii.gz" % (base_contrast + i)))) - tstats.append(os.path.join(pth, ("tstat%d.nii.gz" % (base_contrast + i)))) - if copes: - if name == "copes": - return copes - elif name == "varcopes": - return varcopes - elif name == "zstats": - return zstats - elif name == "tstats": - return tstats - fstats = [] - zfstats = [] - for i in range(numfcons): - fstats.append(os.path.join(pth, ("fstat%d.nii.gz" % (base_contrast + i)))) - zfstats.append(os.path.join(pth, ("zfstat%d.nii.gz" % (base_contrast + i)))) - if fstats: - if name == "fstats": - return fstats - elif name == "zfstats": - return zfstats - - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input data file", - "argstr": "--in={in_file}", - "mandatory": True, - "position": -3, - }, - ), - ( - "design_file", - specs.File, - { - "help_string": "design matrix file", - "argstr": "--pd={design_file}", - "position": -2, - }, - ), - ( - "threshold", - float, - -1000.0, - {"help_string": "threshold", "argstr": "--thr={threshold}", "position": -1}, - ), - ( - "tcon_file", - specs.File, - { - "help_string": "contrast file containing T-contrasts", - "argstr": "--con={tcon_file}", - }, - ), - ( - "fcon_file", - specs.File, - { - "help_string": "contrast file containing F-contrasts", - "argstr": "--fcon={fcon_file}", - }, - ), - ( - "mode", - ty.Any, - {"help_string": "Type of analysis to be done", "argstr": "--mode={mode}"}, - ), - ( - "surface", - specs.File, - { - "help_string": "input surface for autocorr smoothing in surface-based analyses", - "argstr": "--in2={surface}", - }, - ), - ( - "smooth_autocorr", - bool, - {"help_string": "Smooth auto corr estimates", "argstr": "--sa"}, - ), - ( - "mask_size", - int, - {"help_string": "susan mask size", "argstr": "--ms={mask_size}"}, - ), - ( - "brightness_threshold", - ty.Any, - { - "help_string": "susan brightness threshold, otherwise it is estimated", - "argstr": "--epith={brightness_threshold}", - }, - ), - ("full_data", bool, {"help_string": "output full data", "argstr": "-v"}), - ( - "autocorr_estimate_only", - bool, - { - "help_string": "perform autocorrelation estimation only", - "argstr": "--ac", - "xor": [ - "autocorr_estimate_only", - "fit_armodel", - "tukey_window", - "multitaper_product", - "use_pava", - "autocorr_noestimate", - ], - }, - ), - ( - "fit_armodel", - bool, - { - "help_string": "fits autoregressive model - default is to use tukey with M=sqrt(numvols)", - "argstr": "--ar", - "xor": [ - "autocorr_estimate_only", - "fit_armodel", - "tukey_window", - "multitaper_product", - "use_pava", - "autocorr_noestimate", - ], - }, - ), - ( - "tukey_window", - int, - { - "help_string": "tukey window size to estimate autocorr", - "argstr": "--tukey={tukey_window}", - "xor": [ - "autocorr_estimate_only", - "fit_armodel", - "tukey_window", - "multitaper_product", - "use_pava", - "autocorr_noestimate", - ], - }, - ), - ( - "multitaper_product", - int, - { - "help_string": "multitapering with slepian tapers and num is the time-bandwidth product", - "argstr": "--mt={multitaper_product}", - "xor": [ - "autocorr_estimate_only", - "fit_armodel", - "tukey_window", - "multitaper_product", - "use_pava", - "autocorr_noestimate", - ], - }, - ), - ( - "use_pava", - bool, - {"help_string": "estimates autocorr using PAVA", "argstr": "--pava"}, - ), - ( - "autocorr_noestimate", - bool, - { - "help_string": "do not estimate autocorrs", - "argstr": "--noest", - "xor": [ - "autocorr_estimate_only", - "fit_armodel", - "tukey_window", - "multitaper_product", - "use_pava", - "autocorr_noestimate", - ], - }, - ), - ( - "output_pwdata", - bool, - { - "help_string": "output prewhitened data and average design matrix", - "argstr": "--outputPWdata", - }, - ), - ( - "results_dir", - str, - "results", - {"help_string": "directory to store results in", "argstr": "--rn={results_dir}"}, - ), -] -FILMGLS_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "results_dir", - specs.Directory, - { - "help_string": "Directory storing model estimation output", - "callable": FILMGLS_output, - }, - ), - ( - "param_estimates", - specs.MultiOutputFile, - { - "help_string": "Parameter estimates for each column of the design matrix", - "callable": FILMGLS_output, - }, - ), - ( - "residual4d", - specs.File, - { - "help_string": "Model fit residual mean-squared error for each time point", - "callable": FILMGLS_output, - }, - ), - ( - "dof_file", - specs.File, - {"help_string": "degrees of freedom", "callable": FILMGLS_output}, - ), - ( - "sigmasquareds", - specs.File, - { - "help_string": "summary of residuals, See Woolrich, et. al., 2001", - "callable": FILMGLS_output, - }, - ), - ( - "thresholdac", - specs.File, - { - "help_string": "The FILM autocorrelation parameters", - "callable": FILMGLS_output, - }, - ), - ( - "logfile", - specs.File, - {"help_string": "FILM run logfile", "callable": FILMGLS_output}, - ), - ( - "copes", - specs.MultiOutputFile, - { - "help_string": "Contrast estimates for each contrast", - "requires": ["tcon_file"], - "callable": FILMGLS_output, - }, - ), - ( - "varcopes", - specs.MultiOutputFile, - { - "help_string": "Variance estimates for each contrast", - "requires": ["tcon_file"], - "callable": FILMGLS_output, - }, - ), - ( - "zstats", - specs.MultiOutputFile, - { - "help_string": "z-stat file for each contrast", - "requires": ["tcon_file"], - "callable": FILMGLS_output, - }, - ), - ( - "tstats", - specs.MultiOutputFile, - { - "help_string": "t-stat file for each contrast", - "requires": ["tcon_file"], - "callable": FILMGLS_output, - }, - ), - ( - "fstats", - specs.MultiOutputFile, - { - "help_string": "f-stat file for each contrast", - "requires": ["fcon_file"], - "callable": FILMGLS_output, - }, - ), - ( - "zfstats", - specs.MultiOutputFile, - { - "help_string": "z-stat file for each F contrast", - "requires": ["fcon_file"], - "callable": FILMGLS_output, - }, - ), -] -FILMGLS_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class FILMGLS(ShellCommandTask): - """ - Example - ------- - >>> task = FILMGLS() - >>> task.inputs.in_file = "test_film_gls.nii.gz" - >>> task.inputs.design_file = "design_film_gls.mat" - >>> task.inputs.threshold = 10 - >>> task.inputs.results_dir = "stats" - >>> task.cmdline - 'film_gls --rn=stats --in=test_film_gls.nii.gz --pd=design_film_gls.mat --thr=10' - """ - - input_spec = FILMGLS_input_spec - output_spec = FILMGLS_output_spec - executable = "film_gls" diff --git a/pydra/tasks/fsl/model/flameo.py b/pydra/tasks/fsl/model/flameo.py deleted file mode 100644 index f5bb54d..0000000 --- a/pydra/tasks/fsl/model/flameo.py +++ /dev/null @@ -1,336 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def FLAMEO_output(field, inputs): - import os, glob, attr - - def human_order_sorted(l): - """ - Sorts string in human order (i.e. 'stat10' will go after 'stat2') - """ - - def atoi(text): - return int(text) if text.isdigit() else text - - def natural_keys(text): - import re - - if isinstance(text, tuple): - text = text[0] - return [atoi(c) for c in re.split(r"(\d+)", text)] - - return sorted(l, key=natural_keys) - - pth = inputs.log_dir - name = field.name - - if name == "pes": - pes = human_order_sorted(glob.glob(os.path.join(pth, "pe[0-9]*.*"))) - if len(pes) >= 1: - return pes - elif name == "res4d": - res4d = human_order_sorted(glob.glob(os.path.join(pth, "res4d.*"))) - if len(res4d) == 1: - return res4d[0] - elif name == "copes": - copes = human_order_sorted(glob.glob(os.path.join(pth, "cope[0-9]*.*"))) - if len(copes) >= 1: - return copes - elif name == "var_copes": - var_copes = human_order_sorted(glob.glob(os.path.join(pth, "varcope[0-9]*.*"))) - if len(var_copes) >= 1: - return var_copes - elif name == "zstats": - zstats = human_order_sorted(glob.glob(os.path.join(pth, "zstat[0-9]*.*"))) - if len(zstats) >= 1: - return zstats - elif name == "tstats": - tstats = human_order_sorted(glob.glob(os.path.join(pth, "tstat[0-9]*.*"))) - if len(tstats) >= 1: - return tstats - elif name == "mrefvars": - mrefs = human_order_sorted(glob.glob(os.path.join(pth, "mean_random_effects_var[0-9]*.*"))) - if len(mrefs) >= 1: - return mrefs - elif name == "tdof": - tdof = human_order_sorted(glob.glob(os.path.join(pth, "tdof_t[0-9]*.*"))) - if len(tdof) >= 1: - return tdof - elif name == "weights": - weights = human_order_sorted(glob.glob(os.path.join(pth, "weights[0-9]*.*"))) - if len(weights) >= 1: - return weights - elif name == "stats_dir": - return pth - elif inputs.f_con_file not in [None, attr.NOTHING]: - if name == "zfstats": - zfstats = human_order_sorted(glob.glob(os.path.join(pth, "zfstat[0-9]*.*"))) - if len(zfstats) >= 1: - return zfstats - elif name == "fstats": - fstats = human_order_sorted(glob.glob(os.path.join(pth, "fstat[0-9]*.*"))) - if len(fstats) >= 1: - return fstats - else: - raise Exception( - f"this function should be run only for pes, res4d, copes, var_copes, zfstats," - f"fstats, zstats, tstats, mrefs, tdof, weights, or stats_dir, not for {name}" - ) - - -input_fields = [ - ( - "cope_file", - specs.File, - { - "help_string": "cope regressor data file", - "argstr": "--copefile={cope_file}", - "mandatory": True, - }, - ), - ( - "var_cope_file", - specs.File, - { - "help_string": "varcope weightings data file", - "argstr": "--varcopefile={var_cope_file}", - }, - ), - ( - "dof_var_cope_file", - specs.File, - { - "help_string": "dof data file for varcope data", - "argstr": "--dofvarcopefile={dof_var_cope_file}", - }, - ), - ( - "mask_file", - specs.File, - { - "help_string": "mask file", - "argstr": "--maskfile={mask_file}", - "mandatory": True, - }, - ), - ( - "design_file", - specs.File, - { - "help_string": "design matrix file", - "argstr": "--designfile={design_file}", - "mandatory": True, - }, - ), - ( - "t_con_file", - specs.File, - { - "help_string": "ascii matrix specifying t-contrasts", - "argstr": "--tcontrastsfile={t_con_file}", - "mandatory": True, - }, - ), - ( - "f_con_file", - specs.File, - { - "help_string": "ascii matrix specifying f-contrasts", - "argstr": "--fcontrastsfile={f_con_file}", - }, - ), - ( - "cov_split_file", - specs.File, - { - "help_string": "ascii matrix specifying the groups the covariance is split into", - "argstr": "--covsplitfile={cov_split_file}", - "mandatory": True, - }, - ), - ( - "run_mode", - ty.Any, - { - "help_string": "inference to perform", - "argstr": "--runmode={run_mode}", - "mandatory": True, - }, - ), - ( - "n_jumps", - int, - {"help_string": "number of jumps made by mcmc", "argstr": "--njumps={n_jumps}"}, - ), - ( - "burnin", - int, - { - "help_string": "number of jumps at start of mcmc to be discarded", - "argstr": "--burnin={burnin}", - }, - ), - ( - "sample_every", - int, - { - "help_string": "number of jumps for each sample", - "argstr": "--sampleevery={sample_every}", - }, - ), - ("fix_mean", bool, {"help_string": "fix mean for tfit", "argstr": "--fixmean"}), - ( - "infer_outliers", - bool, - {"help_string": "infer outliers - not for fe", "argstr": "--inferoutliers"}, - ), - ( - "no_pe_outputs", - bool, - {"help_string": "do not output pe files", "argstr": "--nopeoutput"}, - ), - ( - "sigma_dofs", - int, - { - "help_string": "sigma (in mm) to use for Gaussian smoothing the DOFs in FLAME 2. Default is 1mm, -1 indicates no smoothing", - "argstr": "--sigma_dofs={sigma_dofs}", - }, - ), - ( - "outlier_iter", - int, - { - "help_string": "Number of max iterations to use when inferring outliers. Default is 12.", - "argstr": "--ioni={outlier_iter}", - }, - ), - ("log_dir", ty.Any, "stats", {"help_string": "", "argstr": "--ld={log_dir}"}), -] -FLAMEO_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "pes", - specs.MultiOutputFile, - { - "help_string": "Parameter estimates for each column of the design matrix for each voxel", - "callable": FLAMEO_output, - }, - ), - ( - "res4d", - specs.MultiOutputFile, - { - "help_string": "Model fit residual mean-squared error for each time point", - "callable": FLAMEO_output, - }, - ), - ( - "copes", - specs.MultiOutputFile, - { - "help_string": "Contrast estimates for each contrast", - "callable": FLAMEO_output, - }, - ), - ( - "var_copes", - specs.MultiOutputFile, - { - "help_string": "Variance estimates for each contrast", - "callable": FLAMEO_output, - }, - ), - ( - "zstats", - specs.MultiOutputFile, - { - "help_string": "z-stat file for each contrast", - "requires": ["t_con_file"], - "callable": FLAMEO_output, - }, - ), - ( - "tstats", - specs.MultiOutputFile, - { - "help_string": "t-stat file for each contrast", - "requires": ["t_con_file"], - "callable": FLAMEO_output, - }, - ), - ( - "zfstats", - specs.MultiOutputFile, - { - "help_string": "z stat file for each f contrast", - "requires": ["f_con_file"], - "callable": FLAMEO_output, - }, - ), - ( - "fstats", - specs.MultiOutputFile, - { - "help_string": "f-stat file for each contrast", - "requires": ["f_con_file"], - "callable": FLAMEO_output, - }, - ), - ( - "mrefvars", - specs.MultiOutputFile, - { - "help_string": "mean random effect variances for each contrast", - "callable": FLAMEO_output, - }, - ), - ( - "tdof", - specs.MultiOutputFile, - { - "help_string": "temporal dof file for each contrast", - "callable": FLAMEO_output, - }, - ), - ( - "weights", - specs.MultiOutputFile, - {"help_string": "weights file for each contrast", "callable": FLAMEO_output}, - ), - ( - "stats_dir", - specs.Directory, - { - "help_string": "directory storing model estimation output", - "callable": FLAMEO_output, - }, - ), -] -FLAMEO_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class FLAMEO(ShellCommandTask): - """ - Example - ------- - >>> task = FLAMEO() - >>> task.inputs.cope_file = "cope_merged.nii.gz" - >>> task.inputs.var_cope_file = "varcope_merged.nii.gz" - >>> task.inputs.cov_split_file = "design.grp" - >>> task.inputs.design_file = "design.mat" - >>> task.inputs.t_con_file = "design.con" - >>> task.inputs.mask_file = "mask.nii.gz" - >>> task.inputs.run_mode = "fe" - >>> task.cmdline - 'flameo --copefile=cope_merged.nii.gz --varcopefile=varcope_merged.nii.gz --maskfile=mask.nii.gz --designfile=design.mat --tcontrastsfile=design.con --covsplitfile=design.grp --runmode=fe --ld=stats' - """ - - input_spec = FLAMEO_input_spec - output_spec = FLAMEO_output_spec - executable = "flameo" diff --git a/pydra/tasks/fsl/model/glm.py b/pydra/tasks/fsl/model/glm.py deleted file mode 100644 index 7d42391..0000000 --- a/pydra/tasks/fsl/model/glm.py +++ /dev/null @@ -1,194 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input file name (text matrix or 3D/4D image file)", - "argstr": "-i {in_file}", - "mandatory": True, - "position": 1, - }, - ), - ( - "out_file", - str, - { - "help_string": "filename for GLM parameter estimates (GLM betas)", - "argstr": "-o {out_file}", - "position": 3, - "output_file_template": "{in_file}_glm", - }, - ), - ( - "design", - specs.File, - { - "help_string": "file name of the GLM design matrix (text time courses for temporal regression or an image file for spatial regression)", - "argstr": "-d {design}", - "mandatory": True, - "position": 2, - }, - ), - ( - "contrasts", - specs.File, - {"help_string": "matrix of t-statics contrasts", "argstr": "-c {contrasts}"}, - ), - ( - "mask", - specs.File, - { - "help_string": "mask image file name if input is image", - "argstr": "-m {mask}", - }, - ), - ( - "dof", - int, - {"help_string": "set degrees of freedom explicitly", "argstr": "--dof={dof}"}, - ), - ( - "des_norm", - bool, - { - "help_string": "switch on normalization of the design matrix columns to unit std deviation", - "argstr": "--des_norm", - }, - ), - ( - "dat_norm", - bool, - { - "help_string": "switch on normalization of the data time series to unit std deviation", - "argstr": "--dat_norm", - }, - ), - ( - "var_norm", - bool, - { - "help_string": "perform MELODIC variance-normalisation on data", - "argstr": "--vn", - }, - ), - ( - "demean", - bool, - { - "help_string": "switch on demeaining of design and data", - "argstr": "--demean", - }, - ), - ( - "out_cope", - str, - { - "help_string": "output file name for COPE (either as txt or image", - "argstr": "--out_cope={out_cope}", - }, - ), - ( - "out_z_name", - str, - { - "help_string": "output file name for Z-stats (either as txt or image", - "argstr": "--out_z={out_z_name}", - }, - ), - ( - "out_t_name", - str, - { - "help_string": "output file name for t-stats (either as txt or image", - "argstr": "--out_t={out_t_name}", - }, - ), - ( - "out_p_name", - str, - { - "help_string": "output file name for p-values of Z-stats (either as text file or image)", - "argstr": "--out_p={out_p_name}", - }, - ), - ( - "out_f_name", - str, - { - "help_string": "output file name for F-value of full model fit", - "argstr": "--out_f={out_f_name}", - }, - ), - ( - "out_pf_name", - str, - { - "help_string": "output file name for p-value for full model fit", - "argstr": "--out_pf={out_pf_name}", - }, - ), - ( - "out_res_name", - str, - { - "help_string": "output file name for residuals", - "argstr": "--out_res={out_res_name}", - }, - ), - ( - "out_varcb_name", - str, - { - "help_string": "output file name for variance of COPEs", - "argstr": "--out_varcb={out_varcb_name}", - }, - ), - ( - "out_sigsq_name", - str, - { - "help_string": "output file name for residual noise variance sigma-square", - "argstr": "--out_sigsq={out_sigsq_name}", - }, - ), - ( - "out_data_name", - str, - { - "help_string": "output file name for pre-processed data", - "argstr": "--out_data={out_data_name}", - }, - ), - ( - "out_vnscales_name", - str, - { - "help_string": "output file name for scaling factors for variance normalisation", - "argstr": "--out_vnscales={out_vnscales_name}", - }, - ), -] -GLM_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -GLM_output_spec = specs.SpecInfo(name="Output", fields=output_fields, bases=(specs.ShellOutSpec,)) - - -class GLM(ShellCommandTask): - """ - Example - ------- - >>> task = GLM() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.design = "confounds_regressors.tsv" - >>> task.cmdline # doctest: +SKIP - 'fsl_glm -i test.nii.gz -d confounds_regressors.tsv' - """ - - input_spec = GLM_input_spec - output_spec = GLM_output_spec - executable = "fsl_glm" diff --git a/pydra/tasks/fsl/model/melodic.py b/pydra/tasks/fsl/model/melodic.py deleted file mode 100644 index 5cecdb3..0000000 --- a/pydra/tasks/fsl/model/melodic.py +++ /dev/null @@ -1,356 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def MELODIC_output(field, inputs): - import os, attr - - name = field.name - if name == "out_dir": - if inputs.out_dir not in [None, attr.NOTHING]: - outputs = inputs.out_dir - else: - outputs = os.getcwd() - elif name == "report_dir": - if inputs.report not in [None, attr.NOTHING]: - if inputs.out_dir not in [None, attr.NOTHING]: - out_dir = inputs.out_dir - else: - out_dir = os.getcwd() - outputs = os.path.join(out_dir, "report") - return outputs - - -input_fields = [ - ( - "in_files", - specs.MultiInputFile, - { - "help_string": "input file names (either single file name or a list)", - "argstr": "-i {in_files}", - "mandatory": True, - "position": 0, - "sep": ",", - }, - ), - ( - "out_dir", - ty.Any, - {"help_string": "output directory name", "argstr": "-o {out_dir}"}, - ), - ( - "mask", - specs.File, - {"help_string": "file name of mask for thresholding", "argstr": "-m {mask}"}, - ), - ("no_mask", bool, {"help_string": "switch off masking", "argstr": "--nomask"}), - ( - "update_mask", - bool, - {"help_string": "switch off mask updating", "argstr": "--update_mask"}, - ), - ("no_bet", bool, {"help_string": "switch off BET", "argstr": "--nobet"}), - ( - "bg_threshold", - float, - { - "help_string": "brain/non-brain threshold used to mask non-brain voxels, as a percentage (only if --nobet selected)", - "argstr": "--bgthreshold={bg_threshold}", - }, - ), - ( - "dim", - int, - { - "help_string": "dimensionality reduction into #num dimensions (default: automatic estimation)", - "argstr": "-d {dim}", - }, - ), - ( - "dim_est", - str, - { - "help_string": "use specific dim. estimation technique: lap, bic, mdl, aic, mean (default: lap)", - "argstr": "--dimest={dim_est}", - }, - ), - ( - "sep_whiten", - bool, - {"help_string": "switch on separate whitening", "argstr": "--sep_whiten"}, - ), - ( - "sep_vn", - bool, - { - "help_string": "switch off joined variance normalization", - "argstr": "--sep_vn", - }, - ), - ( - "migp", - bool, - {"help_string": "switch on MIGP data reduction", "argstr": "--migp"}, - ), - ( - "migpN", - int, - {"help_string": "number of internal Eigenmaps", "argstr": "--migpN {migpN}"}, - ), - ( - "migp_shuffle", - bool, - { - "help_string": "randomise MIGP file order (default: TRUE)", - "argstr": "--migp_shuffle", - }, - ), - ( - "migp_factor", - int, - { - "help_string": "Internal Factor of mem-threshold relative to number of Eigenmaps (default: 2)", - "argstr": "--migp_factor {migp_factor}", - }, - ), - ( - "num_ICs", - int, - { - "help_string": "number of IC's to extract (for deflation approach)", - "argstr": "-n {num_ICs}", - }, - ), - ( - "approach", - str, - { - "help_string": "approach for decomposition, 2D: defl, symm (default), 3D: tica (default), concat", - "argstr": "-a {approach}", - }, - ), - ( - "non_linearity", - str, - { - "help_string": "nonlinearity: gauss, tanh, pow3, pow4", - "argstr": "--nl={non_linearity}", - }, - ), - ( - "var_norm", - bool, - {"help_string": "switch off variance normalization", "argstr": "--vn"}, - ), - ( - "pbsc", - bool, - { - "help_string": "switch off conversion to percent BOLD signal change", - "argstr": "--pbsc", - }, - ), - ( - "cov_weight", - float, - { - "help_string": "voxel-wise weights for the covariance matrix (e.g. segmentation information)", - "argstr": "--covarweight={cov_weight}", - }, - ), - ( - "epsilon", - float, - {"help_string": "minimum error change", "argstr": "--eps={epsilon}"}, - ), - ( - "epsilonS", - float, - { - "help_string": "minimum error change for rank-1 approximation in TICA", - "argstr": "--epsS={epsilonS}", - }, - ), - ( - "maxit", - int, - { - "help_string": "maximum number of iterations before restart", - "argstr": "--maxit={maxit}", - }, - ), - ( - "max_restart", - int, - { - "help_string": "maximum number of restarts", - "argstr": "--maxrestart={max_restart}", - }, - ), - ( - "mm_thresh", - float, - { - "help_string": "threshold for Mixture Model based inference", - "argstr": "--mmthresh={mm_thresh}", - }, - ), - ( - "no_mm", - bool, - {"help_string": "switch off mixture modelling on IC maps", "argstr": "--no_mm"}, - ), - ( - "ICs", - specs.File, - { - "help_string": "filename of the IC components file for mixture modelling", - "argstr": "--ICs={ICs}", - }, - ), - ( - "mix", - specs.File, - { - "help_string": "mixing matrix for mixture modelling / filtering", - "argstr": "--mix={mix}", - }, - ), - ( - "smode", - specs.File, - { - "help_string": "matrix of session modes for report generation", - "argstr": "--smode={smode}", - }, - ), - ( - "rem_cmp", - list, - {"help_string": "component numbers to remove", "argstr": "-f {rem_cmp}"}, - ), - ( - "report", - bool, - {"help_string": "generate Melodic web report", "argstr": "--report"}, - ), - ( - "bg_image", - specs.File, - { - "help_string": "specify background image for report (default: mean image)", - "argstr": "--bgimage={bg_image}", - }, - ), - ("tr_sec", float, {"help_string": "TR in seconds", "argstr": "--tr={tr_sec}"}), - ( - "log_power", - bool, - { - "help_string": "calculate log of power for frequency spectrum", - "argstr": "--logPower", - }, - ), - ( - "t_des", - specs.File, - {"help_string": "design matrix across time-domain", "argstr": "--Tdes={t_des}"}, - ), - ( - "t_con", - specs.File, - { - "help_string": "t-contrast matrix across time-domain", - "argstr": "--Tcon={t_con}", - }, - ), - ( - "s_des", - specs.File, - { - "help_string": "design matrix across subject-domain", - "argstr": "--Sdes={s_des}", - }, - ), - ( - "s_con", - specs.File, - { - "help_string": "t-contrast matrix across subject-domain", - "argstr": "--Scon={s_con}", - }, - ), - ("out_all", bool, {"help_string": "output everything", "argstr": "--Oall"}), - ( - "out_unmix", - bool, - {"help_string": "output unmixing matrix", "argstr": "--Ounmix"}, - ), - ( - "out_stats", - bool, - { - "help_string": "output thresholded maps and probability maps", - "argstr": "--Ostats", - }, - ), - ("out_pca", bool, {"help_string": "output PCA results", "argstr": "--Opca"}), - ( - "out_white", - bool, - {"help_string": "output whitening/dewhitening matrices", "argstr": "--Owhite"}, - ), - ("out_orig", bool, {"help_string": "output the original ICs", "argstr": "--Oorig"}), - ("out_mean", bool, {"help_string": "output mean volume", "argstr": "--Omean"}), - ( - "report_maps", - str, - { - "help_string": "control string for spatial map images (see slicer)", - "argstr": "--report_maps={report_maps}", - }, - ), - ( - "remove_deriv", - bool, - { - "help_string": "removes every second entry in paradigm file (EV derivatives)", - "argstr": "--remove_deriv", - }, - ), -] -MELODIC_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ("out_dir", specs.Directory, {"callable": MELODIC_output}), - ("report_dir", specs.Directory, {"callable": MELODIC_output}), -] -MELODIC_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class MELODIC(ShellCommandTask): - """ - Example - ------- - >>> task = MELODIC() - >>> task.inputs.approach = "tica" - >>> task.inputs.in_files = ['test.nii', 'test2.nii', 'test3.nii'] - >>> task.inputs.no_bet = True - >>> task.inputs.bg_threshold = 10 - >>> task.inputs.tr_sec = 1.5 - >>> task.inputs.out_stats = True - >>> task.inputs.t_des = "timeDesign.mat" - >>> task.inputs.t_con = "timeDesign.con" - >>> task.inputs.s_des = "subjectDesign.mat" - >>> task.inputs.s_con = "subjectDesign.con" - >>> task.inputs.out_dir = "groupICA.out" - >>> task.cmdline - 'melodic -i test.nii,test2.nii,test3.nii -o groupICA.out --nobet --bgthreshold=10 -a tica --tr=1.5 --Tdes=timeDesign.mat --Tcon=timeDesign.con --Sdes=subjectDesign.mat --Scon=subjectDesign.con --Ostats' - """ - - input_spec = MELODIC_input_spec - output_spec = MELODIC_output_spec - executable = "melodic" diff --git a/pydra/tasks/fsl/model/tests/__init__.py b/pydra/tasks/fsl/model/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/model/tests/test_run_cluster.py b/pydra/tasks/fsl/model/tests/test_run_cluster.py deleted file mode 100644 index 5543fdc..0000000 --- a/pydra/tasks/fsl/model/tests/test_run_cluster.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..cluster import Cluster - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", - [ - ( - { - "in_file": "zstat1.nii.gz", - "threshold": 2.3, - "use_mm": True, - "out_index_file": True, - }, - [ - "out_index_file", - "out_localmax_txt_file", - "out_localmax_vol_file", - "out_threshold_file", - "out_max_file", - "out_mean_file", - "out_pval_file", - "out_size_file", - "out_threshold_file", - ], - ) - ], -) -def test_Cluster(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = Cluster(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = Cluster(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) diff --git a/pydra/tasks/fsl/model/tests/test_run_feat.py b/pydra/tasks/fsl/model/tests/test_run_feat.py deleted file mode 100644 index abcf1e5..0000000 --- a/pydra/tasks/fsl/model/tests/test_run_feat.py +++ /dev/null @@ -1,72 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..feat import FEAT - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_FEAT(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FEAT(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FEAT(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FEAT_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FEAT(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FEAT(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/model/tests/test_run_featmodel.py b/pydra/tasks/fsl/model/tests/test_run_featmodel.py deleted file mode 100644 index 1ec43ca..0000000 --- a/pydra/tasks/fsl/model/tests/test_run_featmodel.py +++ /dev/null @@ -1,72 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..featmodel import FEATModel - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_FEATModel(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FEATModel(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FEATModel(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FEATModel_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FEATModel(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FEATModel(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/model/tests/test_run_filmgls.py b/pydra/tasks/fsl/model/tests/test_run_filmgls.py deleted file mode 100644 index ed5d1ff..0000000 --- a/pydra/tasks/fsl/model/tests/test_run_filmgls.py +++ /dev/null @@ -1,62 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..filmgls import FILMGLS - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", - [ - ( - { - "in_file": "test_film_gls.nii.gz", - "design_file": "design_film_gls.mat", - "threshold": 10, - "results_dir": "stats", - }, - [ - "dof_file", - "logfile", - "param_estimates", - "residual4d", - "results_dir", - "sigmasquareds", - "thresholdac", - ], - ) - ], -) -def test_FILMGLS(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FILMGLS(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FILMGLS(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) diff --git a/pydra/tasks/fsl/model/tests/test_run_flameo.py b/pydra/tasks/fsl/model/tests/test_run_flameo.py deleted file mode 100644 index c7e11d9..0000000 --- a/pydra/tasks/fsl/model/tests/test_run_flameo.py +++ /dev/null @@ -1,69 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..flameo import FLAMEO - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", - [ - ( - { - "cope_file": "cope_merged.nii.gz", - "var_cope_file": "varcope_merged.nii.gz", - "cov_split_file": "design.grp", - "design_file": "design.mat", - "t_con_file": "design.con", - "mask_file": "mask.nii.gz", - "run_mode": "fe", - "log_dir": "stats", - }, - [ - "copes", - "var_copes", - "mrefvars", - "pes", - "res4d", - "tdof", - "weights", - "tstats", - "zstats", - "stats_dir", - ], - ) - ], -) -def test_FLAMEO(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FLAMEO(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FLAMEO(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) diff --git a/pydra/tasks/fsl/model/tests/test_run_glm.py b/pydra/tasks/fsl/model/tests/test_run_glm.py deleted file mode 100644 index 49b585e..0000000 --- a/pydra/tasks/fsl/model/tests/test_run_glm.py +++ /dev/null @@ -1,44 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..glm import GLM - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", - [({"in_file": "test.nii.gz", "design": "confounds_regressors.tsv"}, ["out_file"])], -) -def test_GLM(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = GLM(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = GLM(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) diff --git a/pydra/tasks/fsl/model/tests/test_run_melodic.py b/pydra/tasks/fsl/model/tests/test_run_melodic.py deleted file mode 100644 index a5b333c..0000000 --- a/pydra/tasks/fsl/model/tests/test_run_melodic.py +++ /dev/null @@ -1,72 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..melodic import MELODIC - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_MELODIC(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = MELODIC(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = MELODIC(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_MELODIC_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = MELODIC(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = MELODIC(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/model/tests/test_spec_cluster.py b/pydra/tasks/fsl/model/tests/test_spec_cluster.py deleted file mode 100644 index 2ed7387..0000000 --- a/pydra/tasks/fsl/model/tests/test_spec_cluster.py +++ /dev/null @@ -1,51 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..cluster import Cluster - - -@pytest.mark.parametrize( - "inputs, outputs", - [ - ( - {"in_file": "zstat1.nii.gz", "threshold": 2.3, "use_mm": True, "out_index_file": True}, - [ - "out_index_file", - "out_localmax_txt_file", - "out_localmax_vol_file", - "out_threshold_file", - "out_max_file", - "out_mean_file", - "out_pval_file", - "out_size_file", - "out_threshold_file", - ], - ) - ], -) -def test_Cluster(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = Cluster(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = Cluster(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/model/tests/test_spec_feat.py b/pydra/tasks/fsl/model/tests/test_spec_feat.py deleted file mode 100644 index 403f6e2..0000000 --- a/pydra/tasks/fsl/model/tests/test_spec_feat.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..feat import FEAT - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_FEAT(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FEAT(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FEAT(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FEAT_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FEAT(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FEAT(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/model/tests/test_spec_featmodel.py b/pydra/tasks/fsl/model/tests/test_spec_featmodel.py deleted file mode 100644 index aead2e6..0000000 --- a/pydra/tasks/fsl/model/tests/test_spec_featmodel.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..featmodel import FEATModel - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_FEATModel(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FEATModel(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FEATModel(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FEATModel_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FEATModel(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FEATModel(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/model/tests/test_spec_filmgls.py b/pydra/tasks/fsl/model/tests/test_spec_filmgls.py deleted file mode 100644 index 08f56db..0000000 --- a/pydra/tasks/fsl/model/tests/test_spec_filmgls.py +++ /dev/null @@ -1,54 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..filmgls import FILMGLS - - -@pytest.mark.parametrize( - "inputs, outputs", - [ - ( - { - "in_file": "test_film_gls.nii.gz", - "design_file": "design_film_gls.mat", - "threshold": 10, - "results_dir": "stats", - }, - [ - "dof_file", - "logfile", - "param_estimates", - "residual4d", - "results_dir", - "sigmasquareds", - "thresholdac", - ], - ) - ], -) -def test_FILMGLS(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FILMGLS(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FILMGLS(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/model/tests/test_spec_flameo.py b/pydra/tasks/fsl/model/tests/test_spec_flameo.py deleted file mode 100644 index 0186889..0000000 --- a/pydra/tasks/fsl/model/tests/test_spec_flameo.py +++ /dev/null @@ -1,61 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..flameo import FLAMEO - - -@pytest.mark.parametrize( - "inputs, outputs", - [ - ( - { - "cope_file": "cope_merged.nii.gz", - "var_cope_file": "varcope_merged.nii.gz", - "cov_split_file": "design.grp", - "design_file": "design.mat", - "t_con_file": "design.con", - "mask_file": "mask.nii.gz", - "run_mode": "fe", - "log_dir": "stats", - }, - [ - "copes", - "var_copes", - "mrefvars", - "pes", - "res4d", - "tdof", - "weights", - "tstats", - "zstats", - "stats_dir", - ], - ) - ], -) -def test_FLAMEO(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FLAMEO(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FLAMEO(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/model/tests/test_spec_glm.py b/pydra/tasks/fsl/model/tests/test_spec_glm.py deleted file mode 100644 index 6ac9d78..0000000 --- a/pydra/tasks/fsl/model/tests/test_spec_glm.py +++ /dev/null @@ -1,36 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..glm import GLM - - -@pytest.mark.parametrize( - "inputs, outputs", - [({"in_file": "test.nii.gz", "design": "confounds_regressors.tsv"}, ["out_file"])], -) -def test_GLM(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = GLM(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = GLM(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/model/tests/test_spec_melodic.py b/pydra/tasks/fsl/model/tests/test_spec_melodic.py deleted file mode 100644 index e6aa73a..0000000 --- a/pydra/tasks/fsl/model/tests/test_spec_melodic.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..melodic import MELODIC - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_MELODIC(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = MELODIC(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = MELODIC(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_MELODIC_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = MELODIC(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = MELODIC(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/__init__.py b/pydra/tasks/fsl/preprocess/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/preprocess/applywarp.py b/pydra/tasks/fsl/preprocess/applywarp.py deleted file mode 100644 index 6480289..0000000 --- a/pydra/tasks/fsl/preprocess/applywarp.py +++ /dev/null @@ -1,129 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "image to be warped", - "argstr": "--in={in_file}", - "mandatory": True, - "position": 0, - }, - ), - ( - "out_file", - str, - { - "help_string": "output filename", - "argstr": "--out={out_file}", - "position": 2, - "output_file_template": "{in_file}_warp", - }, - ), - ( - "ref_file", - specs.File, - { - "help_string": "reference image", - "argstr": "--ref={ref_file}", - "mandatory": True, - "position": 1, - }, - ), - ( - "field_file", - specs.File, - {"help_string": "file containing warp field", "argstr": "--warp={field_file}"}, - ), - ( - "abswarp", - bool, - { - "help_string": "treat warp field as absolute: x' = w(x)", - "argstr": "--abs", - "xor": ["relwarp"], - }, - ), - ( - "relwarp", - bool, - { - "help_string": "treat warp field as relative: x' = x + w(x)", - "argstr": "--rel", - "position": -1, - "xor": ["abswarp"], - }, - ), - ( - "datatype", - ty.Any, - { - "help_string": "Force output data type [char short int float double].", - "argstr": "--datatype={datatype}", - }, - ), - ( - "supersample", - bool, - { - "help_string": "intermediary supersampling of output, default is off", - "argstr": "--super", - }, - ), - ( - "superlevel", - ty.Any, - { - "help_string": "level of intermediary supersampling, a for 'automatic' or integer level. Default = 2", - "argstr": "--superlevel={superlevel}", - }, - ), - ( - "premat", - specs.File, - { - "help_string": "filename for pre-transform (affine matrix)", - "argstr": "--premat={premat}", - }, - ), - ( - "postmat", - specs.File, - { - "help_string": "filename for post-transform (affine matrix)", - "argstr": "--postmat={postmat}", - }, - ), - ( - "mask_file", - specs.File, - { - "help_string": "filename for mask image (in reference space)", - "argstr": "--mask={mask_file}", - }, - ), - ( - "interp", - ty.Any, - { - "help_string": "interpolation method", - "argstr": "--interp={interp}", - "position": -2, - }, - ), -] -ApplyWarp_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -ApplyWarp_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class ApplyWarp(ShellCommandTask): - input_spec = ApplyWarp_input_spec - output_spec = ApplyWarp_output_spec - executable = "applywarp" diff --git a/pydra/tasks/fsl/preprocess/bet.py b/pydra/tasks/fsl/preprocess/bet.py deleted file mode 100644 index 2674cc2..0000000 --- a/pydra/tasks/fsl/preprocess/bet.py +++ /dev/null @@ -1,306 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input file to skull strip", - "argstr": "{in_file}", - "mandatory": True, - "position": 0, - }, - ), - ( - "out_file", - str, - { - "help_string": "name of output skull stripped image", - "argstr": "{out_file}", - "position": 1, - "output_file_template": "{in_file}_brain", - }, - ), - ("outline", bool, {"help_string": "create surface outline image", "argstr": "-o"}), - ("mask", bool, {"help_string": "create binary mask image", "argstr": "-m"}), - ("skull", bool, {"help_string": "create skull image", "argstr": "-s"}), - ( - "no_output", - bool, - {"help_string": "Don't generate segmented output", "argstr": "-n"}, - ), - ( - "frac", - float, - {"help_string": "fractional intensity threshold", "argstr": "-f {frac:.2f}"}, - ), - ( - "vertical_gradient", - float, - { - "help_string": "vertical gradient in fractional intensity threshold (-1, 1)", - "argstr": "-g {vertical_gradient:.2f}", - }, - ), - ("radius", int, {"help_string": "head radius", "argstr": "-r {radius}"}), - ( - "center", - list, - {"help_string": "center of gravity in voxels", "argstr": "-c {center}"}, - ), - ( - "threshold", - bool, - { - "help_string": "apply thresholding to segmented brain image and mask", - "argstr": "-t", - }, - ), - ( - "mesh", - bool, - {"help_string": "generate a vtk mesh brain surface", "argstr": "-e"}, - ), - ( - "robust", - bool, - { - "help_string": "robust brain centre estimation (iterates BET several times)", - "argstr": "-R", - "xor": ( - "functional", - "reduce_bias", - "robust", - "padding", - "remove_eyes", - "surfaces", - "t2_guided", - ), - }, - ), - ( - "padding", - bool, - { - "help_string": "improve BET if FOV is very small in Z (by temporarily padding end slices)", - "argstr": "-Z", - "xor": ( - "functional", - "reduce_bias", - "robust", - "padding", - "remove_eyes", - "surfaces", - "t2_guided", - ), - }, - ), - ( - "remove_eyes", - bool, - { - "help_string": "eye & optic nerve cleanup (can be useful in SIENA)", - "argstr": "-S", - "xor": ( - "functional", - "reduce_bias", - "robust", - "padding", - "remove_eyes", - "surfaces", - "t2_guided", - ), - }, - ), - ( - "surfaces", - bool, - { - "help_string": "run bet2 and then betsurf to get additional skull and scalp surfaces (includes registrations)", - "argstr": "-A", - "xor": ( - "functional", - "reduce_bias", - "robust", - "padding", - "remove_eyes", - "surfaces", - "t2_guided", - ), - }, - ), - ( - "t2_guided", - str, - { - "help_string": "as with creating surfaces, when also feeding in non-brain-extracted T2 (includes registrations)", - "argstr": "-A2 {t2_guided}", - "xor": ( - "functional", - "reduce_bias", - "robust", - "padding", - "remove_eyes", - "surfaces", - "t2_guided", - ), - }, - ), - ( - "functional", - bool, - { - "help_string": "apply to 4D fMRI data", - "argstr": "-F", - "xor": ( - "functional", - "reduce_bias", - "robust", - "padding", - "remove_eyes", - "surfaces", - "t2_guided", - ), - }, - ), - ( - "reduce_bias", - bool, - { - "help_string": "bias field and neck cleanup", - "argstr": "-B", - "xor": ( - "functional", - "reduce_bias", - "robust", - "padding", - "remove_eyes", - "surfaces", - "t2_guided", - ), - }, - ), -] -BET_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "mask_file", - specs.File, - { - "help_string": "path/name of binary brain mask (if generated)", - "requires": [[("mask", True)], [("reduce_bias", True)]], - "output_file_template": "{out_file}_mask", - }, - ), - ( - "outline_file", - specs.File, - { - "help_string": "path/name of outline file (if generated)", - "requires": [("outline", True)], - "output_file_template": "{out_file}_overlay", - }, - ), - ( - "meshfile", - specs.File, - { - "help_string": "path/name of vtk mesh file (if generated)", - "requires": [[("mesh", True)], [("surfaces", True)]], - "output_file_template": "{out_file}_mesh.vtk", - }, - ), - ( - "inskull_mask_file", - specs.File, - { - "help_string": "path/name of inskull mask (if generated)", - "requires": [("surfaces", True)], - "output_file_template": "{out_file}_inskull_mask", - }, - ), - ( - "inskull_mesh_file", - specs.File, - { - "help_string": "path/name of inskull mesh outline (if generated)", - "requires": [("surfaces", True)], - "output_file_template": "{out_file}_inskull_mesh", - }, - ), - ( - "outskull_mask_file", - specs.File, - { - "help_string": "path/name of outskull mask (if generated)", - "requires": [("surfaces", True)], - "output_file_template": "{out_file}_outskull_mask", - }, - ), - ( - "outskull_mesh_file", - specs.File, - { - "help_string": "path/name of outskull mesh outline (if generated)", - "requires": [("surfaces", True)], - "output_file_template": "{out_file}_outskull_mesh", - }, - ), - ( - "outskin_mask_file", - specs.File, - { - "help_string": "path/name of outskin mask (if generated)", - "requires": [("surfaces", True)], - "output_file_template": "{out_file}_outskin_mask", - }, - ), - ( - "outskin_mesh_file", - specs.File, - { - "help_string": "path/name of outskin mesh outline (if generated)", - "requires": [("surfaces", True)], - "output_file_template": "{out_file}_outskin_mesh", - }, - ), - ( - "skull_mask_file", - specs.File, - { - "help_string": "path/name of skull mask (if generated)", - "requires": [("surfaces", True)], - "output_file_template": "{out_file}_skull_mask", - }, - ), - ( - "skull_file", - specs.File, - { - "help_string": "path/name of skull file (if generated)", - "requires": [("skull", True)], - "output_file_template": "{out_file}_skull", - }, - ), -] -BET_output_spec = specs.SpecInfo(name="Output", fields=output_fields, bases=(specs.ShellOutSpec,)) - - -class BET(ShellCommandTask): - """ - Example - ------- - >>> task = BET() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.out_file = "test_brain.nii.gz" - >>> task.inputs.frac = 0.7 - >>> task.cmdline - 'bet test.nii.gz test_brain.nii.gz -f 0.70' - """ - - input_spec = BET_input_spec - output_spec = BET_output_spec - executable = "bet" diff --git a/pydra/tasks/fsl/preprocess/fast.py b/pydra/tasks/fsl/preprocess/fast.py deleted file mode 100644 index 732fbc2..0000000 --- a/pydra/tasks/fsl/preprocess/fast.py +++ /dev/null @@ -1,280 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def FAST_output(field, in_files, out_basename): - import attr - - if out_basename in [None, attr.NOTHING]: - out_basename = in_files[-1] - name = field.name - if name == "tissue_class_map": - return f"{out_basename}_seg" - elif name == "mixeltype": - return f"{out_basename}_mixeltype" - elif name == "partial_volume_map": - return f"{out_basename}_pveseg" - else: - raise Exception( - f"this function should be run only for issue_class_map, " - f"or mixeltype, not for {name}" - ) - - outputs = [] - if len(in_files) > 1: - # for multi-image segmentation there is one corrected image - # per input - for val, f in enumerate(in_files): - # image numbering is 1-based - outputs.append(f"{out_basename}_restore_{val+1}") - else: - # single image segmentation has unnumbered output image - outputs.append(f"{out_basename}_restore") - return outputs - - -def FAST_output_infile(field, in_files, out_basename): - import attr - - if out_basename in [None, attr.NOTHING]: - out_basename = in_files[-1] - name = field.name - if name == "restored_image": - suffix = "restore" - elif name == "bias_field": - suffix = "bias" - else: - raise Exception( - f"this function should be run only for restored_image, " - f"or bias_field, not for {name}" - ) - - outputs = [] - if len(in_files) > 1: - # for multi-image segmentation there is one corrected image - # per input - for val, f in enumerate(in_files): - # image numbering is 1-based - outputs.append(f"{out_basename}_{suffix}_{val+1}") - else: - # single image segmentation has unnumbered output image - outputs.append(f"{out_basename}_{suffix}") - return outputs - - -def FAST_output_nclass(field, in_files, nclasses, out_basename): - import attr - - if out_basename in [None, attr.NOTHING]: - out_basename = in_files[-1] - name = field.name - - if name == "tissue_class_files": - suffix = "seg" - elif name == "partial_volume_files": - suffix = "pve" - elif name == "probability_maps": - suffix = "prob" - else: - raise Exception( - f"this function should be run only for tissue_class_files, " - f"partial_volume_files or probability_maps, not for {name}" - ) - - outputs = [] - for ii in range(nclasses): - outputs.append(f"{out_basename}_{suffix}_{ii}") - return outputs - - -input_fields = [ - ( - "in_files", - specs.MultiInputFile, - { - "help_string": "image, or multi-channel set of images, to be segmented", - "argstr": "{in_files}", - "copyfile": False, - "mandatory": True, - "position": -1, - }, - ), - ( - "out_basename", - str, - {"help_string": "base name of output files", "argstr": "-o {out_basename}"}, - ), - ( - "number_classes", - ty.Any, - 3, - { - "help_string": "number of tissue-type classes", - "argstr": "-n {number_classes}", - }, - ), - ( - "output_biasfield", - bool, - {"help_string": "output estimated bias field", "argstr": "-b"}, - ), - ( - "output_biascorrected", - bool, - {"help_string": "output restored image (bias-corrected image)", "argstr": "-B"}, - ), - ( - "img_type", - ty.Any, - { - "help_string": "int specifying type of image: (1 = T1, 2 = T2, 3 = PD)", - "argstr": "-t {img_type}", - }, - ), - ( - "bias_iters", - ty.Any, - { - "help_string": "number of main-loop iterations during bias-field removal", - "argstr": "-I {bias_iters}", - }, - ), - ( - "bias_lowpass", - ty.Any, - { - "help_string": "bias field smoothing extent (FWHM) in mm", - "argstr": "-l {bias_lowpass}", - }, - ), - ( - "init_seg_smooth", - ty.Any, - { - "help_string": "initial segmentation spatial smoothness (during bias field estimation)", - "argstr": "-f {init_seg_smooth:.3f}", - }, - ), - ( - "segments", - bool, - { - "help_string": "outputs a separate binary image for each tissue type", - "argstr": "-g", - }, - ), - ( - "init_transform", - specs.File, - { - "help_string": " initialise using priors", - "argstr": "-a {init_transform}", - }, - ), - ( - "other_priors", - specs.MultiInputFile, - {"help_string": "alternative prior images", "argstr": "-A {other_priors}"}, - ), - ( - "no_pve", - bool, - { - "help_string": "turn off PVE (partial volume estimation)", - "argstr": "--nopve", - }, - ), - ("no_bias", bool, {"help_string": "do not remove bias field", "argstr": "-N"}), - ("use_priors", bool, {"help_string": "use priors throughout", "argstr": "-P"}), - ( - "segment_iters", - ty.Any, - { - "help_string": "number of segmentation-initialisation iterations", - "argstr": "-W {segment_iters}", - }, - ), - ( - "mixel_smooth", - ty.Any, - { - "help_string": "spatial smoothness for mixeltype", - "argstr": "-R {mixel_smooth:.2f}", - }, - ), - ( - "iters_afterbias", - ty.Any, - { - "help_string": "number of main-loop iterations after bias-field removal", - "argstr": "-O {iters_afterbias}", - }, - ), - ( - "hyper", - ty.Any, - {"help_string": "segmentation spatial smoothness", "argstr": "-H {hyper:.2f}"}, - ), - ("verbose", bool, {"help_string": "switch on diagnostic messages", "argstr": "-v"}), - ( - "manual_seg", - specs.File, - {"help_string": "Filename containing intensities", "argstr": "-s {manual_seg}"}, - ), - ( - "probability_maps", - bool, - {"help_string": "outputs individual probability maps", "argstr": "-p"}, - ), -] -FAST_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "tissue_class_files", - specs.MultiOutputFile, - {"requires": [("segments", True)], "callable": "FAST_output_nclass"}, - ), - ( - "partial_volume_map", - specs.File, - { - "help_string": "path/name of partial volume file _pveseg", - "requires": [("no_pve", False)], - "callable": "FAST_output", - }, - ), - ( - "partial_volume_files", - specs.MultiOutputFile, - {"requires": [("no_pve", False)], "callable": "FAST_output_nclass"}, - ), - ( - "bias_field", - specs.MultiOutputFile, - {"requires": [("output_biasfield", True)], "callable": "FAST_output_infile"}, - ), - ( - "probability_maps", - specs.MultiOutputFile, - {"requires": [("probability_maps", True)], "callable": "FAST_output_nclass"}, - ), -] -FAST_output_spec = specs.SpecInfo(name="Output", fields=output_fields, bases=(specs.ShellOutSpec,)) - - -class FAST(ShellCommandTask): - """ - Example - ------- - >>> task = FAST() - >>> task.inputs.in_files = "test.nii.gz" - >>> task.inputs.out_basename = "fast_" - >>> task.cmdline - 'fast -o fast_ -n 3 test.nii.gz' - """ - - input_spec = FAST_input_spec - output_spec = FAST_output_spec - executable = "fast" diff --git a/pydra/tasks/fsl/preprocess/first.py b/pydra/tasks/fsl/preprocess/first.py deleted file mode 100644 index 26d824c..0000000 --- a/pydra/tasks/fsl/preprocess/first.py +++ /dev/null @@ -1,138 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input data file", - "argstr": "-i {in_file}", - "copyfile": False, - "mandatory": True, - "position": -2, - }, - ), - ( - "out_file", - str, - { - "help_string": "output data file", - "argstr": "-o {out_file}", - "mandatory": True, - "position": -1, - }, - ), - ( - "verbose", - bool, - {"help_string": "Use verbose logging.", "argstr": "-v", "position": 1}, - ), - ( - "brain_extracted", - bool, - { - "help_string": "Input structural image is already brain-extracted", - "argstr": "-b", - "position": 2, - }, - ), - ( - "no_cleanup", - bool, - { - "help_string": "Input structural image is already brain-extracted", - "argstr": "-d", - "position": 3, - }, - ), - ( - "method", - ty.Any, - "auto", - { - "help_string": "Method must be one of auto, fast, none, or it can be entered using the 'method_as_numerical_threshold' input", - "argstr": "-m {method}", - "position": 4, - "xor": ["method_as_numerical_threshold"], - }, - ), - ( - "method_as_numerical_threshold", - float, - { - "help_string": "Specify a numerical threshold value or use the 'method' input to choose auto, fast, or none", - "argstr": "-m {method_as_numerical_threshold:.4f}", - "position": 4, - }, - ), - ( - "list_of_specific_structures", - list, - { - "help_string": "Runs only on the specified structures (e.g. L_Hipp, R_HippL_Accu, R_Accu, L_Amyg, R_AmygL_Caud, R_Caud, L_Pall, R_PallL_Puta, R_Puta, L_Thal, R_Thal, BrStem", - "argstr": "-s {list_of_specific_structures}", - "position": 5, - "sep": ",", - }, - ), - ( - "affine_file", - specs.File, - { - "help_string": "Affine matrix to use (e.g. img2std.mat) (does not re-run registration)", - "argstr": "-a {affine_file}", - "position": 6, - }, - ), -] -FIRST_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "vtk_surfaces", - specs.MultiOutputFile, - { - "help_string": "VTK format meshes for each subcortical region", - "requires": ["in_file"], - "output_file_template": "{in_file}_vtk_surfaces", - }, - ), - ( - "bvars", - specs.MultiOutputFile, - { - "help_string": "bvars for each subcortical region", - "requires": ["in_file"], - "output_file_template": "{in_file}_bvars", - }, - ), - ( - "original_segmentations", - specs.File, - { - "help_string": "3D image file containing the segmented regions as integer values. Uses CMA labelling", - "requires": ["in_file"], - "output_file_template": "{in_file}_original_segmentations", - }, - ), - ( - "segmentation_file", - specs.File, - { - "help_string": "4D image file containing a single volume per segmented region", - "requires": ["in_file"], - "output_file_template": "{in_file}_segmentation_file", - }, - ), -] -FIRST_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class FIRST(ShellCommandTask): - input_spec = FIRST_input_spec - output_spec = FIRST_output_spec - executable = "run_first_all" diff --git a/pydra/tasks/fsl/preprocess/flirt.py b/pydra/tasks/fsl/preprocess/flirt.py deleted file mode 100644 index 9da52c7..0000000 --- a/pydra/tasks/fsl/preprocess/flirt.py +++ /dev/null @@ -1,348 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input file", - "argstr": "-in {in_file}", - "mandatory": True, - "position": 0, - }, - ), - ( - "reference", - specs.File, - { - "help_string": "reference file", - "argstr": "-ref {reference}", - "mandatory": True, - "position": 1, - }, - ), - ( - "out_file", - str, - { - "help_string": "registered output file", - "argstr": "-out {out_file}", - "position": 2, - "output_file_template": "{in_file}_flirt", - }, - ), - ( - "out_matrix_file", - str, - { - "help_string": "output affine matrix in 4x4 asciii format", - "argstr": "-omat {out_matrix_file}", - "position": 3, - "output_file_template": "{in_file}_flirt.mat", - }, - ), - ( - "out_log", - str, - { - "help_string": "output log", - "requires": ["save_log"], - "output_file_template": "{in_file}_flirt.log", - }, - ), - ( - "in_matrix_file", - str, - {"help_string": "input 4x4 affine matrix", "argstr": "-init {in_matrix_file}"}, - ), - ( - "apply_xfm", - bool, - { - "help_string": "apply transformation supplied by in_matrix_file or uses_qform to use the affine matrix stored in the reference header", - "argstr": "-applyxfm", - }, - ), - ( - "apply_isoxfm", - float, - { - "help_string": "as applyxfm but forces isotropic resampling", - "argstr": "-applyisoxfm {apply_isoxfm}", - "xor": ["apply_xfm"], - }, - ), - ( - "datatype", - ty.Any, - {"help_string": "force output data type", "argstr": "-datatype {datatype}"}, - ), - ("cost", ty.Any, {"help_string": "cost function", "argstr": "-cost {cost}"}), - ( - "cost_func", - ty.Any, - {"help_string": "cost function", "argstr": "-searchcost {cost_func}"}, - ), - ( - "uses_qform", - bool, - {"help_string": "initialize using sform or qform", "argstr": "-usesqform"}, - ), - ( - "display_init", - bool, - {"help_string": "display initial matrix", "argstr": "-displayinit"}, - ), - ( - "angle_rep", - ty.Any, - { - "help_string": "representation of rotation angles", - "argstr": "-anglerep {angle_rep}", - }, - ), - ( - "interp", - ty.Any, - { - "help_string": "final interpolation method used in reslicing", - "argstr": "-interp {interp}", - }, - ), - ( - "sinc_width", - int, - {"help_string": "full-width in voxels", "argstr": "-sincwidth {sinc_width}"}, - ), - ( - "sinc_window", - ty.Any, - {"help_string": "sinc window", "argstr": "-sincwindow {sinc_window}"}, - ), - ( - "bins", - int, - {"help_string": "number of histogram bins", "argstr": "-bins {bins}"}, - ), - ( - "dof", - int, - { - "help_string": "number of transform degrees of freedom", - "argstr": "-dof {dof}", - }, - ), - ( - "no_resample", - bool, - {"help_string": "do not change input sampling", "argstr": "-noresample"}, - ), - ( - "force_scaling", - bool, - { - "help_string": "force rescaling even for low-res images", - "argstr": "-forcescaling", - }, - ), - ( - "min_sampling", - float, - { - "help_string": "set minimum voxel dimension for sampling", - "argstr": "-minsampling {min_sampling}", - }, - ), - ( - "padding_size", - int, - { - "help_string": "for applyxfm: interpolates outside image by size", - "argstr": "-paddingsize {padding_size}", - }, - ), - ( - "searchr_x", - list, - { - "help_string": "search angles along x-axis, in degrees", - "argstr": "-searchrx {searchr_x}", - }, - ), - ( - "searchr_y", - list, - { - "help_string": "search angles along y-axis, in degrees", - "argstr": "-searchry {searchr_y}", - }, - ), - ( - "searchr_z", - list, - { - "help_string": "search angles along z-axis, in degrees", - "argstr": "-searchrz {searchr_z}", - }, - ), - ( - "no_search", - bool, - { - "help_string": "set all angular searches to ranges 0 to 0", - "argstr": "-nosearch", - }, - ), - ( - "coarse_search", - int, - { - "help_string": "coarse search delta angle", - "argstr": "-coarsesearch {coarse_search}", - }, - ), - ( - "fine_search", - int, - { - "help_string": "fine search delta angle", - "argstr": "-finesearch {fine_search}", - }, - ), - ( - "schedule", - specs.File, - {"help_string": "replaces default schedule", "argstr": "-schedule {schedule}"}, - ), - ( - "ref_weight", - specs.File, - { - "help_string": "File for reference weighting volume", - "argstr": "-refweight {ref_weight}", - }, - ), - ( - "in_weight", - specs.File, - { - "help_string": "File for input weighting volume", - "argstr": "-inweight {in_weight}", - }, - ), - ( - "no_clamp", - bool, - {"help_string": "do not use intensity clamping", "argstr": "-noclamp"}, - ), - ( - "no_resample_blur", - bool, - { - "help_string": "do not use blurring on downsampling", - "argstr": "-noresampblur", - }, - ), - ( - "rigid2D", - bool, - {"help_string": "use 2D rigid body mode - ignores dof", "argstr": "-2D"}, - ), - ("save_log", bool, {"help_string": "save to log file"}), - ( - "verbose", - int, - {"help_string": "verbose mode, 0 is least", "argstr": "-verbose {verbose}"}, - ), - ( - "bgvalue", - float, - { - "help_string": "use specified background value for points outside FOV", - "argstr": "-setbackground {bgvalue}", - }, - ), - ( - "wm_seg", - str, - { - "help_string": "white matter segmentation volume needed by BBR cost function", - "argstr": "-wmseg {wm_seg}", - }, - ), - ( - "wmcoords", - str, - { - "help_string": "white matter boundary coordinates for BBR cost function", - "argstr": "-wmcoords {wmcoords}", - }, - ), - ( - "wmnorms", - str, - { - "help_string": "white matter boundary normals for BBR cost function", - "argstr": "-wmnorms {wmnorms}", - }, - ), - ( - "fieldmap", - str, - { - "help_string": "fieldmap image in rads/s - must be already registered to the reference image", - "argstr": "-fieldmap {fieldmap}", - }, - ), - ( - "fieldmapmask", - str, - { - "help_string": "mask for fieldmap image", - "argstr": "-fieldmapmask {fieldmapmask}", - }, - ), - ( - "pedir", - int, - { - "help_string": "phase encode direction of EPI - 1/2/3=x/y/z & -1/-2/-3=-x/-y/-z", - "argstr": "-pedir {pedir}", - }, - ), - ( - "echospacing", - float, - { - "help_string": "value of EPI echo spacing - units of seconds", - "argstr": "-echospacing {echospacing}", - }, - ), - ( - "bbrtype", - ty.Any, - { - "help_string": "type of bbr cost function: signed [default], global_abs, local_abs", - "argstr": "-bbrtype {bbrtype}", - }, - ), - ( - "bbrslope", - float, - {"help_string": "value of bbr slope", "argstr": "-bbrslope {bbrslope}"}, - ), -] -FLIRT_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -FLIRT_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class FLIRT(ShellCommandTask): - input_spec = FLIRT_input_spec - output_spec = FLIRT_output_spec - executable = "flirt" diff --git a/pydra/tasks/fsl/preprocess/fnirt.py b/pydra/tasks/fsl/preprocess/fnirt.py deleted file mode 100644 index f1a565f..0000000 --- a/pydra/tasks/fsl/preprocess/fnirt.py +++ /dev/null @@ -1,363 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "ref_file", - specs.File, - { - "help_string": "name of reference image", - "argstr": "--ref={ref_file}", - "mandatory": True, - }, - ), - ( - "in_file", - specs.File, - { - "help_string": "name of input image", - "argstr": "--in={in_file}", - "mandatory": True, - }, - ), - ( - "affine_file", - specs.File, - { - "help_string": "name of file containing affine transform", - "argstr": "--aff={affine_file}", - }, - ), - ( - "inwarp_file", - specs.File, - { - "help_string": "name of file containing initial non-linear warps", - "argstr": "--inwarp={inwarp_file}", - }, - ), - ( - "in_intensitymap_file", - specs.MultiInputFile, - { - "help_string": "name of file/files containing initial intensity mapping usually generated by previous fnirt run", - "argstr": "--intin={in_intensitymap_file}", - "copyfile": False, - }, - ), - ( - "fieldcoeff_file", - str, - { - "help_string": "name of output file with field coefficients or true", - "argstr": "--cout={fieldcoeff_file}", - "output_file_template": "{in_file}_fieldwarp", - }, - ), - ( - "warped_file", - str, - { - "help_string": "name of output image", - "argstr": "--iout={warped_file}", - "output_file_template": "{in_file}_warped", - }, - ), - ( - "field_file", - str, - { - "help_string": "name of output file with field or true", - "argstr": "--fout={field_file}", - "output_file_template": "{in_file}_field", - }, - ), - ( - "jacobian_file", - str, - { - "help_string": "name of file for writing out the Jacobian of the field (for diagnostic or VBM purposes)", - "argstr": "--jout={jacobian_file}", - "output_file_template": "{in_file}_field_jacobian", - }, - ), - ( - "modulatedref_file", - str, - { - "help_string": "name of file for writing out intensity modulated --ref (for diagnostic purposes)", - "argstr": "--refout={modulatedref_file}", - "output_file_template": "{in_file}_modulated", - }, - ), - ( - "out_intensitymap_file", - str, - { - "help_string": "name of files for writing information pertaining to intensity mapping", - "argstr": "--intout={out_intensitymap_file}", - }, - ), - ( - "log_file", - str, - { - "help_string": "Name of log-file", - "argstr": "--logout={log_file}", - "output_file_template": "{in_file}_log.txt", - }, - ), - ( - "config_file", - ty.Any, - { - "help_string": "Name of config file specifying command line arguments", - "argstr": "--config={config_file}", - }, - ), - ( - "refmask_file", - specs.File, - { - "help_string": "name of file with mask in reference space", - "argstr": "--refmask={refmask_file}", - }, - ), - ( - "inmask_file", - specs.File, - { - "help_string": "name of file with mask in input image space", - "argstr": "--inmask={inmask_file}", - }, - ), - ( - "skip_refmask", - bool, - { - "help_string": "Skip specified refmask if set, default false", - "argstr": "--applyrefmask=0", - "xor": ["apply_refmask"], - }, - ), - ( - "skip_inmask", - bool, - { - "help_string": "skip specified inmask if set, default false", - "argstr": "--applyinmask=0", - "xor": ["apply_inmask"], - }, - ), - ( - "apply_refmask", - list, - { - "help_string": "list of iterations to use reference mask on (1 to use, 0 to skip)", - "argstr": "--applyrefmask={apply_refmask}", - "sep": ",", - "xor": ["skip_refmask"], - }, - ), - ( - "apply_inmask", - list, - { - "help_string": "list of iterations to use input mask on (1 to use, 0 to skip)", - "argstr": "--applyinmask={apply_inmask}", - "sep": ",", - "xor": ["skip_inmask"], - }, - ), - ( - "skip_implicit_ref_masking", - bool, - { - "help_string": "skip implicit masking based on value in --ref image. Default = 0", - "argstr": "--imprefm=0", - }, - ), - ( - "skip_implicit_in_masking", - bool, - { - "help_string": "skip implicit masking based on value in --in image. Default = 0", - "argstr": "--impinm=0", - }, - ), - ( - "refmask_val", - float, - { - "help_string": "Value to mask out in --ref image. Default =0.0", - "argstr": "--imprefval={refmask_val}", - }, - ), - ( - "inmask_val", - float, - { - "help_string": "Value to mask out in --in image. Default =0.0", - "argstr": "--impinval={inmask_val}", - }, - ), - ( - "max_nonlin_iter", - list, - { - "help_string": "Max # of non-linear iterations list, default [5, 5, 5, 5]", - "argstr": "--miter={max_nonlin_iter}", - "sep": ",", - }, - ), - ( - "subsampling_scheme", - list, - { - "help_string": "sub-sampling scheme, list, default [4, 2, 1, 1]", - "argstr": "--subsamp={subsampling_scheme}", - "sep": ",", - }, - ), - ( - "warp_resolution", - ty.Any, - { - "help_string": "(approximate) resolution (in mm) of warp basis in x-, y- and z-direction, default 10, 10, 10", - "argstr": "--warpres={warp_resolution},{warp_resolution},{warp_resolution}", - }, - ), - ( - "spline_order", - int, - { - "help_string": "Order of spline, 2->Qadratic spline, 3->Cubic spline. Default=3", - "argstr": "--splineorder={spline_order}", - }, - ), - ( - "in_fwhm", - list, - { - "help_string": "FWHM (in mm) of gaussian smoothing kernel for input volume, default [6, 4, 2, 2]", - "argstr": "--infwhm={in_fwhm}", - "sep": ",", - }, - ), - ( - "ref_fwhm", - list, - { - "help_string": "FWHM (in mm) of gaussian smoothing kernel for ref volume, default [4, 2, 0, 0]", - "argstr": "--reffwhm={ref_fwhm}", - "sep": ",", - }, - ), - ( - "regularization_model", - ty.Any, - { - "help_string": "Model for regularisation of warp-field [membrane_energy bending_energy], default bending_energy", - "argstr": "--regmod={regularization_model}", - }, - ), - ( - "regularization_lambda", - list, - { - "help_string": "Weight of regularisation, default depending on --ssqlambda and --regmod switches. See user documetation.", - "argstr": "--lambda={regularization_lambda}", - "sep": ",", - }, - ), - ( - "skip_lambda_ssq", - bool, - { - "help_string": "If true, lambda is not weighted by current ssq, default false", - "argstr": "--ssqlambda=0", - }, - ), - ( - "jacobian_range", - ty.Any, - { - "help_string": "Allowed range of Jacobian determinants, default 0.01, 100.0", - "argstr": "--jacrange={jacobian_range},{jacobian_range}", - }, - ), - ( - "derive_from_ref", - bool, - { - "help_string": "If true, ref image is used to calculate derivatives. Default false", - "argstr": "--refderiv", - }, - ), - ( - "intensity_mapping_model", - ty.Any, - { - "help_string": "Model for intensity-mapping", - "argstr": "--intmod={intensity_mapping_model}", - }, - ), - ( - "intensity_mapping_order", - int, - { - "help_string": "Order of poynomial for mapping intensities, default 5", - "argstr": "--intorder={intensity_mapping_order}", - }, - ), - ( - "biasfield_resolution", - ty.Any, - { - "help_string": "Resolution (in mm) of bias-field modelling local intensities, default 50, 50, 50", - "argstr": "--biasres={biasfield_resolution},{biasfield_resolution},{biasfield_resolution}", - }, - ), - ( - "bias_regularization_lambda", - float, - { - "help_string": "Weight of regularisation for bias-field, default 10000", - "argstr": "--biaslambda={bias_regularization_lambda}", - }, - ), - ( - "skip_intensity_mapping", - bool, - { - "help_string": "Skip estimate intensity-mapping default false", - "argstr": "--estint=0", - "xor": ["apply_intensity_mapping"], - }, - ), - ( - "apply_intensity_mapping", - list, - { - "help_string": "List of subsampling levels to apply intensity mapping for (0 to skip, 1 to apply)", - "argstr": "--estint={apply_intensity_mapping}", - "sep": ",", - "xor": ["skip_intensity_mapping"], - }, - ), - ( - "hessian_precision", - ty.Any, - { - "help_string": "Precision for representing Hessian, double or float. Default double", - "argstr": "--numprec={hessian_precision}", - }, - ), -] -FNIRT_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - - -class FNIRT(ShellCommandTask): - input_spec = FNIRT_input_spec - executable = "fnirt" diff --git a/pydra/tasks/fsl/preprocess/mcflirt.py b/pydra/tasks/fsl/preprocess/mcflirt.py deleted file mode 100644 index 136fde7..0000000 --- a/pydra/tasks/fsl/preprocess/mcflirt.py +++ /dev/null @@ -1,185 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "timeseries to motion-correct", - "argstr": "-in {in_file}", - "mandatory": True, - "position": 0, - }, - ), - ( - "out_file", - str, - { - "help_string": "file to write", - "argstr": "-out {out_file}", - "output_file_template": "{in_file}_mcf", - }, - ), - ( - "cost", - ty.Any, - {"help_string": "cost function to optimize", "argstr": "-cost {cost}"}, - ), - ( - "bins", - int, - {"help_string": "number of histogram bins", "argstr": "-bins {bins}"}, - ), - ( - "dof", - int, - { - "help_string": "degrees of freedom for the transformation", - "argstr": "-dof {dof}", - }, - ), - ( - "ref_vol", - int, - {"help_string": "volume to align frames to", "argstr": "-refvol {ref_vol}"}, - ), - ( - "scaling", - float, - {"help_string": "scaling factor to use", "argstr": "-scaling {scaling:.2f}"}, - ), - ( - "smooth", - float, - { - "help_string": "smoothing factor for the cost function", - "argstr": "-smooth {smooth:.2f}", - }, - ), - ( - "rotation", - int, - { - "help_string": "scaling factor for rotation tolerances", - "argstr": "-rotation {rotation}", - }, - ), - ( - "stages", - int, - { - "help_string": "stages (if 4, perform final search with sinc interpolation", - "argstr": "-stages {stages}", - }, - ), - ( - "init", - specs.File, - {"help_string": "inital transformation matrix", "argstr": "-init {init}"}, - ), - ( - "interpolation", - ty.Any, - { - "help_string": "interpolation method for transformation", - "argstr": "-{interpolation}_final", - }, - ), - ( - "use_gradient", - bool, - {"help_string": "run search on gradient images", "argstr": "-gdt"}, - ), - ( - "use_contour", - bool, - {"help_string": "run search on contour images", "argstr": "-edge"}, - ), - ( - "mean_vol", - bool, - {"help_string": "register to mean volume", "argstr": "-meanvol"}, - ), - ( - "stats_imgs", - bool, - {"help_string": "produce variance and std. dev. images", "argstr": "-stats"}, - ), - ( - "save_mats", - bool, - {"help_string": "save transformation matrices", "argstr": "-mats"}, - ), - ( - "save_plots", - bool, - {"help_string": "save transformation parameters", "argstr": "-plots"}, - ), - ( - "save_rms", - bool, - { - "help_string": "save rms displacement parameters", - "argstr": "-rmsabs -rmsrel", - }, - ), - ( - "ref_file", - specs.File, - { - "help_string": "target image for motion correction", - "argstr": "-reffile {ref_file}", - }, - ), -] -MCFLIRT_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "variance_img", - specs.File, - { - "help_string": "variance image", - "requires": ["in_file", ("stats_imgs", True)], - "output_file_template": "{out_file}_variance.ext", - }, - ), - ( - "std_img", - specs.File, - { - "help_string": "standard deviation image", - "requires": ["in_file", ("stats_imgs", True)], - "output_file_template": "{out_file}_sigma.ext", - }, - ), - ( - "mean_img", - specs.File, - { - "help_string": "mean timeseries image (if mean_vol=True)", - "requires": ["in_file", ("mean_vol", True)], - "output_file_template": "{out_file}_mean_reg.ext", - }, - ), - ( - "par_file", - specs.File, - { - "help_string": "text-file with motion parameters", - "requires": ["save_plots"], - "output_file_template": "{out_file}.par", - }, - ), -] -MCFLIRT_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class MCFLIRT(ShellCommandTask): - input_spec = MCFLIRT_input_spec - output_spec = MCFLIRT_output_spec - executable = "mcflirt" diff --git a/pydra/tasks/fsl/preprocess/prelude.py b/pydra/tasks/fsl/preprocess/prelude.py deleted file mode 100644 index b5b8520..0000000 --- a/pydra/tasks/fsl/preprocess/prelude.py +++ /dev/null @@ -1,155 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "complex_phase_file", - specs.File, - { - "help_string": "complex phase input volume", - "argstr": "--complex={complex_phase_file}", - "mandatory": True, - "xor": ["magnitude_file", "phase_file"], - }, - ), - ( - "magnitude_file", - specs.File, - { - "help_string": "file containing magnitude image", - "argstr": "--abs={magnitude_file}", - "mandatory": True, - "xor": ["complex_phase_file"], - }, - ), - ( - "phase_file", - specs.File, - { - "help_string": "raw phase file", - "argstr": "--phase={phase_file}", - "mandatory": True, - "xor": ["complex_phase_file"], - }, - ), - ( - "unwrapped_phase_file", - str, - { - "help_string": "file containing unwrapepd phase", - "argstr": "--unwrap={unwrapped_phase_file}", - "output_file_template": "{phase_file}_unwrapped", - }, - ), - ( - "num_partitions", - int, - { - "help_string": "number of phase partitions to use", - "argstr": "--numphasesplit={num_partitions}", - }, - ), - ( - "labelprocess2d", - bool, - { - "help_string": "does label processing in 2D (slice at a time)", - "argstr": "--labelslices", - }, - ), - ( - "process2d", - bool, - { - "help_string": "does all processing in 2D (slice at a time)", - "argstr": "--slices", - "xor": ["labelprocess2d"], - }, - ), - ( - "process3d", - bool, - { - "help_string": "forces all processing to be full 3D", - "argstr": "--force3D", - "xor": ["labelprocess2d", "process2d"], - }, - ), - ( - "threshold", - float, - { - "help_string": "intensity threshold for masking", - "argstr": "--thresh={threshold:.10f}", - }, - ), - ( - "mask_file", - specs.File, - { - "help_string": "filename of mask input volume", - "argstr": "--mask={mask_file}", - }, - ), - ( - "start", - int, - { - "help_string": "first image number to process (default 0)", - "argstr": "--start={start}", - }, - ), - ( - "end", - int, - { - "help_string": "final image number to process (default Inf)", - "argstr": "--end={end}", - }, - ), - ( - "savemask_file", - str, - { - "help_string": "saving the mask volume", - "argstr": "--savemask={savemask_file}", - }, - ), - ( - "rawphase_file", - str, - { - "help_string": "saving the raw phase output", - "argstr": "--rawphase={rawphase_file}", - }, - ), - ( - "label_file", - str, - { - "help_string": "saving the area labels output", - "argstr": "--labels={label_file}", - }, - ), - ( - "removeramps", - bool, - { - "help_string": "remove phase ramps during unwrapping", - "argstr": "--removeramps", - }, - ), -] -PRELUDE_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -PRELUDE_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class PRELUDE(ShellCommandTask): - input_spec = PRELUDE_input_spec - output_spec = PRELUDE_output_spec - executable = "prelude" diff --git a/pydra/tasks/fsl/preprocess/slicetimer.py b/pydra/tasks/fsl/preprocess/slicetimer.py deleted file mode 100644 index 28177bb..0000000 --- a/pydra/tasks/fsl/preprocess/slicetimer.py +++ /dev/null @@ -1,97 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "filename of input timeseries", - "argstr": "--in={in_file}", - "mandatory": True, - "position": 0, - }, - ), - ( - "out_file", - str, - { - "help_string": "filename of output timeseries", - "argstr": "--out={out_file}", - "output_file_template": "{in_file}_st", - }, - ), - ( - "index_dir", - bool, - {"help_string": "slice indexing from top to bottom", "argstr": "--down"}, - ), - ( - "time_repetition", - float, - { - "help_string": "Specify TR of data - default is 3s", - "argstr": "--repeat={time_repetition}", - }, - ), - ( - "slice_direction", - ty.Any, - { - "help_string": "direction of slice acquisition (x=1, y=2, z=3) - default is z", - "argstr": "--direction={slice_direction}", - }, - ), - ( - "interleaved", - bool, - {"help_string": "use interleaved acquisition", "argstr": "--odd"}, - ), - ( - "custom_timings", - specs.File, - { - "help_string": "slice timings, in fractions of TR, range 0:1 (default is 0.5 = no shift)", - "argstr": "--tcustom={custom_timings}", - }, - ), - ( - "global_shift", - float, - { - "help_string": "shift in fraction of TR, range 0:1 (default is 0.5 = no shift)", - "argstr": "--tglobal", - }, - ), - ( - "custom_order", - specs.File, - { - "help_string": "filename of single-column custom interleave order file (first slice is referred to as 1 not 0)", - "argstr": "--ocustom={custom_order}", - }, - ), -] -SliceTimer_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "slice_time_corrected_file", - specs.File, - { - "help_string": "slice time corrected file", - "requires": ["out_file"], - "output_file_template": "{out_file}", - }, - ) -] -SliceTimer_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class SliceTimer(ShellCommandTask): - input_spec = SliceTimer_input_spec - output_spec = SliceTimer_output_spec - executable = "slicetimer" diff --git a/pydra/tasks/fsl/preprocess/susan.py b/pydra/tasks/fsl/preprocess/susan.py deleted file mode 100644 index 53fa617..0000000 --- a/pydra/tasks/fsl/preprocess/susan.py +++ /dev/null @@ -1,114 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def format_usans(field: ty.Sequence[ty.Tuple[str, float]]) -> str: - """Format usans argument to its appropriate argstr. - - Examples - -------- - >>> format_usans([]) - '0' - >>> format_usans([('/path/to/file', 2.5)]) - '1 /path/to/file 2.5' - >>> format_usans([('/path/to/file1', 10.5), ('/path/to/file2', 22.1)]) - '2 /path/to/file1 10.5 /path/to/file2 22.1' - """ - return " ".join([f"{len(field)}"] + [f"{usan} {bt}" for usan, bt in field]) - - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "filename of input timeseries", - "argstr": "{in_file}", - "mandatory": True, - "position": 1, - }, - ), - ( - "brightness_threshold", - float, - { - "help_string": "brightness threshold and should be greater than noise level and less than contrast of edges to be preserved.", - "argstr": "{brightness_threshold:.10f}", - "mandatory": True, - "position": 2, - }, - ), - ( - "fwhm", - float, - { - "help_string": "fwhm of smoothing, in mm, gets converted using sqrt(8*log(2))", - "argstr": "{fwhm:.10f}", - "mandatory": True, - "position": 3, - }, - ), - ( - "dimension", - ty.Any, - 3, - { - "help_string": "within-plane (2) or fully 3D (3)", - "argstr": "{dimension}", - "position": 4, - }, - ), - ( - "use_median", - ty.Any, - 1, - { - "help_string": "whether to use a local median filter in the cases where single-point noise is detected", - "argstr": "{use_median}", - "position": 5, - }, - ), - ( - "usans", - ty.Sequence[ty.Tuple[str, float]], - [], - { - "help_string": "determines whether the smoothing area (USAN) is to be found from secondary images (0, 1 or 2). A negative value for any brightness threshold will auto-set the threshold at 10% of the robust range", - "formatter": format_usans, - "position": 6, - }, - ), - ( - "out_file", - str, - { - "help_string": "output file name", - "argstr": "{out_file}", - "position": -1, - "output_file_template": "{in_file}_smooth", - }, - ), -] -SUSAN_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "smoothed_file", - specs.File, - { - "help_string": "smoothed output file", - "requires": ["out_file"], - "output_file_template": "{out_file}", - }, - ) -] -SUSAN_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class SUSAN(ShellCommandTask): - input_spec = SUSAN_input_spec - output_spec = SUSAN_output_spec - executable = "susan" diff --git a/pydra/tasks/fsl/preprocess/tests/__init__.py b/pydra/tasks/fsl/preprocess/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_applywarp.py b/pydra/tasks/fsl/preprocess/tests/test_run_applywarp.py deleted file mode 100644 index f87ef98..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_run_applywarp.py +++ /dev/null @@ -1,22 +0,0 @@ -import os, pytest -from pathlib import Path -from ..applywarp import ApplyWarp - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", [({"ref_file": 'f"{in_file}"'}, ["out_file"])]) -def test_ApplyWarp(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = ApplyWarp(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_bet.py b/pydra/tasks/fsl/preprocess/tests/test_run_bet.py deleted file mode 100644 index 5ca0fb6..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_run_bet.py +++ /dev/null @@ -1,42 +0,0 @@ -import os, pytest -from pathlib import Path -from ..bet import BET - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", - [ - (None, ["out_file"]), - ({"mask": True}, ["out_file", "mask_file"]), - ( - {"surfaces": True}, - [ - "out_file", - "meshfile", - "inskull_mask_file", - "inskull_mesh_file", - "outskull_mask_file", - "outskull_mesh_file", - "outskin_mask_file", - "outskin_mesh_file", - "skull_mask_file", - ], - ), - ], -) -def test_BET(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = BET(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_fast.py b/pydra/tasks/fsl/preprocess/tests/test_run_fast.py deleted file mode 100644 index 0b25fc9..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_run_fast.py +++ /dev/null @@ -1,37 +0,0 @@ -import os, pytest -from pathlib import Path -from ..fast import FAST - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_FAST(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FAST(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FAST_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FAST(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_first.py b/pydra/tasks/fsl/preprocess/tests/test_run_first.py deleted file mode 100644 index e8bcab9..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_run_first.py +++ /dev/null @@ -1,37 +0,0 @@ -import os, pytest -from pathlib import Path -from ..first import FIRST - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_FIRST(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FIRST(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FIRST_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FIRST(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_flirt.py b/pydra/tasks/fsl/preprocess/tests/test_run_flirt.py deleted file mode 100644 index 5c968c0..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_run_flirt.py +++ /dev/null @@ -1,37 +0,0 @@ -import os, pytest -from pathlib import Path -from ..flirt import FLIRT - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_FLIRT(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FLIRT(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FLIRT_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FLIRT(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_fnirt.py b/pydra/tasks/fsl/preprocess/tests/test_run_fnirt.py deleted file mode 100644 index a706054..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_run_fnirt.py +++ /dev/null @@ -1,52 +0,0 @@ -import os, pytest -from pathlib import Path -from ..fnirt import FNIRT - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", - [ - ( - {"ref_file": 'f"{in_file}"'}, - [ - "warped_file", - "field_file", - "jacobian_file", - "modulatedref_file", - "log_file", - "fieldcoeff_file", - ], - ) - ], -) -def test_FNIRT(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FNIRT(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FNIRT_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FNIRT(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_mcflirt.py b/pydra/tasks/fsl/preprocess/tests/test_run_mcflirt.py deleted file mode 100644 index 13525ff..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_run_mcflirt.py +++ /dev/null @@ -1,22 +0,0 @@ -import os, pytest -from pathlib import Path -from ..mcflirt import MCFLIRT - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", [(None, ["out_file"])]) -def test_MCFLIRT(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = MCFLIRT(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_prelude.py b/pydra/tasks/fsl/preprocess/tests/test_run_prelude.py deleted file mode 100644 index 9c6b66f..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_run_prelude.py +++ /dev/null @@ -1,37 +0,0 @@ -import os, pytest -from pathlib import Path -from ..prelude import PRELUDE - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_PRELUDE(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = PRELUDE(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_PRELUDE_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = PRELUDE(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_slicetimer.py b/pydra/tasks/fsl/preprocess/tests/test_run_slicetimer.py deleted file mode 100644 index f03a0c1..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_run_slicetimer.py +++ /dev/null @@ -1,25 +0,0 @@ -import os, pytest -from pathlib import Path -from ..slicetimer import SliceTimer - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", - [({"ref_file": 'f"{in_file}"'}, ["out_file", "slice_time_corrected_file"])], -) -def test_SliceTimer(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = SliceTimer(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() diff --git a/pydra/tasks/fsl/preprocess/tests/test_run_susan.py b/pydra/tasks/fsl/preprocess/tests/test_run_susan.py deleted file mode 100644 index bdb8e42..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_run_susan.py +++ /dev/null @@ -1,40 +0,0 @@ -import os, pytest -from pathlib import Path -from ..susan import SUSAN - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", - [({"brightness_threshold": 0.01, "fwhm": 2}, ["out_file", "smoothed_file"])], -) -def test_SUSAN(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = SUSAN(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_SUSAN_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = SUSAN(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_spec_applywarp.py b/pydra/tasks/fsl/preprocess/tests/test_spec_applywarp.py deleted file mode 100644 index ad2b138..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_spec_applywarp.py +++ /dev/null @@ -1,17 +0,0 @@ -import os, pytest -from pathlib import Path -from ..applywarp import ApplyWarp - - -@pytest.mark.parametrize("inputs, outputs", [({"ref_file": 'f"{in_file}"'}, ["out_file"])]) -def test_ApplyWarp(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = ApplyWarp(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/preprocess/tests/test_spec_bet.py b/pydra/tasks/fsl/preprocess/tests/test_spec_bet.py deleted file mode 100644 index 09dd23a..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_spec_bet.py +++ /dev/null @@ -1,37 +0,0 @@ -import os, pytest -from pathlib import Path -from ..bet import BET - - -@pytest.mark.parametrize( - "inputs, outputs", - [ - (None, ["out_file"]), - ({"mask": True}, ["out_file", "mask_file"]), - ( - {"surfaces": True}, - [ - "out_file", - "meshfile", - "inskull_mask_file", - "inskull_mesh_file", - "outskull_mask_file", - "outskull_mesh_file", - "outskin_mask_file", - "outskin_mesh_file", - "skull_mask_file", - ], - ), - ], -) -def test_BET(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = BET(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/preprocess/tests/test_spec_fast.py b/pydra/tasks/fsl/preprocess/tests/test_spec_fast.py deleted file mode 100644 index 61ec166..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_spec_fast.py +++ /dev/null @@ -1,32 +0,0 @@ -import os, pytest -from pathlib import Path -from ..fast import FAST - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_FAST(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FAST(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FAST_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FAST(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_spec_first.py b/pydra/tasks/fsl/preprocess/tests/test_spec_first.py deleted file mode 100644 index e48756b..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_spec_first.py +++ /dev/null @@ -1,32 +0,0 @@ -import os, pytest -from pathlib import Path -from ..first import FIRST - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_FIRST(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FIRST(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FIRST_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FIRST(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_spec_flirt.py b/pydra/tasks/fsl/preprocess/tests/test_spec_flirt.py deleted file mode 100644 index e806cf4..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_spec_flirt.py +++ /dev/null @@ -1,32 +0,0 @@ -import os, pytest -from pathlib import Path -from ..flirt import FLIRT - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_FLIRT(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FLIRT(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FLIRT_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FLIRT(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_spec_fnirt.py b/pydra/tasks/fsl/preprocess/tests/test_spec_fnirt.py deleted file mode 100644 index 1097d04..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_spec_fnirt.py +++ /dev/null @@ -1,47 +0,0 @@ -import os, pytest -from pathlib import Path -from ..fnirt import FNIRT - - -@pytest.mark.parametrize( - "inputs, outputs", - [ - ( - {"ref_file": 'f"{in_file}"'}, - [ - "warped_file", - "field_file", - "jacobian_file", - "modulatedref_file", - "log_file", - "fieldcoeff_file", - ], - ) - ], -) -def test_FNIRT(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FNIRT(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FNIRT_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = FNIRT(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_spec_mcflirt.py b/pydra/tasks/fsl/preprocess/tests/test_spec_mcflirt.py deleted file mode 100644 index 075cc33..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_spec_mcflirt.py +++ /dev/null @@ -1,17 +0,0 @@ -import os, pytest -from pathlib import Path -from ..mcflirt import MCFLIRT - - -@pytest.mark.parametrize("inputs, outputs", [(None, ["out_file"])]) -def test_MCFLIRT(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = MCFLIRT(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/preprocess/tests/test_spec_prelude.py b/pydra/tasks/fsl/preprocess/tests/test_spec_prelude.py deleted file mode 100644 index 7212865..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_spec_prelude.py +++ /dev/null @@ -1,32 +0,0 @@ -import os, pytest -from pathlib import Path -from ..prelude import PRELUDE - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_PRELUDE(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = PRELUDE(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_PRELUDE_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = PRELUDE(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/preprocess/tests/test_spec_slicetimer.py b/pydra/tasks/fsl/preprocess/tests/test_spec_slicetimer.py deleted file mode 100644 index 2125884..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_spec_slicetimer.py +++ /dev/null @@ -1,20 +0,0 @@ -import os, pytest -from pathlib import Path -from ..slicetimer import SliceTimer - - -@pytest.mark.parametrize( - "inputs, outputs", - [({"ref_file": 'f"{in_file}"'}, ["out_file", "slice_time_corrected_file"])], -) -def test_SliceTimer(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = SliceTimer(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/preprocess/tests/test_spec_susan.py b/pydra/tasks/fsl/preprocess/tests/test_spec_susan.py deleted file mode 100644 index aca65a1..0000000 --- a/pydra/tasks/fsl/preprocess/tests/test_spec_susan.py +++ /dev/null @@ -1,35 +0,0 @@ -import os, pytest -from pathlib import Path -from ..susan import SUSAN - - -@pytest.mark.parametrize( - "inputs, outputs", - [({"brightness_threshold": 0.01, "fwhm": 2}, ["out_file", "smoothed_file"])], -) -def test_SUSAN(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = SUSAN(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_SUSAN_exception(test_data, inputs, error): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = SUSAN(in_file=in_file, **inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/tests/data/anatomical.nii b/pydra/tasks/fsl/tests/data/anatomical.nii deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/confounds_regressors.tsv b/pydra/tasks/fsl/tests/data/confounds_regressors.tsv deleted file mode 100644 index abb2b36..0000000 --- a/pydra/tasks/fsl/tests/data/confounds_regressors.tsv +++ /dev/null @@ -1,527 +0,0 @@ -csf white_matter global_signal std_dvars dvars framewise_displacement t_comp_cor_00 t_comp_cor_01 t_comp_cor_02 t_comp_cor_03 t_comp_cor_04 t_comp_cor_05 a_comp_cor_00 a_comp_cor_01 a_comp_cor_02 a_comp_cor_03 a_comp_cor_04 a_comp_cor_05 cosine00 cosine01 cosine02 cosine03 cosine04 cosine05 cosine06 trans_x trans_y trans_z rot_x rot_y rot_z -428.8565979003906 352.93707275390625 346.7164611816406 n/a n/a n/a 0.0537686856 -0.0015589024 0.0256904886 -0.055431638600000006 0.0334041688 -0.045645886 -0.0254605165 0.0048484609000000005 -0.040182257799999996 -0.00840419 0.028837367000000003 -0.0429884066 0.061662366600000004 0.0616615418 0.061660167 0.0616582424 0.0616557679 0.061652743499999996 0.061649169299999994 -0.0473566 0.07976039999999998 -0.119026 0.00304888 -0.000650074 0.000562989 -423.5132446289063 352.6452331542969 345.640625 1.039311 62.641384 0.2022724 0.062349405499999996 -0.0022176462 0.0345898154 -0.0170098117 0.028544711099999998 -0.0453725769 -0.018702046200000003 -0.0057048807 -0.044379064100000004 -0.0006186997 0.0348451634 -0.0065644783 0.061660167 0.061652743499999996 0.0616403716 0.0616230524 0.0616007872 0.0615735779 0.0615414265 -0.0394607 0.143454 -0.0792087 0.00159675 -0.000862004 0.000409737 -421.8155822753906 352.5387268066406 345.3033752441406 1.001764 60.378342 0.07977654999999999 0.052621478099999994 -0.024067204300000002 0.023976866800000003 -0.0034115172 0.020885618600000003 -0.0105915573 -0.016908982 -0.0029474502000000004 -0.0496521325 0.016617866499999998 0.0331314209 0.0023508823 0.0616557679 0.0616351482 0.0616007872 0.0615526926 0.061490875 0.0614153483 0.061326129199999996 -0.0474473 0.142576 -0.13041100000000003 0.0013054 -0.0008713459999999998 0.000503238 -421.94580078125 352.53643798828125 345.1815185546875 1.034929 62.377281 0.34043935 0.0546193864 -0.0085628441 0.0251114206 0.0089886654 0.0472215468 -0.0388199627 -0.0151842025 -0.0052130304 -0.0459949178 0.0050819396 0.0482500117 0.0124924463 0.061649169299999994 0.0616087584 0.0615414265 0.06144720309999999 0.061326129199999996 0.061178257800000004 0.061003653600000006 -0.0450416 -0.0219745 -0.10445 0.00348336 -0.000295167 0.000306934 -421.6714782714844 352.55206298828125 345.7688903808594 0.984481 59.336678 0.1350055 0.053351830999999995 -0.0129630161 0.01933137 0.0093967082 0.0199816272 -0.013670688799999999 -0.013729844 -0.005543737900000001 -0.0410041867 -0.0028430989 0.0371352979 0.0232120496 0.0616403716 0.0615735779 0.06146230849999999 0.061306644 0.0611066967 0.060862611100000005 0.060574563399999996 -0.0474075 0.035851 -0.0622828 0.00322295 -0.000635691 0.000358938 -421.7160339355469 353.1280212402344 346.5439453125 1.044161 62.933681 0.30546834999999994 0.0491227798 -0.0347523588 0.0275142878 0.014662727 -0.0021947441000000002 -0.0037473461 -0.0233749851 -0.0001679766 -0.04227085690000001 0.0110727573 0.025359982000000003 0.0325656202 0.061629375099999995 0.0615296116 0.0613634587 0.061131095700000006 0.0608327732 0.060468813200000006 0.0600396084 -0.0350914 0.146502 -0.100252 0.000399393 -0.0005856 0.000375931 -422.0044860839844 352.8157043457031 346.26373291015625 1.043894 62.917583 0.3683706 0.051076075 -0.019145380400000002 0.027904492000000003 0.014245225700000001 0.0139551647 -0.0289754181 -0.0163075221 0.0021952172 -0.057152487 -0.0011384181 0.032963130800000004 0.0175916103 0.061616180199999995 0.0614768659 0.0612449087 0.060920658200000005 0.060504603 0.05999737 0.0593997236 -0.0473819 -0.0489117 -0.116 0.0030016 -0.000321411 0.000343959 -421.9078369140625 353.349609375 346.627197265625 0.984202 59.319859 0.1142548 0.0557874392 -0.0176886541 0.019926881 0.017280086200000003 0.0154755351 -0.0015848789000000002 -0.0187503826 0.0042999105 -0.0514848333 -0.007117820600000001 0.0375336971 0.023369584500000002 0.0616007872 0.0614153483 0.0611066967 0.060675451799999995 0.0601224786 0.0594488867 0.058656027300000003 -0.0445358 0.030952 -0.0907497 0.0030545 -0.000303749 0.000288627 -423.7535095214844 352.76971435546875 347.08319091796875 1.041885 62.796497 0.24610505 0.041001723399999995 -0.0329021056 0.0241082723 0.0280948068 -0.0124210021 -0.00035472870000000003 -0.0156891539 -0.00190658 -0.0453808136 0.0013530182000000002 0.0307899465 0.0246374027 0.061583196900000005 0.0613450675 0.060948867000000004 0.060395616299999996 0.059686740999999995 0.058824067699999996 0.057809819299999995 -0.0439007 0.154855 -0.0935258 0.00132579 -0.000880095 0.000359388 -421.46575927734375 352.84381103515625 346.3697204589844 1.022636 61.63633 0.33807078 0.0339742969 -0.0209763399 0.0080653242 0.031088961499999998 -0.0089892564 0.053482818 -0.0198270894 -0.0039345466999999995 -0.0451115432 -0.0056682597 0.0331161027 0.025915474100000002 0.061563409699999995 0.061266033600000006 0.0607714702 0.0600813114 0.0591977785 0.058123715199999995 0.0568625783 -0.0379304 -0.00866658 -0.11276000000000003 0.00374655 -0.0004332 0.000240149 -420.7928161621094 352.7812805175781 346.3152160644531 1.023381 61.681225 0.19639038 0.0188112805 -0.0385910818 -0.011891090600000001 0.0513098766 -0.015556511 0.0644882221 -0.0165915746 0.0008219536 -0.0450252247 0.00041603230000000004 0.024071836800000003 0.0367681956 0.0615414265 0.061178257800000004 0.060574563399999996 0.0597327166 0.058656027300000003 0.057348728499999994 0.05581596 -0.0473786 0.0879448 -0.0859926 0.00291274 -0.000635691 0.000475116 -421.4585876464844 352.84234619140625 346.48553466796875 0.992451 59.817059 0.150551 0.022704300099999998 -0.0338238752 -0.020676612900000002 0.0361390234 -0.0082521286 0.044257989299999995 -0.0169017771 -0.0029269592 -0.029943540600000002 0.0160998063 0.0158351577 0.0326194083 0.061517248 0.0610817528 0.0603582097 0.0593500308 0.0580619705 0.0565001029 0.0546717934 -0.0428669 0.150998 -0.0954755 0.00147358 -0.000635691 0.000444212 -419.8441162109375 352.70477294921875 346.0199279785156 1.0102 60.886803 0.30138802 0.0121409076 -0.0273844306 -0.020543481699999998 0.038220342000000004 0.0089782532 0.0738032034 -0.016070717800000002 -0.0082920227 -0.042922151500000005 -0.0043682968 0.0195660682 0.023063640899999998 0.061490875 0.060976532199999996 0.0601224786 0.0589334724 0.057416137699999995 0.055578927800000004 0.053432078200000004 -0.0402938 0.00294458 -0.113888 0.00370674 -0.000347448 0.000318635 -419.6357421875 352.89276123046875 346.4696960449219 1.005331 60.593327 0.30593151999999996 0.0080609827 -0.028165880600000002 -0.0428730964 0.039591141499999996 0.006099671700000001 0.0412882162 -0.015807618 -0.006021654 -0.0362715204 0.0058374459 0.006954896800000001 0.0316654202 0.06146230849999999 0.060862611100000005 0.0598674458 0.0584832792 0.056719105 0.0545863863 0.052098980999999996 -0.0378821 0.151582 -0.09914750000000003 0.00126458 -0.000635691 0.0002462 -421.9593811035156 352.7574768066406 346.8318786621094 1.026059 61.842636 0.2979096265 0.0198073138 -0.032301819700000005 -0.026579866400000002 0.030936274700000002 0.0014158785000000001 0.0619500371 -0.0174697914 -0.0059961181 -0.0457277961 0.0021469561 0.0067888101 0.0121129255 0.0614315496 0.0607400057 0.059593193200000005 0.057999708 0.0559714938 0.053523752699999996 0.050674831600000005 -0.0319609 0.0190501 -0.134484 0.00350584 -0.000635691 5.05947e-06 -420.6251831054688 352.7864074707031 346.70928955078125 0.975088 58.770504 0.0701924765 0.0160915406 -0.0354456936 -0.0186905975 0.040895061 0.0005614441000000001 0.0579349405 -0.0131619995 -0.0039251202 -0.047525683 0.0008730146000000001 0.015449289 0.027326357599999997 0.0613985992 0.0606087335 0.0592998088 0.0574830349 0.0551739708 0.052392391600000005 0.0491621191 -0.0319432 0.0404246 -0.107731 0.00342707 -0.000454141 0.000185685 -424.9055480957031 352.82977294921875 347.3736572265625 1.057406 63.73201 0.28658500000000003 0.0118732582 -0.06779053639999999 -0.0240485873 0.0191050782 0.008052877 -0.0295202877 -0.0171288314 -0.0017573574 -0.0483553418 0.0153628106 0.0053415358 0.0209976612 0.0613634587 0.060468813200000006 0.0589873867 0.0569335547 0.054327247300000006 0.0511937557 0.047563487 -0.035625 0.126491 -0.182642 0.00138752 -0.000635691 0.000403101 -423.4905700683594 347.3473205566406 343.6858215332031 1.429247 86.143631 1.01910365 -0.1022827734 -0.0474509013 0.0326234375 -0.013203429499999999 0.0635159984 -0.052519164199999996 0.0519471864 -0.0529280342 -0.0578015326 0.05777697230000001 -0.09890198310000001 -0.0313843345 0.061326129199999996 0.060320264900000004 0.058656027300000003 0.056351581 0.053432078200000004 0.0499293841 0.0458817293 -0.0444593 -0.247091 -0.662699 -0.00127977 -0.00108247 0.000384563 -417.0805358886719 350.4700927734375 344.9083251953125 1.76582 106.429535 1.040049655 -0.013605852600000001 -0.0557343939 -0.0017400832 -0.0058479165000000005 0.0225796371 0.0297208929 0.013912976799999999 -0.0026512423 0.035373041699999996 0.10219857689999999 -0.1773525384 0.0702475355 0.0612866121 0.060163109699999995 0.058305837 0.055737446100000004 0.05248926190000001 0.0486009003 0.0441197852 -0.06377090000000002 0.00637318 -0.222933 -0.00548047 -1.50595e-05 -0.000897484 -415.3163757324219 352.7156982421875 345.59564208984375 1.247697 75.20121799999998 0.401132795 0.0094559329 -0.049341345099999996 -0.010199398 0.0032057815 -0.0009929884 0.0598669591 -0.0051992248999999996 0.007276668199999999 -0.0045212240999999995 0.0392568501 -0.054685968200000004 0.032555336000000004 0.0612449087 0.05999737 0.0579369282 0.0550915004 0.05149963900000001 0.04721001019999999 0.042280734 -0.0550415 0.03651 0.00631375 -0.00372069 -0.000214771 -0.000196579 -419.47216796875 352.7251281738281 346.4576110839844 1.080105 65.100143 0.41858265 0.025813557 -0.0377546422 -0.0011280455 0.0032204269 -0.0089464002 0.0289313254 -0.0164287725 -0.0046135459 -0.0228354537 0.0063972364 0.0021225244 0.010151818 0.061201020700000004 0.0598230695 0.0575494194 0.0544141125 0.050464092099999996 0.0457584997 0.0403677898 -0.0457497 -0.0767672 0.07715769999999998 9.54066e-05 -0.000730162 -2.46726e-05 -421.4810791015625 353.1749267578125 346.563720703125 1.071692 64.593079 0.33040096 0.0077320123 -0.054674985999999995 -0.0065563106 0.0193986012 0.0007480275 7.75396e-05 -0.017688266499999997 0.0017400876000000002 -0.0172017285 0.029327895899999998 -0.0063180142 0.0330795564 0.061154949400000005 0.059640233 0.057143434800000004 0.053705669000000004 0.0493835445 0.0442482328 0.0383842957 -0.0311852 0.103738 0.0519469 -0.0014082700000000003 -0.0012479800000000003 0.000156242 -419.31378173828125 352.78167724609375 345.8904724121094 1.041467 62.771336 0.14350323000000004 -0.0178676366 -0.0449070646 -0.0320796904 0.026965532 -0.0031668111 0.0495382303 -0.0137813548 0.0019540808 -0.016928535800000002 0.0157095403 0.0031698915000000004 0.0307664177 0.0611066967 0.0594488867 0.056719105 0.0529665744 0.0482589599 0.042681148499999995 0.0363337182 -0.0406102 0.0749191 0.0909968 -0.000655001 -0.0008579749999999998 -2.46726e-05 -422.8047790527344 352.604736328125 346.1974792480469 1.055401 63.611164 0.07445132999999998 -0.0142758577 -0.0432600812 -0.0699937293 0.0244232171 0.023965530899999997 -0.0510595659 -0.0125283464 0.0003246777 -0.0117045255 0.017569212600000002 -0.0081520177 0.0179983371 0.0610562642 0.059249057800000005 0.05627656599999999 0.052197250300000005 0.0470913411 0.041059259300000005 0.0342196412 -0.0364433 0.101577 0.111208 -0.000476084 -0.000706535 0.000113277 -420.7060241699219 350.52545166015625 343.35455322265625 1.372377 82.715958 0.5722636000000001 -0.0744274488 -0.0074701433999999995 -0.047068429800000006 -0.0173755697 0.034343122000000004 -0.0376298668 0.0223343425 0.01634942 0.0276490393 0.0556881186 0.044624588 -0.051700614299999996 0.061003653600000006 0.0590407749 0.05581596 0.051398136 0.0458817293 0.039384647599999996 0.032045759300000004 -0.177749 -0.0180122 0.22425 -0.00386358 -0.000500808 -0.000260034 -420.1304016113281 349.28533935546875 341.61187744140625 1.717919 103.542458 1.5768292 -0.1203087953 0.061222523200000004 -0.0103574369 -0.0671542308 -0.1656955096 -0.0248116825 0.08135555629999999 0.1108777782 0.053629350199999995 -0.0648930502 -0.0518459153 -0.040079954 0.060948867000000004 0.058824067699999996 0.0553374348 0.050569687300000006 0.044631203099999996 0.0376594638 0.0298158718 -0.594501 -0.123645 0.549579 -0.0129923 -0.00312881 -0.00308562 -420.0106201171875 350.4721984863281 341.4777526855469 1.189683 71.704628 0.8598327 -0.0766104331 -0.0011321699 -0.0171281904 -0.0842365336 -0.1322071649 -0.0391631577 0.0612840931 0.1153356112 0.062109298099999995 0.0223132797 -0.09018488599999999 -0.045105018899999995 0.0608919062 0.058598967 0.0548411441 0.049712377300000006 0.043340877699999995 0.0358859231 0.0275338758 -0.197552 -0.103441 0.401287 -0.0140042 -0.00469922 0.000219824 -420.8648681640625 352.74041748046875 346.4868469238281 1.175502 70.849884 0.44343045 -0.0590932687 0.0056311127 -0.0242823688 -0.049743768499999994 -0.09130462460000001 -0.047662057300000005 0.0162643853 0.0960500007 0.0839526051 0.0528457576 -0.0678838777 -0.0326066126 0.0608327732 0.0583655051 0.054327247300000006 0.0488266951 0.0420119037 0.034066302799999996 0.0252037594 -0.170904 -0.0789298 0.316497 -0.00920198 -0.00370526 0.000573269 -422.3285827636719 352.9872131347656 346.9273681640625 1.065876 64.242516 0.3102057 -0.044653840099999995 -0.0049897139000000005 -0.0584648942 -0.0314740389 -0.0624348944 -0.0613848693 0.0010178028 0.0667218101 0.0708351471 0.047145317400000004 -0.0626980809 -0.0255755202 0.0607714702 0.058123715199999995 0.0537959092 0.0479131463 0.0406454662 0.0322029395 0.0228295951 -0.159661 -0.0522662 0.225198 -0.00571034 -0.00358018 0.000576551 -423.484375 353.3213195800781 346.7541198730469 0.99789 60.144844 0.15635430999999997 -0.030048197999999998 -0.022438739 -0.0587792625 -0.0717754746 -0.0718904174 -0.0090266302 -0.005497474699999999 0.056706593 0.0572944617 0.0449399609 -0.07251513679999999 -0.0620536454 0.060707999400000004 0.0578736318 0.0532473004 0.0469722521 0.0392427837 0.030298225699999997 0.020415532 -0.157928 0.00961641 0.159951 -0.00591866 -0.00385606 0.000510917 -422.6296691894531 352.5272521972656 346.68585205078125 1.218467 73.439507 0.6499810400000001 0.015572802299999999 0.0038197293 -0.0405419556 -0.0759826957 0.0156560179 0.0629763753 -0.0182669232 -0.021118611699999998 -0.015509651200000002 -0.0067083703000000005 -0.0030548094 -0.1021812774 0.060642363 0.057615290599999994 0.0526815972 0.046004549699999994 0.0378051071 0.0283546073 0.0179657891 -0.130787 0.00327637 -0.0549245 0.00168537 -0.00356012 0.000378397 -421.4149475097656 352.7333984375 346.0684814453125 1.07985 65.084755 0.241332065 0.0209045278 0.0011166150999999999 -0.0104159162 -0.0825885704 0.0221189512 0.063141819 -0.0195401296 -0.0152460197 -0.0075687529000000005 0.0042409039 0.006294318399999999 -0.0916082194 0.060574563399999996 0.057348728499999994 0.052098980999999996 0.0450105913 0.0363337182 0.02637458 0.0154846479 -0.116168 0.0715134 0.011055 2.7343e-06 -0.00340434 0.000389912 -421.584716796875 353.0647888183594 346.3740234375 1.021754 61.583206 0.128318865 0.0325952896 -0.015737330900000002 0.0052867411 -0.0684415757 0.0177161657 0.042312542300000006 -0.0250786205 -0.0131969716 -0.014223595 0.0198133617 -0.0135185928 -0.0799757221 0.060504603 0.0570739836 0.05149963900000001 0.0439909442 0.0348299293 0.024360686200000002 0.0129764445 -0.117702 0.0848395 -0.007221799999999999 -0.00120561 -0.00386425 0.000625297 -420.8820495605469 352.388916015625 346.1412658691406 1.017181 61.307583 0.26043195 0.046300783600000006 -0.0138193137 0.0271737991 -0.064659733 0.0366652871 0.0376056794 -0.023186009100000002 -0.0260975862 -0.023854651600000002 0.0088141475 0.016341030700000002 -0.0686629118 0.0604324842 0.056791094900000005 0.0508837635 0.0429461904 0.0332950814 0.022315511899999998 0.0104455625 -0.127731 -0.0369069 -0.0206677 0.00087025 -0.00367072 0.00066012 -422.7683410644531 352.6333312988281 346.459228515625 1.086044 65.458061 0.24922650000000005 0.054704745 -0.011635776799999999 0.034030816 -0.046617276500000006 0.028861273700000002 -0.0600267943 -0.018493584 -0.0213040354 -0.0346088526 0.00048352059999999997 0.011412013700000001 -0.0220784731 0.0603582097 0.0565001029 0.0502515524 0.041876926 0.031730543 0.0202416832 0.007896425 -0.120646 0.0814662 0.0342868 -0.000492052 -0.00367072 0.000646144 -423.384765625 352.8699951171875 346.6176452636719 1.045051 62.987331 0.1679798 0.0574015149 -0.04572617019999999 0.036392041800000004 -0.018424803700000002 0.0049927445 -0.048185742999999996 -0.0164273839 -0.007311853399999999 -0.0375152985 0.0284772792 0.0045837666 0.0044404464 0.0602817821 0.056201049100000004 0.0496032084 0.0407837614 0.0301377094 0.0181418631 0.005333487099999999 -0.125901 0.0299356 0.024601 -0.00241004 -0.00361808 0.000586604 -422.10693359375 353.3209228515625 346.6868591308594 1.034287 62.338581 0.16245489999999999 0.0469631784 -0.0329227317 0.0281633687 0.0083475625 -0.00048329199999999997 -0.0141796619 -0.0236444559 -0.0034240401 -0.0348991242 0.0281253477 0.00769393 0.011555743200000001 0.0602032042 0.055893976100000006 0.0489389399 0.0396673204 0.0285180009 0.0160187477 0.0027612279999999997 -0.144605 0.0216047 0.0614511 -0.00165331 -0.00255512 0.000434896 -398.93359375 335.9974670410156 327.3197021484375 2.372919 143.02063 1.7024711 -0.1427911374 0.047946572800000004 0.1193466606 0.0544291915 0.1623886163 -0.0263057648 0.221133462 -0.10771889949999999 0.13227521539999998 0.0017588622 -0.0046823567 0.0931726563 0.0601224786 0.055578927800000004 0.0482589599 0.038528240299999995 0.0268728619 0.0138750634 0.0001841432 -0.0850468 0.352415 1.15167 -0.00345532 -0.00132072 0.00183616 -431.0296325683594 351.3997497558594 347.8903503417969 2.497537 150.531601 1.0051556 -0.06591874639999999 0.0765469858 0.0095970056 -0.0178579808 -0.1354692434 -0.0243402297 0.0276067227 0.068102204 0.0898778094 -0.075914126 -0.0438739834 0.006149240500000001 0.0600396084 0.0552559492 0.047563487 0.0373671711 0.0252037594 0.011713562700000001 -0.0023932635000000002 -0.0399239 0.0523428 0.694779 -0.00622349 -0.00199618 0.00245392 -419.92950439453125 352.5096740722656 347.37646484375 1.408989 84.922646 0.6610651000000001 -0.025038992200000002 0.0758815888 -0.0168802328 0.0013054832000000001 -0.0176771591 -0.047734745300000006 -0.0099677826 -0.0081084539 0.0800175586 -0.0452100625 -0.0072860112 0.0076167113 0.059954596500000006 0.0549250863 0.0468527442 0.0361847754 0.023512181899999998 0.0095370211 -0.0049664875 -0.0493701 0.0342794 0.351993 -0.00158095 -0.00193633 0.00134092 -419.6159362792969 352.8754577636719 347.1625671386719 1.087554 65.549065 0.1817865 -0.0222122365 0.081284435 -0.0233879573 -0.0060134726 -0.0247465624 -0.0339021706 -0.0105451511 -0.0037452589000000003 0.0901970535 -0.0379553977 -0.022177183 -0.0048742068 0.0598674458 0.0545863863 0.0461269599 0.0349817282 0.0217996377 0.0073482335 -0.0075310317 -0.0463575 0.126588 0.338763 -0.00236933 -0.00207881 0.0008070739999999999 -422.2381896972656 352.85284423828125 346.58770751953125 1.062381 64.031845 0.11410094999999998 0.0071009763 0.0851601353 -0.0074290737 -0.027577419 -0.0400239131 -0.003893772 -0.0183355596 -0.005928689599999999 0.0739623988 -0.0350165671 0.013235366 -0.044375791100000006 0.0597781596 0.054239897599999996 0.0453863669 0.033758716 0.020067654 0.0051500103000000005 -0.010082414100000001 -0.0492555 0.106455 0.313232 -0.00199062 -0.00265628 0.000452475 -420.8116455078125 352.6007385253906 345.61712646484375 1.011807 60.983639 0.09175215 0.021658197799999997 0.0967694036 0.0164264371 -0.0287854502 -0.0353801541 0.0036693646000000003 -0.015388752 -0.014942166299999999 0.0712594591 -0.0406792588 0.0261162648 -0.035990155499999996 0.059686740999999995 0.053885669500000004 0.044631203099999996 0.0325164369 0.0183177752 0.0029451740999999997 -0.012616175600000001 -0.0393361 0.0916108 0.344488 -0.00175217 -0.00227646 0.000548856 -422.9323120117188 352.4203796386719 345.6949768066406 1.059777 63.874928 0.09987395 0.0260364647 0.09381332869999999 0.025705270099999997 0.0045152457 -0.0281201 -0.0459503911 -0.0141642325 -0.014653931499999998 0.0794819558 -0.0379641987 0.020624369099999998 0.0040923684 0.059593193200000005 0.053523752699999996 0.043861710899999996 0.0312555998 0.0165515619 0.0007365563000000001 -0.0151278882 -0.0392628 0.133787 0.339265 -0.00238847 -0.00250708 0.0007299649999999998 -420.8698425292969 352.14141845703125 344.97369384765625 1.016259 61.251968 0.14305134999999997 0.0403816914 0.08101173589999999 0.0465354984 0.0348371691 -0.0185282176 -0.0314608136 -0.0147986393 -0.0246743783 0.053034382000000005 -0.0381648646 0.0415512989 0.0253855283 0.0594975196 0.053154198799999997 0.0430781374 0.029976924199999998 0.0147705889 -0.0014730073999999998 -0.0176131622 -0.0519379 0.08368119999999998 0.331422 -0.00109394 -0.00257144 0.000640306 -419.6549377441406 352.02508544921875 344.7625732421875 0.980091 59.072094 0.0865202 0.024214802400000002 0.068124497 0.0184677969 0.0677674363 -0.0561211904 0.0364049215 -0.0113373764 -0.0218900068 0.052820999400000006 -0.0478279063 0.0230809311 0.0567904983 0.0593997236 0.0527770605 0.042280734 0.0286811401 0.0129764445 -0.0036806797 -0.020067654 -0.046333 0.112999 0.345634 -0.00145787 -0.0022119 0.000616066 -419.5580139160156 351.7615661621094 344.95654296875 0.977007 58.886185 0.08806160000000002 0.0084624295 0.06577136110000001 -0.0008156749 0.0838519674 -0.0086116087 0.0357125007 -0.011538676000000001 -0.0301710611 0.06352220780000001 -0.0348161446 0.0099240873 0.0590846897 0.0592998088 0.052392391600000005 0.0414697568 0.0273689869 0.011170728500000001 -0.0058836257 -0.022487074 -0.0491731 0.139818 0.33718 -0.00183489 -0.0026047 0.0008452159999999998 -418.5008850097656 351.43280029296875 344.5787658691406 0.974061 58.708618 0.12656724999999996 -0.016421414 0.0651636451 -0.0194463884 0.086367444 -0.0015944016 0.047496738 -0.007705545899999999 -0.0310243167 0.05627512 -0.042952150700000004 0.0371919003 0.053349555300000004 0.0591977785 0.0520002471 0.0406454662 0.026041213599999998 0.0093550512 -0.0080790168 -0.0248671939 -0.0556319 0.099929 0.334977 -0.000686556 -0.00233067 0.000707251 -420.9892578125 351.54791259765625 345.009521484375 1.003108 60.459343 0.07933844999999998 -0.0164994482 0.0617951317 -0.048894435 0.0763371138 0.0193727231 -0.0279058335 -0.0062813855 -0.0340348075 0.0623236254 -0.0297092848 0.0046927951 0.0416852363 0.0590936366 0.0516006827 0.0398081268 0.0246985778 0.0075310317 -0.010264034 -0.027203854 -0.049199 0.137466 0.339039 -0.00115688 -0.0023668 0.000587574 -420.02740478515625 352.0018005371094 345.2995910644531 0.984135 59.315811 0.07033299999999998 -0.0226097346 0.0694879792 -0.0554352651 0.057112466900000006 0.0241277383 0.006725675 -0.0115110718 -0.033804618 0.0619905498 -0.0190197189 0.0063840547 0.0102565166 0.0589873867 0.0511937557 0.0389580073 0.023341845899999998 0.0057002965 -0.012435871599999999 -0.0294929706 -0.0491411 0.132809 0.305769 -0.00142164 -0.0026515 0.000685076 -420.0936584472656 352.0654296875 345.16571044921875 0.957042 57.682842 0.13281205 -0.0285900512 0.0773623299 -0.06706773519999999 0.046439384400000006 0.0308971175 -0.0326689468 -0.0159388611 -0.0339291298 0.0665602976 -0.035628336600000005 0.0218685 0.0085294545 0.0588790326 0.050779524000000006 0.0380953808 0.021971792200000003 0.0038644781 -0.0145917409 -0.031730543 -0.0521226 0.0966436 0.330312 -0.000687571 -0.00211005 0.000578152 -420.8419494628906 351.9255065917969 345.1107177734375 1.074755 64.777657 0.14086359999999998 -0.0194845099 0.08939296029999999 -0.0719224272 0.0217078052 0.0193211646 -0.027653851899999998 -0.004147429 -0.035500839900000004 0.0582776025 -0.0666198221 -0.0075161073 -0.023371317599999997 0.058768578200000005 0.0503580468 0.0372205242 0.020589198700000002 0.0020252136 -0.0167288735 -0.0339126607 -0.056943 0.164878 0.329525 -0.00145408 -0.00230616 0.000200335 -421.6316223144531 352.25726318359375 345.7149963378906 1.050525 63.317265 0.10525315 -0.0108672556 0.07977497759999999 -0.0706419742 -0.0005168124 -0.0023040367 0.008923870300000001 -0.014216630400000001 -0.022347716400000002 0.0827686301 -0.0387851744 -0.0123695003 -0.0396643459 0.058656027300000003 0.0499293841 0.0363337182 0.019194854299999998 0.0001841432 -0.0188445253 -0.036035509900000005 -0.046556 0.173401 0.318929 -0.00230152 -0.00249998 0.000674018 -422.5867004394531 352.7898254394531 345.7652893066406 1.004552 60.54636 0.1451869 -0.0117407584 0.0833498846 -0.0438805796 -0.005164172 0.0397863951 -0.049954360999999996 -0.0183958325 -0.028527547400000002 0.06408507349999999 -0.0336385317 0.005388817299999999 -0.0388999162 0.0585413841 0.049493597199999996 0.0354352477 0.017789555 -0.0016570915 -0.020935979599999998 -0.0380953808 -0.0543704 0.10232500000000001 0.310844 -0.00140163 -0.00223564 0.000674018 -420.9111633300781 352.42889404296875 345.86029052734375 0.99781 60.140015 0.043292800000000006 -0.0149964254 0.089559924 -0.0596858254 0.009553058199999999 0.0212191985 0.012677600700000001 -0.0178423251 -0.0266844646 0.0701058886 -0.04581336900000001 0.0076488453 -0.0333499027 0.058424652599999995 0.0490507482 0.0345254011 0.0163741027 -0.0034968484000000005 -0.023000551 -0.0400886733 -0.0491631 0.100818 0.33726 -0.00131407 -0.00211995 0.000674018 -422.1372680664063 352.82208251953125 346.4076232910156 0.992392 59.813477 0.13316890000000003 -0.0063103494999999996 0.07559037910000001 -0.0564093232 -0.0113529032 -0.0004702771 0.0081464173 -0.0210727 -0.0209745732 0.0761021816 -0.050849091500000006 0.0016676946 -0.042464985 0.058305837 0.0486009003 0.0336044704 0.0149493052 -0.005333487099999999 -0.0250355883 -0.0420119037 -0.051959 0.152228 0.316758 -0.00207414 -0.0025291 0.000674018 -422.01220703125 352.0959167480469 345.8276062011719 0.992604 59.826241 0.14353344999999998 -0.0012500598 0.0938199256 -0.036478351400000004 -0.025344492000000003 0.0098315538 0.0326452235 -0.0204448392 -0.0429510079 0.0639378764 -0.041268719700000005 0.0069091149 -0.07418235150000001 0.058184941500000004 0.048144117699999996 0.0326727513 0.013515975800000002 -0.007165369699999999 -0.0270384785 -0.043861710899999996 -0.059927 0.0966176 0.307193 -0.000981214 -0.00228794 0.000600303 -421.3096923828125 351.9723815917969 345.3363037109375 0.99018 59.680157 0.10080695000000003 0.020632556399999998 0.1107013187 -0.0042676456 -0.028600071600000002 0.0053936869 0.0581724645 -0.015060127 -0.0415001583 0.070320965 -0.0450211627 0.030595126099999998 -0.056845413399999996 0.0580619705 0.0476804656 0.031730543 0.0120749325 -0.0089908627 -0.0290066498 -0.0456348621 -0.049109 0.130359 0.344162 -0.0011809 -0.00240011 0.000674018 -423.3329162597656 352.4549255371094 345.5524597167969 1.036358 62.463375 0.08394100000000003 0.0321221653 0.0821588092 0.0112712098 -0.0241307394 0.0094092558 0.0090994626 -0.0209235269 -0.0335143023 0.0544769421 -0.0458167459 0.022111012599999997 -0.0387157813 0.0579369282 0.04721001019999999 0.0307781479 0.010626997800000001 -0.010808338300000001 -0.0309375749 -0.0473282582 -0.0516745 0.14868 0.324001 -0.00203155 -0.00239289 0.000674018 -421.2816162109375 352.1495666503906 345.1146545410156 0.984695 59.349564 0.13054564999999999 0.049276664299999995 0.098600015 0.045764886500000004 -0.0026007236 0.0297581227 -0.0253809388 -0.0196968869 -0.049635215999999996 0.0475783343 -0.0535346671 0.0425155371 -0.012113746399999998 0.057809819299999995 0.046732818499999995 0.0298158718 0.0091729979 -0.012616175600000001 -0.032828774399999996 -0.0489389399 -0.0562372 0.102166 0.314577 -0.000720861 -0.00230268 0.000674018 -421.7989501953125 352.4520263671875 345.4519958496094 1.01417 61.12606 0.09187944999999997 0.0471833567 0.0775306207 0.0453196231 0.032335164900000005 0.0193860546 -0.0480464934 -0.018753318300000002 -0.0390848721 0.0405697037 -0.040324131 0.0439859162 0.023938551000000002 0.057680648099999995 0.0462489587 0.028844023599999997 0.0077137627000000005 -0.0144127627 -0.0346778198 -0.050464092099999996 -0.0562707 0.131836 0.33684 -0.00148306 -0.00226662 0.000674018 -421.82696533203125 351.92694091796875 345.33880615234375 0.984491 59.337288 0.090953 0.04884894769999999 0.057143655300000006 0.036861062 0.0558083891 0.010391676899999999 -0.0066740566000000005 -0.0153641154 -0.0516928866 0.0332340851 -0.0403141081 0.0337259373 0.0364109779 0.0575494194 0.0457584997 0.0278629153 0.0062501251 -0.0161964974 -0.036482337000000004 -0.0519010494 -0.0585374 0.145674 0.303843 -0.00122302 -0.00264945 0.000479862 -420.4350891113281 351.8567199707031 344.9952392578125 0.970668 58.504154 0.10880215 0.038339435299999995 0.06106300480000001 0.037040957299999996 0.0712971091 0.019802508 0.00498487 -0.0171071933 -0.055865911799999994 0.0221849333 -0.037471685299999995 0.046710996500000004 0.0362973912 0.057416137699999995 0.0452615117 0.0268728619 0.0047829204 -0.0179657891 -0.038240008799999996 -0.0532473004 -0.0562867 0.111549 0.314946 -0.000640772 -0.00216584 0.000319251 -411.7018432617188 343.9233703613281 336.9710388183594 2.315594 139.565567 1.0493242999999999 -0.140014633 0.0263660836 0.1527444433 -0.019366587 0.1276142973 -0.0339685631 0.1477971323 -0.06483377059999999 -0.022276556 0.0825939779 0.2615088252 -0.0525655451 0.0572808079 0.0447580654 0.025874181200000002 0.003312986 -0.0197190601 -0.0399485782 -0.0545004924 -0.34335 0.00579925 0.580768 -0.00451201 -0.000408454 -0.00186591 -406.6715393066406 337.8937072753906 328.2170715332031 3.021919 182.137177 4.63682895 -0.1512857521 -0.0405221311 0.12172312539999999 -0.0424288011 -0.0358941775 -0.0363868485 0.24780462050000002 -0.0267579577 -0.20872831649999998 -0.4869278987 -0.26469541879999997 0.0315440031 0.057143434800000004 0.0442482328 0.0248671939 0.0018411607000000001 -0.0214547469 -0.041605851299999996 -0.055658435199999995 -0.785518 -0.598966 0.124274 -0.0342055 0.0186851 -0.0157469 -426.7735900878906 353.6833801269531 349.4693298339844 2.737723 165.008102 2.5332849 -0.0602188473 -0.06905555070000001 0.0827582711 -0.0346816995 -0.0053623935 -0.0393583732 0.0442475612 0.134109126 -0.0977769148 0.09789014 0.11653050890000001 -0.0254722208 0.0570040233 0.0437320865 0.0238522233 0.0003682847 -0.023171301800000002 -0.04320970019999999 -0.056719105 -0.345343 -0.361124 0.0526061 -0.0186456 0.00785401 -0.00646589 -423.85748291015625 352.9365539550781 346.9892272949219 1.355973 81.72721099999998 1.3039016 -0.010290669 -0.1105192422 0.0698629266 -0.047344492 0.0201073664 0.0140158973 0.0150962047 0.0533928544 -0.0871943519 0.0893268112 -0.0278773912 -0.0027797946 0.0568625783 0.04320970019999999 0.0228295951 -0.0011048015 -0.0248671939 -0.0447580654 -0.057680648099999995 -0.198136 -0.126131 0.0313255 -0.0104505 0.00244788 -0.0020587 -421.3736267089844 351.91943359375 345.1015625 0.986294 59.445927 0.1167808 -0.013490106799999999 -0.0973536541 0.09162838039999999 -0.055564845700000004 0.0044217701 -0.026089552599999996 0.0322233682 0.044706223499999996 -0.0799900065 0.0781528511 -0.011253983 0.0017219964 0.056719105 0.042681148499999995 0.0217996377 -0.0025772572 -0.0265409112 -0.0462489587 -0.0585413841 -0.198155 -0.171326 0.0816158 -0.0105364 0.00278751 -0.0020587 -425.155029296875 352.4478759765625 345.5978698730469 1.075659 64.83215300000002 0.4580656499999999 0.0074858701 -0.1053277941 0.06825491040000001 -0.035462776099999996 -0.0421025007 -0.051882841 0.019173816899999998 0.058738713399999996 -0.0809222911 0.052828784299999994 -0.0391781207 0.026246303500000002 0.0565736083 0.0421465068 0.0207626817 -0.0040482420000000005 -0.0281909609 -0.0476804656 -0.0592998088 -0.144181 -0.0643765 0.182013 -0.0102576 0.000888942 -0.000301169 -422.0338134765625 352.4966125488281 345.1971740722656 1.048604 63.201485 0.09340305000000008 0.0008459817999999999 -0.08343886589999999 0.0710851889 0.0030720336 -0.0366290739 0.004945483 0.0192978559 0.055334574500000004 -0.0657208242 0.0634196843 -0.0165337258 0.0418577167 0.056426093600000005 0.041605851299999996 0.0197190601 -0.0055169164 -0.0298158718 -0.0490507482 -0.059954596500000006 -0.133104 -0.111184 0.171253 -0.0100454 0.000695615 -0.000390813 -422.3327026367188 352.5309753417969 344.9027404785156 0.976954 58.882984 0.1101332 -0.0010449014 -0.11094984779999999 0.0549021776 0.013715550900000002 -0.0335557518 0.0472933558 0.0153818674 0.0501034229 -0.0652949671 0.0659490225 -0.0249431474 0.0566696309 0.05627656599999999 0.041059259300000005 0.0186691079 -0.0069824421 -0.0314141948 -0.0503580468 -0.060504603 -0.138634 -0.0963438 0.148473 -0.00918632 0.000347823 -0.000523601 -423.12579345703125 352.14959716796875 344.9751892089844 0.974718 58.748241 0.09280588499999994 -0.009164399200000001 -0.1193736657 0.0352633273 0.0346495531 -0.007306515600000001 0.015210751100000001 0.010604373600000001 0.040092527200000005 -0.0582455717 0.0617013226 -0.04832178559999999 0.0619843492 0.0561250309 0.0405068086 0.0176131622 -0.0084439827 -0.0329845047 -0.0516006827 -0.060948867000000004 -0.138671 -0.0354011 0.151107 -0.009162890000000002 0.000264909 -4.61013e-05 -420.6154174804688 352.36676025390625 344.5677795410156 0.985531 59.399971 0.191710215 -0.021823414399999998 -0.083125815 0.0096157646 0.0317464067 -0.022184738500000002 0.0598005704 0.012138259299999999 0.034367673599999995 -0.0408439282 0.0531002897 -0.0316605711 0.050811753 0.0559714938 0.0399485782 0.0165515619 -0.0099007042 -0.0345254011 -0.0527770605 -0.0612866121 -0.11513300000000003 -0.0784964 0.210933 -0.00824821 0.000123522 0.00020285 -421.3871765136719 351.6932373046875 344.2662048339844 0.996876 60.083744 0.06981079999999998 -0.0435387141 -0.0896067772 -0.0100391779 0.0382412935 -0.010765718600000002 0.0097776887 0.0190488044 0.0439872049 -0.0336495534 0.0522168985 -0.041098047900000004 0.0626021572 0.05581596 0.039384647599999996 0.0154846479 -0.011351775 -0.036035509900000005 -0.053885669500000004 -0.061517248 -0.11696 -0.0484236 0.227956 -0.00848776 0.000301732 0.00020285 -420.5823669433594 352.1018371582031 344.6817932128906 0.987586 59.523834 0.09902055000000007 -0.0399608287 -0.0987900573 -0.0164352011 0.0291720993 0.029245059500000004 0.0135080397 0.0137511808 0.031064280299999997 -0.046117299199999996 0.0779014383 -0.042572051799999996 0.031308939 0.055658435199999995 0.038815097400000005 0.0144127627 -0.012796367099999999 -0.0375134847 -0.0549250863 -0.0616403716 -0.126945 -0.0452775 0.16998 -0.007987869999999998 0.000243353 0.00020285 -421.11663818359375 352.0289001464844 344.3695983886719 0.988543 59.581467 0.1015212 -0.0519278193 -0.0808235913 -0.0539017575 0.0079110811 0.0360284556 -0.0337369291 0.013846895900000001 0.0326332931 -0.030396788900000003 0.06924780900000001 -0.040652541699999996 0.0058117472 0.0554989249 0.038240008799999996 0.0133362505 -0.014233656 -0.0389580073 -0.055893976100000006 -0.0616557679 -0.122992 -0.092175 0.200805 -0.007710299999999998 0.000362697 0.00020285 -421.8263854980469 352.24920654296875 344.9517517089844 0.993521 59.881538 0.15708899999999998 -0.0513925392 -0.06611677980000001 -0.0697473975 -0.0284605222 0.0141361492 -0.030075356 0.012946848200000001 0.0417068195 -0.012562811100000001 0.054984658 -0.0493826808 -0.0243462438 0.0553374348 0.0376594638 0.012255456699999999 -0.0156628214 -0.0403677898 -0.056791094900000005 -0.061563409699999995 -0.10947 -0.0295423 0.230782 -0.008388879999999998 0.000123522 0.000101459 -412.33538818359375 345.93560791015625 338.9577941894531 1.414911 85.279579 1.30734705 -0.1609145862 -0.0006602997000000001 0.0217906127 -0.0284179267 0.0580589071 0.0200380702 0.1151009034 0.024335341899999998 -0.0016513557999999998 0.020284848 0.0769789823 -0.055700632800000004 0.0551739708 0.037073545299999996 0.011170728500000001 -0.0170830476 -0.0417415748 -0.057615290599999994 -0.0613634587 -0.600279 -0.15884799999999996 0.460186 -0.0119036 0.0011248400000000002 -0.00453907 -422.26361083984375 352.21002197265625 345.0701599121094 1.628014 98.123718 0.8224001 -0.0556032232 0.0076044111 -0.0383490161 -0.042735997000000005 -0.0806892439 -0.0077987622 0.0236245798 0.0701054165 0.012761761299999999 -0.030042388599999997 -0.011574696 -0.027771065299999998 0.055008538600000004 0.036482337000000004 0.010082414100000001 -0.018493524 -0.0430781374 -0.0583655051 -0.0610562642 -0.372361 -0.08851739999999998 0.378429 -0.00901273 -0.00244952 -0.00215641 -419.70654296875 352.1386413574219 344.7178039550781 1.148872 69.244812 0.649793823 -0.0316314017 -0.0059245074 -0.045988676799999996 -0.050562445 -0.0098425192 0.026574572400000003 0.0110040743 0.0329047992 0.0189949095 0.0229840498 -0.0291243716 -0.0489673327 0.0548411441 0.0358859231 0.0089908627 -0.0198934458 -0.044376285700000004 -0.0590407749 -0.060642363 -0.194562 0.000699273 0.287894 -0.00702926 -0.00116084 0.000416303 -421.6029052734375 352.6191101074219 345.4739685058594 1.001007 60.332726 0.16053932299999998 -0.0230571044 0.0040054329 -0.037859123599999996 -0.0595543309 -0.006473151999999999 0.030290801200000002 -0.0019553795000000003 0.0201338049 0.0183163278 0.015452433500000001 -0.026197428 -0.0640191682 0.0546717934 0.0352843888 0.007896425 -0.0212820138 -0.0456348621 -0.059640233 -0.0601224786 -0.166946 -0.017082199999999995 0.2657 -0.0060121 -0.000764249 0.000861509 -421.3460998535156 351.92645263671875 345.3215026855469 0.98042 59.091919 0.05068375000000004 -0.0095626285 0.0107966055 -0.006839978399999999 -0.0710822701 -0.0249390302 0.058705664000000005 0.0041221452 0.0158317552 0.0243756202 0.0139965473 -0.0219018265 -0.054577558899999996 0.0545004924 0.0346778198 0.006799452199999999 -0.022658435600000002 -0.0468527442 -0.060163109699999995 -0.0594975196 -0.162101 -0.0126845 0.289122 -0.00600269 -0.0007449839999999998 0.000529803 -422.08251953125 352.1204833984375 345.5599670410156 1.020867 61.529728 0.094746 0.0111026098 0.0027382465000000003 0.0424968238 -0.062038024500000004 -0.016072580700000002 0.0230514466 0.0017398342 0.0135934221 0.016300346299999997 0.0170587955 -0.014983705 -0.038680295 0.054327247300000006 0.034066302799999996 0.0057002965 -0.0240219257 -0.0480288462 -0.0606087335 -0.058768578200000005 -0.14863 0.0193024 0.286774 -0.00637674 -0.00122803 0.000611509 -423.6099243164063 352.4850769042969 345.4602966308594 1.021817 61.586975 0.09845851999999998 0.0326022333 -0.0018843774 0.054401008 -0.0395938994 0.0063552339 -0.0775646331 -0.0035065216999999997 0.0035503328 -0.0158895316 0.0314019293 -0.0021568734 -0.0127554307 0.0541520642 0.033449925 0.0045993107 -0.0253717058 -0.0491621191 -0.060976532199999996 -0.0579369282 -0.148625 -0.00932372 0.270622 -0.00571006 -0.00130709 0.000939277 -422.0148010253906 352.59234619140625 345.0855712890625 1.025261 61.794582 0.07011804999999999 0.03530306 -0.0052949603 0.0517087126 0.0324944294 -0.0201829015 -0.0139581524 -0.007947328299999999 0.0025202964 -0.026179402400000003 0.0164536396 0.013674565900000001 0.0393571142 0.05397494940000001 0.032828774399999996 0.0034968484000000005 -0.0267070056 -0.0502515524 -0.061266033600000006 -0.0570040233 -0.148652 0.00681013 0.259946 -0.00515821 -0.00116597 0.000766623 -419.9576110839844 352.22589111328125 344.8659362792969 1.017478 61.325474 0.15858056999999998 -0.0066042404 -0.015216674 0.0178103278 0.0667976788 -0.022552459599999998 0.0443864479 0.0051016187 0.0095032546 -0.0082688539 0.0197394979 -0.0029553319 0.0729415628 0.0537959092 0.0322029395 0.0023932635000000002 -0.0280270631 -0.0512961746 -0.0614768659 -0.0559714938 -0.131833 0.0442354 0.319501 -0.00589689 -0.00122803 0.000861509 -419.1692199707031 351.9072570800781 344.8193054199219 0.999974 60.270443 0.17284706999999996 -0.013523736599999999 -0.0316973263 -0.0183360914 0.0655494045 0.0207046488 0.047339624500000003 0.0022922893 0.0008444959 -0.0114018374 0.030239916800000002 -0.0168914584 0.0489900895 0.05361495 0.0315725097 0.0012889102 -0.0293311248 -0.052295054199999996 -0.0616087584 -0.0548411441 -0.14864 -0.00463002 0.26083 -0.00501378 -0.00122803 0.000774546 -422.2080993652344 351.77520751953125 345.0199890136719 1.0209990000000002 61.537674 0.04832348999999999 -0.029674133199999998 -0.0130227646 -0.0652469496 0.024245606099999997 0.036242947000000005 -0.0680246689 -8.74695e-05 -0.007513824200000001 0.002493322 0.0195387395 -0.0176419092 0.0109649026 0.053432078200000004 0.0309375749 0.0001841432 -0.030618446400000002 -0.0532473004 -0.0616615418 -0.05361495 -0.148639 0.00334912 0.273765 -0.00460119 -0.00122803 0.000910123 -421.1476745605469 352.0025634765625 345.3072204589844 1.011521 60.966393 0.13087913000000004 -0.0253533942 -0.0075364622999999995 -0.0520653275 -0.0298595659 -0.0055366024 0.0271307961 -0.0015108367999999998 0.0123181726 0.0081131835 0.0098232076 -0.0330897874 -0.038171439700000004 0.0532473004 0.030298225699999997 -0.000920683 -0.0318882933 -0.0541520642 -0.0616351482 -0.052295054199999996 -0.148659 0.0466931 0.273959 -0.00606827 -0.00111506 0.00074375 -422.443603515625 353.1455383300781 345.93023681640625 1.013024 61.056988 0.11047275 -0.0047724107 -0.004100558 -0.028383765699999997 -0.0331047151 0.0145684476 -0.0096712461 -0.0057066719999999994 0.0231407948 -0.0044196893 0.0176076219 -0.0178620323 -0.034342598700000004 0.053060623200000004 0.0296545534 -0.0020252136 -0.0331399408 -0.055008538600000004 -0.0615296116 -0.0508837635 -0.15298 0.0181712 0.247213 -0.00519017 -0.000976694 0.000744961 -423.72509765625 352.70269775390625 346.3428649902344 1.239178 74.687798 0.63970315 0.0100820409 -0.0100970238 -0.0181514204 -0.009900476 0.047882884400000006 -0.0085173117 -0.0154346176 -0.0387876704 -0.0670135483 -0.026783944700000003 0.026712436800000003 -0.030635157200000002 0.052872053200000005 0.0290066498 -0.0031290940000000002 -0.0343726744 -0.05581596 -0.0613450675 -0.0493835445 -0.255264 -0.0532813 0.155492 -0.000184466 0.000173296 -0.000584258 -424.0235900878906 353.2411804199219 348.4553527832031 1.18508 71.427155 0.4619082 0.0116415245 -0.015717168 -0.0075574978 -0.0008989042 -0.0137517773 0.0390175523 -0.0194846575 -0.0068618892 -0.0346567923 0.003789184 -0.012907359399999999 0.0054819002000000006 0.0526815972 0.0283546073 -0.0042319699 -0.0355857906 -0.0565736083 -0.0610817528 -0.047797019100000004 -0.164493 0.0668166 0.184002 -0.00331075 -0.00024928 0.000317468 -426.7287292480469 353.33331298828125 349.5809631347656 1.067668 64.350525 0.12247159999999997 0.0329395123 -0.0380657972 0.0284983517 -0.002208613 -0.0349453147 -0.044464301399999996 -0.0199671418 -0.0052670569 -0.0497692444 0.0009301260000000001 -0.0112891829 0.013866178 0.05248926190000001 0.027698518999999998 -0.005333487099999999 -0.0367785971 -0.0572808079 -0.0607400057 -0.0461269599 -0.147122 0.0918347 0.184067 -0.00433099 -0.000494035 0.000652823 -425.2648010253906 353.80419921875 349.080078125 1.087379 65.538528 0.1739615 -0.0025439508 -0.0645197586 0.0044449224 0.0196160725 -0.011476529499999999 0.0236914491 -0.029681967599999998 -0.0038229805 -0.050313753899999994 0.0333174243 -0.004880085399999999 0.0304541764 0.052295054199999996 0.0270384785 -0.0064332921 -0.0379504132 -0.0579369282 -0.060320264900000004 -0.044376285700000004 -0.147487 0.0111253 0.178028 -0.00399612 -0.0015237 0.00102525 -424.3199157714844 353.46234130859375 347.88885498046875 1.065323 64.209198 0.11361006 -0.019359129 -0.030299344199999998 -0.0324576533 0.0174173986 0.0207967768 -0.038853588599999996 -0.0228127766 -0.0012870534 -0.030859670099999997 0.0166370144 -0.0055382187 0.0176991012 0.052098980999999996 0.02637458 -0.0075310317 -0.0391005699 -0.0585413841 -0.0598230695 -0.0425480561 -0.144523 0.00122084 0.217871 -0.00346856 -0.00117411 0.000684428 -424.447265625 353.04541015625 347.0809631347656 1.044102 62.930126 0.12319001 -0.007949013000000001 -0.0157325317 -0.0546440931 -0.0284994912 0.0053424232 -0.014564523400000001 -0.0152612384 -0.0047259256 -0.0159998027 0.0038210345000000002 -0.018898113600000002 -0.033176218199999996 0.0519010494 0.025706918199999998 -0.0086263535 -0.0402284109 -0.0590936366 -0.059249057800000005 -0.0406454662 -0.136115 0.0699199 0.227507 -0.00390468 -0.00100735 0.000810487 -423.0267639160156 353.0918273925781 346.9169006347656 1.02029 61.494957 0.07468219999999999 0.0034204138 -0.0082671429 -0.0231595077 -0.049812618499999996 0.0191993818 0.0346481726 -0.0183531311 -0.0015581166 -0.0215650322 0.0173019094 -0.0017136954 -0.0507609716 0.0517012663 0.0250355883 -0.009718906 -0.0413332925 -0.059593193200000005 -0.058598967 -0.038671841299999996 -0.14455 0.0535372 0.206661 -0.00363215 -0.00106519 0.000560487 -420.7662963867188 352.67364501953125 346.5449523925781 1.032509 62.231434 0.11187555 0.0315689345 0.0005005732 0.0090839018 -0.055163859 0.024191062000000003 0.0688759226 -0.0214015533 -0.0260780576 -0.0288583213 0.0045324983 0.0205198012 -0.0564557695 0.05149963900000001 0.024360686200000002 -0.010808338300000001 -0.0424145842 -0.0600396084 -0.0578736318 -0.0366306304 -0.14456 0.0353493 0.191298 -0.0022169 -0.00100735 0.000467284 -423.93927001953125 352.5133056640625 346.2904052734375 1.121366 67.587013 0.13035599999999997 0.04733408769999999 0.0014156239999999999 0.0426647129 -0.0281864587 0.0436816138 -0.055045484400000004 -0.0168542044 -0.0198235189 -0.0301330254 0.0034365110999999998 0.0225717539 -0.007694141999999999 0.0512961746 0.0236823082 -0.0118943007 -0.0434716687 -0.0604324842 -0.0570739836 -0.0345254011 -0.128064 0.0706941 0.223599 -0.00304798 -0.00100735 0.000560488 -422.9907531738281 352.2771301269531 345.9111633300781 1.059446 63.854927 0.06807634999999995 0.0442387282 -0.0284216713 0.025997447200000003 0.0273458532 0.0077598147 0.013992617800000001 -0.0158320237 -0.0179919105 -0.0417256952 0.0108040882 0.0150001183 0.0402561939 0.0510908803 0.023000551 -0.0129764445 -0.0445039428 -0.0607714702 -0.056201049100000004 -0.0323598325 -0.139381 0.0585212 0.218982 -0.00361761 -0.00109559 0.000702007 -419.16290283203125 351.9938659667969 345.31610107421875 1.019405 61.441601 0.05480925 0.0150123446 -0.0270548918 0.0077729106 0.059490626 0.0148409418 0.072820679 -0.0107184326 -0.020377359299999998 -0.0480038273 -0.002207285 0.0071492234 0.052335488 0.0508837635 0.022315511899999998 -0.0140544224 -0.0455108174 -0.0610562642 -0.0552559492 -0.0301377094 -0.145269 0.0476894 0.216105 -0.00314312 -0.00100735 0.000560488 -420.52490234375 351.8774108886719 345.6357727050781 0.999323 60.231236 0.059066500000000015 -0.0107894136 -0.0372027549 -0.0268895183 0.0663575781 0.0234962714 0.030529397799999997 -0.0052345711999999996 -0.014752473600000001 -0.0299254003 0.0086204664 0.0013052941 0.0584147304 0.050674831600000005 0.0216272887 -0.0151278882 -0.046491717800000006 -0.0612866121 -0.054239897599999996 -0.0278629153 -0.135848 0.0685374 0.233604 -0.00336909 -0.00100735 0.000560488 -421.9220886230469 352.42132568359375 346.16473388671875 0.995017 59.971672 0.04684109999999999 -0.0122464302 -0.040987799 -0.0398151606 0.055075004500000004 0.0432028292 0.002654992 -0.011446894099999999 -0.0064407833 -0.013427454699999999 0.0138111577 0.0096921309 0.0349358148 0.050464092099999996 0.020935979599999998 -0.0161964974 -0.0474460842 -0.06146230849999999 -0.053154198799999997 -0.0255394259 -0.133894 0.0640341 0.233579 -0.00408037 -0.00100735 0.000464592 -423.655029296875 352.2032165527344 346.036865234375 1.022664 61.63802 0.10244109999999997 -0.0108924143 -0.0253291679 -0.059484086299999996 0.028498052000000003 0.0525746077 -0.06541205 -0.0124911596 -0.0142341454 -0.0016922448000000001 -0.0060012252 -0.0004682761 0.0039740597 0.0502515524 0.0202416832 -0.0172599069 -0.048373371799999995 -0.061583196900000005 -0.0520002471 -0.023171301800000002 -0.139211 0.0372603 0.233612 -0.00276992 -0.00100735 0.000560488 -422.8269348144531 351.8955078125 345.72015380859375 1.032901 62.255028 0.0628376 0.0031846202 0.0016965867000000002 -0.0647812814 -0.0371533884 0.013863221499999998 0.0237596798 -0.0114849906 -0.0128405735 -0.0009810438 -0.0067530767 -0.0004806187 -0.058595716299999996 0.050037220099999995 0.0195444986 -0.0183177752 -0.049273051500000005 -0.061649169299999994 -0.050779524000000006 -0.0207626817 -0.135747 0.0694379 0.260808 -0.00276992 -0.00100735 0.000560488 -422.3298034667969 352.5283508300781 345.53253173828125 1.020615 61.514542 0.07075455 0.028310892400000003 0.0079770818 -0.009284709300000001 -0.04194572269999999 0.0335758861 0.028091559900000004 -0.0169482192 -0.009203803 -0.0025219066 -0.0036709369 0.008990871899999999 -0.0511325767 0.0498211028 0.0188445253 -0.0193697628 -0.0501446098 -0.061660167 -0.049493597199999996 -0.0183177752 -0.133156 0.0794016 0.233624 -0.00313038 -0.0011925 0.000635195 -421.76397705078125 352.1412658691406 345.0396728515625 1.016233 61.250404 0.09796690000000002 0.0469079034 0.0065316156 0.0302794958 -0.0399010428 0.029765555099999997 -0.0041900644 -0.015813141 -0.0197245233 -0.0148329272 -0.010684626599999998 0.022028690899999998 -0.0380047714 0.0496032084 0.0181418631 -0.020415532 -0.0509875493 -0.061616180199999995 -0.048144117699999996 -0.0158408552 -0.145298 0.0511935 0.233596 -0.00255463 -0.000832047 0.000419622 -421.668212890625 352.4126281738281 345.1544189453125 1.045984 63.043587 0.08495395000000001 0.056014343 0.0065050339 0.042569275 0.0029886021000000004 0.0305112313 -0.0542951683 -0.0190169963 -0.0198410097 -0.023766057900000002 -0.0019867001 0.0425179317 0.0130088221 0.0493835445 0.0174366123 -0.0214547469 -0.0518013888 -0.061517248 -0.046732818499999995 -0.0133362505 -0.12381 0.064013 0.251332 -0.00289667 -0.00100735 0.000560488 -421.45733642578125 352.3363952636719 345.3581848144531 1.029687 62.061314 0.11506919999999997 0.0430590613 -0.017535858600000002 0.0227367471 0.04986738 -0.00021544389999999999 0.036789385200000004 -0.016639526 -0.0161129623 -0.0191894439 -0.0074022048 0.0092403925 0.0589014053 0.0491621191 0.0167288735 -0.022487074 -0.052585664000000004 -0.0613634587 -0.0452615117 -0.010808338300000001 -0.128126 0.0936919 0.233655 -0.00367163 -0.00119648 0.0008643439999999999 -418.5904541015625 352.453125 344.7914733886719 1.01177 60.981419 0.12501580000000004 0.022747450699999998 -0.0227798644 -0.0007045468 0.0713965647 0.0101405214 0.0707293147 -0.015597615700000001 -0.0205560827 -0.0209622727 0.0001307197 0.012972831499999999 0.0712868117 0.0489389399 0.0160187477 -0.023512181899999998 -0.0533399272 -0.061154949400000005 -0.0437320865 -0.008261536600000001 -0.139388 0.0469917 0.23284 -0.00267814 -0.00100735 0.0007221919999999998 -420.1970520019531 352.1481628417969 345.12286376953125 1.0163700000000002 61.258701 0.06638705000000002 -0.0115672437 -0.0187214364 -0.0363913226 0.0772506508 0.0304733467 0.0134410365 -0.0129747108 -0.012850633799999999 -0.014532846399999999 0.0015036911 0.0148998483 0.0623525065 0.048714014900000005 0.015306336299999999 -0.024529741400000003 -0.054063747800000006 -0.0608919062 -0.0421465068 -0.0057002965 -0.129702 0.0639967 0.248669 -0.00283088 -0.000844453 0.000560488 -421.1519470214844 352.2944030761719 345.677490234375 1.028679 62.000572 0.08387764999999998 -0.0191555198 -0.0113687279 -0.0740546282 0.0326278564 0.033587060499999995 -0.04848576809999999 -0.0153904427 -0.0097177639 0.0035198442 -0.0053295571 -0.005014884 0.0145594218 0.0484873523 0.0145917409 -0.0255394259 -0.0547567129 -0.060574563399999996 -0.0405068086 -0.0031290940000000002 -0.128796 0.0916396 0.244544 -0.00330199 -0.00124153 0.000716376 -420.250732421875 351.9621887207031 345.43682861328125 1.021072 61.54208 0.12908690000000003 -0.0100714281 0.0078229543 -0.0756675527 -0.0127729425 0.033883288399999996 0.0120054373 -0.014763998700000001 -0.0144829328 -0.0054237747 -0.0115784902 -0.0006444371 -0.0383104183 0.0482589599 0.0138750634 -0.0265409112 -0.055418427 -0.0602032042 -0.038815097400000005 -0.0005524229 -0.140138 0.048092 0.224358 -0.00233185 -0.0011525900000000002 0.00069523 -420.20587158203125 352.2241516113281 345.4471435546875 1.004652 60.552383 0.06247405000000001 0.0155805453 0.0206955664 -0.037445390099999996 -0.046230978 0.0278935853 0.06871978969999999 -0.016195846599999997 -0.0170747834 0.0057310854000000005 -0.0194562041 0.0012556731 -0.0625127771 0.0480288462 0.0131564061 -0.0275338758 -0.056048512300000006 -0.0597781596 -0.037073545299999996 0.0020252136 -0.131823 0.0750799 0.237256 -0.00247947 -0.00106181 0.000648167 -420.1483459472656 352.3724365234375 345.9701232910156 1.010679 60.915668 0.08034924999999998 0.0428934479 0.0249091123 0.0047707122 -0.0436802046 -0.0006592569 0.0430127964 -0.0195466625 -0.0125282939 0.006737321700000001 -0.011866213600000002 0.010091188000000001 -0.0478874401 0.047797019100000004 0.012435871599999999 -0.0285180009 -0.056646609199999996 -0.0592998088 -0.0352843888 0.0045993107 -0.137174 0.090847 0.241034 -0.00320294 -0.0013864 0.00070917 -422.59063720703125 351.7917175292969 345.74945068359375 1.052734 63.450413 0.12072649999999997 0.0608201066 0.010710332099999999 0.0371698071 -0.030235705800000002 0.0369771852 -0.0638726565 -0.0184212899 -0.0223792846 -0.011411773899999998 -0.0036626540000000004 0.0234727806 -0.016307429499999998 0.047563487 0.011713562700000001 -0.0294929706 -0.0572123765 -0.058768578200000005 -0.033449925 0.007165369699999999 -0.137594 0.0525486 0.224341 -0.00220331 -0.00115182 0.000637078 -421.29986572265625 351.9552917480469 345.8060302734375 1.047556 63.138294 0.10921329999999996 0.0576419067 0.0026029484 0.025511076299999998 0.0335547387 -0.0055348796 -0.0131980484 -0.015406261999999999 -0.0208065425 -0.0107481317 -0.0217062896 0.022369652 0.0380040641 0.0473282582 0.0109895824 -0.0304584719 -0.0577454912 -0.058184941500000004 -0.0315725097 0.009718906 -0.1307 0.0885306 0.247465 -0.0029793 -0.0011392 0.000712734 -420.73577880859375 352.3150634765625 345.733154296875 0.99917 60.222 0.07258354999999997 0.041706262200000004 -0.0184354864 0.0223997494 0.060025749 -0.0183994632 0.054697039100000004 -0.0161431204 -0.014500616000000001 -0.0241901799 -0.0057932007999999995 0.0292429917 0.0519678439 0.0470913411 0.010264034 -0.0314141948 -0.058245649000000004 -0.0575494194 -0.0296545534 0.012255456699999999 -0.133555 0.0733817 0.218638 -0.00256723 -0.00123053 0.0007243869999999998 -420.08306884765625 351.7671203613281 345.2939147949219 1.007793 60.741749 0.05333959999999999 0.0041891768 -0.0198254472 -0.0175932816 0.0756969538 0.0085742553 0.07434574769999999 -0.015336922099999999 -0.021096962200000003 -0.010582414699999999 -0.012598728200000001 0.0238587301 0.0611686637 0.0468527442 0.0095370211 -0.0323598325 -0.0587125645 -0.0568625783 -0.027698518999999998 0.0147705889 -0.131418 0.0657809 0.225155 -0.00207763 -0.00100897 0.000693851 -423.5035095214844 351.83343505859375 345.78704833984375 1.055552 63.620228 0.14582495 -0.0022212572 -0.0221618295 -0.06857367730000001 0.0524280401 0.031936897 -0.08536141960000002 -0.0120981647 -0.0079309727 -0.0012811015 -0.0092078352 -0.0135205056 0.039327342 0.04661247599999999 0.0088086474 -0.0332950814 -0.059145971299999996 -0.0561250309 -0.025706918199999998 0.0172599069 -0.131354 0.113338 0.236542 -0.00307468 -0.0014429899999999997 0.000999118 -420.44146728515625 352.1424255371094 345.2920227050781 1.025828 61.828732 0.15480639999999998 -0.009734274499999999 -0.0033179588 -0.0761535579 -0.0010935507 0.0418810987 -0.012085762199999999 -0.0173074398 -0.0125526141 0.0104438516 -0.0050322672 -0.0010668259 -0.026027195 0.046370545 0.0080790168 -0.0342196412 -0.059545621900000005 -0.0553374348 -0.0236823082 0.0197190601 -0.14636 0.0411022 0.222327 -0.00220048 -0.00130746 0.000941856 -421.156005859375 351.77032470703125 345.34906005859375 0.997059 60.094769 0.05751199999999997 -0.0017915813 0.0222328836 -0.0659835125 -0.0349563418 0.0141904167 0.0483168108 -0.0128353294 -0.0167858246 0.0134502323 -0.014430826599999998 0.014295206699999998 -0.052305559800000005 0.0461269599 0.0073482335 -0.0351332152 -0.059911288300000004 -0.0545004924 -0.0216272887 0.0221437508 -0.141406 0.0622067 0.229839 -0.00214055 -0.00106879 0.0007616259999999998 -419.8749084472656 352.1002502441406 346.0054016113281 0.991145 59.738308 0.1235847 0.0187830046 0.0270941066 -0.048787141799999996 -0.0478364564 0.001308069 0.06684412969999999 -0.0192428624 -0.0078237746 0.018825390600000002 -0.0105304061 -0.0106381323 -0.0510144708 0.0458817293 0.0066164016 -0.036035509900000005 -0.060242761799999996 -0.05361495 -0.0195444986 0.024529741400000003 -0.13136 0.0998262 0.229849 -0.00310297 -0.00138267 0.0010035100000000002 -420.2380676269531 352.2232360839844 345.88690185546875 0.988142 59.557339 0.15901319999999997 0.0352320536 0.0180660672 -0.0206930178 -0.05477329190000001 0.0099443012 0.051767195 -0.020777261 -0.015811713300000002 0.0042228475 -0.011487230900000001 0.0123809277 -0.0636190823 0.0456348621 0.0058836257 -0.0369262359 -0.0605398531 -0.0526815972 -0.0174366123 0.0268728619 -0.144141 0.0623446 0.20504 -0.00206782 -0.00118201 0.000560488 -421.3014831542969 352.3474426269531 346.1163024902344 0.989916 59.664249 0.14210615 0.043538395 0.0317309044 0.0102378228 -0.0487624504 -0.010808993400000001 0.031209129500000002 -0.0197088058 -0.0061556642 0.0148086964 -0.014702346299999999 0.0260625643 -0.0499614533 0.0453863669 0.0051500103000000005 -0.0378051071 -0.0608023928 -0.0517012663 -0.015306336299999999 0.029169017400000004 -0.121592 0.0897106 0.244455 -0.00257634 -0.00138801 0.000901491 -423.5082092285156 352.45684814453125 346.5848388671875 1.007349 60.714935 0.06765149999999999 0.050004422300000004 0.0128519024 0.0184041507 -0.0470810616 -0.0021615157 -0.0185358183 -0.024310150200000002 -0.0097524138 0.0065539677 -0.0097770711 0.0234881856 -0.043787389100000004 0.045136252800000005 0.00441566 -0.038671841299999996 -0.061030231 -0.050674831600000005 -0.0131564061 0.0314141948 -0.129537 0.0878117 0.207519 -0.00225687 -0.0014389200000000004 0.000948543 -421.98175048828125 352.4674377441406 346.48699951171875 0.984024 59.309135 0.07226484999999999 0.0659706736 0.0255153135 0.0346400304 -0.024407384700000003 0.0037840275 -0.04567679980000001 -0.021180083399999997 -0.011121165700000001 -0.012753838 -0.0226552331 0.0406522816 -0.014079683300000001 0.0448845285 0.0036806797 -0.0395261602 -0.061223237699999995 -0.0496032084 -0.0109895824 0.0336044704 -0.139404 0.0709347 0.210039 -0.00190666 -0.00111379 0.000763866 -421.91644287109375 352.5434875488281 347.06170654296875 0.979836 59.056713 0.13207965 0.0511720541 0.0247754577 0.0404636385 -0.0038592081 -0.0043677991999999995 -0.0362591308 -0.020074775700000002 -0.0028774296999999997 -0.0009055799000000001 -0.0180998293 0.0259114375 0.0206788938 0.044631203099999996 0.0029451740999999997 -0.0403677898 -0.061381302699999994 -0.0484873523 -0.0088086474 0.0357360162 -0.125705 0.0913252 0.236421 -0.00290738 -0.0013468000000000004 0.000962299 -424.5956726074219 353.0257873535156 347.49896240234375 0.98071 59.109394 0.13525779999999998 0.0548632208 -0.0032903804 0.0345516735 -0.0106383276 -0.017932566299999998 -0.032322239700000005 -0.0281461233 -0.0090072964 -0.0240157807 -0.006515952199999999 0.0448917342 0.013481965600000001 0.044376285700000004 0.0022092484 -0.0411964596 -0.0615043357 -0.0473282582 -0.0066164016 0.0378051071 -0.136125 0.0632198 0.185429 -0.00213393 -0.00143565 0.000909791 -423.4337158203125 351.0511169433594 346.9137268066406 1.2241050000000002 73.779297 0.75588715 0.053105325 -0.051482634299999996 0.0533746272 -0.0263710535 0.073343466 -0.034570880299999995 -0.0194396851 -0.0767557274 -0.0967289998 0.0204480105 -0.00023613720000000002 -0.014254611499999998 0.0441197852 0.0014730073999999998 -0.0420119037 -0.0615922667 -0.0461269599 -0.00441566 0.0398081268 -0.209025 -0.0640874 -0.180222 0.00115299 -0.00168165 0.00117745 -423.36016845703125 352.31549072265625 347.3530578613281 1.279965 77.146057 0.7079362 0.0488106375 -0.0740092487 0.055478573600000004 -0.0132529394 -0.0077959643 -0.028707068 -0.0234683633 -0.0042026457 -0.054213518200000005 0.0194330744 -0.026318547 0.0205494757 0.043861710899999996 0.0007365563000000001 -0.0428138604 -0.0616450454 -0.0448845285 -0.0022092484 0.0417415748 -0.183722 0.0479202 0.0779605 -0.00383844 -0.00104118 0.000560488 -421.776611328125 353.0386657714844 347.6093444824219 1.115311 67.222038 0.2461377 0.0415283392 -0.024650441800000002 0.0269411138 -0.001303686 0.008462173 0.0012100341 -0.031195321 -0.0106448976 -0.0287546604 0.010190751999999999 0.0249977378 -0.0006807941999999999 0.043602072 0.0 -0.043602072 -0.0616626416 -0.043602072 -0.0 0.043602072 -0.156998 0.0258659 0.154264 -0.0018317 -0.00132201 0.000694036 -422.5987854003906 352.61468505859375 347.6229553222656 1.022264 61.613914 0.13955905 0.0475939041 -0.013389565700000002 0.0287908345 -0.0147380645 -0.0239198597 0.027153790499999997 -0.0257270585 -0.0133116777 -0.0144547541 0.0011449723 0.0154432904 -0.0008908646000000001 0.043340877699999995 -0.0007365563000000001 -0.044376285700000004 -0.0616450454 -0.042280734 0.0022092484 0.0453863669 -0.13451 0.0802086 0.174842 -0.00218975 -0.00159915 0.000901853 -427.1851501464844 352.84423828125 347.3974914550781 1.082326 65.233986 0.05052445000000001 0.0491078215 -0.0157803929 0.015651703200000002 -0.0030897131 -0.021324849 -0.0639854846 -0.0327311224 -0.0151717324 -0.0193028815 -0.00851609 0.0035450101 0.0125782207 0.0430781374 -0.0014730073999999998 -0.045136252800000005 -0.0615922667 -0.0409216928 0.00441566 0.0470913411 -0.13269 0.072536 0.167481 -0.00241841 -0.0018716 0.00107416 -419.48223876953125 347.6390380859375 341.1233215332031 1.44651 87.184082 0.5044752000000001 -0.019203801399999998 0.046765963099999995 0.0594293788 0.0349410231 -0.0192411494 -0.0195017133 0.0452155049 -0.0100364884 0.0166977451 -0.010073003399999999 0.1048758047 -0.0040857441 0.0428138604 -0.0022092484 -0.0458817293 -0.0615043357 -0.0395261602 0.0066164016 0.048714014900000005 -0.228279 0.0697857 0.448684 -0.00413023 -0.00136517 0.000793752 -419.1417236328125 347.2120666503906 337.5389404296875 1.841203 110.97303 1.4824372 -0.05502935900000001 0.0267136498 0.07489594150000001 0.011400609499999999 -0.1360912319 -0.0483217735 0.1098562606 0.12148239949999999 -0.0206135956 -0.11107966710000002 0.0167155558 -0.0092070825 0.0425480561 -0.0029451740999999997 -0.04661247599999999 -0.061381302699999994 -0.0380953808 0.0088086474 0.0502515524 -0.235353 -0.0295037 0.7423889999999999 -0.0213236 -0.00485926 -0.000166164 -420.49713134765625 353.3000793457031 347.6824645996094 1.748108 105.361984 1.12480525 -0.0176827585 0.0361692655 0.0272465083 0.0488607996 -0.11479637529999999 -0.0010444564 -0.0023606739 0.0925013391 0.0619237999 0.015038494199999999 0.0210452825 0.062111926399999996 0.042280734 -0.0036806797 -0.0473282582 -0.061223237699999995 -0.0366306304 0.0109895824 0.0517012663 -0.145046 -0.0305184 0.467571 -0.00907012 -0.00290248 0.000796887 -417.9351501464844 352.1173095703125 345.0296325683594 1.061603 63.984955 0.33119735 -0.0041427598 0.0534190014 0.0158289934 0.0496063208 -0.08463287189999999 -0.0086600734 -0.0005150928 0.0422400353 0.0694249962 -0.0070432314 0.0090077151 0.0635416773 0.0420119037 -0.00441566 -0.0480288462 -0.061030231 -0.0351332152 0.0131564061 0.053060623200000004 -0.133051 0.0166828 0.407861 -0.00555546 -0.00248713 0.0011127 -419.62432861328125 351.81707763671875 345.2821960449219 0.9782090000000002 58.958622 0.20785619999999996 0.010336882 0.034207974700000005 0.013431401200000002 0.06367034690000001 -0.0829388836 0.013018621299999998 -0.0080108489 0.018207352 0.0620223901 -0.0058426155 -0.0031011603000000005 0.0761695229 0.0417415748 -0.0051500103000000005 -0.048714014900000005 -0.0608023928 -0.0336044704 0.015306336299999999 0.054327247300000006 -0.12483 0.103701 0.360968 -0.00447347 -0.00266038 0.00105346 -419.2793884277344 351.5086669921875 344.9368896484375 0.9436270000000002 56.874313 0.10590359999999996 0.0038737775 0.0474468904 0.0113542924 0.0767864601 -0.07373601910000001 0.0147486442 -0.0048971062 0.0135201385 0.06766060730000001 -0.0131480668 -0.0047792035 0.0813065539 0.0414697568 -0.0058836257 -0.0493835445 -0.0605398531 -0.032045759300000004 0.0174366123 0.0554989249 -0.118662 0.0658139 0.365455 -0.00395702 -0.00228322 0.00130708 -422.5331726074219 352.1214904785156 345.411865234375 0.994598 59.946453 0.05805619999999999 -0.0132485511 0.0239049621 -0.027214396000000002 0.07308669450000001 -0.061404889299999994 -0.0409484815 -0.007108525300000001 0.027448917200000002 0.0661398563 -0.0079355572 -0.0100719283 0.0768889316 0.0411964596 -0.0066164016 -0.050037220099999995 -0.060242761799999996 -0.0304584719 0.0195444986 0.0565736083 -0.121603 0.0845931 0.35236 -0.00414747 -0.00250512 0.00135955 -420.5591125488281 352.3153991699219 345.3928527832031 0.989638 59.647511 0.049286099999999985 -0.0261165281 0.0352267331 -0.0518468379 0.052470860599999995 -0.0288522 -0.0425686204 -0.0082149038 0.0361605607 0.07844623440000001 0.0013565006 -0.0241743635 0.048225897999999996 0.0409216928 -0.0073482335 -0.050674831600000005 -0.059911288300000004 -0.028844023599999997 0.0216272887 0.0575494194 -0.117411 0.0910577 0.341351 -0.00457876 -0.00260855 0.00137724 -420.8538818359375 351.761962890625 345.1949157714844 0.990924 59.724972 0.09462979999999997 -0.034232918 0.0641273601 -0.0727171938 0.02582455 -0.032460812400000004 -0.0862393421 -0.006406631800000001 0.026143427 0.09465700710000001 -0.0220991269 -0.011682726599999999 0.0040293177 0.0406454662 -0.0080790168 -0.0512961746 -0.059545621900000005 -0.027203854 0.0236823082 0.058424652599999995 -0.119174 0.0670379 0.36722 -0.00387323 -0.00251508 0.00131668 -421.5807800292969 351.71038818359375 345.1061706542969 0.991945 59.786514 0.08226339999999997 -0.010969500600000001 0.0690144107 -0.0752790087 -0.0239052366 -0.06046973940000001 0.0123430576 -0.0065658648 0.037534899100000005 0.0951308567 -0.0233743665 -0.0214610171 -0.027553254300000003 0.0403677898 -0.0088086474 -0.0519010494 -0.059145971299999996 -0.0255394259 0.025706918199999998 0.0591977785 -0.121249 0.0945728 0.352592 -0.00439605 -0.00260855 0.00117246 -421.98486328125 351.43084716796875 344.9309387207031 0.977981 58.944904 0.05250900000000003 0.0035815448999999997 0.07562464599999999 -0.0279477518 -0.0340343374 -0.0500115701 -0.0133699486 -0.0075526021999999995 0.0208858548 0.0950582344 -0.024865594900000003 -0.0048351959 -0.0407517608 0.0400886733 -0.0095370211 -0.05248926190000001 -0.0587125645 -0.0238522233 0.027698518999999998 0.0598674458 -0.115948 0.07234129999999998 0.345431 -0.00417581 -0.00260855 0.00130853 -419.6445617675781 351.8945007324219 344.824951171875 0.989353 59.630318 0.062248299999999986 0.013701867099999999 0.09863174429999999 -0.0009302833000000001 -0.0329776995 -0.0491290622 0.0264491718 -0.0078268423 0.022080031 0.1006648616 -0.039635962000000004 0.014033177800000001 -0.0217804113 0.0398081268 -0.010264034 -0.053060623200000004 -0.058245649000000004 -0.0221437508 0.0296545534 0.0604324842 -0.120389 0.0642655 0.358305 -0.00376193 -0.00242135 0.00117246 -420.3621520996094 352.1670227050781 345.20892333984375 1.027115 61.906322 0.11939499999999997 0.0198336879 0.0768257307 0.0165001363 -0.034115407599999995 -0.0574503299 -0.0093596371 -0.0103679342 0.0367467085 0.0967823497 -0.0193439899 0.0065000488 -0.0050220867 0.0395261602 -0.0109895824 -0.05361495 -0.0577454912 -0.020415532 0.0315725097 0.0608919062 -0.119368 0.106769 0.364701 -0.00479984 -0.00240695 0.00150964 -421.5797424316406 351.4495849609375 344.98822021484375 0.973075 58.649216 0.09145819999999998 0.037697913199999995 0.0837219441 0.0398759446 0.000930913 -0.046664974500000005 -0.0784680812 -0.0052781029000000005 0.0197200828 0.0841707952 -0.025320864900000004 0.0229921663 0.0212022806 0.0392427837 -0.011713562700000001 -0.0541520642 -0.0572123765 -0.0186691079 0.033449925 0.0612449087 -0.122979 0.0624388 0.364371 -0.00421027 -0.00260855 0.00143707 -420.4116516113281 351.5838928222656 344.9733581542969 0.996178 60.041687 0.06491369999999996 0.043820576900000005 0.0728100706 0.027101428700000003 0.0445694885 -0.0728180773 -0.0374639761 -0.0081432496 0.019124061100000003 0.0852125102 -0.0368273096 0.0331443855 0.0597517625 0.0389580073 -0.012435871599999999 -0.0546717934 -0.056646609199999996 -0.0169060359 0.0352843888 0.061490875 -0.124342 0.08260499999999998 0.353241 -0.00367422 -0.00260855 0.00132803 -421.0395202636719 351.544921875 345.14874267578125 0.987114 59.495369 0.08192300000000002 0.014556900400000001 0.0551584402 3.1248e-05 0.0701555796 -0.0986551407 0.008468997800000001 -0.0036840351 0.027374709 0.07622668860000001 -0.0231944932 0.0049024996000000005 0.0759539063 0.038671841299999996 -0.0131564061 -0.0551739708 -0.056048512300000006 -0.0151278882 0.037073545299999996 0.061629375099999995 -0.126963 0.114593 0.35085 -0.00438206 -0.00260855 0.00151865 -418.25042724609375 351.6273193359375 344.78558349609375 0.980327 59.086285 0.08555980000000002 -0.010328235699999999 0.06565432730000001 -0.0101556374 0.0775104545 -0.07196956 0.0383008322 -0.0073131901 0.0256683023 0.08416575039999999 -0.0230530479 0.0231259491 0.0800698914 0.0383842957 -0.0138750634 -0.055658435199999995 -0.055418427 -0.0133362505 0.038815097400000005 0.061660167 -0.124044 0.0754857 0.356901 -0.00388878 -0.00252128 0.00134955 -419.4575805664063 351.6487731933594 345.09423828125 0.986188 59.439548 0.048152000000000014 -0.0260739149 0.05726497 -0.046342767800000004 0.0840485894 -0.0511862601 -0.012933463899999999 -0.0042413227 0.0223493802 0.0900996702 -0.0278557823 0.005765305 0.0697280064 0.0380953808 -0.0145917409 -0.0561250309 -0.0547567129 -0.0115327203 0.0405068086 0.061583196900000005 -0.114806 0.0873067 0.355092 -0.00351538 -0.00242015 0.0013184 -421.58831787109375 351.7852478027344 345.87432861328125 1.009516 60.845562 0.1262378 -0.0185013774 0.06655887190000001 -0.0779951131 0.0383424573 -0.0527735854 -0.0969095514 -0.0030888267 0.0368584241 0.1101801889 -0.0258630358 -0.0078068795 0.037544356800000005 0.0378051071 -0.015306336299999999 -0.0565736083 -0.054063747800000006 -0.009718906 0.0421465068 0.0613985992 -0.12057 0.121652 0.340379 -0.00450709 -0.00260855 0.0015666 -421.7759399414063 351.9810485839844 345.7310485839844 1.001103 60.338512 0.12806309999999999 -0.0232374117 0.092479576 -0.0837831392 0.00292924 -0.0626836058 -0.022470951099999997 -0.0123324719 0.026087216 0.11246701519999999 -0.0207844968 -0.0130843348 -0.0071272601 0.0375134847 -0.0160187477 -0.0570040233 -0.0533399272 -0.007896425 0.0437320865 0.0611066967 -0.122423 0.0597034 0.334443 -0.00378691 -0.00239843 0.00133039 -421.8748474121094 351.870361328125 345.957275390625 0.995423 59.996162 0.12857530000000003 0.0019898686 0.0948397663 -0.06803665589999999 -0.0304614736 -0.060040231500000006 0.0228883066 -0.0135771648 0.0152939257 0.1041015215 -0.044272621100000006 -0.0082723064 -0.0423675723 0.0372205242 -0.0167288735 -0.057416137699999995 -0.052585664000000004 -0.0060669025 0.0452615117 0.060707999400000004 -0.110223 0.0908212 0.308865 -0.00289224 -0.00225744 0.00117246 -420.8256530761719 352.49835205078125 346.4927673339844 1.105437 66.626953 0.2628535 0.0171351093 0.08457232449999999 -0.015610962800000001 -0.044062884000000004 -0.0849410561 0.026704057200000002 -0.0169552458 0.0338395762 0.07334408049999999 -0.041988968099999996 0.0085082976 -0.0418398454 0.0369262359 -0.0174366123 -0.057809819299999995 -0.0518013888 -0.0042319699 0.046732818499999995 0.0602032042 -0.143256 0.151593 0.26226 -0.0027699 -0.00260855 -0.0008029639999999998 -420.0455322265625 351.53558349609375 345.9622802734375 1.233448 74.34238399999998 0.40248775 0.0349089357 0.0407256221 0.0175790917 -0.0628559366 -0.0349492572 0.0214626033 -0.0027215177000000004 0.0086519935 0.043244582999999996 0.018371331299999998 0.042298605 -0.0561036209 0.0366306304 -0.0181418631 -0.058184941500000004 -0.0509875493 -0.0023932635000000002 0.048144117699999996 0.059593193200000005 -0.112935 0.008415149999999998 0.147193 -0.00340674 -0.00261427 0.000832914 -371.8408203125 319.4721374511719 317.13128662109375 2.695495 162.462921 4.5592784 -0.22982537649999998 0.0660880391 0.20263495969999998 -0.0304630009 0.1203307259 0.034400257000000004 0.4023250324 -0.29489698870000003 0.0102890986 -0.0337780382 -0.3993795026 0.057695294400000006 0.0363337182 -0.0188445253 -0.0585413841 -0.0501446098 -0.0005524229 0.049493597199999996 0.0588790326 -0.242945 -1.05812 -2.26129 -0.0175487 0.00130519 -0.000190671 -388.5560302734375 325.427978515625 323.8311767578125 2.978447 179.51705899999996 1.84074905 -0.2072273094 0.18541149640000001 0.1204360401 0.015630603899999998 0.20550099600000002 0.0627507547 0.3619995774 -0.23847223760000003 0.1085712506 0.1602848676 -0.08238694440000001 -0.10405390630000001 0.036035509900000005 -0.0195444986 -0.0588790326 -0.049273051500000005 0.0012889102 0.050779524000000006 0.0580619705 -0.189946 -0.561132 -1.45172 -0.0224386 -0.0021674 0.00107068 -446.2183837890625 358.96343994140625 356.27215576171875 3.0819 185.752365 2.19632375 -0.0170385669 -0.0969058071 0.0272631398 -0.0788873693 -0.0782021948 0.007906609 -0.060092058200000006 0.1392848764 -0.17949356579999998 0.0045532283 0.0456448692 -0.1357348719 0.0357360162 -0.0202416832 -0.0591977785 -0.048373371799999995 0.0031290940000000002 0.0520002471 0.057143434800000004 -0.077342 -0.17363 -0.432441 -0.0101056 -0.0019108 0.000121505 -426.2521362304688 352.3639221191406 349.082763671875 1.201052 72.38981599999998 0.2936817500000001 -0.034226029 -0.0970712113 0.0415512388 -0.0728341244 -0.0008469578999999999 0.0291118375 0.0048558405 0.0593840928 -0.07714488900000001 0.0621739332 -0.0484108211 -0.0580779885 0.0354352477 -0.020935979599999998 -0.0594975196 -0.0474460842 0.0049664875 0.053154198799999997 0.0561250309 -0.0823867 -0.148694 -0.279671 -0.00972644 -0.00296558 0.000906186 -422.6844482421875 352.3898620605469 347.7001953125 1.022394 61.62175 0.22604705 -0.0201318079 -0.089603122 0.0577608293 -0.0734382729 0.016965808 -0.0036360960999999997 0.0042130504 0.0423293985 -0.065783112 0.0808476196 -0.0272599543 -0.048523075199999995 0.0351332152 -0.0216272887 -0.0597781596 -0.046491717800000006 0.006799452199999999 0.054239897599999996 0.055008538600000004 -0.0835529 -0.179997 -0.222187 -0.00746464 -0.0028402 0.000571489 -424.8573303222656 351.83721923828125 347.0563049316406 1.033289 62.278442 0.12920795 -0.011289496100000001 -0.09116565119999999 0.0607617591 -0.0640008322 0.0122083214 -0.0791823033 0.0030361637 0.0333806716 -0.06789766929999999 0.0764826813 -0.0497500216 -0.0106133487 0.0348299293 -0.022315511899999998 -0.0600396084 -0.0455108174 0.0086263535 0.0552559492 0.0537959092 -0.0918004 -0.121509 -0.255577 -0.007469639999999999 -0.00340796 0.000580378 -424.8421936035156 352.13555908203125 347.1554870605469 1.007909 60.748692 0.12244779999999998 0.0025444573 -0.1019771853 0.049156763799999996 -0.0209229573 0.0061476887 -0.0285107711 -0.006291230500000001 0.0311930517 -0.0686275497 0.0752187262 -0.0397872454 0.012709487 0.0345254011 -0.023000551 -0.0602817821 -0.0445039428 0.0104455625 0.056201049100000004 0.05248926190000001 -0.0952568 -0.144071 -0.212203 -0.00694939 -0.00294291 0.000656186 -422.4728088378906 351.80108642578125 346.5733642578125 0.992611 59.826687 0.1030241 -0.0098025868 -0.0924194057 0.0319791472 -0.0055226976 -0.0019092552 0.0347978328 0.0011449789 0.024866761600000002 -0.0658331163 0.0695249133 -0.0294918819 0.0184346317 0.0342196412 -0.0236823082 -0.060504603 -0.0434716687 0.012255456699999999 0.0570739836 0.0510908803 -0.0953404 -0.12004600000000003 -0.218076 -0.00551143 -0.0029658 0.000656186 -422.5759582519531 351.4847106933594 346.56536865234375 0.984502 59.33794 0.14416359999999992 -0.010765733700000002 -0.1035114103 0.0173941424 0.0088542747 0.007404955699999999 0.0180018879 0.0037366757 0.025295633999999997 -0.0608298275 0.0700055811 -0.0563518125 0.0275643179 0.0339126607 -0.024360686200000002 -0.060707999400000004 -0.0424145842 0.0140544224 0.0578736318 0.0496032084 -0.0931421 -0.08417589999999998 -0.217778 -0.00678802 -0.00347359 0.00098775 -420.9371337890625 351.7113342285156 346.44708251953125 0.9767420000000002 58.870228 0.1839856 -0.01588401 -0.0912572111 0.015906652900000002 0.0032158040999999997 0.0130156692 0.056767869699999994 -0.0020004005 0.0219296762 -0.0617466614 0.0686505949 -0.0338214716 0.0237334751 0.0336044704 -0.0250355883 -0.0608919062 -0.0413332925 0.0158408552 0.058598967 0.0480288462 -0.104994 -0.144422 -0.207731 -0.00547704 -0.002963 0.000772508 -423.8532104492188 351.5809631347656 346.5943298339844 0.992221 59.80315 0.1289245 -0.0275264642 -0.107889165 -0.006779010699999999 0.0086406829 0.0099218627 0.010104832900000001 0.0012167211 0.0250443026 -0.054092663799999996 0.0544819145 -0.052155023099999996 0.0206710153 0.0332950814 -0.025706918199999998 -0.0610562642 -0.0402284109 0.0176131622 0.059249057800000005 0.046370545 -0.10504 -0.0841849 -0.179717 -0.00580597 -0.00331294 0.000906186 -422.5363464355469 351.7102355957031 346.67083740234375 0.983412 59.272236 0.08249860000000002 -0.034388189900000005 -0.0966847596 -0.018507543600000002 0.006575534300000001 0.0388053187 -0.0013669889999999999 -0.0043658928 0.0156729808 -0.04463154230000001 0.0550661487 -0.0430433917 0.015391821299999999 0.0329845047 -0.02637458 -0.061201020700000004 -0.0391005699 0.0193697628 0.0598230695 0.044631203099999996 -0.112126 -0.10412900000000001 -0.199566 -0.00513781 -0.00335717 0.000906186 -424.6297607421875 351.6400451660156 346.61871337890625 1.021613 61.574673 0.07801899999999995 -0.0312695573 -0.0867668339 -0.0518614853 -0.018042229099999998 0.056600449500000004 -0.0980467454 -0.0034487216 0.025869639 -0.0379895092 0.0581101521 -0.0379647537 -0.0199175245 0.0326727513 -0.0270384785 -0.061326129199999996 -0.0379504132 0.0211090908 0.060320264900000004 0.0428138604 -0.105061 -0.113356 -0.1821 -0.00455676 -0.003053 0.000906186 -424.0057067871094 351.641357421875 346.29254150390625 1.014974 61.174534 0.14543669999999992 -0.023366110899999997 -0.0751545073 -0.0481119238 -0.0579066158 0.0233885701 -0.016651642 -0.0038979473 0.021873633599999998 -0.021519916 0.0631843046 -0.0430295685 -0.0475350788 0.0323598325 -0.027698518999999998 -0.0614315496 -0.0367785971 0.0228295951 0.0607400057 0.0409216928 -0.105098 -0.059611 -0.185821 -0.00555472 -0.00339019 0.00132971 -423.8024597167969 351.4261474609375 345.0937194824219 1.173586 70.734413 0.55995755 -0.0134620972 -0.0434374304 -0.0207158982 -0.0646235605 0.044712007000000005 0.015809633400000002 -0.0005134006 0.0117718104 -0.0410361775 0.0232161703 -0.0089896232 -0.060399298399999996 0.032045759300000004 -0.0283546073 -0.061517248 -0.0355857906 0.024529741400000003 0.0610817528 0.0389580073 -0.160006 -0.08683169999999998 -0.310637 -0.000176446 -0.00222378 0.000814137 -423.8966674804688 352.117431640625 346.4755859375 1.265707 76.28675099999998 0.2610007 0.0020204745999999997 -0.0382612394 -0.0210711655 -0.0293188605 0.0558932503 -0.0321826733 -0.0151106858 -0.0021762998000000003 -0.0719529459 -0.002261629 -0.0067719543999999994 -0.0423707641 0.031730543 -0.0290066498 -0.061583196900000005 -0.0343726744 0.0262080137 0.0613450675 0.0369262359 -0.117865 0.0215905 -0.292692 0.000784101 -0.00197592 0.00145558 -424.9112854003906 352.21783447265625 347.5047302246094 1.073799 64.720024 0.25835995 -0.0088369365 -0.056155679800000004 -0.0103845381 -0.044445636399999995 0.0352619975 -0.014107638700000001 -0.0150569544 0.005299499599999999 -0.0432470249 0.005991164 -0.0216692546 -0.0227751879 0.0314141948 -0.0296545534 -0.061629375099999995 -0.0331399408 0.0278629153 0.0615296116 0.0348299293 -0.0978827 0.0264831 -0.265458 -0.0019666 -0.003002 0.00180382 -424.5313720703125 352.70330810546875 348.140625 1.08171 65.196838 0.17423700000000003 0.0096342635 -0.0650172923 0.00072536 -0.017175623799999998 0.0035691578999999998 0.042765554299999994 -0.020828586899999998 0.006742971899999999 -0.0635016733 0.0088991969 -0.0020432216000000002 -0.0161847361 0.031096726 -0.030298225699999997 -0.0616557679 -0.0318882933 0.0294929706 0.0616351482 0.0326727513 -0.100189 -0.0887781 -0.249987 -0.00133538 -0.00291596 0.00169711 -422.3537902832031 352.4111328125 347.2664794921875 1.00957 60.848808 0.11087464999999996 -0.0046294295 -0.0626231593 0.0023633305 0.0192921969 0.0176411146 0.0488911513 -0.0173293094 -0.005222608 -0.0615740913 0.0130575713 -0.0042309635 0.0181647551 0.0307781479 -0.0309375749 -0.061662366600000004 -0.030618446400000002 0.031096726 0.0616615418 0.0304584719 -0.0978289 -0.0979367 -0.229826 -0.000485801 -0.00243164 0.00144711 -425.0855407714844 352.34771728515625 347.18243408203125 1.058717 63.810993 0.39789085 -0.017565411 -0.060799221900000006 -0.0415021535 0.0167501043 0.0240358788 -0.0598611658 -0.0183302354 0.0027364575 -0.0313436832 0.024527518199999997 -0.0194046471 0.0120168996 0.0304584719 -0.0315725097 -0.061649169299999994 -0.0293311248 0.0326727513 0.0616087584 0.0281909609 -0.0893022 0.0409965 -0.173185 -0.00221824 -0.00398043 0.00204168 -421.9892578125 352.3133544921875 346.42840576171875 1.014923 61.17149 0.10958549999999996 -0.019776966200000003 -0.0396059068 -0.044169424900000004 0.0065530132999999996 0.049677442800000006 -0.0071229608 -0.0169455724 -0.0022990865 -0.031145808100000002 0.018515976899999998 -0.0022832476 -0.0202326522 0.0301377094 -0.0322029395 -0.061616180199999995 -0.0280270631 0.0342196412 0.0614768659 0.025874181200000002 -0.0979872 -0.0145015 -0.193463 -0.00179631 -0.00405489 0.00204778 -423.8751831054688 351.60650634765625 346.2781677246094 1.021762 61.583668 0.11621590000000002 -0.0101199052 -0.0372622187 -0.0668542423 -0.0349916222 0.050195645899999995 -0.046445779400000005 -0.0172424859 -0.0093788649 -0.0221878236 -0.002450315 -0.0192703353 -0.0461667125 0.0298158718 -0.032828774399999996 -0.061563409699999995 -0.0267070056 0.0357360162 0.061266033600000006 0.023512181899999998 -0.0979068 -0.0139641 -0.202865 -0.000771808 -0.00303685 0.00212916 -422.0880737304688 351.6440734863281 346.3509216308594 1.00375 60.498028 0.2349168 -0.0077274316 -0.0287179407 -0.04968493190000001 -0.0555592369 0.0315583796 0.0250690143 -0.0164157642 -0.007248081700000001 -0.0182552356 0.0029483324 -0.027057425 -0.051043318600000005 0.0294929706 -0.033449925 -0.061490875 -0.0253717058 0.0372205242 0.060976532199999996 0.0211090908 -0.0937063 0.0513641 -0.16982 -0.00215963 -0.00410835 0.00194162 -422.6476135253906 351.5140380859375 345.9818115234375 0.996538 60.063381 0.18880095 0.0054559386 -0.0131062597 -0.0223561998 -0.060367823 0.05616988480000001 0.0371567604 -0.0155241847 -0.0216681904 -0.0236113308 0.0009333467 -0.0025882881 -0.0678949463 0.029169017400000004 -0.034066302799999996 -0.0613985992 -0.0240219257 0.038671841299999996 0.0606087335 0.0186691079 -0.0935034 -0.00591445 -0.206831 -0.00103637 -0.00363977 0.00223595 -420.2033996582031 351.52252197265625 345.60125732421875 0.997148 60.100101 0.09428277999999997 0.011983648000000001 -0.0011753077 -0.0155850351 -0.056316245 0.0419143613 0.0711083567 -0.014318583000000001 -0.0246130181 -0.023210971299999997 -0.0092365638 -0.0062122674 -0.053827034100000004 0.028844023599999997 -0.0346778198 -0.0612866121 -0.022658435600000002 0.0400886733 0.060163109699999995 0.0161964974 -0.0979138 0.00816503 -0.209357 -0.000285002 -0.0030495 0.00211225 -420.6841735839844 351.7802429199219 346.08441162109375 1.002271 60.408901 0.26820586999999996 0.0209380038 -0.006810462 0.011523040600000001 -0.0536550391 0.0349658143 0.07163965679999999 -0.017780752900000002 -0.0178421674 -0.011088294399999999 0.007430624100000001 0.0138845689 -0.0570843086 0.0285180009 -0.0352843888 -0.061154949400000005 -0.0212820138 0.0414697568 0.059640233 0.013695580700000001 -0.08688089999999998 0.08296109999999998 -0.159058 -0.00171596 -0.00404077 0.00189292 -421.4260559082031 351.34722900390625 345.8697509765625 0.997961 60.149109 0.18633054 0.027952597000000003 -0.013184781699999999 0.0307975507 -0.0532364623 0.051519719900000004 0.0232240819 -0.0098676711 -0.0280273485 -0.030692753399999998 0.0043202779 0.0230849214 -0.0518366738 0.0281909609 -0.0358859231 -0.061003653600000006 -0.0198934458 0.0428138604 0.0590407749 0.011170728500000001 -0.0979368 0.00874246 -0.194395 -0.0010183 -0.00348613 0.001955 -422.3150634765625 351.6091003417969 345.9823303222656 1.011959 60.992813 0.08459588999999999 0.0439283797 -0.0148099047 0.0489802127 -0.0424390049 0.059420296399999996 -0.0565382715 -0.0121507608 -0.022295684700000002 -0.037552105 0.0042611439 0.034019372400000004 -0.0244058482 0.0278629153 -0.036482337000000004 -0.0608327732 -0.018493524 0.0441197852 0.0583655051 0.0086263535 -0.0979379 0.0601683 -0.175272 -0.0008633109999999999 -0.00359749 0.00196957 -422.8018798828125 351.4815673828125 346.05987548828125 1.025106 61.785191 0.07743475000000001 0.044449181500000004 -0.024852973900000002 0.0441605584 -0.012044073999999998 0.0477918442 -0.0548200347 -0.0172399741 -0.023714606000000003 -0.051128777300000004 -0.0100344076 0.0209731267 0.0044276048 0.0275338758 -0.037073545299999996 -0.060642363 -0.0170830476 0.0453863669 0.057615290599999994 0.0060669025 -0.0979781 0.0688394 -0.169723 -0.0015208 -0.00416387 0.00200919 -421.4130859375 351.9045104980469 345.7351989746094 0.990878 59.722214 0.1366389 0.0428110164 -0.0208371795 0.0486993857 0.017308966999999998 0.0405193698 -0.0247940268 -0.0194296388 -0.0226295869 -0.04770863 -0.0146526985 0.0285268514 0.0185153052 0.027203854 -0.0376594638 -0.0604324842 -0.0156628214 0.04661247599999999 0.056791094900000005 0.0034968484000000005 -0.097946 0.016423199999999995 -0.179682 -0.0008448779999999998 -0.00343447 0.0020885 -421.0196228027344 351.72174072265625 346.04754638671875 0.997698 60.133293 0.11708410000000002 0.046634374000000006 -0.018130558600000003 0.0372039938 0.0396095414 0.010542983799999999 0.0272720729 -0.0165808055 -0.027307909900000003 -0.0414866421 -0.016381121000000002 0.0324867895 0.0438015833 0.0268728619 -0.038240008799999996 -0.0602032042 -0.014233656 0.047797019100000004 0.055893976100000006 0.000920683 -0.0979415 0.0670117 -0.141974 -0.00122366 -0.00357062 0.00202777 -421.4193115234375 351.4181823730469 345.9225158691406 1.007482 60.72298 0.10243845 0.0232310957 -0.0360561301 0.0196652834 0.051050268200000005 0.022884451099999998 0.0420647933 -0.012879491699999999 -0.0275002011 -0.041010233199999996 -0.0151841028 0.0168696551 0.0325580484 0.0265409112 -0.038815097400000005 -0.059954596500000006 -0.012796367099999999 0.0489389399 0.0549250863 -0.0016570915 -0.0939676 0.0796652 -0.191883 -0.000572849 -0.00359342 0.00198334 -419.16650390625 351.9150390625 345.5081481933594 0.986818 59.477516 0.13402215 0.0167236996 -0.0165595864 0.004435298 0.048532786200000004 0.0059336078 0.0612036542 -0.014108946499999999 -0.0234068803 -0.0406376717 -0.012138823799999999 0.031367512599999994 0.033083182 0.0262080137 -0.039384647599999996 -0.059686740999999995 -0.011351775 0.050037220099999995 0.053885669500000004 -0.0042319699 -0.0983398 0.0210847 -0.175271 -0.000939398 -0.00314015 0.00225267 -420.06427001953125 351.91522216796875 345.9388732910156 0.974281 58.721912 0.1831128 0.0213552913 -0.0161051913 -0.012788989399999999 0.053905654299999994 0.0045942387 0.0416618223 -0.0175791825 -0.0202333947 -0.0172551651 -0.0044477053 0.019185091100000003 0.037581111800000004 0.025874181200000002 -0.0399485782 -0.0593997236 -0.0099007042 0.0510908803 0.0527770605 -0.006799452199999999 -0.0993679 0.0755338 -0.11843 -0.00156367 -0.00383019 0.00215109 -418.86944580078125 351.7622985839844 346.0969543457031 0.9888650000000002 59.600891 0.1386867 0.006226570799999999 -0.0144626319 -0.004429177 0.057197238399999996 0.0158663996 0.049112549000000005 -0.0135825373 -0.0279540406 -0.0234131004 -0.0156103574 0.027723295499999998 0.040027528799999997 0.0255394259 -0.0405068086 -0.0590936366 -0.0084439827 0.052098980999999996 0.0516006827 -0.0093550512 -0.102261 0.0653096 -0.181053 -0.000725032 -0.00355907 0.00200192 -419.2788391113281 352.1996154785156 346.2226257324219 0.970639 58.502384 0.08818175000000002 0.0040933279 -0.005643300699999999 -0.0119869722 0.052544139000000004 0.0106335412 0.058115428399999995 -0.0187126665 -0.0316683569 -0.0273974818 -0.0240820695 0.023157892200000002 0.036345007400000004 0.0252037594 -0.041059259300000005 -0.058768578200000005 -0.0069824421 0.053060623200000004 0.0503580468 -0.0118943007 -0.101391 0.0225561 -0.172906 -0.000601997 -0.00311965 0.00216769 -422.3112182617188 352.235107421875 346.813720703125 1.003327 60.472576 0.22410545 -0.0039162877 -0.0158253332 -0.039360043 0.0606922411 0.0052133778 -0.0017137435999999998 -0.021749364 -0.0225440815 -0.0118048892 -0.017586881699999998 0.0044711055 0.0407604931 0.0248671939 -0.041605851299999996 -0.058424652599999995 -0.0055169164 0.05397494940000001 0.0490507482 -0.0144127627 -0.0899385 0.0986779 -0.128795 -0.0013519 -0.00416563 0.00211517 -420.5513916015625 352.23455810546875 346.8238220214844 0.983902 59.301788 0.17272380000000004 -0.0078055305 -0.0104412852 -0.029775232999999998 0.0433006666 0.030872658799999998 0.0426146366 -0.0193255684 -0.0302616359 -0.02386947 -0.0100758059 0.0208563193 0.0210815874 0.024529741400000003 -0.0421465068 -0.0580619705 -0.0040482420000000005 0.0548411441 0.0476804656 -0.0169060359 -0.0906523 0.0430298 -0.17394 -0.000667012 -0.00370378 0.00239277 -422.8477478027344 351.93603515625 346.871826171875 0.993878 59.903023 0.09734886499999998 -0.019065979 -0.009418314399999999 -0.0369988694 0.050810347900000004 0.0450666434 -0.021428536499999998 -0.0165772304 -0.027827252900000002 -0.018063672700000002 -0.0029267685 0.0199271688 0.031070478199999998 0.0241914138 -0.042681148499999995 -0.057680648099999995 -0.0025772572 0.055658435199999995 0.0462489587 -0.0193697628 -0.097145 0.0534703 -0.179467 6.92013e-05 -0.00308518 0.00224981 -423.6578369140625 351.89031982421875 347.078125 1.028198 61.971561 0.213494365 -0.0079924236 -0.010467770999999999 -0.043437965599999996 0.0351692472 0.0426682801 -0.06768680690000001 -0.0173991763 -0.0275578017 -0.0059331529000000004 -0.0134814331 0.0060418965 0.011379178500000002 0.0238522233 -0.04320970019999999 -0.0572808079 -0.0011048015 0.056426093600000005 0.0447580654 -0.0217996377 -0.0901059 0.10022 -0.133417 -0.00120738 -0.00399535 0.00216345 -421.5909423828125 352.0312805175781 346.44940185546875 1.010465 60.90279 0.233848502 -0.018988345 0.0075105909 -0.056996379699999995 0.0104285614 0.0707207768 -0.035727597400000005 -0.0181501643 -0.0315426596 0.0027320756 -0.0082031421 0.0238144098 -0.0117490142 0.023512181899999998 -0.0437320865 -0.0568625783 0.0003682847 0.057143434800000004 0.04320970019999999 -0.0241914138 -0.0981038 0.0241496 -0.168326 9.26404e-06 -0.00318944 0.00243832 -422.1461791992188 351.7137451171875 346.37445068359375 1.016089 61.241753 0.193018952 -0.0113091626 0.0212366934 -0.0620492184 -0.0213935994 0.0410174458 0.0127283346 -0.018338563000000002 -0.0314527411 -0.0005377416 -0.012851893400000002 0.0113963927 -0.041663478999999996 0.023171301800000002 -0.0442482328 -0.056426093600000005 0.0018411607000000001 0.057809819299999995 0.041605851299999996 -0.0265409112 -0.0936131 0.0883674 -0.121257 -0.000749305 -0.00368793 0.00215055 -421.1915283203125 352.3005065917969 346.2352600097656 0.991681 59.770592 0.0689275 0.0021453077999999998 0.025261975099999997 -0.0457860187 -0.0355744166 0.0559366899 0.0081743036 -0.024218786000000003 -0.0365534107 -0.0037880759999999996 -0.0219948602 0.008709355 -0.0495849237 0.0228295951 -0.0447580654 -0.0559714938 0.003312986 0.058424652599999995 0.0399485782 -0.028844023599999997 -0.0934163 0.0797497 -0.159274 -0.0009183450000000002 -0.00378511 0.00232625 -421.8989868164063 351.7101135253906 346.1007385253906 0.99133 59.749489 0.10970357499999998 -0.00037756370000000005 0.0280387235 -0.0484059064 -0.0456048841 0.037888938399999995 0.0570989518 -0.0188422279 -0.0359994341 -0.0033002228999999997 -0.038290958300000004 0.0227541677 -0.0695258677 0.022487074 -0.0452615117 -0.0554989249 0.0047829204 0.0589873867 0.038240008799999996 -0.031096726 -0.0933916 0.0395275 -0.159303 -8.590149999999998e-05 -0.00333879 0.00243604 -421.0643310546875 352.281982421875 346.2794494628906 0.99785 60.142418 0.181458875 0.019755148700000003 0.039561813599999995 -0.0222871537 -0.0398664622 0.0423408678 0.072756141 -0.0257199859 -0.0429269284 0.0116810141 -0.035326259900000004 0.0335479931 -0.054743069000000005 0.0221437508 -0.0457584997 -0.055008538600000004 0.0062501251 0.0594975196 0.036482337000000004 -0.0332950814 -0.0894043 0.108057 -0.13228100000000004 -0.0008826129999999998 -0.00399425 0.00224981 -421.2106323242188 351.82904052734375 345.9365539550781 0.993903 59.90453 0.19137607 0.0224605944 0.035569854500000005 7.868e-06 -0.0469302428 0.053187272599999995 0.0553340731 -0.021601498599999998 -0.0448099514 -0.012984470900000001 -0.0349708722 0.035010204100000004 -0.057474907699999994 0.0217996377 -0.0462489587 -0.0545004924 0.0077137627000000005 0.059954596500000006 0.0346778198 -0.0354352477 -0.0934032 0.050352 -0.174009 8.596039999999998e-05 -0.00345394 0.00249981 -422.6008605957031 351.6798095703125 346.0926208496094 1.020569 61.511738 0.11545716999999997 0.0443057905 0.0421902104 0.0273883029 -0.0391200583 0.048825785499999996 0.015916538 -0.0208291249 -0.0475315154 -0.011822358100000001 -0.032614427 0.052265043 -0.039580505099999996 0.0214547469 -0.046732818499999995 -0.05397494940000001 0.0091729979 0.0603582097 0.032828774399999996 -0.0375134847 -0.0934184 0.0912663 -0.1377 -8.951299999999998e-05 -0.00379284 0.00224981 -422.640380859375 351.410888671875 345.8951110839844 1.046788 63.09206 0.09617099999999998 0.0413968392 0.0324033059 0.0345564698 -0.0330001924 0.0624924455 -0.0659391079 -0.0182127504 -0.052187339400000005 -0.005900954599999999 -0.0357695209 0.045933985 -0.0244660064 0.0211090908 -0.04721001019999999 -0.053432078200000004 0.010626997800000001 0.060707999400000004 0.0309375749 -0.0395261602 -0.0934309 0.0993467 -0.118793 -0.000753525 -0.00439106 0.002371 -420.9017028808594 351.4735107421875 345.5483703613281 1.021847 61.588802 0.16460514999999998 0.0573194032 0.026875347 0.046981658200000005 0.0087816004 0.057997775599999996 -0.0425989243 -0.0197826566 -0.0499876892 -0.0170227118 -0.0345115088 0.0578974887 0.0042791229 0.0207626817 -0.0476804656 -0.052872053200000005 0.0120749325 0.061003653600000006 0.0290066498 -0.0414697568 -0.110118 0.0447392 -0.146089 -0.000235854 -0.00370963 0.00224981 -420.91143798828125 351.27850341796875 345.8308410644531 1.0019650000000002 60.39045 0.15107305 0.0547965641 0.0300509383 0.044849274800000005 0.048834196600000004 0.040883339500000004 -0.004001709 -0.0146951942 -0.0550336663 -0.0313041217 -0.0483818906 0.0425699894 0.035760641600000004 0.020415532 -0.048144117699999996 -0.052295054199999996 0.013515975800000002 0.0612449087 0.0270384785 -0.043340877699999995 -0.100232 0.0888884 -0.110721 -0.000959531 -0.00409264 0.00237652 -421.18096923828125 351.7684020996094 345.97088623046875 0.9805910000000002 59.102196 0.06165 0.0459281581 0.0175686366 0.0349558566 0.0642166546 0.029880529399999998 0.0194120419 -0.0178887381 -0.0484858393 -0.034810578599999996 -0.0382573361 0.0522929209 0.0398187996 0.020067654 -0.0486009003 -0.0517012663 0.0149493052 0.0614315496 0.0250355883 -0.045136252800000005 -0.0934274 0.0785719 -0.136119 -0.0007746129999999998 -0.00411645 0.00255041 -420.58203125 351.601318359375 345.96722412109375 0.98439 59.331211 0.1353011 0.0409700965 0.0179135298 0.0213988443 0.0763914057 0.0107000395 0.052761634 -0.0176066402 -0.0563738575 -0.0413642112 -0.0428915557 0.0386115671 0.042052087 0.0197190601 -0.0490507482 -0.0510908803 0.0163741027 0.061563409699999995 0.023000551 -0.0468527442 -0.090569 0.047357 -0.152871 0.000112723 -0.00359613 0.00283227 -417.2941284179688 345.3746337890625 338.2203674316406 1.784158 107.534798 1.20907865 -0.0244726194 0.0093742151 0.035897461 0.07777163200000001 -0.0303684668 0.0071617827 0.1040713297 -0.0240124576 -0.044294756500000004 -0.0333279632 0.16387961339999998 -0.020172699 0.0193697628 -0.049493597199999996 -0.050464092099999996 0.017789555 0.0616403716 0.020935979599999998 -0.0484873523 -0.103549 -0.162898 0.120828 -0.0123284 -0.00331471 0.00131192 -424.7168273925781 351.8787841796875 346.9467468261719 1.899814 114.505653 0.46324965 -0.047295163 4.48162e-05 0.0220492181 0.0365253393 -0.1283501825 0.029243329 0.0414085373 0.1143861293 0.0176700199 -0.012257761200000002 -0.0162649261 0.0550814901 0.0190197746 -0.0499293841 -0.0498211028 0.019194854299999998 0.061662366600000004 0.0188445253 -0.050037220099999995 -0.0773709 -0.244581 0.152006 -0.0182037 -0.0035371 0.000925399 -421.4012756347656 351.4746398925781 345.48040771484375 1.028646 61.998592 0.29885175 -0.051966765899999996 -0.0071256712 -0.0012379977 0.039429626 -0.1028233958 0.0049518201000000005 0.0402705124 0.0905400982 0.0419800318 0.0036049604999999997 -0.0167499971 0.0645163332 0.0186691079 -0.0503580468 -0.0491621191 0.020589198700000002 0.061629375099999995 0.0167288735 -0.05149963900000001 -0.0818451 -0.167259 0.168046 -0.0147047 -0.00317771 0.00108732 -423.1089477539063 351.7129821777344 345.75860595703125 0.968234 58.357426 0.18166439999999998 -0.0471293475 -0.0112730129 -0.0099505788 0.0433757125 -0.0763654375 -0.016315737099999998 0.0298493525 0.0709356074 0.0451183215 0.0178954715 -0.0363432324 0.0646190379 0.0183177752 -0.050779524000000006 -0.0484873523 0.021971792200000003 0.0615414265 0.0145917409 -0.052872053200000005 -0.08502999999999998 -0.121696 0.140409 -0.0130288 -0.00334613 0.00134859 -423.0423889160156 351.5523376464844 345.71624755859375 0.956474 57.648624 0.13263110000000009 -0.0615120205 -0.004930438499999999 -0.0217314196 0.0241467473 -0.0627655343 -0.021971764700000004 0.026169980699999998 0.0660052543 0.048049134800000004 0.023897136800000003 -0.0267778734 0.045540051500000005 0.0179657891 -0.0511937557 -0.047797019100000004 0.023341845899999998 0.0613985992 0.012435871599999999 -0.0541520642 -0.0881566 -0.153154 0.134861 -0.0114513 -0.00316229 0.00143722 -426.3393859863281 351.7640380859375 346.1451416015625 1.020152 61.48661 0.13517539999999997 -0.0403398221 0.0022675158999999998 -0.0636538128 -0.0075901047 -0.0465500789 -0.10176338509999999 0.018648545 0.059232743600000005 0.0651620576 0.019608566100000002 -0.0363461798 0.0066964791000000004 0.0176131622 -0.0516006827 -0.0470913411 0.0246985778 0.061201020700000004 0.010264034 -0.0553374348 -0.08487269999999998 -0.08651799999999998 0.141238 -0.0105728 -0.00329765 0.00160093 -423.4654541015625 351.7749938964844 346.0797119140625 0.993894 59.903992 0.12247720000000002 -0.0341961546 0.0133512097 -0.0421187369 -0.0326078888 -0.0362158423 -0.0275064365 0.011337238999999999 0.0473662702 0.0654131779 0.008802183 -0.0341876644 -0.029068193500000002 0.0172599069 -0.0520002471 -0.046370545 0.026041213599999998 0.060948867000000004 0.0080790168 -0.056426093600000005 -0.0797419 -0.0724393 0.08841079999999998 -0.010183 -0.00370348 0.00181411 -423.8712463378906 352.0328369140625 346.2323913574219 0.994781 59.957493 0.1598977 -0.023220433999999998 0.0286381 -0.040912017599999996 -0.0540266615 -0.0466986219 0.0423915454 0.0070449811 0.0367662968 0.0460822625 0.0052590282 -0.025611222000000003 -0.0543224698 0.0169060359 -0.052392391600000005 -0.0456348621 0.0273689869 0.060642363 0.0058836257 -0.057416137699999995 -0.0876595 -0.115471 0.0786899 -0.008288659999999998 -0.00367054 0.00187138 -421.52813720703125 351.5581359863281 345.9969177246094 0.982469 59.215405 0.1993312 -0.0020146135 0.044557184699999995 -0.0093184571 -0.0630931085 -0.0623296234 0.058509373499999996 0.0088499414 0.033816361499999996 0.0746768547 0.0018906545 -0.034695650099999996 -0.0308188992 0.0165515619 -0.0527770605 -0.0448845285 0.0286811401 0.0602817821 0.0036806797 -0.058305837 -0.0745547 -0.0217697 0.131954 -0.008884559999999998 -0.00376485 0.00196639 -424.36614990234375 351.9421691894531 346.2874450683594 1.0263350000000002 61.859291 0.1964816 0.017362050900000002 0.0327483045 0.025601837599999996 -0.052947338600000005 -0.0112390287 -0.0057812624 -0.0023575676000000003 0.0141540424 0.0444799277 0.0049808671 -0.0019177547 -0.039960696000000004 0.0161964974 -0.053154198799999997 -0.0441197852 0.029976924199999998 0.0598674458 0.0014730073999999998 -0.0590936366 -0.07942019999999998 -0.0681896 0.0692983 -0.007538119999999999 -0.00403607 0.00199954 -423.3648681640625 351.61138916015625 345.8852844238281 0.994223 59.923851 0.09422880000000003 0.0315013476 0.0272749264 0.0462887229 -0.0354235913 -0.0014099557 -0.045145552199999994 0.0005759388 0.0070887046 0.0323585742 -0.0043356243 0.018714535600000002 -0.0120754401 0.0158408552 -0.053523752699999996 -0.043340877699999995 0.0312555998 0.0593997236 -0.0007365563000000001 -0.0597781596 -0.0918848 -0.0602115 0.0591302 -0.00677487 -0.00369122 0.00183528 -423.40228271484375 351.9134826660156 346.06304931640625 1.039104 62.628887 0.194276 0.0328661099 0.029443089500000002 0.0537095122 -0.006629089 -0.0202112416 -0.0723990082 0.0047721402 0.0179099644 0.0384570677 -0.016193028300000002 0.0119897496 0.0277432541 0.0154846479 -0.053885669500000004 -0.0425480561 0.0325164369 0.0588790326 -0.0029451740999999997 -0.0603582097 -0.08445379999999998 -0.01113 0.0964447 -0.008022899999999998 -0.00411934 0.00216811 -423.3897399902344 351.6880798339844 345.78656005859375 0.988752 59.594078 0.15253169999999996 0.045402413600000004 0.025410369500000002 0.0476353602 0.0333954418 -0.0215123975 -0.0335446102 -0.0025440534 0.0014290379 0.0195097245 -0.0018649439 0.014256956000000001 0.0411759325 0.0151278882 -0.054239897599999996 -0.0417415748 0.033758716 0.058305837 -0.0051500103000000005 -0.0608327732 -0.0902044 -0.0719686 0.0699242 -0.00703126 -0.00392905 0.0021616 -422.7668762207031 351.4952392578125 345.99603271484375 0.9755720000000002 58.799713 0.09536039999999997 0.025201566 0.0171973013 0.0280993198 0.0483696895 -0.059364945 0.025616817000000004 0.0026399909000000004 0.0040565251 0.0247700931 -0.0120644462 0.008000493000000001 0.051159029800000005 0.0147705889 -0.0545863863 -0.0409216928 0.0349817282 0.057680648099999995 -0.0073482335 -0.061201020700000004 -0.0917033 -0.0278846 0.0798142 -0.00651845 -0.00375262 0.00227011 -424.080322265625 351.4493713378906 346.17706298828125 0.992622 59.827328 0.11118245 0.014840133 0.0086544572 0.012217308400000002 0.0595060734 -0.0687002662 0.0213362999 0.0024970962 0.0108179537 0.032458341200000004 0.0016845879999999999 0.00104682 0.0484065117 0.0144127627 -0.0549250863 -0.0400886733 0.0361847754 0.0570040233 -0.0095370211 -0.06146230849999999 -0.0919712 -0.00416325 0.0957754 -0.00752283 -0.00411934 0.00221657 -417.5284729003906 348.4391174316406 341.1147155761719 1.580422 95.255257 1.445874345 -0.0790233671 0.0314003006 0.0489106264 0.0443080946 -0.0509156609 0.0189071722 0.0817259511 0.0172028724 0.00035558650000000003 -0.0166687705 0.09875713119999999 0.0370810799 0.0140544224 -0.0552559492 -0.0392427837 0.0373671711 0.05627656599999999 -0.011713562700000001 -0.061616180199999995 -0.438044 -0.247257 0.146285 -0.0128594 9.95139e-05 -0.00435197 -418.19091796875 348.2479248046875 339.64501953125 1.880119 113.318604 0.9360719049999998 -0.1109426106 0.030597105299999997 0.0355856374 0.0367447243 -0.0724148784 0.0169703295 0.10202465039999999 0.0825147918 -0.0582945687 -0.1734329634 -0.073767431 0.0588038653 0.013695580700000001 -0.055578927800000004 -0.0383842957 0.038528240299999995 0.0554989249 -0.0138750634 -0.061662366600000004 -0.390372 -0.326547 0.0556109 -0.0226449 0.00144462 -0.00759008 -424.94091796875 352.2395935058594 347.3620300292969 1.559419 93.989342 1.1128402499999999 -0.0792304399 -0.0242622273 -0.0018140702 0.0257119977 -0.0388553289 -0.0603107957 0.033887173199999995 0.0824656954 -0.0022610285 0.0307639394 0.028266095800000002 0.030548457200000004 0.0133362505 -0.055893976100000006 -0.0375134847 0.0396673204 0.0546717934 -0.0160187477 -0.0616007872 -0.25822 -0.160444 0.0142407 -0.0137564 -0.000676261 -0.00313516 -421.6093444824219 351.98199462890625 346.223388671875 1.024628 61.756397 0.37193627000000007 -0.069063072 -0.0065112223 -0.008524024 0.006548840699999999 -0.0308709598 0.0036452315000000002 0.0166342935 0.0514752556 0.0032358711 0.024863652000000003 0.0022249138 0.011267113799999999 0.0129764445 -0.056201049100000004 -0.0366306304 0.0407837614 0.0537959092 -0.0181418631 -0.0614315496 -0.221457 -0.16666 0.00168588 -0.00982569 -0.00145083 -0.00151239 -422.35382080078125 352.2723388671875 346.2593078613281 0.972845 58.635365 0.17737693000000002 -0.06318649309999999 -0.0069691785 -0.0404669607 -6.15042e-05 -0.0225879446 -0.02120398 0.0162400143 0.04619489 0.0115332741 0.020731117 -0.0210893988 0.0200870344 0.012616175600000001 -0.0565001029 -0.0357360162 0.041876926 0.052872053200000005 -0.0202416832 -0.061154949400000005 -0.189513 -0.12929 0.00700116 -0.00936539 -0.00225015 -0.000717057 -424.7076110839844 352.8108215332031 347.04071044921875 1.03486 62.373127 0.23513748999999995 -0.041279871 -0.0158013198 -0.0345595492 0.010057102 -0.0232909723 -0.04506566730000001 0.0061182703 0.044376871 0.0243955783 0.0209189102 -0.022134108599999997 0.014762108500000001 0.012255456699999999 -0.056791094900000005 -0.0348299293 0.0429461904 0.0519010494 -0.022315511899999998 -0.0607714702 -0.1253 -0.091163 0.0106486 -0.00918997 -0.00336622 0.000574454 -424.1550598144531 352.6535949707031 346.78173828125 0.986096 59.433998 0.14767120000000003 -0.0530107915 0.0014335181 -0.043869512 0.0113073676 -0.0047418153000000005 -0.0639371577 0.0028142119 0.0321738869 0.0219080758 0.0157849263 -0.0174264049 0.0057008584 0.0118943007 -0.0570739836 -0.0339126607 0.0439909442 0.0508837635 -0.024360686200000002 -0.0602817821 -0.139926 -0.115312 0.0373337 -0.008045049999999998 -0.00300062 0.000440752 -424.0668640136719 352.33819580078125 346.44195556640625 1.0070960000000002 60.699738 0.10894034999999996 -0.043764011 0.0095077361 -0.055993126500000004 -0.0389070675 -0.0330319588 -0.0364280065 0.0048033953 0.0328917434 0.036890122000000004 -0.0020304148 -0.030578072799999998 -0.0225901649 0.0115327203 -0.057348728499999994 -0.0329845047 0.0450105913 0.0498211028 -0.02637458 -0.059686740999999995 -0.139912 -0.0597373 0.0451467 -0.008779749999999998 -0.0030263 0.000591145 -424.81427001953125 352.2562255859375 346.2680969238281 1.005395 60.597179 0.1207324 -0.016634396699999998 0.0245449987 -0.0351348135 -0.0551324978 -0.023535043999999998 0.015581861499999999 -0.0029063514000000003 0.019695968 0.030668974300000002 -0.0016384833 -0.0103057548 -0.0517783618 0.011170728500000001 -0.057615290599999994 -0.032045759300000004 0.046004549699999994 0.048714014900000005 -0.0283546073 -0.0589873867 -0.139914 -0.0938236 0.0373613 -0.007752239999999999 -0.00340638 0.000760729 -422.05657958984375 352.1700134277344 345.8394775390625 1.004128 60.520805 0.06196264999999996 -0.0051074901 0.0426428254 0.0029461911 -0.06260347200000001 -0.0107359058 0.0503716549 0.00017778310000000002 0.0208265643 0.031235145 -1.67866e-05 -0.0043443327 -0.059382320999999995 0.010808338300000001 -0.0578736318 -0.031096726 0.0469722521 0.047563487 -0.030298225699999997 -0.058184941500000004 -0.139928 -0.07565439999999998 0.0566884 -0.00765562 -0.00311962 0.0008663959999999999 -422.1356201171875 352.1509704589844 346.02471923828125 1.013172 61.065945 0.09017365 0.0005078042 0.0338096632 0.0255557172 -0.055044300899999996 -0.0191295571 0.035163219 0.0001789774 0.0191552577 0.040011024 -0.0143766945 -0.0017187985999999999 -0.0336436133 0.0104455625 -0.058123715199999995 -0.0301377094 0.0479131463 0.046370545 -0.0322029395 -0.0572808079 -0.139882 -0.0422079 0.0666327 -0.00826958 -0.00333473 0.000760729 -423.0480346679688 352.432861328125 345.9150695800781 0.994727 59.954189 0.12457345 0.0168576369 0.0283689547 0.0458419426 -0.0467421792 0.0173151995 -0.0147536723 -0.0051258326000000005 0.010918133100000001 0.0122718123 0.0040361265 0.0166511349 -0.0331144979 0.010082414100000001 -0.0583655051 -0.029169017400000004 0.0488266951 0.045136252800000005 -0.034066302799999996 -0.05627656599999999 -0.139882 -0.102134 0.0541894 -0.0072255 -0.00333473 0.000760728 -423.0245361328125 351.4356994628906 345.81500244140625 0.981028 59.128548 0.09885295000000002 0.0229049619 0.0275829859 0.0580657096 -0.0309894851 0.0120718393 -0.045163619 0.0036244445000000003 0.0016662813 0.0099794702 0.0003019519 0.0175682356 0.0039418668 0.009718906 -0.058598967 -0.0281909609 0.049712377300000006 0.043861710899999996 -0.0358859231 -0.0551739708 -0.139882 -0.0557233 0.07391209999999998 -0.00787989 -0.00333473 0.000760729 -425.8929443359375 352.049560546875 346.0365295410156 1.022274 61.614555 0.07602049999999991 0.0281748873 0.0019910404 0.0511038937 0.0038703767 -0.0117534851 -0.07182500139999999 -0.0011808922 0.0071077747 -0.0132773886 0.0023438021 0.0109371375 0.0279793742 0.0093550512 -0.058824067699999996 -0.027203854 0.050569687300000006 0.0425480561 -0.0376594638 -0.05397494940000001 -0.146812 -0.0524673 0.0403272 -0.00794319 -0.00373216 0.000944991 -421.2095642089844 351.776611328125 345.5497741699219 0.989831 59.659138 0.12880155 0.0290451071 0.016655511799999998 0.054114432000000004 0.0338961096 -0.0105474724 -0.0007520843 -0.0005066492 -0.0030560644 -0.0003386763 0.006854194 0.0127307835 0.044577704100000004 0.0089908627 -0.0590407749 -0.0262080137 0.051398136 0.0411964596 -0.039384647599999996 -0.0526815972 -0.144347 -0.105569 0.0555291 -0.00702109 -0.00358736 0.00103875 -422.1073303222656 352.2035217285156 345.9828796386719 0.9997990000000002 60.259895 0.14915840000000002 0.0105781406 -8.877e-07 0.032017690099999996 0.0594295998 -0.0419285448 0.0261311088 -0.0036693878000000004 0.0076564526 0.0031731805 -0.0026860795000000002 0.019973951299999997 0.062792141 0.0086263535 -0.059249057800000005 -0.0252037594 0.052197250300000005 0.0398081268 -0.041059259300000005 -0.0512961746 -0.13993 -0.0411533 0.08632779999999998 -0.0074634 -0.00333473 0.00133435 -420.1533203125 351.8241271972656 345.6193542480469 0.985431 59.393944 0.1133233 -0.0036475565000000003 -0.0035924693 0.0195532126 0.0634018384 -0.013870218799999999 0.07490759030000001 -0.0022980046 -0.003375367 0.009495073 -0.0056338174 0.0091184499 0.0612307694 0.008261536600000001 -0.0594488867 -0.0241914138 0.0529665744 0.0383842957 -0.042681148499999995 -0.0498211028 -0.148517 -0.0782892 0.0624944 -0.00695459 -0.00364104 0.00127413 -421.9633483886719 351.81988525390625 345.7237854003906 1.00546 60.601082 0.07361039999999999 -0.0139059176 -0.0073569058 -0.0184929164 0.0696343915 0.0166994205 -0.0107983508 0.0022909904000000003 -0.0022764995 0.0153074193 0.0156275915 -0.0124444305 0.06663919509999999 0.007896425 -0.059640233 -0.023171301800000002 0.053705669000000004 0.0369262359 -0.0442482328 -0.0482589599 -0.15215 -0.0568948 0.0822684 -0.00668472 -0.00333473 0.00127413 -424.2965087890625 351.56085205078125 345.83709716796875 1.003746 60.497784 0.10487530000000003 -0.030254825699999998 -0.0056435636 -0.0431778134 0.040154926699999996 0.0322793283 -0.09062475769999999 0.0037399202000000004 0.0042248381 0.0354233479 0.010486508200000001 -0.0071166361 0.0401991452 0.0075310317 -0.0598230695 -0.0221437508 0.0544141125 0.0354352477 -0.0457584997 -0.04661247599999999 -0.144784 -0.0224411 0.0801703 -0.00790387 -0.00333473 0.00127413 -422.2561340332031 352.03302001953125 345.5464172363281 0.997692 60.132896 0.14641510000000002 -0.0284321891 0.0191379649 -0.0644608032 0.0068671501 0.0397403621 -0.0343684524 -0.0013267062 -0.000839966 0.0221413069 0.0061532712 0.0034484659000000003 -0.0181531915 0.007165369699999999 -0.05999737 -0.0211090908 0.0550915004 0.0339126607 -0.04721001019999999 -0.0448845285 -0.152293 -0.08534859999999998 0.0679727 -0.00662785 -0.00333473 0.00127413 -422.4893798828125 351.54461669921875 345.3058776855469 1.013685 61.096817 0.0530353 -0.0168435102 0.0295242741 -0.055421379800000004 -0.04849598 0.0091537535 0.0379827129 -0.0030656595000000003 -0.0090239335 0.018157121000000002 -0.0101408437 -0.0189606584 -0.0586017456 0.006799452199999999 -0.060163109699999995 -0.020067654 0.055737446100000004 0.0323598325 -0.0486009003 -0.0430781374 -0.14835 -0.067322 0.0504075 -0.006459 -0.00323357 0.00127413 -421.2701416015625 351.62396240234375 345.5201721191406 1.002561 60.426357 0.14919729999999998 0.0071914035 0.0392955731 -0.0064449432 -0.060810755999999994 -0.0009298527 0.0611106487 0.0020865948 0.0030022984999999998 0.0398691345 -0.011479557900000001 -0.014858703999999999 -0.05409250559999999 0.0064332921 -0.060320264900000004 -0.0190197746 0.056351581 0.0307781479 -0.0499293841 -0.0411964596 -0.146068 -0.0287711 0.0972094 -0.007589089999999999 -0.00333473 0.00127413 -423.9424743652344 351.7538146972656 345.59564208984375 1.035838 62.432076 0.11697359999999997 0.0227044779 0.0250585396 0.0252282669 -0.0507769229 0.0253156247 -0.0071299534 -0.0035962576 -0.0072132989 0.014479565500000001 0.0022321204 -0.006930486800000001 -0.045635389400000004 0.0060669025 -0.060468813200000006 -0.0179657891 0.0569335547 0.029169017400000004 -0.0511937557 -0.0392427837 -0.15213 -0.0638625 0.0657622 -0.00708433 -0.00371743 0.00127413 -421.79791259765625 351.64263916015625 345.25250244140625 0.98693 59.484264 0.06247239999999996 0.039199561699999996 0.0251434323 0.0485003339 -0.0241995272 0.0313294155 -0.0457119578 -0.0021932328 -0.0172731525 0.008723049 -0.0052449575 0.0154686873 -0.009607239 0.0057002965 -0.0606087335 -0.0169060359 0.0574830349 0.0275338758 -0.052392391600000005 -0.0372205242 -0.147224 -0.0663918 0.0676908 -0.00640486 -0.00333473 0.00127413 -421.93072509765625 352.1482849121094 345.708740234375 1.026816 61.888298 0.1272926 0.0470898203 0.0207069948 0.0610288358 0.0146292004 0.0031783196000000004 -0.0333325724 -0.0061132941000000005 -0.0073838742 -0.001646058 -0.0054390672 0.023915826299999998 0.0397765263 0.005333487099999999 -0.0607400057 -0.0158408552 0.057999708 0.025874181200000002 -0.053523752699999996 -0.0351332152 -0.152643 -0.0101424 0.0783385 -0.00714534 -0.00369378 0.00127413 -423.099853515625 351.7292785644531 345.8302307128906 0.990612 59.7062 0.1305567 0.0469942033 0.008852149 0.0428985004 0.0405635142 -0.0064250910999999996 0.0076453484999999995 -0.0069496159 -0.017051946499999998 -0.0171191389 -0.0058363784 0.0185908797 0.043179329800000006 0.0049664875 -0.060862611100000005 -0.0147705889 0.0584832792 0.0241914138 -0.0545863863 -0.0329845047 -0.147397 -0.0658508 0.0696422 -0.00614075 -0.00348025 0.00127413 -421.5107421875 352.27752685546875 346.03955078125 0.989419 59.634304 0.0531963 0.020022476 -0.0036083053 0.0310779838 0.0671342506 -0.023294095299999998 0.0523726357 -0.009906657 -0.015509258500000001 -0.0105998873 -0.0183705534 0.0199972097 0.0616241134 0.0045993107 -0.060976532199999996 -0.013695580700000001 0.0589334724 0.022487074 -0.055578927800000004 -0.0307781479 -0.150358 -0.0380616 0.0813828 -0.00611743 -0.0034356 0.00142027 -422.28912353515625 351.97943115234375 346.1861877441406 0.999593 60.247524 0.08907579999999998 0.0032203551000000003 -0.013936120900000001 0.0085176652 0.0704002095 -0.0102516257 0.0275278861 -0.0058939463 -0.0046106728 0.009313088800000001 0.0027355609000000005 -0.0086485306 0.0769878695 0.0042319699 -0.0610817528 -0.012616175600000001 0.0593500308 0.0207626817 -0.0565001029 -0.0285180009 -0.150482 -0.0177823 0.0608183 -0.00675984 -0.00360921 0.00127413 -420.774658203125 351.58770751953125 345.85504150390625 1.003311 60.471558 0.10080179999999998 -0.0196344023 -0.0064488235999999996 -0.0433020962 0.061712373499999994 0.0466474791 -0.0070087343000000005 -0.0012070985000000002 -0.0202283669 0.0011430699000000001 0.0144320524 -5.71065e-05 0.0274773977 0.0038644781 -0.061178257800000004 -0.0115327203 0.0597327166 0.0190197746 -0.057348728499999994 -0.0262080137 -0.153062 -0.0648663 0.054811 -0.00589529 -0.00357115 0.00127413 -422.6864929199219 351.8775634765625 346.20751953125 1.033639 62.299541 0.1168921 -0.026893925899999997 0.0107180713 -0.0731417439 0.017215149199999998 0.022736507599999997 -0.0677866313 -0.0054545991000000005 -0.0071645738 0.027143106099999998 -0.0006317544 -0.0108997546 -0.008140302 0.0034968484000000005 -0.061266033600000006 -0.0104455625 0.0600813114 0.0172599069 -0.058123715199999995 -0.0238522233 -0.146675 -0.0134394 0.0925847 -0.00627281 -0.00352258 0.00127413 -422.8456115722656 352.4344787597656 346.22808837890625 0.994814 59.959465 0.08209830000000001 -0.010621235900000001 0.021378302400000004 -0.052403482300000005 -0.024496937799999997 0.030314101200000002 0.0064703908 -0.0122472211 -0.0053087295 0.0217521445 0.0021283870000000002 -0.0151414997 -0.040866952000000005 0.0031290940000000002 -0.0613450675 -0.0093550512 0.060395616299999996 0.0154846479 -0.058824067699999996 -0.0214547469 -0.150762 -0.0247122 0.0462732 -0.00630376 -0.00390017 0.00127413 -422.9660339355469 352.00299072265625 346.23626708984375 0.9918 59.777802 0.09859279999999998 0.0033584942999999997 0.0287212617 -0.0472375124 -0.048790541900000005 0.0084625901 0.0406435552 -0.0117558295 -0.0152058781 0.0047684817 -0.0067508376 -0.0115114222 -0.06563714820000001 0.0027612279999999997 -0.0614153483 -0.008261536600000001 0.060675451799999995 0.013695580700000001 -0.0594488867 -0.0190197746 -0.150703 -0.0395441 0.0623171 -0.00564199 -0.00337131 0.00143666 -422.44915771484375 351.9327697753906 346.5376281738281 0.989137 59.617283 0.12046626999999997 0.018384969299999998 0.039892994 -0.0054338065 -0.0537514678 -0.001585472 0.06653288019999999 -0.0072107003 -0.0074497122999999995 0.025523831 -0.0028616592 -0.0084084583 -0.0664157242 0.0023932635000000002 -0.0614768659 -0.007165369699999999 0.060920658200000005 0.0118943007 -0.05999737 -0.0165515619 -0.14666499999999996 -0.008350329999999998 0.0906711 -0.00668082 -0.00345629 0.00145046 -423.9931335449219 352.3074951171875 346.7554626464844 1.011729 60.978962 0.10625807 0.024933695 0.021902189300000003 0.0333136702 -0.062121087 0.0106012578 0.0043502983 -0.010044719399999999 -0.011308383799999999 -0.0015908532 -0.0125697599 0.0036901995 -0.057059823200000005 0.0020252136 -0.0615296116 -0.0060669025 0.061131095700000006 0.010082414100000001 -0.060468813200000006 -0.0140544224 -0.152155 -0.032254 0.0564882 -0.0061437 -0.00372816 0.00140582 -423.6745910644531 352.1184387207031 346.8763427734375 0.98844 59.575275 0.07847870000000003 0.0447592452 0.0255725063 0.0537008268 -0.035567461099999996 0.0194432168 -0.0402978534 -0.0107025817 -0.0209731744 0.0010398476 -0.0125732225 0.0182753466 -0.011926136399999999 0.0016570915 -0.0615735779 -0.0049664875 0.061306644 0.008261536600000001 -0.060862611100000005 -0.0115327203 -0.146409 -0.0485833 0.0650126 -0.00566166 -0.00334158 0.00149478 -424.34906005859375 352.42840576171875 347.3380126953125 1.042073 62.807858 0.12424978000000003 0.0488040451 0.0089761566 0.052543589800000005 0.002944869 -0.0199920901 -0.0530406286 -0.0098403771 -0.0092902134 -0.0094402303 -0.0057109295 0.0119313315 0.0186552891 0.0012889102 -0.0616087584 -0.0038644781 0.06144720309999999 0.0064332921 -0.061178257800000004 -0.0089908627 -0.145747 -0.00454162 0.0908037 -0.00644768 -0.00354873 0.00141285 -423.4538269042969 352.07965087890625 347.1715087890625 1.017207 61.309105 0.11093467999999997 0.035279282200000005 -0.0099449915 0.0268605023 0.0468246833 -0.0358520774 0.045555255 -0.0094717593 -0.0177346076 -0.02287013 -0.0052841443999999994 0.0152549147 0.054979404800000006 0.000920683 -0.0616351482 -0.0027612279999999997 0.0615526926 0.0045993107 -0.0614153483 -0.0064332921 -0.145745 -0.0317784 0.0468788 -0.00586563 -0.00374777 0.00139852 -422.6480712890625 352.08612060546875 346.703125 1.014634 61.154064 0.037242899999999995 0.0033816905 -0.0233172889 -0.0066642587 0.0656518367 -0.0027511182 0.032191565299999995 -0.0083457415 -0.0152698077 -0.024685920099999998 0.0022264366000000002 0.0003469703 0.0541358792 0.0005524229 -0.061652743499999996 -0.0016570915 0.0616230524 0.0027612279999999997 -0.0615735779 -0.0038644781 -0.145772 -0.0358861 0.0550545 -0.00595598 -0.00335771 0.00138028 -425.5208740234375 351.64764404296875 347.0054626464844 1.044097 62.929871 0.11216687 -0.0180362575 -0.010253023100000001 -0.055090863600000005 0.027054304100000003 0.0231150246 -0.083615245 -0.00351559 -0.0060941651 0.0094704862 0.0242820773 -0.0166484252 0.0144462064 0.0001841432 -0.0616615418 -0.0005524229 0.0616582424 0.000920683 -0.061652743499999996 -0.0012889102 -0.145743 0.00108797 0.0803908 -0.00650628 -0.00363701 0.00154723 -423.056396484375 351.6148376464844 346.5876770019531 1.034194 62.33297 0.09589186999999998 0.0016956422 0.0032560717 -0.0482294484 -0.0370651803 0.0156615799 0.021735155 -0.007353035799999999 -0.0186052074 0.0129778098 0.010067210600000001 -0.017737501699999998 -0.05009777940000001 -0.0001841432 -0.0616615418 0.0005524229 0.0616582424 -0.000920683 -0.061652743499999996 0.0012889102 -0.145747 -0.042523 0.0563679 -0.00622338 -0.00362793 0.00127413 -423.0142211914063 351.8645935058594 346.55059814453125 1.008234 60.768295 0.08314669999999999 0.0241448692 0.014098157 -0.007604683399999999 -0.056266075199999994 0.015186296100000002 0.0551742581 -0.010641140700000001 -0.016262713 0.0028514632 -0.0076045986999999995 -0.017857669 -0.06778292849999999 -0.0005524229 -0.061652743499999996 0.0016570915 0.0616230524 -0.0027612279999999997 -0.0615735779 0.0038644781 -0.151153 -0.0469808 0.08058329999999998 -0.0056934 -0.00347605 0.00157362 -424.0895385742188 351.9103698730469 346.6689453125 1.091821 65.806252 0.11193832000000005 0.0363140147 0.0180340179 0.0407674153 -0.048622809 0.0153853476 -0.0503740466 -0.0085678722 -0.0116771003 0.0028042871000000004 0.0029113337 -0.0049580244 -0.022957021600000002 -0.000920683 -0.0616351482 0.0027612279999999997 0.0615526926 -0.0045993107 -0.0614153483 0.0064332921 -0.14575 0.00393002 0.0833273 -0.00642673 -0.00367341 0.00170054 -423.2201843261719 351.49432373046875 346.393310546875 1.03575 62.426769 0.12321862000000003 0.0660591741 0.0010317133 0.0523422112 0.0003475424 0.015706557700000002 -0.0607401239 -0.0099515447 -0.029016688500000002 -0.0229334363 -0.0001448073 0.0150579 0.0192092267 -0.0012889102 -0.0616087584 0.0038644781 0.06144720309999999 -0.0064332921 -0.061178257800000004 0.0089908627 -0.153091 -0.0436701 0.06585480000000002 -0.00561298 -0.00360936 0.0015622399999999997 -421.7550659179688 351.44525146484375 346.4691467285156 1.01372 61.098969 0.06358719999999998 0.03991794 -0.0167302547 0.0339420531 0.04879327730000001 -0.0224715214 0.061852524900000004 -0.0079213945 -0.0199438373 -0.0220940869 -0.0049164514 0.0049871574 0.0536179506 -0.0016570915 -0.0615735779 0.0049664875 0.061306644 -0.008261536600000001 -0.060862611100000005 0.0115327203 -0.14577 -0.0255227 0.08472359999999998 -0.00579584 -0.00349337 0.00164839 -421.45635986328125 352.1016845703125 346.6666259765625 0.996851 60.082253 0.09657218 0.0067522789 -0.0163490636 0.0028501807 0.055377361900000005 -0.0185816307 0.034071564900000004 -0.007544854 -0.012234094 -0.0060462588 0.0015124323 -0.0149976616 0.041548512200000005 -0.0020252136 -0.0615296116 0.0060669025 0.061131095700000006 -0.010082414100000001 -0.060468813200000006 0.0140544224 -0.145759 0.00169778 0.0755389 -0.00673733 -0.00367341 0.0015668 -420.78070068359375 352.3178405761719 346.60931396484375 0.9817570000000002 59.172493 0.12888128 -0.0082579993 -0.010545012900000001 -0.0106295156 0.0603809941 0.007689063 0.041915391499999996 -0.012972514499999999 -0.012361843899999999 -0.0053890872999999995 0.0082497868 -0.0118962461 0.05040502400000001 -0.0023932635000000002 -0.0614768659 0.007165369699999999 0.060920658200000005 -0.0118943007 -0.05999737 0.0165515619 -0.151568 -0.0476931 0.0751275 -0.00547346 -0.00359273 0.00168765 -423.9154357910156 352.0771789550781 347.07659912109375 1.039327 62.642365 0.11952255999999997 -0.0216324404 -0.0142949083 -0.0628127964 0.041317104 0.0213775059 -0.060973049800000005 -0.0094777205 -0.0139018346 0.0055140706000000005 0.0120257388 -0.0218017902 0.017972361200000002 -0.0027612279999999997 -0.0614153483 0.008261536600000001 0.060675451799999995 -0.013695580700000001 -0.0594488867 0.0190197746 -0.145759 0.00283246 0.104202 -0.00599235 -0.00367341 0.00177035 -423.5655822753906 351.8409423828125 347.0753479003906 1.024534 61.750759 0.07703055999999998 -0.0176274877 -0.0089197872 -0.0669768304 -0.0164901895 0.011178166699999999 -0.0165854421 -0.010543627 -0.0157270396 0.0072771764 0.000917608 -0.035881979 -0.0304492454 -0.0031290940000000002 -0.0613450675 0.0093550512 0.060395616299999996 -0.0154846479 -0.058824067699999996 0.0214547469 -0.15458 -0.0311391 0.0852925 -0.00574857 -0.00367341 0.0017075599999999997 -423.7508850097656 352.0266418457031 346.920654296875 1.006564 60.667675 0.039044800000000005 -0.0008721005000000001 0.0208999401 -0.0509749696 -0.059626320700000006 -0.0135086782 0.0365194986 -0.0118750665 -0.0143820142 0.0052321532 -0.0062634497 -0.0261125069 -0.0746038392 -0.0034968484000000005 -0.061266033600000006 0.0104455625 0.0600813114 -0.0172599069 -0.058123715199999995 0.0238522233 -0.145751 -0.0440656 0.0882948 -0.00558059 -0.00367341 0.0015898 -422.8259582519531 351.642578125 347.02508544921875 0.9935790000000002 59.885006 0.10655752 0.0090213507 0.0173016 -0.0150729829 -0.0686909738 -0.019873698000000002 0.059805524699999994 -0.0100660838 -0.0120027288 0.0203194708 0.012105850900000001 -0.0262434077 -0.0644347867 -0.0038644781 -0.061178257800000004 0.0115327203 0.0597327166 -0.0190197746 -0.057348728499999994 0.0262080137 -0.145728 -0.00417308 0.0861038 -0.00655807 -0.00384264 0.00144749 -423.8187561035156 352.1510925292969 346.9847106933594 1.023226 61.671879 0.08029502000000001 0.025017043 0.0081184106 0.0288706673 -0.0719204809 0.0095984751 0.0051992176 -0.014214818999999998 -0.0134285701 -0.0034634064 -0.0005935768 -0.0013883398000000002 -0.0679039268 -0.0042319699 -0.0610817528 0.012616175600000001 0.0593500308 -0.0207626817 -0.0565001029 0.0285180009 -0.150071 -0.0415857 0.0826374 -0.00597614 -0.00394541 0.00143073 -423.77154541015625 352.24627685546875 346.7822265625 1.025837 61.8293 0.09809249999999997 0.0462542136 0.0045895963 0.0528750234 -0.0337791264 0.014640639399999999 -0.0826769938 -0.014960761699999998 -0.019683888400000002 -0.0163221432 0.0003089843 0.0162794878 -0.013701072 -0.0045993107 -0.060976532199999996 0.013695580700000001 0.0589334724 -0.022487074 -0.055578927800000004 0.0307781479 -0.155761 -0.0316946 0.0970898 -0.00535261 -0.00354894 0.00177191 -424.74017333984375 351.98748779296875 347.145263671875 1.055362 63.60878 0.15959460000000003 0.038639568199999995 -0.0221509825 0.039015003 0.015586193 -0.0216206435 -0.0067438341 -0.011418741699999999 -0.0076103907 -0.0189863249 0.005863291 -0.007974851 0.023153043999999998 -0.0049664875 -0.060862611100000005 0.0147705889 0.0584832792 -0.0241914138 -0.0545863863 0.0329845047 -0.14574 0.0195532 0.0761805 -0.006566 -0.00385949 0.00174752 -424.1434020996094 352.32257080078125 347.3174743652344 1.009025 60.81599 0.11422493999999997 0.023327357200000003 -0.0472761317 0.0227958246 0.0381810159 -0.0056383471 0.0327575389 -0.0154189558 -0.012063331299999999 -0.0408557636 0.0172012801 -0.0008544442 0.0393667154 -0.005333487099999999 -0.0607400057 0.0158408552 0.057999708 -0.025874181200000002 -0.053523752699999996 0.0351332152 -0.145694 -0.00341794 0.0165542 -0.00675019 -0.00427144 0.00171203 -420.5997924804688 352.46820068359375 346.83648681640625 1.0157600000000002 61.221905 0.23348786 0.0230027377 -0.026321017999999998 0.0073961525 0.0481740687 -0.0258750672 0.0570177761 -0.0190412917 -0.0189156865 -0.0337267949 0.0056392796999999995 -0.0018588097 0.0378277006 -0.0057002965 -0.0606087335 0.0169060359 0.0574830349 -0.0275338758 -0.052392391600000005 0.0372205242 -0.153047 -0.0749817 0.0791918 -0.00538721 -0.00381492 0.00169286 -421.5812683105469 351.8645324707031 347.01214599609375 1.016085 61.241528 0.11568909999999998 -0.0054021876 -0.036047570099999995 -0.0241367298 0.0647287272 0.0027367992 0.025964602799999997 -0.0086185152 -0.017722553500000002 -0.0178451891 0.0159175127 -0.0092236977 0.0483897796 -0.0060669025 -0.060468813200000006 0.0179657891 0.0569335547 -0.029169017400000004 -0.0511937557 0.0392427837 -0.145791 -0.0174313 0.101565 -0.00545372 -0.00331124 0.00169286 -424.6976318359375 352.34686279296875 347.7719421386719 1.046371 63.066868 0.08850182000000002 -0.0169693845 -0.031527144900000005 -0.059322451 0.0237630808 0.019130016200000002 -0.07052876940000001 -0.0116476029 -0.0035495692 -0.0020103394 0.0179923372 -0.036666341 -0.0010285908 -0.0064332921 -0.060320264900000004 0.0190197746 0.056351581 -0.0307781479 -0.0499293841 0.0411964596 -0.145762 0.007672919999999998 0.0871884 -0.00590856 -0.00367341 0.00185569 -424.1856384277344 351.9267272949219 347.33856201171875 1.034116 62.328259 0.10547602000000003 0.0070415302 -0.0138493196 -0.0503529284 -0.0439065488 0.0023470018 0.0031596439 -0.0145304 -0.0149719259 -0.0031095309000000004 0.0014870031 -0.01944538 -0.0637206926 -0.006799452199999999 -0.060163109699999995 0.020067654 0.055737446100000004 -0.0323598325 -0.0486009003 0.0430781374 -0.14575 -0.056337 0.09365250000000003 -0.00537159 -0.00367341 0.00169286 -423.38916015625 351.97882080078125 347.2102966308594 1.023629 61.696205 0.08362345999999996 0.033392038 -0.0016165898000000001 0.0032592431 -0.06263700929999999 0.0018841526999999999 0.0281980177 -0.0080398172 -0.0168520058 -0.0080411059 0.0033164558 -0.0088972508 -0.0556316124 -0.007165369699999999 -0.05999737 0.0211090908 0.0550915004 -0.0339126607 -0.04721001019999999 0.0448845285 -0.14574 -0.00815854 0.109331 -0.00541879 -0.00383285 0.00188135 -424.82818603515625 351.9365234375 347.30462646484375 1.092296 65.834877 0.06538249 0.0476112853 -0.0126601705 0.0404942914 -0.043062602 0.0070755124 -0.0670686508 -0.011319074699999999 -0.010602446599999999 -0.0189241225 0.0133420657 -0.011950173 -0.0162473525 -0.0075310317 -0.0598230695 0.0221437508 0.0544141125 -0.0354352477 -0.0457584997 0.04661247599999999 -0.145762 0.00982145 0.101999 -0.00603963 -0.00367341 0.00190204 -422.53363037109375 352.3207702636719 347.1430969238281 1.039734 62.666893 0.15682205 0.05639283480000001 -0.0157825986 0.044799062699999996 0.0202534014 -0.0176818867 -0.0077057314000000005 -0.0177922968 -0.0252166545 -0.0480801009 0.017273620700000002 0.0020732161999999998 0.024072958300000002 -0.007896425 -0.059640233 0.023171301800000002 0.053705669000000004 -0.0369262359 -0.0442482328 0.0482589599 -0.145734 -0.0605666 0.0746975 -0.00516325 -0.00385766 0.00178058 -422.9571838378906 352.22271728515625 347.1920166015625 1.02439 61.742062 0.09931673999999997 0.010622128 -0.045723022599999996 0.009569438000000001 0.0531784314 -0.0062161276 0.046503306900000006 -0.0138414285 -0.0140305059 -0.0352662386 0.0095441368 -0.0192941482 0.050782990599999994 -0.008261536600000001 -0.0594488867 0.0241914138 0.0529665744 -0.0383842957 -0.042681148499999995 0.0498211028 -0.147987 -0.00296826 0.0985779 -0.00520297 -0.00367341 0.00169285 -424.906982421875 352.1824951171875 347.2353515625 1.038994 62.622253 0.11594815999999998 -0.0051423623 -0.050358807900000004 -0.0350585877 0.0295090925 0.0282228962 -0.0468504982 -0.0146681127 -0.006622089300000001 -0.008694141899999999 0.045584791 -0.0398838542 0.0228892271 -0.0086263535 -0.059249057800000005 0.0252037594 0.052197250300000005 -0.0398081268 -0.041059259300000005 0.0512961746 -0.145689 0.0355939 0.0945914 -0.0059103 -0.00417242 0.00190854 -423.4152526855469 351.8850402832031 346.5765075683594 1.033736 62.305393 0.122037 -0.003448004 -0.0284800076 -0.0632263175 -0.0208423459 0.021239447999999998 -0.029798318900000002 -0.013741626000000002 -0.015185738 -0.0124831997 0.020881561 -0.0246763623 -0.0350786415 -0.0089908627 -0.0590407749 0.0262080137 0.051398136 -0.0411964596 -0.039384647599999996 0.0526815972 -0.145691 -0.0314626 0.08619839999999998 -0.00504354 -0.00417242 0.00184359 -422.3483276367188 351.3887939453125 346.0973205566406 1.016984 61.295673 0.05798449999999999 0.020825352 -0.007977205400000001 -0.041685711 -0.0652662406 0.0204827338 0.04883233730000001 -0.011724732 -0.0250426273 -0.0126569267 0.0159793476 -0.0324552615 -0.07986357820000001 -0.0093550512 -0.058824067699999996 0.027203854 0.050569687300000006 -0.0425480561 -0.0376594638 0.05397494940000001 -0.145718 -0.0167102 0.0934285 -0.00484384 -0.00379368 0.00198465 -422.2748718261719 351.71759033203125 346.2295227050781 1.008756 60.799755 0.11634870000000003 0.0299340027 -0.011695148700000001 0.004381459 -0.0602362714 0.0081581148 0.043900467699999994 -0.0123940505 -0.0165054741 -0.0025180971 0.0244170522 -0.0246205027 -0.0583530781 -0.009718906 -0.058598967 0.0281909609 0.049712377300000006 -0.043861710899999996 -0.0358859231 0.0551739708 -0.145756 0.018509 0.117126 -0.00592362 -0.00376121 0.00202028 -422.718505859375 352.04962158203125 346.31982421875 1.017756 61.342197 0.1144385 0.045343036100000005 -0.0263671653 0.0412184963 -0.058902891299999996 0.021277525699999997 -0.0060841318999999994 -0.017678732 -0.0190525298 -0.0212998712 0.025238842200000004 -0.017160889 -0.047041514900000005 -0.010082414100000001 -0.0583655051 0.029169017400000004 0.0488266951 -0.045136252800000005 -0.034066302799999996 0.05627656599999999 -0.145703 -0.0295023 0.0982763 -0.00530639 -0.00408005 0.00200586 -422.1099243164063 351.9504699707031 346.4938659667969 0.984848 59.35881 0.0433124 0.060287010599999996 -0.0174425404 0.048151882699999995 -0.0274210729 0.018581709199999998 -0.058369866900000004 -0.017142591000000002 -0.0217055929 -0.027296614900000002 0.021584801600000002 -0.0089845655 -0.0106874843 -0.0104455625 -0.058123715199999995 0.0301377094 0.0479131463 -0.046370545 -0.0322029395 0.0572808079 -0.145737 -0.023353 0.0932532 -0.00492651 -0.00386643 0.00195724 -423.7091674804688 352.0915832519531 347.0028076171875 1.032212 62.213509 0.10736609999999996 0.0586275556 -0.0354025879 0.044459265199999994 0.0048383178 -0.011817707 -0.0289568589 -0.017851856399999998 -0.014880365900000001 -0.0279544681 0.0140970602 -0.0045805519 0.0228996648 -0.010808338300000001 -0.0578736318 0.031096726 0.0469722521 -0.047563487 -0.030298225699999997 0.058184941500000004 -0.139365 0.0249503 0.102666 -0.00574148 -0.00387646 0.00191668 -421.5442199707031 352.4117126464844 346.8356628417969 0.989607 59.645592 0.1240591 0.0472242227 -0.0442042697 0.026575413 0.0401719722 -0.0224274486 0.0398233484 -0.0195155471 -0.0214943618 -0.0446623845 0.016171305 -0.0044929325 0.037657791499999996 -0.011170728500000001 -0.057615290599999994 0.032045759300000004 0.046004549699999994 -0.048714014900000005 -0.0283546073 0.0589873867 -0.132264 -0.031324 0.0918057 -0.00509904 -0.00400667 0.00169286 -420.6295776367188 350.8545837402344 345.02227783203125 1.168657 70.437317 0.25510549999999993 0.0148706421 -0.0554163036 0.0235735903 0.0476593143 -0.0366593026 0.0534355809 0.0124539124 -0.0061993434 -0.050260397400000004 0.0500016899 0.0249562616 0.0410605719 -0.0115327203 -0.057348728499999994 0.0329845047 0.0450105913 -0.0498211028 -0.02637458 0.059686740999999995 -0.129556 -0.0837447 0.14995 -0.0076283 -0.00417242 0.0018345 -422.6178588867188 351.5042419433594 345.54022216796875 1.358652 81.88868 0.37498197 -0.0014688322 -0.07695412459999999 -0.004849271 0.039514092599999995 -0.0635779209 0.00039524 0.0062495355 0.0350227281 -0.0251286543 0.0097157511 -0.053903538499999994 0.0503580432 -0.0118943007 -0.0570739836 0.0339126607 0.0439909442 -0.0508837635 -0.024360686200000002 0.0602817821 -0.0654082 0.00338597 0.135923 -0.009860130000000003 -0.00533363 0.00263499 -420.6769714355469 352.3966369628906 346.6168212890625 1.120178 67.515404 0.28085887 -0.0133455466 -0.0488771263 -0.0220569381 0.027313674 -0.0328615391 0.051491877 -0.0094324671 0.017665354299999998 -0.0130409728 0.051504332699999995 -0.0166837217 0.0338754846 -0.012255456699999999 -0.056791094900000005 0.0348299293 0.0429461904 -0.0519010494 -0.022315511899999998 0.0607714702 -0.08371499999999998 -0.07057860000000002 0.140476 -0.00703084 -0.00478372 0.0023335 -422.7582702636719 351.9284362792969 346.5043029785156 0.97896 59.003902 0.10698750000000001 -0.016422506599999998 -0.0549309717 -0.0433468909 0.0284524913 -0.022590903500000002 -0.0022184689000000002 -0.003498682 0.0167817936 0.0027847465999999996 0.0386297067 -0.03575692 0.030469596600000003 -0.012616175600000001 -0.0565001029 0.0357360162 0.041876926 -0.052872053200000005 -0.0202416832 0.061154949400000005 -0.102312 -0.0160031 0.155845 -0.0070238 -0.00448303 0.00227231 -422.84375 352.2189636230469 346.8207702636719 0.964336 58.122475 0.0774803 -0.0145992953 -0.058557927999999995 -0.0424643644 0.015744261699999998 -0.020013881100000002 0.0196514939 -0.014168373 0.0101208601 0.00022264150000000002 0.048837958099999995 -0.0391397556 0.011757996599999999 -0.0129764445 -0.056201049100000004 0.0366306304 0.0407837614 -0.0537959092 -0.0181418631 0.0614315496 -0.110227 -0.0290379 0.143161 -0.00619207 -0.00443783 0.00227231 -423.8365173339844 352.55279541015625 346.9889221191406 1.001551 60.365532 0.08324310000000003 -0.0098700877 -0.0529568599 -0.061541105 0.0200284701 0.017987659 -0.0554965717 -0.0169523745 0.0041132797 -0.0009852164999999999 0.034727085899999996 -0.0500017382 0.0043647567 -0.0133362505 -0.055893976100000006 0.0375134847 0.0396673204 -0.0546717934 -0.0160187477 0.0616007872 -0.105186 -0.032385 0.131572 -0.00511668 -0.0042479 0.00227231 -424.3617248535156 351.87579345703125 346.8218078613281 0.9938920000000002 59.903885 0.1365014 -0.012420121200000002 -0.0452155183 -0.0688329871 -0.0237948699 0.0078060239 -0.0689877966 -0.0145568198 0.0063200292000000005 0.0191307811 0.0390222379 -0.0373914738 -0.022765977799999997 -0.013695580700000001 -0.055578927800000004 0.0383842957 0.038528240299999995 -0.0554989249 -0.0138750634 0.061662366600000004 -0.107132 0.0300154 0.143111 -0.00602979 -0.00454711 0.00227231 -422.29010009765625 352.276123046875 346.68463134765625 0.974888 58.758476 0.1413646 -0.0034901336 -0.0368069848 -0.06949750240000001 -0.0403706286 0.013703283 -0.0226037608 -0.0189569937 -0.0077822803000000005 0.0038286287 0.0336041878 -0.0385197021 -0.0438986892 -0.0140544224 -0.0552559492 0.0392427837 0.0373671711 -0.05627656599999999 -0.011713562700000001 0.061616180199999995 -0.105689 -0.0266737 0.123571 -0.00487044 -0.00449451 0.00233421 -422.5505676269531 351.8749694824219 346.6341552734375 0.9847570000000002 59.353287 0.05286497399999997 -0.002167942 -0.028766027799999996 -0.07607462599999999 -0.062303696 0.0059415323999999995 0.020479888300000002 -0.016628863600000002 -0.0031687068 0.003857267 0.0257887107 -0.0379424954 -0.06564794110000001 -0.0144127627 -0.0549250863 0.0400886733 0.0361847754 -0.0570040233 -0.0095370211 0.06146230849999999 -0.10600200000000001 0.000830274 0.12144 -0.00450004 -0.00446847 0.00227231 -422.6456909179688 352.3600158691406 346.9045715332031 0.9853090000000002 59.386581 0.11083832599999996 0.0077365503000000006 -0.0240850261 -0.056410402400000004 -0.0717334884 0.0042848031 0.0458891525 -0.0208762657 -0.0021544422 -0.0041681425 0.025687652400000004 -0.0497983677 -0.0827506308 -0.0147705889 -0.0545863863 0.0409216928 0.0349817282 -0.057680648099999995 -0.0073482335 0.061201020700000004 -0.0922927 0.0384368 0.11277 -0.00541728 -0.00456828 0.00227231 -423.7093811035156 352.1448669433594 346.72174072265625 1.017677 61.337456 0.1199639 0.02461359 -0.0182305379 -0.032310691600000004 -0.0812785104 0.0141625643 0.0389227234 -0.0192172169 -0.0074533546 -0.019561557 0.029298173900000002 -0.0202829003 -0.0858611032 -0.0151278882 -0.054239897599999996 0.0417415748 0.033758716 -0.058305837 -0.0051500103000000005 0.0608327732 -0.0993306 -0.0326072 0.115636 -0.00466176 -0.00454348 0.00227231 -421.2937316894531 352.0890808105469 346.230712890625 1.078237 64.987511 0.2223304 0.0250452419 -0.0074110574 -0.0082451319 -0.07068775 0.0109136174 0.0609189597 -0.0137984499 -0.018711523100000002 -0.0335353204 -0.0084279776 -0.0411021827 -0.0759983316 -0.0154846479 -0.053885669500000004 0.0425480561 0.0325164369 -0.0588790326 -0.0029451740999999997 0.0603582097 -0.114905 0.0444918 0.135491 -0.00598668 -0.00416994 0.00177473 -421.4561462402344 352.227783203125 346.6115417480469 1.049795 63.273277 0.09400490000000003 0.0385089746 -0.0144814374 -0.0058419611 -0.0687047625 -0.0034088853000000005 0.0615125967 -0.0151748193 0.0045066681 0.0030896777 0.0327425365 -0.0300551802 -0.056591387 -0.0158408552 -0.053523752699999996 0.043340877699999995 0.0312555998 -0.0593997236 -0.0007365563000000001 0.0597781596 -0.105755 0.0445967 0.126141 -0.00544197 -0.00466537 0.00224259 -423.6142578125 351.9715270996094 347.0666809082031 1.013613 61.092537 0.2177588 0.0167637999 -0.0117756175 -0.005412407199999999 -0.0620226625 -0.034436012099999996 0.030865654300000003 -0.0110315416 0.0164970131 0.0204331765 0.0231988043 -0.0505995215 -0.035057669799999996 -0.0161964974 -0.053154198799999997 0.0441197852 0.029976924199999998 -0.0598674458 0.0014730073999999998 0.0590936366 -0.103266 0.110771 0.201107 -0.00669981 -0.00465603 0.002458 -427.740234375 352.4847106933594 347.1923828125 1.05381 63.515274 0.2609612 0.024877446600000002 -0.0559776802 -0.0246304569 -0.0512546847 -0.0171045689 -0.0913772999 -0.018423078 0.0200505984 -0.0079608371 0.0401458068 -0.040262107400000004 -0.0402735102 -0.0165515619 -0.0527770605 0.0448845285 0.0286811401 -0.0602817821 0.0036806797 0.058305837 -0.108416 -0.0269597 0.145813 -0.00613822 -0.00523027 0.0025779 -423.3394775390625 353.0061950683594 346.8187561035156 1.234664 74.41567999999998 0.4004576 0.0063593151 -0.0325957304 -0.025438136899999998 -0.0193870761 0.0069204352 0.0119839502 -0.0264957321 -0.00017609439999999999 -0.0487983171 0.0147207082 -0.0122212533 -0.022759951 -0.0169060359 -0.052392391600000005 0.0456348621 0.0273689869 -0.060642363 0.0058836257 0.057416137699999995 -0.191272 -0.084914 0.0820212 -0.00257154 -0.00552273 0.00251993 -421.97845458984375 349.72161865234375 344.50994873046875 1.496215 90.179893 1.0792577 -0.0012798273 -0.046241961100000006 -0.0029049118 0.0199219524 0.0869564028 0.0356474281 0.0095975031 -0.0723173962 -0.1199444347 -0.0347604158 0.0510009564 -0.028026108799999998 -0.0172599069 -0.0520002471 0.046370545 0.026041213599999998 -0.060948867000000004 0.0080790168 0.056426093600000005 -0.284592 -0.0303675 -0.265353 0.00646376 -0.00289899 0.00249863 -424.1256713867188 353.44305419921875 349.127197265625 1.451313 87.473602 1.0715289 0.0445281501 -0.0699649765 -0.0196453693 -0.0046037047999999995 0.0057414096 0.041156126 -0.0372914667 -0.0168640065 -0.0787979162 0.013916442 -0.0261348623 0.009069177 -0.0176131622 -0.0516006827 0.0470913411 0.0246985778 -0.061201020700000004 0.010264034 0.0553374348 -0.166239 0.0730873 0.0551311 -0.00319971 -0.00264181 0.00183454 -425.1435241699219 353.13153076171875 348.6854553222656 1.051298 63.363842 0.059509599999999975 0.057746738799999996 -0.0718942896 0.013702285 -0.0044518692 0.0293604835 -0.0541616599 -0.032873114700000004 -0.016904306799999998 -0.0636160845 0.0171360495 -0.0216423856 0.011169146999999999 -0.0179657891 -0.0511937557 0.047797019100000004 0.023341845899999998 -0.0613985992 0.012435871599999999 0.0541520642 -0.153895 0.07285719999999998 0.0516151 -0.0033907 -0.00315692 0.00199683 -422.7452697753906 353.29705810546875 347.9543762207031 1.019454 61.444538 0.15587456 0.0420840797 -0.06346851 0.020126138000000002 0.0186987252 -0.0016357363000000001 0.040097863500000004 -0.033330087200000004 -0.013189423999999998 -0.07132720669999999 0.0276283368 -0.0079039478 0.0239118248 -0.0183177752 -0.050779524000000006 0.0484873523 0.021971792200000003 -0.0615414265 0.0145917409 0.052872053200000005 -0.152211 -0.00784506 0.0743409 -0.0024331 -0.00312874 0.0020263 -424.16485595703125 352.35308837890625 346.89385986328125 1.038503 62.592697 0.06613685999999999 0.0149720576 -0.0831111812 -0.0184594144 0.0287169178 0.026716054399999998 0.0087715771 -0.024333394700000004 -0.0232936969 -0.06290824610000001 0.0351210388 -0.0139469091 0.027704867 -0.0186691079 -0.0503580468 0.0491621191 0.020589198700000002 -0.061629375099999995 0.0167288735 0.05149963900000001 -0.152143 0.0313076 0.0769561 -0.0027276 -0.00326344 0.00208312 -381.43780517578125 328.59796142578125 318.6061706542969 3.266707 196.891068 4.998244499999999 -0.27949821329999996 0.0493168888 0.19188755870000002 -0.011588620800000001 0.27473458030000003 0.1383723112 0.3781581853 -0.1450526235 0.084602809 0.2117462949 0.31736477949999997 0.0833617164 -0.0190197746 -0.0499293841 0.0498211028 0.019194854299999998 -0.061662366600000004 0.0188445253 0.050037220099999995 -0.590689 -0.677089 1.46892 -0.0447741 0.00053772 0.00542222 -430.1203918457031 348.6003112792969 337.3504333496094 3.559375 214.530762 1.912353 -0.0821045373 -0.0365527078 0.032241907400000006 -0.0291464888 -0.0476142554 -0.1442313003 0.1142043246 0.1589983794 -0.13013242279999998 -0.2885125416 0.1279321592 -0.0699563358 -0.0193697628 -0.049493597199999996 0.050464092099999996 0.017789555 -0.0616403716 0.020935979599999998 0.0484873523 -0.238862 -0.263924 1.87262 -0.0368451 -0.00245278 0.0014685 -420.9122314453125 350.6184387207031 344.6624755859375 2.237752 134.873871 1.5853179499999999 -0.09660376539999999 0.0274469187 0.0335664597 0.0168789102 -0.0016264710999999998 -0.053468085 0.0829219735 0.145673912 0.0025913276000000002 -0.08234539910000001 0.0639192953 -0.023081462 -0.0197190601 -0.0490507482 0.0510908803 0.0163741027 -0.061563409699999995 0.023000551 0.0468527442 -0.139761 -0.284412 1.02678 -0.0261859 -0.0034299 0.000707041 -416.0423889160156 351.7149658203125 343.8774108886719 1.249672 75.32029 0.63827645 -0.08787958720000001 0.0469013786 0.0482506743 0.029953811 -0.0347097439 -0.0013538407999999999 0.0598150951 0.1241603616 0.0260196187 -0.024213616099999998 0.0354661675 0.029322807700000002 -0.020067654 -0.0486009003 0.0517012663 0.0149493052 -0.0614315496 0.0250355883 0.045136252800000005 -0.136732 -0.122598 0.9196820000000002 -0.0192144 -0.00338039 0.00101274 -416.6216430664063 351.4099426269531 343.5850524902344 1.147374 69.154549 0.7932158 -0.08651585619999999 0.0317053361 0.0278264586 0.0415710305 -0.0969107884 0.022814073100000002 0.0476876128 0.11132616599999999 0.033368533 -0.016538328300000002 -0.0039084546 0.061998104299999995 -0.020415532 -0.048144117699999996 0.052295054199999996 0.013515975800000002 -0.0612449087 0.0270384785 0.043340877699999995 -0.244915 -0.114362 0.665929 -0.0135094 -0.00219469 -0.000557436 -417.2756042480469 351.6089782714844 343.672119140625 1.072087 64.61685900000002 0.3013182 -0.0885339501 0.0393997498 0.0114484199 0.0334181996 -0.0750047499 -0.0174234578 0.04118784 0.1032295738 0.040453483 -0.011552347 0.0047513762 0.05622744440000001 -0.0207626817 -0.0476804656 0.052872053200000005 0.0120749325 -0.061003653600000006 0.0290066498 0.0414697568 -0.296138 -0.059247 0.623405 -0.0121936 -0.00251497 -0.00197048 -412.31427001953125 346.5185852050781 338.6865539550781 1.354589 81.643822 0.8741875 -0.17176138359999998 0.04558414400000001 0.0711636254 0.0179050913 0.060690622199999995 0.0036113513 0.11824592699999999 0.0817420278 0.0444737349 0.0203566862 0.1322736098 -0.0005133234999999999 -0.0211090908 -0.04721001019999999 0.053432078200000004 0.010626997800000001 -0.060707999400000004 0.0309375749 0.0395261602 -0.552367 -0.135477 0.811977 -0.0165198 -0.00423537 -0.00298701 -420.53814697265625 350.3009338378906 341.71527099609375 1.739488 104.842476 1.9515818 -0.1122973687 -0.0031921453999999997 0.0582734507 -0.0132743728 0.0728957074 -0.0660589099 0.0944983474 0.1399426479 -0.0149088518 -0.1169942427 0.1346583501 -0.012123116699999999 -0.0214547469 -0.046732818499999995 0.05397494940000001 0.0091729979 -0.0603582097 0.032828774399999996 0.0375134847 -1.32604 -0.193237 1.45057 -0.0218548 -0.00614497 -0.000600494 -403.7314147949219 345.10888671875 334.2265930175781 1.444173 87.043259 0.5011631999999997 -0.1424296957 0.0381241223 0.0989981752 -0.006750082199999999 0.0690426135 -0.0166578336 0.1531964284 0.0648963615 0.0247377528 -0.0849648059 0.1256678796 0.0080494822 -0.0217996377 -0.0462489587 0.0545004924 0.0077137627000000005 -0.059954596500000006 0.0346778198 0.0354352477 -1.32894 -0.202312 1.28201 -0.0191909 -0.00428106 0.00128426 -418.6464538574219 352.6941223144531 345.50244140625 1.808055 108.975136 2.1226263 -0.1138750332 0.0766725524 0.0600054884 0.0365209154 -0.0458939588 -0.0043352168 0.0320673433 0.0956600428 0.046863561100000006 -0.0370116257 0.052592152999999996 0.038859774900000005 -0.0221437508 -0.0457584997 0.055008538600000004 0.0062501251 -0.0594975196 0.036482337000000004 0.0332950814 -0.469324 -0.08129369999999998 0.789845 -0.0104851 -0.00765017 0.00220589 -415.0279235839844 351.4504699707031 344.04193115234375 0.942763 56.822212 0.30418820000000013 -0.1017150592 0.0786017312 0.048158628499999995 0.0417232721 -0.065068477 0.0112137188 0.0372076766 0.0765185736 0.0643926115 -0.0254301126 0.0104275035 0.0531444855 -0.022487074 -0.0452615117 0.0554989249 0.0047829204 -0.0589873867 0.038240008799999996 0.031096726 -0.390554 -0.028478 0.708189 -0.009544960000000003 -0.0073794 0.00281391 -418.3803405761719 351.62249755859375 344.8193664550781 0.9751050000000002 58.77153 0.3668353 -0.0801844635 0.0554067799 0.027544582 0.0340847507 -0.0657583232 -0.0022876656 0.022626427799999998 0.063638717 0.0638562263 -0.008382901199999999 -0.0042630786 0.058586199400000004 -0.0228295951 -0.0447580654 0.0559714938 0.003312986 -0.058424652599999995 0.0399485782 0.028844023599999997 -0.351145 0.0194848 0.564413 -0.00831807 -0.00629838 0.00321975 -416.8069763183594 351.5849609375 344.3423156738281 1.026259 61.854683 0.3547696000000001 -0.06968792730000001 0.0724468588 0.0043474851 0.046090084 -0.0314205399 -0.0028625911 0.013401146599999999 0.0337760604 0.0732611953 -0.0177494105 0.0061055216 0.0574833162 -0.023171301800000002 -0.0442482328 0.056426093600000005 0.0018411607000000001 -0.057809819299999995 0.041605851299999996 0.0265409112 -0.319167 0.0239209 0.51541 -0.00433552 -0.00536314 0.00275049 -423.1354675292969 352.40936279296875 346.1038513183594 1.244313 74.99726099999998 0.6488629 -0.0149252484 0.0126746327 -0.053155308899999996 0.0386578883 0.056841211100000004 -0.057410986100000005 -0.019337585 -0.018540563700000002 0.0025758523 0.0042235889 -0.0339061309 0.033533104700000003 -0.023512181899999998 -0.0437320865 0.0568625783 0.0003682847 -0.057143434800000004 0.04320970019999999 0.0241914138 -0.273208 0.022326 0.240882 -0.00111602 -0.00265059 0.00214692 -418.4499206542969 352.0712890625 345.3442687988281 1.017885 61.350006 0.17379210000000003 -0.023854337000000003 0.0299966751 -0.0658393642 0.0114561618 0.0209044326 -0.0352460602 -0.018403136100000002 -0.0164089256 0.0342071832 -0.008356224399999999 -0.0194982112 0.0018115726 -0.0238522233 -0.04320970019999999 0.0572808079 -0.0011048015 -0.056426093600000005 0.0447580654 0.0217996377 -0.271391 0.0955996 0.244251 -0.0018335 -0.00337606 0.00261062 -419.1112365722656 352.1437072753906 345.2984619140625 0.976786 58.872883 0.15570490000000003 -0.0119107696 0.0438664187 -0.0724635387 -0.014711053799999999 0.0166800691 0.0004672146 -0.0179805687 -0.012364441100000002 0.0289318161 -0.0248313827 -0.019431400300000002 -0.0382879047 -0.0241914138 -0.042681148499999995 0.057680648099999995 -0.0025772572 -0.055658435199999995 0.0462489587 0.0193697628 -0.273648 0.0363352 0.265147 -0.00107512 -0.00306929 0.00221002 -420.4413146972656 351.6837463378906 345.521240234375 0.9906 59.705498 0.1736448 -0.004422174 0.0680626179 -0.0481275741 -0.045184999299999994 -0.0095133037 0.049516363 -0.0159525451 -0.0157110527 0.0502104292 -0.0308175607 -0.022644120299999997 -0.051410701399999995 -0.024529741400000003 -0.0421465068 0.0580619705 -0.0040482420000000005 -0.0548411441 0.0476804656 0.0169060359 -0.247245 0.103608 0.29487 -0.00135959 -0.00358014 0.00241962 -419.6473388671875 351.62896728515625 345.6497802734375 0.967 58.283031 0.07151610000000004 0.0189618504 0.06766151320000001 -0.022233211099999997 -0.043993692300000005 0.0002666888 0.0357006199 -0.0167969886 -0.015423474 0.0391091991 -0.0257199105 0.0077114674 -0.0536105537 -0.0248671939 -0.041605851299999996 0.058424652599999995 -0.0055169164 -0.05397494940000001 0.0490507482 0.0144127627 -0.23772 0.0786209 0.287076 -0.0010534 -0.00379233 0.00248544 -418.9615478515625 351.8234558105469 345.80267333984375 0.967743 58.327808 0.06568415000000001 0.0301487805 0.0703560798 -0.0069774165 -0.0393003124 0.0061570858999999995 0.057461163499999995 -0.0186964214 -0.0247389319 0.042906738300000004 -0.0369381559 0.0054517433999999995 -0.052482956 -0.0252037594 -0.041059259300000005 0.058768578200000005 -0.0069824421 -0.053060623200000004 0.0503580468 0.0118943007 -0.23909 0.0757087 0.298645 -0.000304101 -0.00358014 0.00252061 -419.6753234863281 351.7593078613281 346.1188659667969 1.009272 60.830894 0.11859274999999997 0.0276107927 0.06866515549999999 0.021092530699999997 -0.028276063799999997 -0.0248488284 0.019408708 -0.0177545523 -0.0201570228 0.0414372242 -0.0329587837 0.0129256875 -0.0314004408 -0.0255394259 -0.0405068086 0.0590936366 -0.0084439827 -0.052098980999999996 0.0516006827 0.0093550512 -0.239019 0.112943 0.316532 -0.00111388 -0.00379241 0.00276657 -422.27276611328125 351.53399658203125 346.1166687011719 0.99742 60.116497 0.09682470000000003 0.044067184599999996 0.066210256 0.0447473251 -0.0193339788 -0.002002235 -0.0551286987 -0.013770552 -0.020730941200000002 0.0386171194 -0.0263255869 0.0169869058 -0.0050380914 -0.025874181200000002 -0.0399485782 0.0593997236 -0.0099007042 -0.0510908803 0.0527770605 0.006799452199999999 -0.239134 0.0751837 0.329917 -0.000782472 -0.00349075 0.00248833 -422.04248046875 351.7495422363281 345.74310302734375 1.009807 60.86314 0.035670499999999994 0.0495643625 0.051569550199999994 0.0411217369 0.0310298427 -0.026947155499999997 -0.0432072606 -0.0180884813 -0.0225546896 0.0136109412 -0.0429351579 0.0267300836 0.0383393096 -0.0262080137 -0.039384647599999996 0.059686740999999995 -0.011351775 -0.050037220099999995 0.053885669500000004 0.0042319699 -0.239099 0.0962352 0.333524 -0.000782472 -0.003588 0.00261062 -421.6839599609375 351.4595642089844 345.8724670410156 0.999159 60.221348 0.1157992 0.017132814099999998 0.027773046000000003 0.027932422999999998 0.063342975 -0.06338024639999999 0.0227716881 -0.013739878799999999 -0.007751890500000001 0.026026464 -0.0215084302 0.0112781667 0.06580490230000001 -0.0265409112 -0.038815097400000005 0.059954596500000006 -0.012796367099999999 -0.0489389399 0.0549250863 0.0016570915 -0.244236 0.118076 0.341341 -0.00191486 -0.00396659 0.00271973 -417.738037109375 351.3692626953125 345.33258056640625 0.96524 58.17696 0.13038679999999997 -0.000270669 0.0312168344 0.0037762311999999998 0.07441905160000001 -0.010850259499999999 0.057639717800000004 -0.014111835500000001 -0.0266302828 0.029569029700000003 -0.0278649781 0.0176900778 0.0656814815 -0.0268728619 -0.038240008799999996 0.0602032042 -0.014233656 -0.047797019100000004 0.055893976100000006 -0.000920683 -0.244722 0.0766613 0.336405 -0.000793038 -0.00352652 0.00261062 -419.8628845214844 351.568359375 345.51226806640625 0.960336 57.881405 0.060819449999999976 -0.01070881 0.0281359439 -0.0244137148 0.0777633915 -0.0091804062 0.0044453755 -0.0130626528 -0.015988826499999997 0.0339401093 -0.0201823184 0.0067077535 0.0732611837 -0.027203854 -0.0376594638 0.0604324842 -0.0156628214 -0.04661247599999999 0.056791094900000005 -0.0034968484000000005 -0.239189 0.0995235 0.327475 -0.0008354929999999998 -0.00326034 0.00244937 -422.4987487792969 351.3699645996094 346.0322570800781 0.994591 59.946003 0.11540434999999998 -0.014313031499999998 0.0185412544 -0.0387777866 0.0580043118 0.011305381000000001 -0.0708969293 -0.0086500406 -0.010106941099999999 0.0399708752 -0.012745536799999999 -0.0166379345 0.0526798053 -0.0275338758 -0.037073545299999996 0.060642363 -0.0170830476 -0.0453863669 0.057615290599999994 -0.0060669025 -0.23901 0.127879 0.336526 -0.00167625 -0.00381471 0.00261062 -419.77490234375 351.44244384765625 345.6802673339844 0.981476 59.155567 0.11940634999999995 -0.028755087599999996 0.0394407414 -0.0603907303 0.0281335252 0.0144500952 -0.0327123158 -0.0123311932 -0.0168627979 0.048842275899999996 -0.0198487369 -0.0171848882 0.010335123199999999 -0.0278629153 -0.036482337000000004 0.0608327732 -0.018493524 -0.0441197852 0.0583655051 -0.0086263535 -0.23906 0.0774393 0.330282 -0.000603147 -0.00363436 0.00261062 -421.48577880859375 351.2916564941406 345.5426940917969 0.990654 59.708748 0.04891735000000005 -0.0190920045 0.0655958814 -0.07128014490000001 -0.023667556 -0.0060796043 0.0079269932 -0.0139786079 -0.0191278401 0.0533322608 -0.0333970323 -0.0140409817 -0.044440648099999994 -0.0281909609 -0.0358859231 0.061003653600000006 -0.0198934458 -0.0428138604 0.0590407749 -0.011170728500000001 -0.239145 0.106642 0.329783 -0.00072408 -0.00337268 0.00261062 -420.5012512207031 351.2781982421875 345.6613464355469 0.969045 58.40633 0.108104 0.0059798062 0.058926953600000005 -0.025717250299999998 -0.04403736230000001 -0.014884317 0.0439250403 -0.0111031498 -0.0108040105 0.0587366876 -0.0263536079 -0.0187305097 -0.045449246299999996 -0.0285180009 -0.0352843888 0.061154949400000005 -0.0212820138 -0.0414697568 0.059640233 -0.013695580700000001 -0.238982 0.131304 0.336535 -0.00171888 -0.00390842 0.00261062 -421.4539794921875 351.36175537109375 345.560791015625 0.960475 57.889786 0.14115905 0.0283283069 0.060085735 0.0006942722 -0.0449613669 -0.0211546235 0.0396752889 -0.014757578200000001 -0.0174069405 0.0444395266 -0.0388275309 0.0044987638 -0.0453782116 -0.028844023599999997 -0.0346778198 0.0612866121 -0.022658435600000002 -0.0400886733 0.060163109699999995 -0.0161964974 -0.239088 0.0888294 0.328379 -0.000377261 -0.0035485 0.00250371 -422.3851623535156 351.499755859375 345.82940673828125 1.029197 62.031773 0.06255749999999997 0.044296603899999995 0.049730095300000006 0.0363155293 -0.0456064928 0.0008636684 -0.0315394366 -0.0146453347 -0.0196351105 0.0274457405 -0.0197615486 0.0100781716 -0.029350047 -0.029169017400000004 -0.034066302799999996 0.0613985992 -0.0240219257 -0.038671841299999996 0.0606087335 -0.0186691079 -0.239108 0.109027 0.319032 -0.000855789 -0.00347408 0.00261062 -422.9940185546875 351.74468994140625 345.89935302734375 1.0179 61.350899 0.058277549999999914 0.044980719599999996 0.0388065309 0.0314733021 0.0102872676 -0.0160080667 -0.07114038240000001 -0.0159623464 -0.0183381406 0.0186001831 -0.01911889 -0.0022809312 0.0241486519 -0.0294929706 -0.033449925 0.061490875 -0.0253717058 -0.0372205242 0.060976532199999996 -0.0211090908 -0.239021 0.1278 0.314715 -0.00124426 -0.00378762 0.00261062 -420.0005493164063 351.4852294921875 345.6397705078125 0.9854520000000002 59.395176 0.11547944999999996 0.049970423 0.0409867702 0.0415755323 0.0446576617 -0.015918626 -0.011482043999999999 -0.0138804619 -0.0230172463 0.0142293099 -0.0217899453 0.0241337044 0.0407006636 -0.0298158718 -0.032828774399999996 0.061563409699999995 -0.0267070056 -0.0357360162 0.061266033600000006 -0.023512181899999998 -0.23909 0.0831601 0.324432 -0.000268039 -0.00354277 0.00261062 -419.77874755859375 351.7409362792969 345.9888000488281 0.9620820000000002 57.986626 0.15881895000000001 0.0257785591 0.030920624700000003 0.036847313300000004 0.0623546788 -0.04241853190000001 0.019138481399999997 -0.0144525498 -0.0128197185 0.0163072796 -0.026480350899999998 0.009546998499999999 0.052247860800000004 -0.0301377094 -0.0322029395 0.061616180199999995 -0.0280270631 -0.0342196412 0.0614768659 -0.025874181200000002 -0.232227 0.12533200000000003 0.362065 -0.00109217 -0.00390842 0.00286386 -421.4137878417969 351.4993591308594 346.0808410644531 0.948517 57.169018 0.13293990000000008 0.0241768774 0.0216466076 0.0267440806 0.0632782305 -0.032641542200000005 0.0319893767 -0.0153144977 -0.0196070669 0.009989455999999999 -0.023494488900000002 0.0096383724 0.0611890787 -0.0304584719 -0.0315725097 0.061649169299999994 -0.0293311248 -0.0326727513 0.0616087584 -0.0281909609 -0.239098 0.102255 0.320878 -0.000592462 -0.00351614 0.00251975 -419.7642211914063 351.5432434082031 345.8372497558594 0.955116 57.566761 0.03203845 0.0118799146 0.011933361799999999 0.0194238104 0.0819066423 -0.0290689906 0.052364873099999994 -0.0121584906 -0.0207505289 0.008646064200000001 -0.015994832 0.0020155634 0.0765288251 -0.0307781479 -0.0309375749 0.061662366600000004 -0.030618446400000002 -0.031096726 0.0616615418 -0.0304584719 -0.23592 0.0999434 0.319537 -0.000260585 -0.00343473 0.00261062 -421.5929260253906 351.73516845703125 346.27178955078125 0.966336 58.243 0.15059984999999998 0.000633771 0.007841551700000001 -0.0163623639 0.0679138036 -0.0269585205 -0.0194229671 -0.016341434 -0.0103828397 0.0248953853 -0.0079488724 0.0020822947 0.062367779000000005 -0.031096726 -0.030298225699999997 0.0616557679 -0.0318882933 -0.0294929706 0.0616351482 -0.0326727513 -0.23897 0.144208 0.326903 -0.00147626 -0.00390842 0.00283964 -420.1165771484375 351.8448181152344 345.89190673828125 0.953413 57.464108 0.15674035000000003 -0.009511133599999999 0.0112226854 -0.026039204700000002 0.0668771873 0.0012041023 0.017780471000000003 -0.015233263700000001 -0.0151531919 0.0256219338 -0.008693718100000001 0.0054927089000000005 0.0629778146 -0.0314141948 -0.0296545534 0.061629375099999995 -0.0331399408 -0.0278629153 0.0615296116 -0.0348299293 -0.239051 0.0925071 0.311498 -0.000116481 -0.00363435 0.00268242 -422.8116149902344 351.4920654296875 346.3127136230469 1.015889 61.229706 0.06385375000000003 -0.011790484399999999 0.013517756899999999 -0.05815406 0.047572385700000004 0.0192631501 -0.0745543775 -0.0096448552 -0.0075579220999999995 0.029073036099999998 -0.0096387113 -0.0036768126 0.032135140699999995 -0.031730543 -0.0290066498 0.061583196900000005 -0.0343726744 -0.0262080137 0.0613450675 -0.0369262359 -0.239078 0.121337 0.32677 -0.000438048 -0.00358347 0.00270447 -422.470947265625 352.1724548339844 346.3076171875 1.001201 60.344433 0.06401160000000002 -0.0089600835 0.020398033700000002 -0.0707835758 0.0033972628 0.0121933124 -0.035735455 -0.020784874 -0.005040052 0.0401812994 -0.020351656399999998 -0.020245731200000002 -0.0180856577 -0.032045759300000004 -0.0283546073 0.061517248 -0.0355857906 -0.024529741400000003 0.0610817528 -0.0389580073 -0.238882 0.126617 0.309776 -0.00050901 -0.00424884 0.00279897 -420.9900817871094 351.466796875 345.5939025878906 0.992423 59.815353 0.10382825000000001 0.008642125 0.0356348545 -0.052470708399999996 -0.0479489541 0.005393960600000001 0.0386035891 -0.0129710153 -0.0167328304 0.0291945921 -0.023454275099999998 -0.0085552651 -0.0645480718 -0.0323598325 -0.027698518999999998 0.0614315496 -0.0367785971 -0.0228295951 0.0607400057 -0.0409216928 -0.234075 0.0974146 0.298531 0.000222187 -0.0038151 0.00279243 -420.85333251953125 351.18255615234375 345.5420837402344 1.010029 60.876503 0.11520325000000002 0.0238616994 0.0478588095 0.0032307022 -0.0543540157 -0.0040707380999999996 0.0441912279 -0.0139804593 -0.0189388388 0.03168946 -0.0074028259 -0.0123741256 -0.0516129656 -0.0326727513 -0.0270384785 0.061326129199999996 -0.0379504132 -0.0211090908 0.060320264900000004 -0.0428138604 -0.233282 0.11846400000000003 0.325979 -0.00084999 -0.00391347 0.00294014 -420.587646484375 351.61083984375 345.6195373535156 1.018208 61.369457 0.07042115 0.0480965005 0.0343151731 0.0342079119 -0.0314828169 0.0132165532 -0.048292319900000005 -0.0143470376 -0.0184863023 0.011768637700000001 -0.0197600065 0.017382806 -0.0179098045 -0.0329845047 -0.02637458 0.061201020700000004 -0.0391005699 -0.0193697628 0.0598230695 -0.044631203099999996 -0.238921 0.120498 0.304895 -0.000333807 -0.00413634 0.00303437 -420.0545349121094 351.0417785644531 345.4137878417969 0.99185 59.780785 0.07814894999999998 0.0534678335 0.0308075246 0.0532008375 0.0132956749 0.0156859619 -0.061138613499999994 -0.009399479300000001 -0.029313592000000003 0.008779002 -0.0204073434 0.0185584784 0.0182615811 -0.0332950814 -0.025706918199999998 0.0610562642 -0.0402284109 -0.0176131622 0.059249057800000005 -0.046370545 -0.238962 0.09501200000000003 0.314811 0.000216932 -0.00392023 0.0029471 -419.06982421875 351.9185791015625 346.1664123535156 0.987348 59.509464 0.1546751 0.0392982427 0.0170774649 0.0574791096 0.026759553 0.0029394838 -0.0239683507 -0.0167098779 -0.0159033403 0.0087853367 0.0015374256 0.0194066355 0.0507207215 -0.0336044704 -0.0250355883 0.0608919062 -0.0413332925 -0.0158408552 0.058598967 -0.0480288462 -0.266087 0.10709 0.299248 -0.00105132 -0.00450458 0.00309268 -418.26556396484375 349.0462341308594 343.4554443359375 1.436316 86.569702 1.4229131 -0.0427083697 -0.0464129349 0.0996567479 -0.025932069199999998 -0.0622545584 -0.056743373 0.0537379838 0.058069927400000006 -0.0341438924 0.0293938108 0.019196724499999998 0.0161411588 -0.0339126607 -0.024360686200000002 0.060707999400000004 -0.0424145842 -0.0140544224 0.0578736318 -0.0496032084 -0.8630799999999998 -0.0970921 0.341567 -0.00682284 -0.00975399 0.00366013 -421.3774719238281 351.5942077636719 346.9112548828125 1.568912 94.561485 1.4925633999999999 0.045151076799999995 -0.0481377521 0.035285227200000005 0.0056501936 0.0311654002 -0.0245838443 -0.012504237 -0.043940126399999994 -0.0627044912 0.0085711408 -0.0777075185 0.0510852912 -0.0342196412 -0.0236823082 0.060504603 -0.0434716687 -0.012255456699999999 0.0570739836 -0.0510908803 -0.339639 0.0410516 0.0332948 0.00264788 -0.00967867 0.00275204 -420.4640808105469 352.61004638671875 348.0830993652344 1.110303 66.92023500000002 0.5170956499999999 0.0280117584 -0.0312860258 0.0214475091 -0.0116762011 -0.0036325454999999998 0.035240392999999995 -0.0180002156 -0.009877961 -0.0265741096 0.0385922851 -0.0134685953 -0.006011544200000001 -0.0345254011 -0.023000551 0.0602817821 -0.0445039428 -0.0104455625 0.056201049100000004 -0.05248926190000001 -0.29743 0.11095600000000001 0.152784 -0.000329981 -0.00762056 0.00342593 -420.7907409667969 352.89971923828125 348.29644775390625 0.993989 59.909744 0.2323024 0.028079520299999997 -0.016826168 0.028160857 -0.0282361845 -0.0312581787 0.0534924395 -0.0252868346 -0.0111549777 -0.0184126066 0.027341874199999998 -0.0027492488 -0.0269027943 -0.0348299293 -0.022315511899999998 0.0600396084 -0.0455108174 -0.0086263535 0.0552559492 -0.0537959092 -0.28358 0.0257528 0.221097 9.1163e-05 -0.00686975 0.0035527 -426.1314086914063 353.28369140625 348.26312255859375 1.062628 64.046722 0.13964239999999997 0.044758226799999995 -0.0141650696 0.037351755699999996 -0.0186145734 -0.022651257799999998 -0.0918327185 -0.029208951 -0.0027196233 -0.045858729400000006 0.0185695111 0.018519311200000003 -0.0094021441 -0.0351332152 -0.0216272887 0.0597781596 -0.046491717800000006 -0.006799452199999999 0.054239897599999996 -0.055008538600000004 -0.323266 0.0588256 0.196565 0.000184775 -0.00629649 0.00373286 -423.09552001953125 352.0726623535156 345.57373046875 1.187228 71.55661 0.52537445 0.034151144700000004 -0.0287410289 0.0500722962 -0.0158047363 0.0357959251 -0.020956825 -0.013804329399999999 -0.0464800134 -0.0937738173 -0.0171423639 0.0223064898 0.0046543436 -0.0354352477 -0.020935979599999998 0.0594975196 -0.0474460842 -0.0049664875 0.053154198799999997 -0.0561250309 -0.372226 0.0783868 0.0387735 0.00549274 -0.00573658 0.0036195 -422.4729919433594 352.69287109375 347.9078674316406 1.154509 69.58457900000002 0.46285275 0.0306520525 -0.0345743506 0.0266529138 -0.027237978599999997 0.0157238044 0.0251656874 -0.022939702000000003 -0.006732343199999999 -0.060804915099999995 0.0171744536 0.0159458586 -0.027209941600000002 -0.0357360162 -0.0202416832 0.0591977785 -0.048373371799999995 -0.0031290940000000002 0.0520002471 -0.057143434800000004 -0.30472 0.15937 0.111606 0.000892309 -0.00557319 0.0035527 -424.6060791015625 353.07427978515625 348.17266845703125 1.011044 60.937695 0.18611735000000001 0.0262122463 -0.0360970358 -0.0113536629 -0.0348832011 -0.0169344164 0.038087568100000004 -0.0302962085 -0.0013875878 -0.0402574375 0.026791249 -0.0105860456 -0.0343758943 -0.036035509900000005 -0.0195444986 0.0588790326 -0.049273051500000005 -0.0012889102 0.050779524000000006 -0.0580619705 -0.29082 0.145254 0.17105 -0.000321398 -0.0061735 0.00371183 -422.3190307617188 352.7900390625 347.19244384765625 1.013808 61.104256 0.26793710000000004 0.0368386929 0.0073427868999999995 0.0105617704 -0.0454859374 -0.0070162127 0.0507766016 -0.0322779495 -0.022536824 -0.0231848076 -0.0008651514999999999 0.013295710300000001 -0.047037525 -0.0363337182 -0.0188445253 0.0585413841 -0.0501446098 0.0005524229 0.049493597199999996 -0.0588790326 -0.273138 0.0614688 0.225539 0.00151493 -0.00595564 0.00389726 -424.8175354003906 351.9634094238281 346.4662780761719 1.089061 65.63990800000002 0.16388470000000002 0.061596839800000004 0.0032109389000000003 0.0315267531 -0.030533694500000003 0.0096191929 -0.0849268532 -0.0233790778 -0.023355925299999997 -0.0180870753 -0.0028433409999999997 0.0106175024 -0.0116614878 -0.0366306304 -0.0181418631 0.058184941500000004 -0.0509875493 0.0023932635000000002 0.048144117699999996 -0.059593193200000005 -0.255587 0.137606 0.241498 0.00078356 -0.00617676 0.00402952 -422.3478393554688 351.45587158203125 345.76385498046875 1.032182 62.211716 0.108923 0.0497413094 -0.018536565300000002 0.0258010407 0.031364411 0.0040120957 -0.0055225437 -0.0149559864 -0.030149668199999997 -0.0310847456 0.009740357600000001 0.0026189696 0.021750458900000002 -0.0369262359 -0.0174366123 0.057809819299999995 -0.0518013888 0.0042319699 0.046732818499999995 -0.0602032042 -0.242794 0.127156 0.244011 0.00147122 -0.0068248 0.00435716 -419.2281494140625 350.97857666015625 344.7453918457031 0.992692 59.831581 0.08466749999999998 0.0348095276 -0.0223317969 0.014574410800000001 0.0557634912 0.0145039634 0.06632855780000001 -0.0135319455 -0.0378466331 -0.0365551147 -0.0027290113 0.00944728 0.0398581441 -0.0372205242 -0.0167288735 0.057416137699999995 -0.052585664000000004 0.0060669025 0.0452615117 -0.060707999400000004 -0.245449 0.110229 0.232639 0.00217939 -0.00646389 0.00436235 -420.5752868652344 351.4612731933594 344.791748046875 0.999825 60.261452 0.14300600000000002 0.0025642931 -0.037649743 -0.0268968861 0.0661978361 0.0376993979 0.005742578199999999 -0.010249352199999999 -0.0266560759 -0.0210126958 0.0097272178 -0.0305091848 0.0441610808 -0.0375134847 -0.0160187477 0.0570040233 -0.0533399272 0.007896425 0.0437320865 -0.0611066967 -0.23995 0.170372 0.225857 0.00154999 -0.00712563 0.00448285 -418.60986328125 351.2239074707031 344.4762878417969 1.025423 61.804321 0.148962 -0.0009187987 -0.023025967400000003 -0.050645346699999996 0.0490300254 0.0416764938 0.0161001392 -0.0050857817999999996 -0.025063035499999997 -0.0171083651 0.0100724818 -0.018180431 0.021308102599999997 -0.0378051071 -0.015306336299999999 0.0565736083 -0.054063747800000006 0.009718906 0.0421465068 -0.0613985992 -0.25152 0.108281 0.228501 0.00279199 -0.00704796 0.00434938 -419.7780151367188 351.1497497558594 344.9977722167969 1.035685 62.422844 0.1653135 -0.0171334409 -0.0193118284 -0.0735812729 0.0321877783 0.0411381562 -0.0234386461 -0.00507096 -0.023573141000000002 -0.0097287454 0.0135179942 -0.0341102842 0.015673116299999998 -0.0380953808 -0.0145917409 0.0561250309 -0.0547567129 0.0115327203 0.0405068086 -0.061583196900000005 -0.241149 0.174043 0.214126 0.00195127 -0.00671242 0.00402953 -420.9861755371094 351.3333435058594 345.7593994140625 0.983956 59.304993 0.136672 -0.0024900586 -0.0223691104 -0.0727932416 -0.0027539602000000002 0.0369786327 -0.028127392200000004 -0.0123517018 -0.0138327092 0.0093019138 0.0113528732 -0.0375805374 -0.0260857552 -0.0383842957 -0.0138750634 0.055658435199999995 -0.055418427 0.0133362505 0.038815097400000005 -0.061660167 -0.223141 0.154843 0.237888 0.0010068 -0.00712563 0.00418589 -419.4292907714844 351.51922607421875 345.7696228027344 0.95368 57.480202 0.154135 -0.0101363239 -0.0127263011 -0.07031522429999999 -0.0072413930000000005 0.0425477823 -0.0073646699 -0.010419418100000001 -0.0230755629 0.0015225877 0.0107984845 -0.017747227 -0.022089953399999997 -0.038671841299999996 -0.0131564061 0.0551739708 -0.056048512300000006 0.0151278882 0.037073545299999996 -0.061629375099999995 -0.225909 0.0755725 0.264686 0.00112226 -0.00637229 0.00414872 -422.5391540527344 351.5458984375 346.2972717285156 0.99331 59.868786 0.09324165000000002 0.0007435906 -0.0088808479 -0.0757722708 -0.0347146864 0.0139785137 0.006933953499999999 -0.015652088600000003 -0.0160425703 0.0090240766 0.0056818501 -0.032341437 -0.0517401876 -0.0389580073 -0.012435871599999999 0.0546717934 -0.056646609199999996 0.0169060359 0.0352843888 -0.061490875 -0.221808 0.124771 0.279832 0.000790097 -0.00628739 0.00422758 -421.4190979003906 351.8424072265625 346.0466003417969 0.996511 60.061737 0.0765191 0.030064459300000002 -0.006155646999999999 -0.0373002673 -0.0550091264 0.0214321863 0.0295048204 -0.021355703599999998 -0.0187099967 -0.0092493245 0.0091634614 -0.026237026 -0.0653853502 -0.0392427837 -0.011713562700000001 0.0541520642 -0.0572123765 0.0186691079 0.033449925 -0.0612449087 -0.228247 0.152528 0.247296 0.000875979 -0.00636969 0.00425514 -421.8249206542969 351.82293701171875 345.6173095703125 0.999066 60.215744 0.12351005 0.0484127316 0.0026190826 0.011435261799999999 -0.061812575 0.015167535800000001 0.0191599877 -0.0201692643 -0.022996419700000003 -0.015206345100000001 0.0089799062 0.0006207575 -0.0565394255 -0.0395261602 -0.0109895824 0.05361495 -0.0577454912 0.020415532 0.0315725097 -0.0608919062 -0.22861 0.113153 0.250784 0.00218733 -0.00630097 0.00402953 -422.38189697265625 351.6009216308594 345.6668395996094 1.068634 64.40873000000002 0.20110165 0.0502104756 -0.016926644299999998 0.0293313488 -0.0029377792 -0.000763488 -0.0328569291 -0.0168848136 -0.0168748812 -0.016550026000000002 0.0148851466 -0.0098609422 0.0165083531 -0.0398081268 -0.010264034 0.053060623200000004 -0.058245649000000004 0.0221437508 0.0296545534 -0.0604324842 -0.226211 0.15643399999999996 0.296272 0.000364827 -0.00624478 0.00434951 -420.5960998535156 351.8451843261719 345.13677978515625 1.005516 60.604469 0.14845314999999992 0.0453497663 -0.0268260464 0.004736679000000001 0.0441332887 0.005874332800000001 0.057393618 -0.0195650265 -0.0182916666 -0.0349230533 0.0050343259999999996 0.00015551469999999998 0.030493763700000003 -0.0400886733 -0.0095370211 0.05248926190000001 -0.0587125645 0.0238522233 0.027698518999999998 -0.0598674458 -0.217145 0.116774 0.264919 0.00134365 -0.00617611 0.00402952 -418.92388916015625 350.9462890625 344.8148498535156 0.980357 59.088093 0.038522499999999925 0.0008725984 -0.0372175938 -0.025676630099999997 0.0611059294 0.0233144034 0.0478309214 -0.0090596712 -0.0247666761 -0.0269856633 0.0162297117 -0.0191241619 0.050967423399999996 -0.0403677898 -0.0088086474 0.0519010494 -0.059145971299999996 0.0255394259 0.025706918199999998 -0.0591977785 -0.217133 0.1392 0.275022 0.00134365 -0.00618397 0.00414129 -421.0126647949219 351.3471374511719 345.2958068847656 1.007184 60.705044 0.11184080000000003 -0.0044028034 -0.031975289500000004 -0.0503804201 0.0409745181 0.0449501271 -0.051447616200000004 -0.0091018651 -0.0154957931 -0.0038214097 0.0288008711 -0.0233231025 0.0203564759 -0.0406454662 -0.0080790168 0.0512961746 -0.059545621900000005 0.027203854 0.0236823082 -0.058424652599999995 -0.217081 0.171392 0.285344 0.000274624 -0.00644871 0.00419302 -418.8890686035156 351.1061706542969 344.8015441894531 1.004064 60.516964 0.15524329999999997 -0.0065468733 -0.0121623551 -0.0809509144 -0.007167575799999999 0.0468455658 -0.0080833911 -0.009949921 -0.0201346004 -0.0112972908 0.0231072113 -0.0200708415 -0.0371693415 -0.0409216928 -0.0073482335 0.050674831600000005 -0.059911288300000004 0.028844023599999997 0.0216272887 -0.0575494194 -0.227216 0.114658 0.271802 0.00152863 -0.00631574 0.00408335 -419.6065673828125 350.95562744140625 344.63525390625 0.991268 59.74575 0.11072160000000003 0.0192430509 0.0039507801 -0.044900701900000006 -0.055385047400000005 0.0218977405 0.0590743412 -0.0093862173 -0.0183916295 0.0091995774 0.0063495805 -0.0406411064 -0.0744813919 -0.0411964596 -0.0066164016 0.050037220099999995 -0.060242761799999996 0.0304584719 0.0195444986 -0.0565736083 -0.233222 0.14483 0.300829 0.000706698 -0.00629628 0.00415229 -418.7110290527344 350.68426513671875 344.7242736816406 0.964481 58.131241 0.044644100000000124 0.039812858300000004 0.005251949499999999 -0.007741430600000001 -0.052619886 0.0130840808 0.025501270299999997 -0.006842773199999999 -0.0256415212 -0.0063694469 0.0045377694 -0.0197844854 -0.060714192800000004 -0.0414697568 -0.0058836257 0.0493835445 -0.0605398531 0.032045759300000004 0.0174366123 -0.0554989249 -0.233199 0.14629 0.289967 0.00124514 -0.00639681 0.0041593 -418.6997375488281 351.148681640625 344.94659423828125 0.99062 59.706665 0.05613050000000005 0.0412848583 0.0014078870999999998 0.032436012 -0.0455369565 0.0279453094 -0.0096363213 -0.010562241299999999 -0.0255451166 -0.0193122599 0.0147107041 -0.0015934738 -0.044646205099999996 -0.0417415748 -0.0051500103000000005 0.048714014900000005 -0.0608023928 0.0336044704 0.015306336299999999 -0.054327247300000006 -0.233317 0.124756 0.296371 0.00124514 -0.00596509 0.00402953 -419.0224914550781 351.0936279296875 345.2769775390625 1.027432 61.925388 0.11839174999999998 0.0582157607 -0.012772509 0.0319409587 0.0138603634 0.007021778100000001 -0.030281242599999997 -0.011617181200000002 -0.023789615299999997 -0.030129748199999997 0.010243732 -0.0148066699 0.0162929617 -0.0420119037 -0.00441566 0.0480288462 -0.061030231 0.0351332152 0.0131564061 -0.053060623200000004 -0.233165 0.171355 0.306573 0.0008256249999999998 -0.00653892 0.00426496 -418.2469787597656 350.9664306640625 345.1755065917969 0.988829 59.598732 0.13786774999999998 0.0340829522 -0.023045924500000002 0.016516708 0.0460921739 -0.013266734799999999 0.0630742309 -0.0107308124 -0.032822774900000004 -0.0282865274 0.0044267445 -0.003509633 0.038559604 -0.042280734 -0.0036806797 0.0473282582 -0.061223237699999995 0.0366306304 0.0109895824 -0.0517012663 -0.229438 0.117038 0.291345 0.0020276 -0.00647699 0.00429297 -418.1385803222656 350.6510314941406 345.1667785644531 0.979582 59.041409 0.08105250000000001 -0.0035727810999999997 -0.0368758521 -0.017105248400000002 0.061312665499999995 0.0148426596 0.0529483066 -0.0048930208 -0.0240924404 -0.0108586098 0.0163893037 -0.0107602254 0.0562844112 -0.0425480561 -0.0029451740999999997 0.04661247599999999 -0.061381302699999994 0.0380953808 0.0088086474 -0.0502515524 -0.226519 0.163823 0.301648 0.00176881 -0.00632974 0.0042781 -419.322021484375 351.18682861328125 345.56072998046875 0.993489 59.879604 0.07241714999999997 -0.0093124935 -0.034069369 -0.048402084000000005 0.0446600806 0.0504304331 -0.0399630012 -0.0070483306 -0.0241159562 -0.0006526168 0.0196752687 -0.0154985517 0.022789805 -0.0428138604 -0.0022092484 0.0458817293 -0.0615043357 0.0395261602 0.0066164016 -0.048714014900000005 -0.22113 0.162831 0.299115 0.000946107 -0.00676698 0.00428822 -419.9136352539063 351.31787109375 345.41162109375 0.990019 59.670471 0.17392715 -0.0112979201 -0.0204441241 -0.0815903172 0.0011651585 0.050291491699999996 -0.0304086059 -0.013733061599999999 -0.0222996827 -0.011413415900000001 0.0159576776 -0.0213265696 -0.0204163805 -0.0430781374 -0.0014730073999999998 0.045136252800000005 -0.0615922667 0.0409216928 0.00441566 -0.0470913411 -0.228975 0.112168 0.28106 0.00220493 -0.00624096 0.00412578 -419.70892333984375 351.0538635253906 345.2958679199219 0.986719 59.471577 0.13666300000000003 -0.0009325541000000001 -0.0015074815 -0.0613914222 -0.0482198104 0.007936186500000001 0.0440378064 -0.0084014763 -0.0173103418 0.0097364924 0.0055182669999999994 -0.029953057400000004 -0.0616718932 -0.043340877699999995 -0.0007365563000000001 0.044376285700000004 -0.0616450454 0.042280734 0.0022092484 -0.0453863669 -0.22543 0.164314 0.31439 0.00135024 -0.00623906 0.00402953 -420.0083312988281 351.2267150878906 345.305908203125 0.9790430000000002 59.008919 0.103757 0.0268821644 0.0051051718 -0.0238664991 -0.0626708349 0.0191489225 0.0361193922 -0.015676752 -0.0207469631 -0.0124191631 0.0090439435 -0.0142302434 -0.0663185574 -0.043602072 -0.0 0.043602072 -0.0616626416 0.043602072 0.0 -0.043602072 -0.225589 0.14021800000000004 0.287831 0.00180337 -0.00666753 0.00420679 -418.4749450683594 351.2902526855469 345.12713623046875 0.9876760000000002 59.529247 0.1174825 0.0495170609 0.0026280007 0.0092119516 -0.0551579143 0.0407852449 0.027633895099999996 -0.0164207235 -0.035568266200000004 -0.0199298595 0.0125735665 -0.0104662604 -0.0560686604 -0.043861710899999996 0.0007365563000000001 0.0428138604 -0.0616450454 0.0448845285 -0.0022092484 -0.0417415748 -0.228376 0.1406 0.261194 0.00273639 -0.00608168 0.00397213 -419.9822998046875 351.1683349609375 345.458740234375 1.031149 62.149441 0.16495350000000003 0.0579179976 -0.0080757247 0.0346984465 -0.0120215375 0.0382898554 -0.0415236092 -0.010280294799999999 -0.0200808536 -0.0234720399 0.0019612633 0.0033117848999999998 -0.0041778690999999995 -0.0441197852 0.0014730073999999998 0.0420119037 -0.0615922667 0.0461269599 -0.00441566 -0.0398081268 -0.228359 0.175024 0.30103 0.00125473 -0.00613095 0.00425473 -419.8565673828125 351.4289245605469 345.59130859375 0.991043 59.732185 0.10123850000000001 0.056805089100000004 -0.0300167971 0.0308545096 0.0170885045 0.0063566079 0.0009942288 -0.017101996100000003 -0.0304237276 -0.034941276800000004 0.0045263993 0.0021113754999999997 0.023876295699999998 -0.044376285700000004 0.0022092484 0.0411964596 -0.0615043357 0.0473282582 -0.0066164016 -0.0378051071 -0.228218 0.162516 0.275531 0.00192908 -0.00666753 0.00430561 -418.25531005859375 351.2121887207031 345.2544860839844 0.969216 58.416641 0.10383699999999998 0.0407484892 -0.0358791065 0.0256597637 0.0482668486 0.0035554942 0.0539125237 -0.016464828799999998 -0.0299553754 -0.0416126972 0.0016582820999999999 0.0040142905 0.04312978940000001 -0.044631203099999996 0.0029451740999999997 0.0403677898 -0.061381302699999994 0.0484873523 -0.0088086474 -0.0357360162 -0.226484 0.13593400000000003 0.282081 0.00245506 -0.0060047 0.004115 -418.1759338378906 351.1607971191406 345.63568115234375 0.952877 57.431824 0.14715649999999997 0.028701872000000003 -0.0351265023 0.0010249777999999999 0.052648460599999995 0.0011090207 0.0446112924 -0.0098325896 -0.0227445068 -0.0231141064 0.009336607 -0.0060287843 0.0462650494 -0.0448845285 0.0036806797 0.0395261602 -0.061223237699999995 0.0496032084 -0.0109895824 -0.0336044704 -0.217435 0.169559 0.322811 0.00158545 -0.00627431 0.00425083 -419.2726135253906 351.5273742675781 346.0040588378906 0.939488 56.624874 0.10519800000000001 0.0182229409 -0.0338687055 -0.0108501648 0.0579869982 -0.0034503828000000004 0.0622162856 -0.0131962843 -0.0200389621 -0.0397974513 0.015384211200000001 -0.0016659834 0.0444134672 -0.045136252800000005 0.00441566 0.038671841299999996 -0.061030231 0.050674831600000005 -0.0131564061 -0.0314141948 -0.22445 0.13193 0.301197 0.00204656 -0.00644401 0.00410284 -420.8453674316406 351.4837951660156 346.1204833984375 0.9762900000000002 58.842968 0.05280699999999996 -0.006793975799999999 -0.0517230571 -0.0363095045 0.0583973322 0.0127460116 0.0222390729 -0.0130555854 -0.0226491013 -0.043096626500000006 0.0171374152 -0.0054351101 0.039511206800000004 -0.0453863669 0.0051500103000000005 0.0378051071 -0.0608023928 0.0517012663 -0.015306336299999999 -0.029169017400000004 -0.2254 0.134249 0.284992 0.00266992 -0.00647163 0.00411852 -423.1495666503906 351.3755187988281 346.8636779785156 0.999244 60.226471 0.16088785 0.00044232129999999996 -0.0407450782 -0.06797435660000001 0.020936735 0.0262064889 -0.0797020017 -0.0098704903 -0.012224295500000001 -0.0096882827 0.0265693889 -0.0287361013 0.0075319943999999995 -0.0456348621 0.0058836257 0.0369262359 -0.0605398531 0.0526815972 -0.0174366123 -0.0268728619 -0.215104 0.177588 0.3028 0.000951953 -0.00650979 0.00415129 -420.6086120605469 351.677001953125 346.87945556640625 0.994784 59.957638 0.10820585 -0.0056418377 -0.0292997571 -0.07544255230000001 -0.0263560917 0.0151979122 -0.0117712867 -0.015842258600000002 -0.013487238300000001 -0.0171775725 0.015481478600000001 -0.0192596417 -0.0532682268 -0.0458817293 0.0066164016 0.036035509900000005 -0.060242761799999996 0.05361495 -0.0195444986 -0.024529741400000003 -0.224103 0.127543 0.305769 0.00169338 -0.0065379 0.00430561 -417.4042053222656 345.8686828613281 339.31640625 1.815561 109.427567 1.4955414499999997 -0.11251557539999998 -0.0319293507 0.0384494658 -0.08004535509999999 0.0138116003 0.0154164325 0.0995342205 0.013283488000000001 -0.0146936464 0.0569853408 0.1381705775 -0.0880710751 -0.0461269599 0.0073482335 0.0351332152 -0.059911288300000004 0.0545004924 -0.0216272887 -0.0221437508 -0.762541 0.0473839 0.608691 -0.000616837 0.00182493 0.00511301 -401.0535888671875 334.28424072265625 328.3331298828125 2.575937 155.256927 2.88368305 -0.17067805 -0.0718612143 0.1256120224 -0.08663171630000001 -0.045284629800000004 0.1150823816 0.28378178579999996 0.0850674557 -0.1532921886 -0.047339258200000005 0.17780082649999998 -0.1862327669 -0.046370545 0.0080790168 0.0342196412 -0.059545621900000005 0.0553374348 -0.0236823082 -0.0197190601 -0.905875 -0.370703 1.10652 -0.0302639 0.00415559 0.00962395 -425.2228088378906 355.01593017578125 350.12860107421875 2.592037 156.227341 2.73717 -0.0631876168 -0.0367112126 0.0375583492 -0.08489829550000001 -0.1203590783 -0.030600706600000003 0.0200725275 0.1991905382 -0.0259916984 0.0187745629 0.0290272092 -0.048963395 -0.04661247599999999 0.0088086474 0.0332950814 -0.059145971299999996 0.0561250309 -0.025706918199999998 -0.0172599069 -0.427198 -0.113192 0.719928 -0.0111408 -0.00221785 0.00283269 -418.3553466796875 352.34033203125 346.60186767578125 1.045631 63.022274 0.28534877 -0.0573264199 -0.0166716833 0.048244563399999996 -0.0617467501 -0.11541549970000001 0.0002953114 0.04103142 0.1445303319 -0.0035610747 0.0153524409 -0.006951460600000001 -0.009903948499999999 -0.0468527442 0.0095370211 0.0323598325 -0.0587125645 0.0568625783 -0.027698518999999998 -0.0147705889 -0.417668 0.00112527 0.677739 -0.00938627 -0.00263223 0.00261535 -423.639892578125 351.9698791503906 346.49847412109375 1.013276 61.072227 0.34659593000000005 -0.042291536399999996 -0.0134743655 0.0470948822 -0.049094894800000004 -0.0801538021 -0.088309666 0.0279944798 0.1099328259 0.0166073222 0.0181485594 0.0087418062 0.0017438274 -0.0470913411 0.010264034 0.0314141948 -0.058245649000000004 0.0575494194 -0.0296545534 -0.012255456699999999 -0.360807 0.0320167 0.657141 -0.00669935 -0.00403342 0.00329215 -419.926513671875 351.51007080078125 345.4720458984375 0.915439 55.175354 0.16992030000000002 -0.0424826175 -0.001135014 0.0740451466 -0.0415815099 -0.0655700278 -0.0848999075 0.0312413879 0.09372581449999999 0.014617131200000001 0.011020733500000001 0.0119122864 0.0307375119 -0.0473282582 0.0109895824 0.0304584719 -0.0577454912 0.058184941500000004 -0.0315725097 -0.009718906 -0.34151 0.061943 0.678027 -0.00511095 -0.00376925 0.0031485 -422.8182678222656 351.62860107421875 345.5771484375 0.942178 56.786961 0.13373820000000008 -0.030593648199999997 -0.01709482 0.0468818349 0.0027989356 -0.0854532959 -0.0417944135 0.0219287457 0.0898018914 0.0098331649 0.0099747337 0.0023751913 0.0547919597 -0.047563487 0.011713562700000001 0.0294929706 -0.0572123765 0.058768578200000005 -0.033449925 -0.007165369699999999 -0.334897 0.0999337 0.624597 -0.00492425 -0.00420071 0.00324443 -420.1407775878906 351.92596435546875 345.08807373046875 0.933395 56.257614 0.14430920000000003 -0.046250888399999995 -0.0104052451 0.0418692257 0.027629508900000002 -0.0698781673 0.029967650699999997 0.0155130674 0.0766410858 0.0177124903 0.006694430899999999 -0.0023744721 0.0651697684 -0.047797019100000004 0.012435871599999999 0.0285180009 -0.056646609199999996 0.0592998088 -0.0352843888 -0.0045993107 -0.324179 0.079351 0.642793 -0.0033767 -0.00394794 0.0031485 -419.969482421875 351.41015625 344.58746337890625 0.937462 56.502728 0.05003750000000005 -0.0597244308 -0.0174657837 0.0205170324 0.0269800332 -0.0288500662 -0.0334259043 0.0218315533 0.0753971016 0.0236579162 0.014848971499999999 -0.0007724815 0.049795287199999996 -0.0480288462 0.0131564061 0.0275338758 -0.056048512300000006 0.0597781596 -0.037073545299999996 -0.0020252136 -0.321165 0.111542 0.64354 -0.0033315 -0.00379147 0.00322854 -419.63848876953125 351.3443298339844 344.4804992675781 0.9451250000000002 56.964588 0.09698099999999997 -0.0702521775 -0.008285513199999999 -0.0160535626 0.0122015653 -0.0204324544 -0.0839466698 0.024480403300000002 0.0758313641 0.0313017635 0.0126319972 -0.0156306957 0.027322829500000003 -0.0482589599 0.0138750634 0.0265409112 -0.055418427 0.0602032042 -0.038815097400000005 0.0005524229 -0.318907 0.123564 0.619648 -0.00372831 -0.0044908 0.0031485 -419.18048095703125 351.6879577636719 344.4288330078125 0.939796 56.643387 0.18094659999999999 -0.050443025 0.005534635600000001 -0.037074899700000004 -0.028419983 -0.042817195 -0.0182192523 0.011159026499999999 0.0684213087 0.027278775699999997 0.0095198262 -0.0216319788 -0.0044323109999999995 -0.0484873523 0.0145917409 0.0255394259 -0.0547567129 0.060574563399999996 -0.0405068086 0.0031290940000000002 -0.323167 0.07629289999999998 0.57046 -0.00252792 -0.00419752 0.00303762 -414.00384521484375 349.22418212890625 342.68914794921875 1.070049 64.494019 0.21908610000000006 -0.052708152 0.0079182766 0.006513110600000001 -0.0498609782 0.0098148278 0.046777630199999996 0.0403207359 0.020822224 0.0502541846 0.036897208 0.0047291051 -0.035526673700000004 -0.048714014900000005 0.015306336299999999 0.024529741400000003 -0.054063747800000006 0.0608919062 -0.0421465068 0.0057002965 -0.348077 0.1267 0.587486 -0.00220837 -0.00530706 0.00414339 -418.7090759277344 349.62359619140625 343.7303161621094 1.170467 70.546387 0.27178749999999996 -0.0023893981 -0.0012341646 0.0010100944 -0.0599368187 -0.042336403099999996 -0.0149318939 0.0170941302 0.0335885442 0.061626487 0.0642324026 -0.0651830978 -0.0364550176 -0.0489389399 0.0160187477 0.023512181899999998 -0.0533399272 0.061154949400000005 -0.0437320865 0.008261536600000001 -0.33583 0.120377 0.482186 -0.00366936 -0.00653068 0.00441713 -418.1610107421875 351.3200378417969 344.73492431640625 1.027613 61.936337 0.3126884999999999 -0.00497006 0.0126512642 0.0092579247 -0.048705720099999995 -0.0238414612 0.0185339692 0.0021065032 0.0396825623 0.0408272371 0.0154864176 -0.026147606299999997 -0.0342736809 -0.0491621191 0.0167288735 0.022487074 -0.052585664000000004 0.0613634587 -0.0452615117 0.010808338300000001 -0.267649 0.07413999999999998 0.510834 -0.00239147 -0.00558849 0.00324476 -417.489990234375 351.2864990234375 345.44915771484375 0.958321 57.759937 0.2731505 -0.005074735 0.0048890231 0.0100420673 -0.0439744171 -0.0401060691 0.0436617433 0.0065404204 0.0432167931 0.0451264027 0.0184506455 -0.0308237434 -0.0192929216 -0.0493835445 0.0174366123 0.0214547469 -0.0518013888 0.061517248 -0.046732818499999995 0.0133362505 -0.228217 0.12664 0.503393 -0.0033686 -0.007427279999999999 0.00390439 -420.375 351.4151611328125 345.7641296386719 0.941575 56.750648 0.13407300000000003 0.0029069583 0.0006707944 0.01951861 -0.0424534078 -0.043066507999999996 -0.003712255 0.00037523389999999997 0.0292738718 0.030870213799999997 0.0151870187 -0.0236009473 -0.0233004292 -0.0496032084 0.0181418631 0.020415532 -0.0509875493 0.061616180199999995 -0.048144117699999996 0.0158408552 -0.229209 0.110662 0.509117 -0.00173758 -0.00692563 0.00380948 -421.5080261230469 351.2952575683594 345.37066650390625 0.944269 56.913033 0.10424134999999994 0.006769233100000001 0.0107000132 0.0462590807 -0.036804540499999996 -0.0186319823 -0.0682190437 -0.0005088801999999999 0.016836226200000002 0.0270132743 0.0115917556 -0.0050701923 -0.0025186732 -0.0498211028 0.0188445253 0.0193697628 -0.0501446098 0.061660167 -0.049493597199999996 0.0183177752 -0.229202 0.132987 0.531374 -0.0007804529999999999 -0.006979 0.00399203 -422.3573303222656 351.1561584472656 345.1759033203125 0.9709120000000002 58.518856 0.08516925000000002 0.011782864399999999 -0.0104401049 0.0295348583 0.0134491946 -0.0446254108 -0.035952914100000004 -0.0047222736 0.0117259652 0.011107481 0.0125608466 -0.0122373499 0.029286481200000002 -0.050037220099999995 0.0195444986 0.0183177752 -0.049273051500000005 0.061649169299999994 -0.050779524000000006 0.0207626817 -0.237238 0.153295 0.494315 -0.000455538 -0.00701308 0.00402836 -418.3320007324219 350.81591796875 344.63946533203125 0.948377 57.160614 0.07644943699999998 -0.0015822092999999999 -0.0080473671 0.0187765725 0.0407474619 -0.0472832754 0.0504368258 -0.0013037927 0.0024553631 0.0043466603 0.006777021899999999 -0.0062910506000000005 0.049837899000000005 -0.0502515524 0.0202416832 0.0172599069 -0.048373371799999995 0.061583196900000005 -0.0520002471 0.023171301800000002 -0.234322 0.12175 0.501665 -9.44926e-06 -0.00684928 0.00394548 -419.0291442871094 350.73736572265625 344.4247131347656 0.950617 57.295597 0.09088003700000002 -0.027714285 -0.024207819300000002 -0.0129071285 0.055317900700000006 -0.0104183468 0.0112526458 0.0035382645 0.0069669703 0.0124798852 0.012185829799999999 -0.021004904799999998 0.0581835422 -0.050464092099999996 0.020935979599999998 0.0161964974 -0.0474460842 0.06146230849999999 -0.053154198799999997 0.0255394259 -0.218651 0.152611 0.492772 -0.00021678 -0.00645179 0.00404976 -419.9078369140625 350.88800048828125 344.8514709472656 0.969725 58.447292 0.09394499999999993 -0.025154659500000003 -0.017485806899999998 -0.0391330298 0.024779842200000003 0.0154465992 -0.0712701306 0.0027627305 0.012742018700000001 0.023055723900000002 0.0103685167 -0.0312163181 0.0202162335 -0.050674831600000005 0.0216272887 0.0151278882 -0.046491717800000006 0.0612866121 -0.054239897599999996 0.0278629153 -0.230683 0.183195 0.484036 -0.00089585 -0.00658135 0.00409299 -418.627685546875 350.71728515625 344.50482177734375 0.961652 57.960705 0.16299870000000002 -0.0337426801 0.0005515402 -0.0530740027 -0.0105213819 0.0256303583 -0.0109153564 0.0006183795999999999 0.0035179946 0.033717347200000004 0.0192872366 -0.0312738584 -0.0221996944 -0.0508837635 0.022315511899999998 0.0140544224 -0.0455108174 0.0610562642 -0.0552559492 0.0301377094 -0.230936 0.123349 0.478599 0.000327734 -0.00616933 0.00377934 -419.7203674316406 350.65936279296875 344.578369140625 0.952331 57.398903 0.07777364999999999 -0.0186221546 0.0160508994 -0.053826232800000005 -0.056643099 -0.0029074471 0.0379722769 -0.000575173 0.0015488459 0.0431091012 0.0088690742 -0.025336368199999997 -0.0631064853 -0.0510908803 0.023000551 0.0129764445 -0.0445039428 0.0607714702 -0.056201049100000004 0.0323598325 -0.231985 0.148855 0.466632 0.000442607 -0.00556147 0.00371704 -418.13525390625 350.9497985839844 344.756103515625 0.937633 56.513058 0.12380815000000002 0.00036187510000000003 0.0187234394 -0.0083638586 -0.0507183005 -0.0059237790000000005 0.0458637684 0.0010292075999999999 0.0078310507 0.031556403399999995 -0.0012147421 -0.0161701065 -0.045829792599999995 -0.0512961746 0.0236823082 0.0118943007 -0.0434716687 0.0604324842 -0.0570739836 0.0345254011 -0.236237 0.177375 0.479539 -0.000426376 -0.00616443 0.00380768 -418.9403076171875 351.10467529296875 345.0097961425781 0.938392 56.558765 0.10957804999999998 0.0143785644 0.0216160915 0.0199830614 -0.0524627204 -0.0049021993 0.0007415027 -0.0026392271 -0.0009759616999999999 0.024780247400000004 0.0096317733 -0.0023311529000000003 -0.0352944101 -0.05149963900000001 0.024360686200000002 0.010808338300000001 -0.0424145842 0.0600396084 -0.0578736318 0.0366306304 -0.23638 0.149087 0.47627 0.000798465 -0.00592235 0.00371704 -419.78643798828125 350.8863830566406 345.4639892578125 1.001771 60.378754 0.05696884999999996 0.0208170322 0.0168423264 0.0371791512 -0.0323974846 0.0082724806 -0.0662129578 -0.0008615541000000001 2.0941300000000002e-05 0.018568343799999998 -0.0022218392000000003 -0.0055745462 -0.0083415891 -0.0517012663 0.0250355883 0.009718906 -0.0413332925 0.059593193200000005 -0.058598967 0.038671841299999996 -0.22889 0.168904 0.477898 0.000267158 -0.00589298 0.00371704 -420.4014587402344 350.7684631347656 345.54400634765625 0.971542 58.556782 0.05882003000000001 0.0277686364 -0.0062234356000000005 0.0302384151 0.0190729319 -0.0204543746 -0.0262468795 -0.0012848293 -0.0034238502 6.77657e-05 0.0058437004 -0.0060586560999999995 0.030137306099999997 -0.0519010494 0.025706918199999998 0.0086263535 -0.0402284109 0.0590936366 -0.059249057800000005 0.0406454662 -0.241789 0.175635 0.46773 -9.46626e-05 -0.0061116 0.00371704 -418.5499267578125 351.0373840332031 345.298583984375 0.944894 56.950672 0.10593753000000004 0.0147674458 -0.012813442 0.0227944074 0.043499028099999996 -0.029141160699999998 0.0392172895 -0.0031365529 -0.0040708296 -0.0098617518 -0.005541515 -0.0017562951999999998 0.0371923318 -0.052098980999999996 0.02637458 0.0075310317 -0.0391005699 0.0585413841 -0.0598230695 0.0425480561 -0.242714 0.13504 0.473003 0.000674008 -0.00575616 0.00365826 -418.80108642578125 350.8735656738281 345.5841369628906 0.947787 57.125031 0.1226045 -0.0035168126 -0.013847573 0.0031612231 0.0504453708 -0.0268678526 0.0238292827 0.001502356 0.0023336695 0.0022684587 -0.009782470500000001 -0.006127095999999999 0.0519638242 -0.052295054199999996 0.0270384785 0.0064332921 -0.0379504132 0.0579369282 -0.060320264900000004 0.044376285700000004 -0.24345 0.18418 0.479026 -0.000250792 -0.00610669 0.00371704 -416.5093078613281 350.900390625 345.2369689941406 0.919721 55.43346 0.09366540000000002 -0.0206116948 -0.012135233300000001 -0.0004889139 0.046414383200000006 -0.0143984892 0.0525787595 -0.0025428385999999997 -0.0029410406 0.007639293 0.0072782911 -0.0071778373999999995 0.047803121100000005 -0.05248926190000001 0.027698518999999998 0.005333487099999999 -0.0367785971 0.0572808079 -0.0607400057 0.0461269599 -0.235468 0.151361 0.47156 0.000657176 -0.00610669 0.00371704 -420.34857177734375 351.2936096191406 345.578857421875 0.939917 56.650684 0.04103350000000004 -0.023809936099999998 -0.0223178375 -0.026657696 0.0381799834 0.0231826352 -0.0173189653 -0.0032868319 0.003843613 0.0039814033 0.0169849896 -0.0144150316 0.045490514800000006 -0.0526815972 0.0283546073 0.0042319699 -0.0355857906 0.0565736083 -0.0610817528 0.047797019100000004 -0.232791 0.156093 0.475802 0.000515596 -0.00572694 0.00365072 -421.6963806152344 351.34075927734375 346.02294921875 0.962 57.981709 0.14948014999999998 -0.014243899499999999 -0.0208441785 -0.037484076 0.0150072219 0.017831583300000002 -0.07287896099999999 -0.0068843119 0.0064787648 0.0217066118 -0.0037820347 -0.0192081433 0.0202706589 -0.052872053200000005 0.0290066498 0.0031290940000000002 -0.0343726744 0.05581596 -0.0613450675 0.0493835445 -0.235539 0.193061 0.452102 -0.000595207 -0.00610669 0.00388145 -420.2373352050781 351.41107177734375 345.3829345703125 0.938735 56.579456 0.14608935 -0.029496871400000003 -0.0022655346 -0.050290697599999996 -0.0046379595 0.026824814300000003 -0.0440001675 -0.0072219632 -0.002942738 0.0118555014 0.0035415177000000003 -0.0127555841 -0.0113043046 -0.053060623200000004 0.0296545534 0.0020252136 -0.0331399408 0.055008538600000004 -0.0615296116 0.0508837635 -0.234946 0.145817 0.451785 0.00107338 -0.00603379 0.00366423 -420.4018249511719 350.7237548828125 345.14306640625 0.945062 56.960773 0.1317968 -0.0248406847 0.007390821 -0.058046083600000006 -0.0271540311 -0.0047840873999999995 -0.009177106800000001 -0.0041129113 0.0036086683000000003 0.030896833199999998 7.32259e-05 -0.0313543862 -0.0379862376 -0.0532473004 0.030298225699999997 0.000920683 -0.0318882933 0.0541520642 -0.0616351482 0.052295054199999996 -0.233642 0.188947 0.48118 0.000292084 -0.00615622 0.00391986 -420.4996948242188 351.0235290527344 345.00054931640625 0.936354 56.435978 0.10370185 -0.0099958689 0.0101450884 -0.04644595 -0.0355689447 0.017335723600000002 0.0080697349 -0.0071041714 -0.0038586634 0.0083178916 -0.001035605 -0.0045829191 -0.0460206149 -0.053432078200000004 0.0309375749 -0.0001841432 -0.030618446400000002 0.0532473004 -0.0616615418 0.05361495 -0.233016 0.157022 0.457933 0.000927371 -0.00627619 0.00371704 -418.3293151855469 350.9952392578125 344.46368408203125 0.929517 56.023869 0.0657309500000001 -0.0085167705 0.0185832579 -0.0341031294 -0.046043016900000004 0.0022058807999999997 0.061454807699999996 -0.0038451576000000003 -0.0046459831 0.0210879889 -0.0107168249 -0.010137572099999999 -0.062043925300000004 -0.05361495 0.0315725097 -0.0012889102 -0.0293311248 0.052295054199999996 -0.0616087584 0.0548411441 -0.233521 0.16364 0.466021 0.00128669 -0.00562511 0.00371704 -418.609375 351.0707092285156 344.86260986328125 0.923501 55.661251 0.14297440000000003 -0.0027537563 0.0239166568 -0.0241012665 -0.046316755099999996 -0.0087363102 0.04550461150000001 -0.0044019625 0.0013603428 0.0237606227 -0.0079498313 -0.0240934769 -0.051645349800000004 -0.0537959092 0.0322029395 -0.0023932635000000002 -0.0280270631 0.0512961746 -0.0614768659 0.0559714938 -0.234697 0.201324 0.465396 -0.000165108 -0.00601961 0.00394053 -420.8558654785156 350.8556823730469 344.8001708984375 0.946771 57.06382 0.2094704 0.0142182691 0.0242970813 -0.0077691094 -0.054337204699999996 0.0116205875 0.0276887015 -0.009252251 -0.0108242174 0.0149181212 -0.0095388171 0.0059968905 -0.04910397440000001 -0.05397494940000001 0.032828774399999996 -0.0034968484000000005 -0.0267070056 0.0502515524 -0.061266033600000006 0.0570040233 -0.241815 0.135914 0.444418 0.00146751 -0.00563199 0.00364148 -421.1351623535156 351.05596923828125 344.61041259765625 0.964176 58.112869 0.099838 0.0238255938 0.024206378799999997 0.016603949 -0.0455188128 0.017970810900000002 -0.025425427400000002 -0.0072379811 -0.0118383954 0.0090632207 -0.0089094013 0.012243144499999999 -0.0359534059 -0.0541520642 0.033449925 -0.0045993107 -0.0253717058 0.0491621191 -0.060976532199999996 0.0579369282 -0.235632 0.177827 0.45725 0.00119967 -0.00533627 0.00342684 -420.9743041992188 350.8965759277344 344.7628173828125 0.97974 59.050896 0.11035405 0.0254472446 0.0181669663 0.030478510299999997 -0.0098339056 0.0188232229 -0.0874599695 -0.0060933977 -0.009365655799999999 0.012551516100000002 -0.010360599100000001 0.0021919187 0.006212776 -0.054327247300000006 0.034066302799999996 -0.0057002965 -0.0240219257 0.0480288462 -0.0606087335 0.058768578200000005 -0.232209 0.205919 0.460147 0.000380749 -0.00566583 0.0037972 -419.68548583984375 350.9368591308594 344.4881591796875 0.962718 58.024979 0.15981954999999992 0.0434572326 0.0134759953 0.037873003599999996 0.0109859485 0.0180881336 -0.039286185099999996 -0.008815724799999999 -0.021841643100000002 -0.014021918700000002 -0.012062503600000002 0.0138476726 0.0177594111 -0.0545004924 0.0346778198 -0.006799452199999999 -0.022658435600000002 0.0468527442 -0.060163109699999995 0.0594975196 -0.236723 0.148684 0.436459 0.00175251 -0.00570949 0.00372497 -418.70587158203125 350.9047546386719 344.5514831542969 1.049567 63.259548 0.16711535 0.023814825 0.0051243257 0.0191002847 0.0457761137 -0.0121058055 0.026883402200000003 0.000464457 -0.0161672608 -0.0308687895 -0.029595094500000002 0.0005034041000000001 0.034157695099999996 -0.0546717934 0.0352843888 -0.007896425 -0.0212820138 0.0456348621 -0.059640233 0.0601224786 -0.243096 0.208144 0.422123 0.000486943 -0.0054139 0.0035472 -418.9501647949219 350.9698181152344 344.9352722167969 1.0275 61.929497 0.10446839999999996 0.013359122900000001 -0.0084664833 0.0142170582 0.053813224400000005 -0.0108142877 0.0376673987 -0.0028023717 -0.0098832801 -0.0086836869 -0.0053336152 -0.00037888669999999996 0.0504345777 -0.0548411441 0.0358859231 -0.0089908627 -0.0198934458 0.044376285700000004 -0.0590407749 0.060642363 -0.231841 0.230889 0.426822 -0.000108395 -0.00578491 0.00389624 -418.6065673828125 350.62451171875 344.8167419433594 0.950138 57.26672 0.19757625000000004 0.0014676821 0.00033405580000000004 0.0037159314 0.052614851 -0.0072145574 0.0430347696 -0.0055474726 -0.0145364942 -0.0053052224 -0.007678050600000001 0.008603279 0.0496174681 -0.055008538600000004 0.036482337000000004 -0.010082414100000001 -0.018493524 0.0430781374 -0.0583655051 0.0610562642 -0.226127 0.14031 0.444392 0.00142433 -0.00574241 0.0037972 -419.5608825683594 350.93426513671875 345.4009094238281 0.928062 55.936207 0.1280148 0.006617082 0.0095160877 0.006912648299999999 0.0469731565 -0.0033011570000000003 0.0055851971 -0.0061310895999999995 -0.006444045600000001 0.0078789092 -0.0171830522 0.0112116717 0.045875762 -0.0551739708 0.037073545299999996 -0.011170728500000001 -0.0170830476 0.0417415748 -0.057615290599999994 0.0613634587 -0.233619 0.168842 0.458099 0.000238534 -0.00606261 0.00373752 -421.56353759765625 351.1623229980469 345.9136047363281 0.929007 55.993153 0.05451605000000001 0.0062619 0.0038774378000000003 0.021524089500000003 0.051602081200000004 -0.0259531202 0.0120703967 -0.011335819099999998 -0.0049119498999999995 0.010206333100000001 -0.0140928123 0.0162336436 0.043055429000000006 -0.0553374348 0.0376594638 -0.012255456699999999 -0.0156628214 0.0403677898 -0.056791094900000005 0.061563409699999995 -0.233186 0.167694 0.466401 0.000513275 -0.00662085 0.0037972 -418.6884460449219 351.4188537597656 345.4598388671875 0.9300020000000002 56.053116 0.09262725000000004 -0.0008469192999999999 0.0012237684 0.017422336200000003 0.0576475607 -0.015412991000000001 0.043030307000000004 -0.0102514627 -0.0097602064 0.0044168268 -0.022661770699999997 0.0085294904 0.0686948294 -0.0554989249 0.038240008799999996 -0.0133362505 -0.014233656 0.0389580073 -0.055893976100000006 0.0616557679 -0.228782 0.140409 0.466145 0.0013179 -0.00621183 0.0037972 -420.4953918457031 351.1655578613281 345.89141845703125 0.952693 57.420715 0.19139110000000006 -0.0016481431 -0.0012536873 -0.0077198943 0.057626763 -0.0087953567 0.003950844199999999 -0.007971773 -0.002523514 0.005435338499999999 -0.0141757374 -0.0089111857 0.061926227 -0.055658435199999995 0.038815097400000005 -0.0144127627 -0.012796367099999999 0.0375134847 -0.0549250863 0.0616403716 -0.228748 0.202497 0.417083 -0.000163272 -0.0062817 0.0038503 -418.4041442871094 351.3333435058594 345.490966796875 0.941253 56.731255 0.19445760000000006 -0.036773567 0.0092110578 -0.0151368622 0.0560736692 0.0021053977 0.0256899487 -0.0085122316 -0.0103731562 0.0128539192 -0.013549044599999999 0.012443520500000001 0.048915449400000005 -0.05581596 0.039384647599999996 -0.0154846479 -0.011351775 0.036035509900000005 -0.053885669500000004 0.061517248 -0.22148 0.143168 0.465195 0.00123664 -0.00626739 0.00366955 -422.4244384765625 350.6268310546875 345.5655212402344 0.993748 59.895184 0.09019299999999998 -0.0231102212 0.0035809207000000003 -0.0452504986 0.026553689900000003 0.0415271452 -0.0957326783 -0.0017414879999999998 -0.012663555600000001 0.012218587 -0.0087979731 -0.0009847838 0.0182880853 -0.0559714938 0.0399485782 -0.0165515619 -0.0099007042 0.0345254011 -0.0527770605 0.0612866121 -0.222802 0.184889 0.485259 0.0008659199999999998 -0.00622404 0.0037972 -421.0320739746094 351.03155517578125 345.2795715332031 0.973408 58.669277 0.05855755000000003 -0.0246530772 0.022827351800000003 -0.048461986799999995 -0.0090033544 0.0245669865 -0.0282077367 -0.0072880161 -0.014112999499999999 0.023742194700000004 -0.0178799526 -0.0017767958 -0.025849704100000002 -0.0561250309 0.0405068086 -0.0176131622 -0.0084439827 0.0329845047 -0.0516006827 0.060948867000000004 -0.217076 0.186647 0.460301 0.000927601 -0.00638611 0.00409576 -419.76055908203125 350.7131042480469 344.8580627441406 0.954479 57.528362 0.11808145000000007 -0.0107272027 0.0428483884 -0.045481765300000004 -0.0395386344 0.0123920571 0.044547691699999996 -0.0067430624 -0.0289708958 0.0312878724 -0.0322022835 0.0071923484 -0.0563508233 -0.05627656599999999 0.041059259300000005 -0.0186691079 -0.0069824421 0.0314141948 -0.0503580468 0.060504603 -0.228744 0.155322 0.45063 0.00187688 -0.00620342 0.00391938 -418.66314697265625 350.2662658691406 344.6717224121094 0.936714 56.457645 0.10684300000000004 0.0011296417999999999 0.046707636799999994 -0.0062487343 -0.0370799233 0.0205338354 0.0442839259 -0.0048249126 -0.023222726699999998 0.0339542146 -0.025052172 -0.0066333016000000005 -0.046475883499999995 -0.056426093600000005 0.041605851299999996 -0.0197190601 -0.0055169164 0.0298158718 -0.0490507482 0.059954596500000006 -0.22393 0.183965 0.471994 0.00118574 -0.00636046 0.00411164 -420.3843078613281 350.7799072265625 344.6791687011719 0.990563 59.703217 0.037690000000000015 0.0213719622 0.0439354704 0.0208558883 -0.03019639 0.0298511021 -0.0201951203 -0.0089042551 -0.0210983904 0.0219319308 -0.015570004699999999 0.0177801638 -0.030808651800000003 -0.0565736083 0.0421465068 -0.0207626817 -0.0040482420000000005 0.0281909609 -0.0476804656 0.0592998088 -0.222283 0.188286 0.450505 0.00120411 -0.00648859 0.00405348 -417.90380859375 350.1667175292969 344.4388732910156 0.94024 56.670155 0.10437000000000003 0.0215020898 0.05221095059999999 0.0323387697 -0.0092074466 0.033127428 -0.0165281522 -0.0029364513 -0.0301447474 0.0155110163 -0.0291634435 0.0206836127 -0.004924322 -0.056719105 0.042681148499999995 -0.0217996377 -0.0025772572 0.0265409112 -0.0462489587 0.0585413841 -0.210677 0.163251 0.482466 0.00143984 -0.00602168 0.0040662 -418.4532775878906 350.86175537109375 345.35711669921875 0.9386310000000002 56.573166 0.15345229999999999 0.0222181219 0.0496605008 0.0384308481 0.0015176109 0.0261619014 -0.0261713166 -0.0065568624 -0.0189467135 0.0224226032 -0.021934032599999997 0.022899531600000002 0.0075194284 -0.0568625783 0.04320970019999999 -0.0228295951 -0.0011048015 0.0248671939 -0.0447580654 0.057680648099999995 -0.201905 0.197146 0.475432 0.000317284 -0.00668689 0.00435346 -419.7340393066406 351.2686462402344 345.7000732421875 0.951528 57.350525 0.08760885000000003 0.0298966145 0.0363880967 0.0401888235 0.0360609977 0.0011340438 -0.0405455731 -0.0071559843 -0.0112678654 0.001278756 -0.0293992369 0.0304581556 0.0380530225 -0.0570040233 0.0437320865 -0.0238522233 0.0003682847 0.023171301800000002 -0.04320970019999999 0.056719105 -0.213971 0.160457 0.45798 0.000640961 -0.00671358 0.00427579 -419.6258239746094 350.8326110839844 345.3352966308594 1.32808 80.046074 1.10770195 0.0466338755 -0.0045629455 0.0452108857 0.028510273 0.058606711900000004 0.0045383437 -0.0083821446 -0.054121162800000004 -0.1264120008 -0.0656220055 0.06444425940000001 0.0047237487 -0.057143434800000004 0.0442482328 -0.0248671939 0.0018411607000000001 0.0214547469 -0.041605851299999996 0.055658435199999995 -0.387708 0.0698633 0.0623497 0.007730919999999999 -0.00513288 0.00455995 -421.9286804199219 351.986572265625 346.7840881347656 1.448526 87.305611 0.94662975 0.0368767433 -0.015569886100000001 0.0311879778 0.028801254199999998 0.0274019442 -0.027637689700000002 -0.016795151100000003 -0.0071492946 -0.0642753924 -0.0170580415 0.0252961734 0.0374730659 -0.0572808079 0.0447580654 -0.025874181200000002 0.003312986 0.0197190601 -0.0399485782 0.0545004924 -0.245279 0.221022 0.252796 0.000195535 -0.00358566 0.00439064 -420.03265380859375 352.2621765136719 346.7864074707031 1.111261 66.977974 0.23146905 0.0191965423 0.0097517223 -0.0021952819 0.0209932689 0.0169289039 0.0187509875 -0.015195520300000001 -0.0051002724 -0.0246458913 -0.0109813553 0.023263653500000002 -0.0015841612 -0.057416137699999995 0.0452615117 -0.0268728619 0.0047829204 0.0179657891 -0.038240008799999996 0.0532473004 -0.223133 0.198169 0.325596 -0.000575956 -0.00494457 0.00424764 -422.753662109375 352.4790954589844 347.1820373535156 1.009739 60.85902 0.2499303 0.026419751499999998 0.025557087200000002 -0.006157446600000001 -0.0090072802 -0.006250615 0.029137866800000002 -0.02606233 -0.013988417 -0.0151362763 -0.020045925 0.035447221099999995 -0.0202722798 -0.0575494194 0.0457584997 -0.0278629153 0.0062501251 0.0161964974 -0.036482337000000004 0.0519010494 -0.212825 0.115584 0.363372 0.00106699 -0.00565255 0.00421334 -419.8230285644531 351.4459228515625 345.6559143066406 1.001595 60.368179 0.10223 0.0289880059 0.0390068096 0.027997977900000002 -0.0199245626 0.0186179868 -0.0107020125 -0.017171006699999998 -0.030160222599999998 -0.014044333 -0.043868965999999995 0.0356601789 -0.0241504561 -0.057680648099999995 0.0462489587 -0.028844023599999997 0.0077137627000000005 0.0144127627 -0.0346778198 0.050464092099999996 -0.197908 0.153006 0.386041 0.00143232 -0.00561038 0.00435028 -423.03448486328125 351.24542236328125 345.2484436035156 1.000253 60.287277 0.15513215000000002 0.0367041818 0.029105649900000002 0.0245257011 0.0230138311 0.0080292213 -0.0420305281 -0.019953838 -0.0336568406 -0.0120179757 -0.0314411617 0.0310006404 0.0185384528 -0.057809819299999995 0.046732818499999995 -0.0298158718 0.0091729979 0.012616175600000001 -0.032828774399999996 0.0489389399 -0.194464 0.195997 0.38152 0.000452407 -0.00630131 0.00476296 -419.1816711425781 351.166259765625 344.3555908203125 0.995545 60.003525 0.19836814999999997 0.027648154900000003 0.0301338907 0.0249665414 0.048947349800000005 0.0191485594 0.017560491299999998 -0.0165534844 -0.046195669 -0.0132254031 -0.0359686566 0.0389417911 0.021391857200000003 -0.0579369282 0.04721001019999999 -0.0307781479 0.010626997800000001 0.010808338300000001 -0.0309375749 0.0473282582 -0.200427 0.137941 0.392725 0.00239329 -0.00603125 0.00451102 -417.5675354003906 351.25360107421875 344.0668029785156 0.956024 57.621502 0.11819599999999998 0.0093625379 0.024069096499999998 0.013754298 0.07187192790000001 0.025998836299999998 0.0738661556 -0.011686357 -0.0379132279 -0.0075740437 -0.0445936254 0.0341324834 0.055332433099999995 -0.0580619705 0.0476804656 -0.031730543 0.0120749325 0.0089908627 -0.0290066498 0.0456348621 -0.195696 0.169642 0.416252 0.00162573 -0.00572778 0.00460473 -419.3764953613281 351.1673583984375 344.31573486328125 0.969483 58.432682 0.14335944999999997 -0.0028825808000000003 0.019986181999999998 -0.0173452084 0.077460527 0.0425219647 0.0370680435 -0.0125187718 -0.0356233431 0.0038834740999999996 -0.0055530331 0.0227306586 0.052377327800000005 -0.058184941500000004 0.048144117699999996 -0.0326727513 0.013515975800000002 0.007165369699999999 -0.0270384785 0.043861710899999996 -0.197584 0.204598 0.370641 0.000908461 -0.0061093 0.00448543 -418.8160705566406 350.8041687011719 343.9140319824219 0.96527 58.178772 0.16764395000000007 -0.017383794299999998 0.0273567436 -0.044172028700000004 0.0723362385 0.0728134148 -0.0077585569 -0.0084262882 -0.0433164951 0.0006381074 -0.0115533248 0.0235729796 0.0333206038 -0.058305837 0.0486009003 -0.0336044704 0.0149493052 0.005333487099999999 -0.0250355883 0.0420119037 -0.186189 0.137163 0.377149 0.00238318 -0.00625496 0.00445969 -418.76995849609375 350.42877197265625 344.1031494140625 0.982813 59.236111 0.128046 -0.0275793277 0.048098307 -0.0674074776 0.0382466502 0.0678989285 -0.049976339800000005 -0.0014587448000000002 -0.0364533561 0.025377378199999998 -0.0345086177 0.0056784812 -0.0030724006 -0.058424652599999995 0.0490507482 -0.0345254011 0.0163741027 0.0034968484000000005 -0.023000551 0.0400886733 -0.184043 0.176029 0.419343 0.00178977 -0.00603658 0.0045447 -418.3017272949219 350.4978332519531 344.22613525390625 0.9847570000000002 59.353317 0.08960550000000009 -0.0213826042 0.060300545700000006 -0.066825354 0.0029250694 0.0547781526 0.0170630264 -0.005137094 -0.0401032998 0.0243981892 -0.0371756133 0.0155075424 -0.0423874614 -0.0585413841 0.049493597199999996 -0.0354352477 0.017789555 0.0016570915 -0.020935979599999998 0.0380953808 -0.183926 0.198566 0.387664 0.00174422 -0.00634493 0.00489625 -418.2889404296875 350.47552490234375 344.2760009765625 0.9813130000000002 59.145706 0.12374200000000002 -0.0144046673 0.0696317737 -0.051166482199999995 -0.0210428538 0.0379278269 0.056864703899999994 -0.0071204068 -0.0450028846 0.0276242041 -0.0469800857 -0.0032818954999999997 -0.045813282999999996 -0.058656027300000003 0.0499293841 -0.0363337182 0.019194854299999998 -0.0001841432 -0.0188445253 0.036035509900000005 -0.202301 0.186852 0.396058 0.00127278 -0.00587845 0.00412899 -418.7112731933594 350.6602478027344 344.6427307128906 0.9646960000000002 58.14418 0.09461300000000009 0.0105099789 0.07063700889999999 -0.02338341 -0.027180998199999997 0.037205915299999996 0.06802220769999999 -0.0097115083 -0.0442782503 0.0325937378 -0.0522096879 0.0137305242 -0.0395487712 -0.058768578200000005 0.0503580468 -0.0372205242 0.020589198700000002 -0.0020252136 -0.0167288735 0.0339126607 -0.182861 0.199 0.387547 0.00170721 -0.0059569 0.00470639 -419.8245544433594 350.76495361328125 345.0623779296875 0.959747 57.845882 0.062120000000000036 0.0214366228 0.0713033158 -0.0042520129 -0.024328547000000002 0.030119767999999998 0.0280687181 -0.0137978933 -0.049619034299999996 0.0288504286 -0.0586228936 0.017954090500000002 -0.042073201399999996 -0.0588790326 0.050779524000000006 -0.0380953808 0.021971792200000003 -0.0038644781 -0.0145917409 0.031730543 -0.185551 0.181325 0.377505 0.00165562 -0.00621217 0.00437899 -419.5951232910156 351.09197998046875 345.2314453125 0.965823 58.212086 0.11128800000000001 0.021386477999999997 0.0767072062 0.0145596267 -0.0198973203 0.0364604719 0.0316911778 -0.014736906499999999 -0.0520747749 0.023880753199999997 -0.0527391952 0.0427320471 -0.0295623265 -0.0589873867 0.0511937557 -0.0389580073 0.023341845899999998 -0.0057002965 -0.012435871599999999 0.0294929706 -0.199058 0.161935 0.399456 0.00252915 -0.0059569 0.00437899 -419.8625793457031 351.43450927734375 345.784423828125 1.009441 60.841042 0.13779949999999994 0.0260563418 0.072221724 0.0362160536 -0.006813435600000001 0.022996133 0.004486493 -0.0144637117 -0.043146937 0.0226597094 -0.047775877300000005 0.0471784288 -0.013007228899999999 -0.0590936366 0.0516006827 -0.0398081268 0.0246985778 -0.0075310317 -0.010264034 0.027203854 -0.187294 0.220903 0.398073 0.00179703 -0.00632036 0.0045971 -422.2482604980469 351.4603576660156 345.68243408203125 0.968674 58.383938 0.1139495 0.0342689078 0.0654799495 0.0425336424 0.017369392 0.0250797425 -0.06331440440000001 -0.0197799308 -0.04837699559999999 0.0032208269 -0.050572310499999995 0.0504082208 -0.0028729896 -0.0591977785 0.0520002471 -0.0406454662 0.026041213599999998 -0.0093550512 -0.0080790168 0.0248671939 -0.182697 0.179165 0.381958 0.00248897 -0.0064403 0.00437899 -420.7378234863281 351.1676025390625 345.3408508300781 0.948902 57.192253 0.0394925 0.040160190400000004 0.0614438863 0.05066816019999999 0.0340669967 0.022389577999999997 -0.0507508325 -0.013051144399999999 -0.0478650914 -0.0045321797 -0.0526932226 0.061173578 0.028930331200000003 -0.0592998088 0.052392391600000005 -0.0414697568 0.0273689869 -0.011170728500000001 -0.0058836257 0.022487074 -0.186873 0.180908 0.395487 0.00237201 -0.00615637 0.00437899 -421.2898864746094 351.5527038574219 345.8719787597656 0.942634 56.81448 0.07079299999999994 0.0332596226 0.051119302 0.0452601574 0.0627745902 0.0125202051 -0.0202914722 -0.018572023400000002 -0.0484164595 0.0049989381 -0.0450878492 0.0513066233 0.053063832400000004 -0.0593997236 0.0527770605 -0.042280734 0.0286811401 -0.0129764445 -0.0036806797 0.020067654 -0.184936 0.19256 0.374865 0.00196341 -0.00628361 0.00457479 -421.4818420410156 351.624755859375 346.1165771484375 0.962598 58.017754 0.12456899999999994 0.0254547686 0.058762414000000006 0.0359049132 0.054239398499999994 0.039904488700000004 -0.0537941309 -0.0206714856 -0.0529402495 -0.010225448 -0.042448392 0.06821294160000001 0.029656297999999998 -0.0594975196 0.053154198799999997 -0.0430781374 0.029976924199999998 -0.0147705889 -0.0014730073999999998 0.0176131622 -0.182875 0.149502 0.375563 0.00293504 -0.005876 0.00437899 -421.2866516113281 350.93756103515625 346.57965087890625 1.313785 79.184486 0.5838386 0.0442127008 -0.028747438900000002 0.045673888200000005 0.032807444500000005 0.0411461188 -0.0015565267000000002 -0.012219836999999999 -0.0711013184 -0.0850286923 0.0320860685 0.0434996003 0.027728736099999998 -0.059593193200000005 0.053523752699999996 -0.043861710899999996 0.0312555998 -0.0165515619 0.0007365563000000001 0.0151278882 -0.199108 0.0946779 0.0262147 0.0007942859999999998 -0.00612699 0.00350207 -399.9601745605469 335.7095947265625 334.87237548828125 2.126 128.13833600000004 2.1411364 -0.1280517782 -0.0692234734 0.1297085093 0.0264703913 0.20212647620000002 0.044718956399999996 0.21649608760000003 -0.1438987491 -0.051908612 0.2725837175 0.007131560699999999 -0.025822702599999997 -0.059686740999999995 0.053885669500000004 -0.044631203099999996 0.0325164369 -0.0183177752 0.0029451740999999997 0.012616175600000001 -0.163138 -0.46237 -0.502026 -0.0160769 -0.00448637 0.00161632 -416.7155456542969 347.0284423828125 338.27484130859375 2.508385 151.18544 1.7217067499999998 -0.0876704714 -0.1231097427 0.0534457667 -0.060056381799999996 -0.1566820157 0.0864498344 0.13066259800000002 0.1058735392 -0.2528589296 -0.232073235 -0.19043857670000003 -0.018399076 -0.0597781596 0.054239897599999996 -0.0453863669 0.033758716 -0.020067654 0.0051500103000000005 0.010082414100000001 -0.144593 -0.347792 0.439702 -0.0276709 -0.00409947 0.000660105 -428.805908203125 353.9019470214844 350.6581726074219 2.028446 122.25853 0.82655815 -0.025629405600000002 -0.1064844145 0.0269844066 -0.0160835322 -0.1352069099 -0.0231695152 0.017747449499999998 0.1532806933 -0.0676913361 0.1067419941 0.0548928012 0.0101125145 -0.0598674458 0.0545863863 -0.0461269599 0.0349817282 -0.0217996377 0.0073482335 0.0075310317 -0.120055 -0.217439 0.356161 -0.0167047 -0.00357945 0.000936408 -422.5929870605469 352.3768005371094 347.3529968261719 1.057573 63.742081 0.2869126 -0.0372934543 -0.09791113060000001 0.036765779 -0.0063169666000000005 -0.1288141408 0.0077413280000000004 0.0305317305 0.1157251464 -0.038638307999999996 0.0627373336 -0.0134890024 0.0426632396 -0.059954596500000006 0.0549250863 -0.0468527442 0.0361847754 -0.023512181899999998 0.0095370211 0.0049664875 -0.115114 -0.132311 0.389803 -0.0140428 -0.00391794 0.00120005 -422.9916687011719 352.130859375 346.5309143066406 0.968452 58.370586 0.1658033 -0.039889662 -0.0954367281 0.0088103091 0.0076124083999999995 -0.1049339936 -0.020610409099999998 0.026262106299999997 0.1070203303 -0.013517774299999999 0.0688715981 -0.0396257408 0.0390798219 -0.0600396084 0.0552559492 -0.047563487 0.0373671711 -0.0252037594 0.011713562700000001 0.0023932635000000002 -0.11942 -0.0676117 0.382854 -0.0127377 -0.00408757 0.0015223 -421.4900817871094 352.22509765625 346.1685485839844 0.982176 59.197731 0.14192439999999998 -0.0558046851 -0.0706098276 -0.023420474500000003 0.0216604435 -0.0701943269 -0.008550604100000001 0.015222325900000002 0.09060300630000001 -0.009311135600000001 0.0550243019 -0.0284520563 0.04716321440000001 -0.0601224786 0.055578927800000004 -0.0482589599 0.038528240299999995 -0.0268728619 0.0138750634 -0.0001841432 -0.11260800000000003 -0.0702246 0.382847 -0.0104295 -0.00405328 0.00182966 -423.6424255371094 352.2194519042969 345.86810302734375 1.0034630000000002 60.480724 0.14448749999999996 -0.0460940505 -0.0553105019 -0.0583586232 -0.0067716065 -0.0416513841 -0.1040707858 0.0110042441 0.08629297289999999 0.0157615186 0.0561222629 -0.0426516391 0.0102182914 -0.0602032042 0.055893976100000006 -0.0489389399 0.0396673204 -0.0285180009 0.0160187477 -0.0027612279999999997 -0.102392 -0.0102651 0.38287 -0.00991538 -0.00466158 0.00219302 -421.90277099609375 351.81500244140625 345.2787170410156 0.984481 59.336681 0.1268682 -0.0547948474 -0.0463257384 -0.0478135479 -0.0486826822 -0.0419529335 -0.028883373900000002 0.0124696545 0.07729747 0.024601654700000003 0.046521195700000004 -0.0487214722 -0.0333964588 -0.0602817821 0.056201049100000004 -0.0496032084 0.0407837614 -0.0301377094 0.0181418631 -0.005333487099999999 -0.0982034 -0.0398787 0.366004 -0.0103043 -0.00533279 0.00265689 -421.8422546386719 352.50921630859375 345.8283386230469 1.024073 61.722923 0.344535486 -0.0216504798 -0.0154094171 -0.0597656716 -0.0671998619 -0.032011793999999996 0.036236968599999995 -0.0034610566 0.055602965899999995 0.021241660899999997 0.0345453264 -0.0236405249 -0.055816234299999996 -0.0603582097 0.0565001029 -0.0502515524 0.041876926 -0.031730543 0.0202416832 -0.007896425 -0.119415 -0.000321314 0.303257 -0.00710248 -0.00432866 0.00244245 -422.1711730957031 351.5225830078125 344.93341064453125 1.268932 76.481079 0.6198898860000001 0.026784846400000003 -0.0228160246 -0.0432289897 -0.0515553051 0.045481266799999996 0.0564727018 -0.013377770800000001 -0.019454991499999998 -0.059468798600000004 0.0038591721999999998 0.023136595899999998 -0.0793468359 -0.0604324842 0.056791094900000005 -0.0508837635 0.0429461904 -0.0332950814 0.022315511899999998 -0.0104455625 -0.21151 -0.0260087 0.159813 -0.0007924899999999998 -0.00378812 0.00211971 -424.112548828125 352.7214050292969 346.77642822265625 1.290278 77.767685 0.5486042 0.0224473533 -0.05523145 -0.0240807644 -0.057226968600000004 0.0151649193 -0.0425916499 -0.0154371995 0.0281335394 -0.0162452477 0.0225942359 -0.0413965209 -0.0431882898 -0.060504603 0.0570739836 -0.05149963900000001 0.0439909442 -0.0348299293 0.024360686200000002 -0.0129764445 -0.117572 0.124869 0.193596 -0.0055711 -0.00430915 0.00222018 -424.0768432617188 352.3007507324219 346.93017578125 1.076316 64.871735 0.2404377 0.0065282913 -0.037076371600000005 -0.0284498335 -0.0145296266 -0.0002060113 -0.0348300385 -0.0174873787 0.006020318199999999 -0.0015273763 0.038327232999999995 -0.028334303999999998 -0.0149453701 -0.060574563399999996 0.057348728499999994 -0.052098980999999996 0.0450105913 -0.0363337182 0.02637458 -0.0154846479 -0.124961 0.0273768 0.238283 -0.00445776 -0.00475034 0.00248304 -423.2519836425781 352.6043701171875 346.9412536621094 1.070907 64.545761 0.07287609999999994 0.0010400405999999999 -0.0363212014 -0.05121451269999999 -0.0100911294 0.0220208294 -0.024530569900000004 -0.0206159411 0.0010494503999999999 0.0006442926000000001 0.0323686035 -0.0188277518 -0.011472773799999999 -0.060642363 0.057615290599999994 -0.0526815972 0.046004549699999994 -0.0378051071 0.0283546073 -0.0179657891 -0.1169 0.0394639 0.232831 -0.00395279 -0.00431941 0.00247342 -422.2267761230469 351.9680480957031 346.0373840332031 1.043865 62.91584 0.16281079999999998 0.0072036109999999995 -0.0148172754 -0.0413669625 -0.0550342285 0.0104536319 0.0463244349 -0.0114889456 0.0082549427 0.0195629699 0.020824224199999998 -0.0293326794 -0.0471719384 -0.060707999400000004 0.0578736318 -0.0532473004 0.0469722521 -0.0392427837 0.030298225699999997 -0.020415532 -0.11221 0.08817719999999998 0.265771 -0.00482867 -0.00491323 0.00253307 -423.38409423828125 352.0017395019531 345.3860778808594 1.021042 61.54026 0.0575217 0.0380783666 -0.0014998632999999998 0.0100344352 -0.055189355499999995 0.0275531334 -0.013140171 -0.0152467991 -0.0028645473 0.011986636 0.0181232865 -0.0057148884 -0.0400035199 -0.0607714702 0.058123715199999995 -0.0537959092 0.0479131463 -0.0406454662 0.0322029395 -0.0228295951 -0.118267 0.0698375 0.260366 -0.00448459 -0.00476633 0.00259649 -420.6625061035156 351.26953125 344.8603210449219 1.02904 62.022346 0.09730379999999997 0.053374200499999996 0.0058280643000000005 0.038593734500000004 -0.0196502383 0.0373108902 -0.054177921500000004 -0.0088971954 -0.0103554784 -0.010358443299999999 0.0126805955 0.007087885699999999 -0.0131216874 -0.0608327732 0.0583655051 -0.054327247300000006 0.0488266951 -0.0420119037 0.034066302799999996 -0.0252037594 -0.125135 0.0474352 0.244845 -0.00393455 -0.00431456 0.00254805 -419.7892150878906 351.7342224121094 344.9761962890625 1.046973 63.103176 0.1949898 0.0348268222 -0.0071921639 0.0222846597 0.038177168 -0.007666212800000001 0.0315534524 -0.0102283949 0.0020103927 0.0078154554 0.0038825555 -0.0054931089 0.051992141799999995 -0.0608919062 0.058598967 -0.0548411441 0.049712377300000006 -0.043340877699999995 0.0358859231 -0.0275338758 -0.112126 0.10774 0.275304 -0.00479333 -0.00498764 0.00284053 -418.7413024902344 351.1280212402344 344.80572509765625 0.997383 60.114265 0.15845739999999997 0.013482196200000001 -0.018684654 -0.0048283247999999996 0.0649365866 0.0094822091 0.0618010524 -0.0078076848 -0.0132017193 -0.0048834025 0.0107021479 -0.0017909292000000002 0.06266650480000001 -0.060948867000000004 0.058824067699999996 -0.0553374348 0.050569687300000006 -0.044631203099999996 0.0376594638 -0.0298158718 -0.126718 0.0593756 0.244366 -0.00396714 -0.00459401 0.00276909 -420.9377746582031 351.9564514160156 345.2381286621094 1.040242 62.697521 0.06017419999999999 -0.011314081699999999 -0.0278842001 -0.0477065966 0.0688739096 0.060157833200000004 -0.0240738002 -0.0118185596 -0.0057897978000000004 0.0011005910000000002 0.0162354137 -0.0062478229 0.0474022611 -0.061003653600000006 0.0590407749 -0.05581596 0.051398136 -0.0458817293 0.039384647599999996 -0.032045759300000004 -0.111431 0.0758303 0.241882 -0.00384966 -0.00473658 0.00251017 -421.99810791015625 351.0489196777344 345.5321044921875 1.033145 62.26973 0.1209072 -0.0147406323 0.0019164622 -0.07832891809999999 0.0007858286999999999 0.0245240442 -0.0313982364 -0.0095381006 -0.0138418155 0.0264993474 -0.00039530809999999996 -0.024030364900000004 -0.011574345500000001 -0.0610562642 0.059249057800000005 -0.05627656599999999 0.052197250300000005 -0.0470913411 0.041059259300000005 -0.0342196412 -0.111476 0.124043 0.266333 -0.00445542 -0.00480476 0.0028002 -420.36517333984375 351.1342468261719 345.2734375 1.008703 60.796574 0.16074429999999998 0.0104759351 0.0085441607 -0.052527981200000004 -0.050008154299999996 0.014420084 0.054802933899999996 -0.0093308946 -0.017644979499999998 0.0224587853 -0.010171875300000001 -0.0189921052 -0.068499219 -0.0611066967 0.0594488867 -0.056719105 0.0529665744 -0.0482589599 0.042681148499999995 -0.0363337182 -0.112557 0.0624852 0.241435 -0.00342674 -0.00437992 0.00278957 -420.7155456542969 350.9720764160156 345.3565368652344 1.008094 60.759869 0.058259700000000025 0.0415136324 0.0125072425 0.0069699213 -0.044191524 0.0202096811 0.0118389709 -0.0106788653 -0.022302747400000003 0.0107642662 -0.0026232565 -0.015773281599999998 -0.0336852052 -0.061154949400000005 0.059640233 -0.057143434800000004 0.053705669000000004 -0.0493835445 0.0442482328 -0.0383842957 -0.12578 0.0808674 0.238196 -0.00368899 -0.0044243 0.00262789 -420.4479370117188 351.3194885253906 345.677001953125 1.0813100000000002 65.172768 0.15503460000000002 0.047682265599999996 0.0175540487 0.0489314856 -0.0101481014 0.0139244733 -0.0756840656 -0.006811980699999999 -0.0101218017 0.0130763145 -0.0064996524 0.0070456124 0.01049434 -0.061201020700000004 0.0598230695 -0.0575494194 0.0544141125 -0.050464092099999996 0.0457584997 -0.0403677898 -0.111499 0.110419 0.271664 -0.00480817 -0.00465371 0.00283398 -419.498046875 351.53302001953125 345.9704895019531 1.029841 62.070583 0.09417479999999998 0.0470628254 0.007376436700000001 0.0361783563 0.0318275237 -0.0161019607 0.00337993 -0.0105687204 -0.0228434812 -0.0004417203 -0.0075867415 0.0120447149 0.0435731803 -0.0612449087 0.05999737 -0.0579369282 0.0550915004 -0.05149963900000001 0.04721001019999999 -0.042280734 -0.11524400000000003 0.0749852 0.250632 -0.0043111 -0.00473658 0.00293332 -417.7709655761719 351.4949951171875 346.0661926269531 1.00018 60.282906 0.08305440000000006 0.0164367723 -0.0004995701 0.013952514099999999 0.066492379 -0.021701244900000003 0.06762079110000001 -0.0110603679 -0.0254391371 -0.008274535500000001 -0.0113863292 0.0027926934000000003 0.0530494656 -0.0612866121 0.060163109699999995 -0.058305837 0.055737446100000004 -0.05248926190000001 0.0486009003 -0.0441197852 -0.12570300000000004 0.0699593 0.236253 -0.00387974 -0.00434618 0.00269127 -420.03070068359375 351.7759094238281 346.6172180175781 1.018497 61.386848 0.1691612 -0.0314743369 -0.0102726609 -0.02180923 0.0696488867 -0.011764894 0.0241853628 -0.0096268385 -0.0051703754 0.0094091357 -0.0048425501 -0.013219706999999999 0.0603396846 -0.061326129199999996 0.060320264900000004 -0.058656027300000003 0.056351581 -0.053432078200000004 0.0499293841 -0.0458817293 -0.111384 0.107338 0.273193 -0.00460122 -0.00498385 0.00294259 -421.60845947265625 352.45343017578125 347.2548828125 1.009959 60.872246 0.15057970000000007 -0.0256647037 0.0005163879 -0.0507417025 0.034918601699999996 0.011617632900000001 -0.0313109273 -0.0194350817 -0.015940431499999998 0.013334853999999998 0.0021401931 -0.0198508594 0.015688409599999998 -0.0613634587 0.060468813200000006 -0.0589873867 0.0569335547 -0.054327247300000006 0.0511937557 -0.047563487 -0.121452 0.0575558 0.230565 -0.00402311 -0.00473658 0.00280594 -422.3707580566406 352.4518737792969 347.8758544921875 1.012851 61.046562 0.0592844 -0.013647577099999999 0.006125055 -0.06887951 -0.012839508999999999 0.010887618 -0.0392331893 -0.022555605899999998 -0.0166405108 0.0201722734 0.0048147549 -0.0328312681 -0.032712656 -0.0613985992 0.0606087335 -0.0592998088 0.0574830349 -0.0551739708 0.052392391600000005 -0.0491621191 -0.12002 0.0707792 0.230593 -0.00359188 -0.00442055 0.00266118 -421.72943115234375 352.23681640625 347.91278076171875 1.00168 60.373264 0.1312348 -0.0026898913 0.0135188589 -0.029777488300000002 -0.0496757054 -0.0224497455 0.03261933 -0.0170265793 -0.0091950457 0.0192573991 0.000224868 -0.0204236831 -0.052530132599999994 -0.0614315496 0.0607400057 -0.059593193200000005 0.057999708 -0.0559714938 0.053523752699999996 -0.050674831600000005 -0.10506 0.10708 0.247001 -0.00459617 -0.0046683 0.00268046 -422.26556396484375 352.25299072265625 347.68084716796875 1.015506 61.206627 0.09617179999999997 0.026363765 0.0228187609 0.0097683903 -0.0552644821 -0.0100202481 0.0265584463 -0.022286539900000003 -0.0143782431 0.0147867239 0.0031726192 0.0055927768 -0.048099828399999996 -0.06146230849999999 0.060862611100000005 -0.0598674458 0.0584832792 -0.056719105 0.0545863863 -0.052098980999999996 -0.116538 0.0761012 0.227561 -0.00410443 -0.00473658 0.00280594 -421.0836791992188 352.23712158203125 347.4114990234375 0.993424 59.875683 0.0528107 0.0344300282 0.026865599900000002 0.0439509109 -0.031134814 0.020750702700000002 -0.0201194326 -0.0212483685 -0.024854825499999997 0.0024740129 -0.007875861999999999 0.0155869187 -0.0246105421 -0.061490875 0.060976532199999996 -0.0601224786 0.0589334724 -0.057416137699999995 0.055578927800000004 -0.053432078200000004 -0.11157 0.0772409 0.227499 -0.00382909 -0.00429321 0.00259183 -423.3153991699219 352.1808776855469 347.6640930175781 1.04036 62.70462 0.1723511 0.0314483635 0.0069168028 0.038593766200000004 0.014005086100000001 -0.0191369675 -0.0301891844 -0.0206926744 -0.0185820124 -0.0035260791999999997 -0.016039978700000002 0.0062774867 0.024999485499999998 -0.061517248 0.0610817528 -0.0603582097 0.0593500308 -0.0580619705 0.0565001029 -0.0546717934 -0.111399 0.127638 0.260449 -0.00475495 -0.00498421 0.00275163 -421.71282958984375 352.2409362792969 347.1488037109375 1.002166 60.402573 0.13683079999999997 0.0271744969 0.0015163845000000001 0.025763855699999998 0.0499472431 -0.0261006619 0.0402759187 -0.0169465364 -0.0250337745 -0.007249771800000001 0.0009704044 0.0063263352 0.0485999375 -0.0615414265 0.061178257800000004 -0.060574563399999996 0.0597327166 -0.058656027300000003 0.057348728499999994 -0.05581596 -0.111503 0.0696532 0.238549 -0.00412388 -0.00453274 0.00280593 -420.95794677734375 351.55804443359375 346.8887023925781 0.980891 59.120312 0.039432699999999966 0.018563746399999997 -0.0017437245999999999 0.015592283500000002 0.0699698942 -0.0189452991 0.06333085299999999 -0.0126904754 -0.0257302339 0.0020127883 -0.0005758355000000001 -0.0008228822 0.056738310099999995 -0.061563409699999995 0.061266033600000006 -0.0607714702 0.0600813114 -0.0591977785 0.058123715199999995 -0.0568625783 -0.111504 0.0859344 0.248921 -0.00396849 -0.00457196 0.00286689 -422.2423706054688 351.723876953125 347.05621337890625 0.994362 59.932224 0.10751260000000001 0.0022134376999999998 -0.0211319623 -0.014810129699999999 0.0659470958 0.0059990238 0.0126242008 -0.0148947101 -0.0227536138 0.013746433700000001 -0.000859843 -0.015347276299999999 0.054628272699999994 -0.061583196900000005 0.0613450675 -0.060948867000000004 0.060395616299999996 -0.059686740999999995 0.058824067699999996 -0.057809819299999995 -0.10703 0.120201 0.230786 -0.00440255 -0.00509613 0.0029214 -421.8899230957031 351.7915954589844 346.7508544921875 1.017657 61.336273 0.14446660000000003 -0.015388519 -0.022791758999999998 -0.041555322900000004 0.060412622400000004 0.0664526441 -0.0352038977 -0.0163509164 -0.0282916005 0.0054836228 0.0111122116 -0.006100890699999999 0.035625105899999995 -0.0616007872 0.0614153483 -0.0611066967 0.060675451799999995 -0.0601224786 0.0594488867 -0.058656027300000003 -0.110814 0.0622799 0.226982 -0.00342081 -0.00461419 0.00280593 -419.475341796875 346.569580078125 339.4344482421875 1.621333 97.721054 0.8422699 -0.060588875099999995 -0.025163469900000002 -0.0345421064 -0.0149674769 0.0055548147 -0.0705371986 0.0881760367 0.010057830799999999 -0.0277921859 0.0133373391 0.09058812179999999 -0.0635773054 -0.061616180199999995 0.0614768659 -0.0612449087 0.060920658200000005 -0.060504603 0.05999737 -0.0593997236 -0.104784 -0.089261 0.363692 -0.0133824 -0.00553932 0.00273287 -425.2885437011719 352.3264465332031 347.6260681152344 1.754944 105.77401 0.244977 -0.0617111459 -0.0424335949 -0.026480202 -0.061380522400000005 -0.054977903700000004 0.008906026800000001 0.0284929712 0.1055191519 -0.0043276145 0.0328242821 -0.0375287711 -0.0202048105 -0.061629375099999995 0.0615296116 -0.0613634587 0.061131095700000006 -0.0608327732 0.060468813200000006 -0.0600396084 -0.0938495 -0.152035 0.379953 -0.0159306 -0.00582372 0.00246532 -420.75860595703125 351.138671875 344.8719177246094 1.066348 64.270981 0.25311920000000004 -0.0369242793 -0.0033569290000000002 -0.0006735921 -0.0777995521 -0.0552759762 0.051621468200000006 0.0335690785 0.078022487 0.0250692512 0.017824441899999998 -0.0234486361 -0.0381334383 -0.0616403716 0.0615735779 -0.06146230849999999 0.061306644 -0.0611066967 0.060862611100000005 -0.060574563399999996 -0.0892588 -0.0874425 0.407397 -0.0135491 -0.0053038 0.00269374 -419.7999267578125 351.4358215332031 345.1805114746094 0.964989 58.16185 0.2307048 -0.023679175 0.0070704538 0.0202688006 -0.06289879450000001 -0.0569715155 0.0406695013 0.0251892076 0.061623254800000006 0.0299540123 0.014245055 -0.023699705 -0.0428694041 -0.061649169299999994 0.0616087584 -0.0615414265 0.06144720309999999 -0.061326129199999996 0.061178257800000004 -0.061003653600000006 -0.068303 -0.01901 0.394174 -0.0122135 -0.0061456 0.00307821 -421.88525390625 351.54473876953125 345.47784423828125 0.967501 58.313236 0.20407260000000002 -0.0112502858 0.0043324475 0.0352424739 -0.06106296 -0.048241136399999995 0.0193180422 0.013328851000000001 0.0471989272 0.0301798489 0.0153739543 -0.0136828072 -0.030833595499999998 -0.0616557679 0.0616351482 -0.0616007872 0.0615526926 -0.061490875 0.0614153483 -0.061326129199999996 -0.0772062 -0.0497254 0.367467 -0.0100973 -0.00551319 0.00307188 -421.8799743652344 351.5860900878906 345.7599182128906 0.981342 59.147472 0.13091309999999998 -0.00023811459999999998 0.0014113579000000001 0.0589832312 -0.05759092440000001 -0.0366861115 -0.010808996699999998 0.0170013236 0.0492634999 0.0243669302 0.008810704300000001 -0.0088384347 -0.015403706699999999 -0.061660167 0.061652743499999996 -0.0616403716 0.0616230524 -0.0616007872 0.0615735779 -0.0615414265 -0.0728679 0.0122509 0.385343 -0.0106585 -0.00574298 0.00321534 -424.6867980957031 351.6780090332031 346.01348876953125 0.975821 58.814686 0.11073759199999994 0.0081499757 -0.006383630899999999 0.0507607209 -0.027885499100000002 -0.044596878099999994 -0.0923937341 0.0100422214 0.040500660699999996 0.0224932248 0.0096666228 -0.019763769599999998 0.0127408286 -0.061662366600000004 0.0616615418 -0.061660167 0.0616582424 -0.0616557679 0.061652743499999996 -0.061649169299999994 -0.0761831 -0.000731992 0.362164 -0.0100236 -0.00628587 0.00346276 diff --git a/pydra/tasks/fsl/tests/data/cope_merged.nii.gz b/pydra/tasks/fsl/tests/data/cope_merged.nii.gz deleted file mode 100644 index d79c4dc..0000000 --- a/pydra/tasks/fsl/tests/data/cope_merged.nii.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ccdedd7aef55301fe634a494ca7df384d59bfab309e20cc042954d66b1774bbc -size 25232078 diff --git a/pydra/tasks/fsl/tests/data/design b/pydra/tasks/fsl/tests/data/design deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/design.con b/pydra/tasks/fsl/tests/data/design.con deleted file mode 100644 index 999adde..0000000 --- a/pydra/tasks/fsl/tests/data/design.con +++ /dev/null @@ -1,8 +0,0 @@ -/ContrastName1 group mean -/NumWaves 1 -/NumContrasts 1 -/PPheights 1 -/RequiredEffect 100 - -/Matrix -1 diff --git a/pydra/tasks/fsl/tests/data/design.grp b/pydra/tasks/fsl/tests/data/design.grp deleted file mode 100644 index b90612e..0000000 --- a/pydra/tasks/fsl/tests/data/design.grp +++ /dev/null @@ -1,30 +0,0 @@ -/NumWaves 1 -/NumPoints 26 - -/Matrix -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 diff --git a/pydra/tasks/fsl/tests/data/design.mat b/pydra/tasks/fsl/tests/data/design.mat deleted file mode 100644 index 03cce9e..0000000 --- a/pydra/tasks/fsl/tests/data/design.mat +++ /dev/null @@ -1,31 +0,0 @@ -/NumWaves 1 -/NumPoints 26 -/PPheights 1 - -/Matrix -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 diff --git a/pydra/tasks/fsl/tests/data/design_film_gls.mat b/pydra/tasks/fsl/tests/data/design_film_gls.mat deleted file mode 100644 index b65f2bd..0000000 --- a/pydra/tasks/fsl/tests/data/design_film_gls.mat +++ /dev/null @@ -1,151 +0,0 @@ -/NumWaves 2 -/NumPoints 146 -/PPheights 3.012332e-01 3.012332e-01 - -/Matrix --5.459164e-02 -1.321669e-01 --5.776502e-02 6.606531e-03 --6.080976e-02 1.543109e-01 --6.371286e-02 1.298120e-01 --6.647145e-02 3.844376e-02 --6.908718e-02 -3.150186e-02 --7.156363e-02 6.090263e-02 --7.390440e-02 1.853853e-01 --7.611377e-02 1.503911e-01 --7.819593e-02 5.456673e-02 --7.486357e-02 -2.261410e-02 -5.867573e-02 -6.685146e-02 -2.012061e-01 -8.703843e-02 -1.717945e-01 -9.469297e-02 -7.582675e-02 -9.654834e-02 -1.559045e-03 -9.605199e-02 -8.987555e-02 -9.498077e-02 -2.104731e-01 -9.314661e-02 -1.717227e-01 -9.140213e-02 -7.226508e-02 -8.973824e-02 --8.360482e-03 -8.285842e-02 --5.583817e-02 5.403689e-02 --7.907882e-02 1.997381e-01 --8.966740e-02 1.733180e-01 --9.433347e-02 8.016810e-02 --9.647567e-02 3.258706e-03 --9.258233e-02 -4.131708e-02 -4.231492e-02 -6.264655e-02 -1.861386e-01 -7.145020e-02 -1.579594e-01 -7.446427e-02 -6.316558e-02 -7.508158e-02 --1.527660e-02 -7.507187e-02 --5.598662e-02 -7.425640e-02 -5.674071e-02 -7.349584e-02 -1.909692e-01 -7.278683e-02 -1.590299e-01 -7.212842e-02 -6.292010e-02 -7.153127e-02 --1.615871e-02 -7.100015e-02 --6.194223e-02 -6.523060e-02 --8.438769e-02 7.058237e-02 --9.421868e-02 2.152288e-01 --9.817426e-02 1.877781e-01 --9.964602e-02 9.360361e-02 --1.004003e-01 1.566834e-02 --9.497193e-02 -2.991771e-02 -4.056806e-02 -5.223350e-02 -1.850072e-01 -6.200044e-02 -1.574158e-01 -6.595827e-02 -6.318250e-02 -6.749883e-02 --1.474421e-02 -6.838785e-02 --6.027821e-02 -6.845050e-02 --8.248644e-02 -6.326130e-02 --9.208075e-02 7.197718e-02 --9.579978e-02 2.160541e-01 --9.703767e-02 1.880415e-01 --9.756266e-02 9.332951e-02 --9.720187e-02 1.486645e-02 --9.682290e-02 -3.125984e-02 --9.113464e-02 -5.411225e-02 -4.465926e-02 -6.440030e-02 -1.893469e-01 -6.886134e-02 -1.619991e-01 -7.088827e-02 -6.800471e-02 -7.224792e-02 --9.690209e-03 -7.276583e-02 --5.499909e-02 -7.330789e-02 --7.169342e-02 -7.387266e-02 -5.431262e-02 -7.445841e-02 -1.950681e-01 -7.506335e-02 -1.662489e-01 -7.568549e-02 -7.147623e-02 -7.632279e-02 --8.176363e-04 -7.697310e-02 -8.937981e-02 -7.765713e-02 -2.117738e-01 -7.835313e-02 -1.747124e-01 -7.905909e-02 -7.684715e-02 -7.977294e-02 --2.244466e-03 -7.520110e-02 --4.825783e-02 5.945172e-02 --7.008473e-02 2.030005e-01 --7.931501e-02 1.745170e-01 --8.268742e-02 7.936397e-02 --8.359340e-02 5.028823e-04 --8.379921e-02 -4.596713e-02 --8.313134e-02 -6.381502e-02 --8.245759e-02 6.103882e-02 --8.177899e-02 2.006207e-01 --8.109666e-02 1.706052e-01 --8.041089e-02 7.462413e-02 --7.970375e-02 1.120672e-03 --7.897786e-02 9.012257e-02 --7.826208e-02 2.113333e-01 --7.756605e-02 1.731043e-01 --7.688548e-02 7.409003e-02 --7.090554e-02 -6.129659e-03 -6.517159e-02 -5.322669e-02 -2.101087e-01 -7.611373e-02 -1.829684e-01 -8.637799e-02 -8.914442e-02 -9.075484e-02 -1.161007e-02 -9.261644e-02 --2.824889e-02 -9.372844e-02 -8.527574e-02 -9.393906e-02 -2.202495e-01 -9.412025e-02 -1.890043e-01 -9.426583e-02 -9.353877e-02 -9.436847e-02 -1.506874e-02 -9.442292e-02 --3.014387e-02 -8.913434e-02 --5.207685e-02 4.629598e-02 --6.145878e-02 1.906580e-01 --6.502444e-02 1.630239e-01 --6.616014e-02 6.878507e-02 --6.661982e-02 -9.088744e-03 --6.623232e-02 -4.921326e-02 --6.587989e-02 6.412036e-02 --6.556584e-02 1.989795e-01 --6.528731e-02 1.676985e-01 --6.504170e-02 7.227823e-02 --6.482819e-02 -6.073926e-03 --6.464721e-02 -4.580406e-02 --6.449977e-02 6.792454e-02 --6.438708e-02 2.031816e-01 --6.431039e-02 1.723052e-01 --6.427118e-02 7.729824e-02 --6.427838e-02 -6.342129e-04 --6.434014e-02 -4.522484e-02 --5.915676e-02 -6.642826e-02 -7.607670e-02 -7.496560e-02 -2.201507e-01 -7.757353e-02 -1.921346e-01 -7.764146e-02 -9.741598e-02 -7.693452e-02 -1.896121e-02 -7.530513e-02 --2.713964e-02 -7.363015e-02 --4.997651e-02 -6.657981e-02 --6.027214e-02 7.066638e-02 --6.476492e-02 2.168997e-01 --6.684551e-02 1.911862e-01 --6.828164e-02 9.891084e-02 --6.896161e-02 2.303913e-02 --6.977084e-02 -2.033853e-02 --6.533284e-02 -4.031109e-02 -6.919543e-02 -4.759994e-02 -2.126028e-01 -4.894233e-02 -1.839457e-01 -4.772757e-02 -8.859665e-02 -4.571982e-02 -9.392948e-03 -4.274329e-02 --3.761005e-02 -3.966346e-02 --6.133499e-02 -3.647896e-02 --7.241645e-02 -3.318836e-02 diff --git a/pydra/tasks/fsl/tests/data/dest.nii.gz b/pydra/tasks/fsl/tests/data/dest.nii.gz deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/ev_1.txt b/pydra/tasks/fsl/tests/data/ev_1.txt deleted file mode 100644 index 64e7df8..0000000 --- a/pydra/tasks/fsl/tests/data/ev_1.txt +++ /dev/null @@ -1,12 +0,0 @@ -32.000000 2.000000 1.000000 -42.000000 2.000000 1.000000 -52.000000 2.000000 1.000000 -64.000000 2.000000 1.000000 -102.000000 2.000000 1.000000 -116.000000 2.000000 1.000000 -144.000000 2.000000 1.000000 -164.000000 2.000000 1.000000 -208.000000 2.000000 1.000000 -220.000000 2.000000 1.000000 -232.000000 2.000000 1.000000 -260.000000 2.000000 1.000000 diff --git a/pydra/tasks/fsl/tests/data/ev_2.txt b/pydra/tasks/fsl/tests/data/ev_2.txt deleted file mode 100644 index c992e50..0000000 --- a/pydra/tasks/fsl/tests/data/ev_2.txt +++ /dev/null @@ -1,12 +0,0 @@ -0.000000 2.000000 1.000000 -10.000000 2.000000 1.000000 -20.000000 2.000000 1.000000 -76.000000 2.000000 1.000000 -88.000000 2.000000 1.000000 -130.000000 2.000000 1.000000 -154.000000 2.000000 1.000000 -174.000000 2.000000 1.000000 -184.000000 2.000000 1.000000 -196.000000 2.000000 1.000000 -246.000000 2.000000 1.000000 -274.000000 2.000000 1.000000 diff --git a/pydra/tasks/fsl/tests/data/flirt.mat b/pydra/tasks/fsl/tests/data/flirt.mat deleted file mode 100644 index 080d687..0000000 --- a/pydra/tasks/fsl/tests/data/flirt.mat +++ /dev/null @@ -1,4 +0,0 @@ -1.06898439 0.04500452499 0.07609409025 -19.99484204 --0.04444970083 1.031806413 0.02891208633 17.8281428 --0.0452495497 -0.07397098198 1.22886291 -3.444566823 -0 0 0 1 diff --git a/pydra/tasks/fsl/tests/data/flirt_inv.mat b/pydra/tasks/fsl/tests/data/flirt_inv.mat deleted file mode 100644 index bc9b4b6..0000000 --- a/pydra/tasks/fsl/tests/data/flirt_inv.mat +++ /dev/null @@ -1,4 +0,0 @@ -0.9312133442 -0.04467547969 -0.05661182412 19.22094134 -0.03908945148 0.9656667535 -0.02514024676 -16.52105463 -0.03664238643 0.0564829259 0.8101625361 2.516332053 -0 0 0 1 diff --git a/pydra/tasks/fsl/tests/data/mask.nii.gz b/pydra/tasks/fsl/tests/data/mask.nii.gz deleted file mode 100644 index 1044603..0000000 --- a/pydra/tasks/fsl/tests/data/mask.nii.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:95cc283387609f9d0653014cbc9636f528135135041f639a17c19d88c3680db5 -size 21201 diff --git a/pydra/tasks/fsl/tests/data/struct2mni.nii b/pydra/tasks/fsl/tests/data/struct2mni.nii deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/subjectDesign.con b/pydra/tasks/fsl/tests/data/subjectDesign.con deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/subjectDesign.mat b/pydra/tasks/fsl/tests/data/subjectDesign.mat deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/test.fsf b/pydra/tasks/fsl/tests/data/test.fsf deleted file mode 100644 index d6e5976..0000000 --- a/pydra/tasks/fsl/tests/data/test.fsf +++ /dev/null @@ -1,11836 +0,0 @@ - -# FEAT version number -set fmri(version) 6.00 - -# Are we in MELODIC? -set fmri(inmelodic) 0 - -# Analysis level -# 1 : First-level analysis -# 2 : Higher-level analysis -set fmri(level) 2 - -# Which stages to run -# 0 : No first-level analysis (registration and/or group stats only) -# 7 : Full first-level analysis -# 1 : Pre-processing -# 2 : Statistics -set fmri(analysis) 2 - -# Use relative filenames -set fmri(relative_yn) 0 - -# Balloon help -set fmri(help_yn) 1 - -# Run Featwatcher -set fmri(featwatcher_yn) 1 - -# Cleanup first-level standard-space images -set fmri(sscleanup_yn) 0 - -# Output directory -set fmri(outputdir) "Flanker_2ndLevel" - -# TR(s) -set fmri(tr) 3 - -# Total volumes -set fmri(npts) 52 - -# Delete volumes -set fmri(ndelete) 0 - -# Perfusion tag/control order -set fmri(tagfirst) 1 - -# Number of first-level analyses -set fmri(multiple) 52 - -# Higher-level input type -# 1 : Inputs are lower-level FEAT directories -# 2 : Inputs are cope images from FEAT directories -set fmri(inputtype) 1 - -# Carry out pre-stats processing? -set fmri(filtering_yn) 0 - -# Brain/background threshold, % -set fmri(brain_thresh) 10 - -# Critical z for design efficiency calculation -set fmri(critical_z) 5.3 - -# Noise level -set fmri(noise) 0.66 - -# Noise AR(1) -set fmri(noisear) 0.34 - -# Motion correction -# 0 : None -# 1 : MCFLIRT -set fmri(mc) 1 - -# Spin-history (currently obsolete) -set fmri(sh_yn) 0 - -# B0 fieldmap unwarping? -set fmri(regunwarp_yn) 0 - -# GDC Test -set fmri(gdc) "" - -# EPI dwell time (ms) -set fmri(dwell) 0.0 - -# EPI TE (ms) -set fmri(te) 0.0 - -# % Signal loss threshold -set fmri(signallossthresh) 10 - -# Unwarp direction -set fmri(unwarp_dir) y- - -# Slice timing correction -# 0 : None -# 1 : Regular up (0, 1, 2, 3, ...) -# 2 : Regular down -# 3 : Use slice order file -# 4 : Use slice timings file -# 5 : Interleaved (0, 2, 4 ... 1, 3, 5 ... ) -set fmri(st) 0 - -# Slice timings file -set fmri(st_file) "" - -# BET brain extraction -set fmri(bet_yn) 1 - -# Spatial smoothing FWHM (mm) -set fmri(smooth) 5 - -# Intensity normalization -set fmri(norm_yn) 0 - -# Perfusion subtraction -set fmri(perfsub_yn) 0 - -# Highpass temporal filtering -set fmri(temphp_yn) 1 - -# Lowpass temporal filtering -set fmri(templp_yn) 0 - -# MELODIC ICA data exploration -set fmri(melodic_yn) 0 - -# Carry out main stats? -set fmri(stats_yn) 1 - -# Carry out prewhitening? -set fmri(prewhiten_yn) 1 - -# Add motion parameters to model -# 0 : No -# 1 : Yes -set fmri(motionevs) 0 -set fmri(motionevsbeta) "" -set fmri(scriptevsbeta) "" - -# Robust outlier detection in FLAME? -set fmri(robust_yn) 0 - -# Higher-level modelling -# 3 : Fixed effects -# 0 : Mixed Effects: Simple OLS -# 2 : Mixed Effects: FLAME 1 -# 1 : Mixed Effects: FLAME 1+2 -set fmri(mixed_yn) 3 - -# Higher-level permutations -set fmri(randomisePermutations) 5000 - -# Number of EVs -set fmri(evs_orig) 26 -set fmri(evs_real) 26 -set fmri(evs_vox) 0 - -# Number of contrasts -set fmri(ncon_orig) 1 -set fmri(ncon_real) 26 - -# Number of F-tests -set fmri(nftests_orig) 0 -set fmri(nftests_real) 0 - -# Add constant column to design matrix? (obsolete) -set fmri(constcol) 0 - -# Carry out post-stats steps? -set fmri(poststats_yn) 0 - -# Pre-threshold masking? -set fmri(threshmask) "" - -# Thresholding -# 0 : None -# 1 : Uncorrected -# 2 : Voxel -# 3 : Cluster -set fmri(thresh) 3 - -# P threshold -set fmri(prob_thresh) 0.05 - -# Z threshold -set fmri(z_thresh) 3.1 - -# Z min/max for colour rendering -# 0 : Use actual Z min/max -# 1 : Use preset Z min/max -set fmri(zdisplay) 0 - -# Z min in colour rendering -set fmri(zmin) 2 - -# Z max in colour rendering -set fmri(zmax) 8 - -# Colour rendering type -# 0 : Solid blobs -# 1 : Transparent blobs -set fmri(rendertype) 1 - -# Background image for higher-level stats overlays -# 1 : Mean highres -# 2 : First highres -# 3 : Mean functional -# 4 : First functional -# 5 : Standard space template -set fmri(bgimage) 1 - -# Create time series plots -set fmri(tsplot_yn) 1 - -# Registration to initial structural -set fmri(reginitial_highres_yn) 0 - -# Search space for registration to initial structural -# 0 : No search -# 90 : Normal search -# 180 : Full search -set fmri(reginitial_highres_search) 90 - -# Degrees of Freedom for registration to initial structural -set fmri(reginitial_highres_dof) 3 - -# Registration to main structural -set fmri(reghighres_yn) 0 - -# Search space for registration to main structural -# 0 : No search -# 90 : Normal search -# 180 : Full search -set fmri(reghighres_search) 90 - -# Degrees of Freedom for registration to main structural -set fmri(reghighres_dof) BBR - -# Registration to standard image? -set fmri(regstandard_yn) 1 - -# Use alternate reference images? -set fmri(alternateReference_yn) 0 - -# Standard image -set fmri(regstandard) "/usr/local/fsl/data/standard/MNI152_T1_2mm_brain" - -# Search space for registration to standard space -# 0 : No search -# 90 : Normal search -# 180 : Full search -set fmri(regstandard_search) 90 - -# Degrees of Freedom for registration to standard space -set fmri(regstandard_dof) 12 - -# Do nonlinear registration from structural to standard space? -set fmri(regstandard_nonlinear_yn) 0 - -# Control nonlinear warp field resolution -set fmri(regstandard_nonlinear_warpres) 10 - -# High pass filter cutoff -set fmri(paradigm_hp) 100 - -# Number of lower-level copes feeding into higher-level analysis -set fmri(ncopeinputs) 4 - -# Use lower-level cope 1 for higher-level analysis -set fmri(copeinput.1) 1 - -# Use lower-level cope 2 for higher-level analysis -set fmri(copeinput.2) 1 - -# Use lower-level cope 3 for higher-level analysis -set fmri(copeinput.3) 1 - -# Use lower-level cope 4 for higher-level analysis -set fmri(copeinput.4) 1 - -# 4D AVW data or FEAT directory (1) -set feat_files(1) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-01/run1.feat" - -# 4D AVW data or FEAT directory (2) -set feat_files(2) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-01/run2.feat" - -# 4D AVW data or FEAT directory (3) -set feat_files(3) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-02/run1.feat" - -# 4D AVW data or FEAT directory (4) -set feat_files(4) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-02/run2.feat" - -# 4D AVW data or FEAT directory (5) -set feat_files(5) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-03/run1.feat" - -# 4D AVW data or FEAT directory (6) -set feat_files(6) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-03/run2.feat" - -# 4D AVW data or FEAT directory (7) -set feat_files(7) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-04/run1.feat" - -# 4D AVW data or FEAT directory (8) -set feat_files(8) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-04/run2.feat" - -# 4D AVW data or FEAT directory (9) -set feat_files(9) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-05/run1.feat" - -# 4D AVW data or FEAT directory (10) -set feat_files(10) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-05/run2.feat" - -# 4D AVW data or FEAT directory (11) -set feat_files(11) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-06/run1.feat" - -# 4D AVW data or FEAT directory (12) -set feat_files(12) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-06/run2.feat" - -# 4D AVW data or FEAT directory (13) -set feat_files(13) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-07/run1.feat" - -# 4D AVW data or FEAT directory (14) -set feat_files(14) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-07/run2.feat" - -# 4D AVW data or FEAT directory (15) -set feat_files(15) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-08/run1.feat" - -# 4D AVW data or FEAT directory (16) -set feat_files(16) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-08/run2.feat" - -# 4D AVW data or FEAT directory (17) -set feat_files(17) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-09/run1.feat" - -# 4D AVW data or FEAT directory (18) -set feat_files(18) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-09/run2.feat" - -# 4D AVW data or FEAT directory (19) -set feat_files(19) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-10/run1.feat" - -# 4D AVW data or FEAT directory (20) -set feat_files(20) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-10/run2.feat" - -# 4D AVW data or FEAT directory (21) -set feat_files(21) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-11/run1.feat" - -# 4D AVW data or FEAT directory (22) -set feat_files(22) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-11/run2.feat" - -# 4D AVW data or FEAT directory (23) -set feat_files(23) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-12/run1.feat" - -# 4D AVW data or FEAT directory (24) -set feat_files(24) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-12/run2.feat" - -# 4D AVW data or FEAT directory (25) -set feat_files(25) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-13/run1.feat" - -# 4D AVW data or FEAT directory (26) -set feat_files(26) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-13/run2.feat" - -# 4D AVW data or FEAT directory (27) -set feat_files(27) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-14/run1.feat" - -# 4D AVW data or FEAT directory (28) -set feat_files(28) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-14/run2.feat" - -# 4D AVW data or FEAT directory (29) -set feat_files(29) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-15/run1.feat" - -# 4D AVW data or FEAT directory (30) -set feat_files(30) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-15/run2.feat" - -# 4D AVW data or FEAT directory (31) -set feat_files(31) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-16/run1.feat" - -# 4D AVW data or FEAT directory (32) -set feat_files(32) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-16/run2.feat" - -# 4D AVW data or FEAT directory (33) -set feat_files(33) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-17/run1.feat" - -# 4D AVW data or FEAT directory (34) -set feat_files(34) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-17/run2.feat" - -# 4D AVW data or FEAT directory (35) -set feat_files(35) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-18/run1.feat" - -# 4D AVW data or FEAT directory (36) -set feat_files(36) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-18/run2.feat" - -# 4D AVW data or FEAT directory (37) -set feat_files(37) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-19/run1.feat" - -# 4D AVW data or FEAT directory (38) -set feat_files(38) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-19/run2.feat" - -# 4D AVW data or FEAT directory (39) -set feat_files(39) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-20/run1.feat" - -# 4D AVW data or FEAT directory (40) -set feat_files(40) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-20/run2.feat" - -# 4D AVW data or FEAT directory (41) -set feat_files(41) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-21/run1.feat" - -# 4D AVW data or FEAT directory (42) -set feat_files(42) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-21/run2.feat" - -# 4D AVW data or FEAT directory (43) -set feat_files(43) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-22/run1.feat" - -# 4D AVW data or FEAT directory (44) -set feat_files(44) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-22/run2.feat" - -# 4D AVW data or FEAT directory (45) -set feat_files(45) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-23/run1.feat" - -# 4D AVW data or FEAT directory (46) -set feat_files(46) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-23/run2.feat" - -# 4D AVW data or FEAT directory (47) -set feat_files(47) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-24/run1.feat" - -# 4D AVW data or FEAT directory (48) -set feat_files(48) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-24/run2.feat" - -# 4D AVW data or FEAT directory (49) -set feat_files(49) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-25/run1.feat" - -# 4D AVW data or FEAT directory (50) -set feat_files(50) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-25/run2.feat" - -# 4D AVW data or FEAT directory (51) -set feat_files(51) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-26/run1.feat" - -# 4D AVW data or FEAT directory (52) -set feat_files(52) "/srv/scratch/yc/fsl/nipype_fsl_comp/gui/sub-26/run2.feat" - - -# Add confound EVs text file -set fmri(confoundevs) 0 - -# EV 1 title -set fmri(evtitle1) "" - -# Basic waveform shape (EV 1) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape1) 2 - -# Convolution (EV 1) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve1) 0 - -# Convolve phase (EV 1) -set fmri(convolve_phase1) 0 - -# Apply temporal filtering (EV 1) -set fmri(tempfilt_yn1) 0 - -# Add temporal derivative (EV 1) -set fmri(deriv_yn1) 0 - -# Custom EV file (EV 1) -set fmri(custom1) "dummy" - -# Orthogonalise EV 1 wrt EV 0 -set fmri(ortho1.0) 0 - -# Orthogonalise EV 1 wrt EV 1 -set fmri(ortho1.1) 0 - -# Orthogonalise EV 1 wrt EV 2 -set fmri(ortho1.2) 0 - -# Orthogonalise EV 1 wrt EV 3 -set fmri(ortho1.3) 0 - -# Orthogonalise EV 1 wrt EV 4 -set fmri(ortho1.4) 0 - -# Orthogonalise EV 1 wrt EV 5 -set fmri(ortho1.5) 0 - -# Orthogonalise EV 1 wrt EV 6 -set fmri(ortho1.6) 0 - -# Orthogonalise EV 1 wrt EV 7 -set fmri(ortho1.7) 0 - -# Orthogonalise EV 1 wrt EV 8 -set fmri(ortho1.8) 0 - -# Orthogonalise EV 1 wrt EV 9 -set fmri(ortho1.9) 0 - -# Orthogonalise EV 1 wrt EV 10 -set fmri(ortho1.10) 0 - -# Orthogonalise EV 1 wrt EV 11 -set fmri(ortho1.11) 0 - -# Orthogonalise EV 1 wrt EV 12 -set fmri(ortho1.12) 0 - -# Orthogonalise EV 1 wrt EV 13 -set fmri(ortho1.13) 0 - -# Orthogonalise EV 1 wrt EV 14 -set fmri(ortho1.14) 0 - -# Orthogonalise EV 1 wrt EV 15 -set fmri(ortho1.15) 0 - -# Orthogonalise EV 1 wrt EV 16 -set fmri(ortho1.16) 0 - -# Orthogonalise EV 1 wrt EV 17 -set fmri(ortho1.17) 0 - -# Orthogonalise EV 1 wrt EV 18 -set fmri(ortho1.18) 0 - -# Orthogonalise EV 1 wrt EV 19 -set fmri(ortho1.19) 0 - -# Orthogonalise EV 1 wrt EV 20 -set fmri(ortho1.20) 0 - -# Orthogonalise EV 1 wrt EV 21 -set fmri(ortho1.21) 0 - -# Orthogonalise EV 1 wrt EV 22 -set fmri(ortho1.22) 0 - -# Orthogonalise EV 1 wrt EV 23 -set fmri(ortho1.23) 0 - -# Orthogonalise EV 1 wrt EV 24 -set fmri(ortho1.24) 0 - -# Orthogonalise EV 1 wrt EV 25 -set fmri(ortho1.25) 0 - -# Orthogonalise EV 1 wrt EV 26 -set fmri(ortho1.26) 0 - -# Higher-level EV value for EV 1 and input 1 -set fmri(evg1.1) 1 - -# Higher-level EV value for EV 1 and input 2 -set fmri(evg2.1) 1.0 - -# Higher-level EV value for EV 1 and input 3 -set fmri(evg3.1) 0 - -# Higher-level EV value for EV 1 and input 4 -set fmri(evg4.1) 0 - -# Higher-level EV value for EV 1 and input 5 -set fmri(evg5.1) 0 - -# Higher-level EV value for EV 1 and input 6 -set fmri(evg6.1) 0 - -# Higher-level EV value for EV 1 and input 7 -set fmri(evg7.1) 0 - -# Higher-level EV value for EV 1 and input 8 -set fmri(evg8.1) 0 - -# Higher-level EV value for EV 1 and input 9 -set fmri(evg9.1) 0 - -# Higher-level EV value for EV 1 and input 10 -set fmri(evg10.1) 0 - -# Higher-level EV value for EV 1 and input 11 -set fmri(evg11.1) 0 - -# Higher-level EV value for EV 1 and input 12 -set fmri(evg12.1) 0 - -# Higher-level EV value for EV 1 and input 13 -set fmri(evg13.1) 0 - -# Higher-level EV value for EV 1 and input 14 -set fmri(evg14.1) 0 - -# Higher-level EV value for EV 1 and input 15 -set fmri(evg15.1) 0 - -# Higher-level EV value for EV 1 and input 16 -set fmri(evg16.1) 0 - -# Higher-level EV value for EV 1 and input 17 -set fmri(evg17.1) 0 - -# Higher-level EV value for EV 1 and input 18 -set fmri(evg18.1) 0 - -# Higher-level EV value for EV 1 and input 19 -set fmri(evg19.1) 0 - -# Higher-level EV value for EV 1 and input 20 -set fmri(evg20.1) 0 - -# Higher-level EV value for EV 1 and input 21 -set fmri(evg21.1) 0 - -# Higher-level EV value for EV 1 and input 22 -set fmri(evg22.1) 0 - -# Higher-level EV value for EV 1 and input 23 -set fmri(evg23.1) 0 - -# Higher-level EV value for EV 1 and input 24 -set fmri(evg24.1) 0 - -# Higher-level EV value for EV 1 and input 25 -set fmri(evg25.1) 0 - -# Higher-level EV value for EV 1 and input 26 -set fmri(evg26.1) 0 - -# Higher-level EV value for EV 1 and input 27 -set fmri(evg27.1) 0 - -# Higher-level EV value for EV 1 and input 28 -set fmri(evg28.1) 0 - -# Higher-level EV value for EV 1 and input 29 -set fmri(evg29.1) 0 - -# Higher-level EV value for EV 1 and input 30 -set fmri(evg30.1) 0 - -# Higher-level EV value for EV 1 and input 31 -set fmri(evg31.1) 0 - -# Higher-level EV value for EV 1 and input 32 -set fmri(evg32.1) 0 - -# Higher-level EV value for EV 1 and input 33 -set fmri(evg33.1) 0 - -# Higher-level EV value for EV 1 and input 34 -set fmri(evg34.1) 0 - -# Higher-level EV value for EV 1 and input 35 -set fmri(evg35.1) 0 - -# Higher-level EV value for EV 1 and input 36 -set fmri(evg36.1) 0 - -# Higher-level EV value for EV 1 and input 37 -set fmri(evg37.1) 0 - -# Higher-level EV value for EV 1 and input 38 -set fmri(evg38.1) 0 - -# Higher-level EV value for EV 1 and input 39 -set fmri(evg39.1) 0 - -# Higher-level EV value for EV 1 and input 40 -set fmri(evg40.1) 0 - -# Higher-level EV value for EV 1 and input 41 -set fmri(evg41.1) 0 - -# Higher-level EV value for EV 1 and input 42 -set fmri(evg42.1) 0 - -# Higher-level EV value for EV 1 and input 43 -set fmri(evg43.1) 0 - -# Higher-level EV value for EV 1 and input 44 -set fmri(evg44.1) 0 - -# Higher-level EV value for EV 1 and input 45 -set fmri(evg45.1) 0 - -# Higher-level EV value for EV 1 and input 46 -set fmri(evg46.1) 0 - -# Higher-level EV value for EV 1 and input 47 -set fmri(evg47.1) 0 - -# Higher-level EV value for EV 1 and input 48 -set fmri(evg48.1) 0 - -# Higher-level EV value for EV 1 and input 49 -set fmri(evg49.1) 0 - -# Higher-level EV value for EV 1 and input 50 -set fmri(evg50.1) 0 - -# Higher-level EV value for EV 1 and input 51 -set fmri(evg51.1) 0 - -# Higher-level EV value for EV 1 and input 52 -set fmri(evg52.1) 0 - -# EV 2 title -set fmri(evtitle2) "" - -# Basic waveform shape (EV 2) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape2) 2 - -# Convolution (EV 2) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve2) 0 - -# Convolve phase (EV 2) -set fmri(convolve_phase2) 0 - -# Apply temporal filtering (EV 2) -set fmri(tempfilt_yn2) 0 - -# Add temporal derivative (EV 2) -set fmri(deriv_yn2) 0 - -# Custom EV file (EV 2) -set fmri(custom2) "dummy" - -# Orthogonalise EV 2 wrt EV 0 -set fmri(ortho2.0) 0 - -# Orthogonalise EV 2 wrt EV 1 -set fmri(ortho2.1) 0 - -# Orthogonalise EV 2 wrt EV 2 -set fmri(ortho2.2) 0 - -# Orthogonalise EV 2 wrt EV 3 -set fmri(ortho2.3) 0 - -# Orthogonalise EV 2 wrt EV 4 -set fmri(ortho2.4) 0 - -# Orthogonalise EV 2 wrt EV 5 -set fmri(ortho2.5) 0 - -# Orthogonalise EV 2 wrt EV 6 -set fmri(ortho2.6) 0 - -# Orthogonalise EV 2 wrt EV 7 -set fmri(ortho2.7) 0 - -# Orthogonalise EV 2 wrt EV 8 -set fmri(ortho2.8) 0 - -# Orthogonalise EV 2 wrt EV 9 -set fmri(ortho2.9) 0 - -# Orthogonalise EV 2 wrt EV 10 -set fmri(ortho2.10) 0 - -# Orthogonalise EV 2 wrt EV 11 -set fmri(ortho2.11) 0 - -# Orthogonalise EV 2 wrt EV 12 -set fmri(ortho2.12) 0 - -# Orthogonalise EV 2 wrt EV 13 -set fmri(ortho2.13) 0 - -# Orthogonalise EV 2 wrt EV 14 -set fmri(ortho2.14) 0 - -# Orthogonalise EV 2 wrt EV 15 -set fmri(ortho2.15) 0 - -# Orthogonalise EV 2 wrt EV 16 -set fmri(ortho2.16) 0 - -# Orthogonalise EV 2 wrt EV 17 -set fmri(ortho2.17) 0 - -# Orthogonalise EV 2 wrt EV 18 -set fmri(ortho2.18) 0 - -# Orthogonalise EV 2 wrt EV 19 -set fmri(ortho2.19) 0 - -# Orthogonalise EV 2 wrt EV 20 -set fmri(ortho2.20) 0 - -# Orthogonalise EV 2 wrt EV 21 -set fmri(ortho2.21) 0 - -# Orthogonalise EV 2 wrt EV 22 -set fmri(ortho2.22) 0 - -# Orthogonalise EV 2 wrt EV 23 -set fmri(ortho2.23) 0 - -# Orthogonalise EV 2 wrt EV 24 -set fmri(ortho2.24) 0 - -# Orthogonalise EV 2 wrt EV 25 -set fmri(ortho2.25) 0 - -# Orthogonalise EV 2 wrt EV 26 -set fmri(ortho2.26) 0 - -# Higher-level EV value for EV 2 and input 1 -set fmri(evg1.2) 0 - -# Higher-level EV value for EV 2 and input 2 -set fmri(evg2.2) 0 - -# Higher-level EV value for EV 2 and input 3 -set fmri(evg3.2) 1.0 - -# Higher-level EV value for EV 2 and input 4 -set fmri(evg4.2) 1.0 - -# Higher-level EV value for EV 2 and input 5 -set fmri(evg5.2) 0 - -# Higher-level EV value for EV 2 and input 6 -set fmri(evg6.2) 0 - -# Higher-level EV value for EV 2 and input 7 -set fmri(evg7.2) 0 - -# Higher-level EV value for EV 2 and input 8 -set fmri(evg8.2) 0 - -# Higher-level EV value for EV 2 and input 9 -set fmri(evg9.2) 0 - -# Higher-level EV value for EV 2 and input 10 -set fmri(evg10.2) 0 - -# Higher-level EV value for EV 2 and input 11 -set fmri(evg11.2) 0 - -# Higher-level EV value for EV 2 and input 12 -set fmri(evg12.2) 0 - -# Higher-level EV value for EV 2 and input 13 -set fmri(evg13.2) 0 - -# Higher-level EV value for EV 2 and input 14 -set fmri(evg14.2) 0 - -# Higher-level EV value for EV 2 and input 15 -set fmri(evg15.2) 0 - -# Higher-level EV value for EV 2 and input 16 -set fmri(evg16.2) 0 - -# Higher-level EV value for EV 2 and input 17 -set fmri(evg17.2) 0 - -# Higher-level EV value for EV 2 and input 18 -set fmri(evg18.2) 0 - -# Higher-level EV value for EV 2 and input 19 -set fmri(evg19.2) 0 - -# Higher-level EV value for EV 2 and input 20 -set fmri(evg20.2) 0 - -# Higher-level EV value for EV 2 and input 21 -set fmri(evg21.2) 0 - -# Higher-level EV value for EV 2 and input 22 -set fmri(evg22.2) 0 - -# Higher-level EV value for EV 2 and input 23 -set fmri(evg23.2) 0 - -# Higher-level EV value for EV 2 and input 24 -set fmri(evg24.2) 0 - -# Higher-level EV value for EV 2 and input 25 -set fmri(evg25.2) 0 - -# Higher-level EV value for EV 2 and input 26 -set fmri(evg26.2) 0 - -# Higher-level EV value for EV 2 and input 27 -set fmri(evg27.2) 0 - -# Higher-level EV value for EV 2 and input 28 -set fmri(evg28.2) 0 - -# Higher-level EV value for EV 2 and input 29 -set fmri(evg29.2) 0 - -# Higher-level EV value for EV 2 and input 30 -set fmri(evg30.2) 0 - -# Higher-level EV value for EV 2 and input 31 -set fmri(evg31.2) 0 - -# Higher-level EV value for EV 2 and input 32 -set fmri(evg32.2) 0 - -# Higher-level EV value for EV 2 and input 33 -set fmri(evg33.2) 0 - -# Higher-level EV value for EV 2 and input 34 -set fmri(evg34.2) 0 - -# Higher-level EV value for EV 2 and input 35 -set fmri(evg35.2) 0 - -# Higher-level EV value for EV 2 and input 36 -set fmri(evg36.2) 0 - -# Higher-level EV value for EV 2 and input 37 -set fmri(evg37.2) 0 - -# Higher-level EV value for EV 2 and input 38 -set fmri(evg38.2) 0 - -# Higher-level EV value for EV 2 and input 39 -set fmri(evg39.2) 0 - -# Higher-level EV value for EV 2 and input 40 -set fmri(evg40.2) 0 - -# Higher-level EV value for EV 2 and input 41 -set fmri(evg41.2) 0 - -# Higher-level EV value for EV 2 and input 42 -set fmri(evg42.2) 0 - -# Higher-level EV value for EV 2 and input 43 -set fmri(evg43.2) 0 - -# Higher-level EV value for EV 2 and input 44 -set fmri(evg44.2) 0 - -# Higher-level EV value for EV 2 and input 45 -set fmri(evg45.2) 0 - -# Higher-level EV value for EV 2 and input 46 -set fmri(evg46.2) 0 - -# Higher-level EV value for EV 2 and input 47 -set fmri(evg47.2) 0 - -# Higher-level EV value for EV 2 and input 48 -set fmri(evg48.2) 0 - -# Higher-level EV value for EV 2 and input 49 -set fmri(evg49.2) 0 - -# Higher-level EV value for EV 2 and input 50 -set fmri(evg50.2) 0 - -# Higher-level EV value for EV 2 and input 51 -set fmri(evg51.2) 0 - -# Higher-level EV value for EV 2 and input 52 -set fmri(evg52.2) 0 - -# EV 3 title -set fmri(evtitle3) "" - -# Basic waveform shape (EV 3) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape3) 2 - -# Convolution (EV 3) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve3) 0 - -# Convolve phase (EV 3) -set fmri(convolve_phase3) 0 - -# Apply temporal filtering (EV 3) -set fmri(tempfilt_yn3) 0 - -# Add temporal derivative (EV 3) -set fmri(deriv_yn3) 0 - -# Custom EV file (EV 3) -set fmri(custom3) "dummy" - -# Orthogonalise EV 3 wrt EV 0 -set fmri(ortho3.0) 0 - -# Orthogonalise EV 3 wrt EV 1 -set fmri(ortho3.1) 0 - -# Orthogonalise EV 3 wrt EV 2 -set fmri(ortho3.2) 0 - -# Orthogonalise EV 3 wrt EV 3 -set fmri(ortho3.3) 0 - -# Orthogonalise EV 3 wrt EV 4 -set fmri(ortho3.4) 0 - -# Orthogonalise EV 3 wrt EV 5 -set fmri(ortho3.5) 0 - -# Orthogonalise EV 3 wrt EV 6 -set fmri(ortho3.6) 0 - -# Orthogonalise EV 3 wrt EV 7 -set fmri(ortho3.7) 0 - -# Orthogonalise EV 3 wrt EV 8 -set fmri(ortho3.8) 0 - -# Orthogonalise EV 3 wrt EV 9 -set fmri(ortho3.9) 0 - -# Orthogonalise EV 3 wrt EV 10 -set fmri(ortho3.10) 0 - -# Orthogonalise EV 3 wrt EV 11 -set fmri(ortho3.11) 0 - -# Orthogonalise EV 3 wrt EV 12 -set fmri(ortho3.12) 0 - -# Orthogonalise EV 3 wrt EV 13 -set fmri(ortho3.13) 0 - -# Orthogonalise EV 3 wrt EV 14 -set fmri(ortho3.14) 0 - -# Orthogonalise EV 3 wrt EV 15 -set fmri(ortho3.15) 0 - -# Orthogonalise EV 3 wrt EV 16 -set fmri(ortho3.16) 0 - -# Orthogonalise EV 3 wrt EV 17 -set fmri(ortho3.17) 0 - -# Orthogonalise EV 3 wrt EV 18 -set fmri(ortho3.18) 0 - -# Orthogonalise EV 3 wrt EV 19 -set fmri(ortho3.19) 0 - -# Orthogonalise EV 3 wrt EV 20 -set fmri(ortho3.20) 0 - -# Orthogonalise EV 3 wrt EV 21 -set fmri(ortho3.21) 0 - -# Orthogonalise EV 3 wrt EV 22 -set fmri(ortho3.22) 0 - -# Orthogonalise EV 3 wrt EV 23 -set fmri(ortho3.23) 0 - -# Orthogonalise EV 3 wrt EV 24 -set fmri(ortho3.24) 0 - -# Orthogonalise EV 3 wrt EV 25 -set fmri(ortho3.25) 0 - -# Orthogonalise EV 3 wrt EV 26 -set fmri(ortho3.26) 0 - -# Higher-level EV value for EV 3 and input 1 -set fmri(evg1.3) 0 - -# Higher-level EV value for EV 3 and input 2 -set fmri(evg2.3) 0 - -# Higher-level EV value for EV 3 and input 3 -set fmri(evg3.3) 0 - -# Higher-level EV value for EV 3 and input 4 -set fmri(evg4.3) 0 - -# Higher-level EV value for EV 3 and input 5 -set fmri(evg5.3) 1.0 - -# Higher-level EV value for EV 3 and input 6 -set fmri(evg6.3) 1.0 - -# Higher-level EV value for EV 3 and input 7 -set fmri(evg7.3) 0 - -# Higher-level EV value for EV 3 and input 8 -set fmri(evg8.3) 0 - -# Higher-level EV value for EV 3 and input 9 -set fmri(evg9.3) 0 - -# Higher-level EV value for EV 3 and input 10 -set fmri(evg10.3) 0 - -# Higher-level EV value for EV 3 and input 11 -set fmri(evg11.3) 0 - -# Higher-level EV value for EV 3 and input 12 -set fmri(evg12.3) 0 - -# Higher-level EV value for EV 3 and input 13 -set fmri(evg13.3) 0 - -# Higher-level EV value for EV 3 and input 14 -set fmri(evg14.3) 0 - -# Higher-level EV value for EV 3 and input 15 -set fmri(evg15.3) 0 - -# Higher-level EV value for EV 3 and input 16 -set fmri(evg16.3) 0 - -# Higher-level EV value for EV 3 and input 17 -set fmri(evg17.3) 0 - -# Higher-level EV value for EV 3 and input 18 -set fmri(evg18.3) 0 - -# Higher-level EV value for EV 3 and input 19 -set fmri(evg19.3) 0 - -# Higher-level EV value for EV 3 and input 20 -set fmri(evg20.3) 0 - -# Higher-level EV value for EV 3 and input 21 -set fmri(evg21.3) 0 - -# Higher-level EV value for EV 3 and input 22 -set fmri(evg22.3) 0 - -# Higher-level EV value for EV 3 and input 23 -set fmri(evg23.3) 0 - -# Higher-level EV value for EV 3 and input 24 -set fmri(evg24.3) 0 - -# Higher-level EV value for EV 3 and input 25 -set fmri(evg25.3) 0 - -# Higher-level EV value for EV 3 and input 26 -set fmri(evg26.3) 0 - -# Higher-level EV value for EV 3 and input 27 -set fmri(evg27.3) 0 - -# Higher-level EV value for EV 3 and input 28 -set fmri(evg28.3) 0 - -# Higher-level EV value for EV 3 and input 29 -set fmri(evg29.3) 0 - -# Higher-level EV value for EV 3 and input 30 -set fmri(evg30.3) 0 - -# Higher-level EV value for EV 3 and input 31 -set fmri(evg31.3) 0 - -# Higher-level EV value for EV 3 and input 32 -set fmri(evg32.3) 0 - -# Higher-level EV value for EV 3 and input 33 -set fmri(evg33.3) 0 - -# Higher-level EV value for EV 3 and input 34 -set fmri(evg34.3) 0 - -# Higher-level EV value for EV 3 and input 35 -set fmri(evg35.3) 0 - -# Higher-level EV value for EV 3 and input 36 -set fmri(evg36.3) 0 - -# Higher-level EV value for EV 3 and input 37 -set fmri(evg37.3) 0 - -# Higher-level EV value for EV 3 and input 38 -set fmri(evg38.3) 0 - -# Higher-level EV value for EV 3 and input 39 -set fmri(evg39.3) 0 - -# Higher-level EV value for EV 3 and input 40 -set fmri(evg40.3) 0 - -# Higher-level EV value for EV 3 and input 41 -set fmri(evg41.3) 0 - -# Higher-level EV value for EV 3 and input 42 -set fmri(evg42.3) 0 - -# Higher-level EV value for EV 3 and input 43 -set fmri(evg43.3) 0 - -# Higher-level EV value for EV 3 and input 44 -set fmri(evg44.3) 0 - -# Higher-level EV value for EV 3 and input 45 -set fmri(evg45.3) 0 - -# Higher-level EV value for EV 3 and input 46 -set fmri(evg46.3) 0 - -# Higher-level EV value for EV 3 and input 47 -set fmri(evg47.3) 0 - -# Higher-level EV value for EV 3 and input 48 -set fmri(evg48.3) 0 - -# Higher-level EV value for EV 3 and input 49 -set fmri(evg49.3) 0 - -# Higher-level EV value for EV 3 and input 50 -set fmri(evg50.3) 0 - -# Higher-level EV value for EV 3 and input 51 -set fmri(evg51.3) 0 - -# Higher-level EV value for EV 3 and input 52 -set fmri(evg52.3) 0 - -# EV 4 title -set fmri(evtitle4) "" - -# Basic waveform shape (EV 4) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape4) 2 - -# Convolution (EV 4) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve4) 0 - -# Convolve phase (EV 4) -set fmri(convolve_phase4) 0 - -# Apply temporal filtering (EV 4) -set fmri(tempfilt_yn4) 0 - -# Add temporal derivative (EV 4) -set fmri(deriv_yn4) 0 - -# Custom EV file (EV 4) -set fmri(custom4) "dummy" - -# Orthogonalise EV 4 wrt EV 0 -set fmri(ortho4.0) 0 - -# Orthogonalise EV 4 wrt EV 1 -set fmri(ortho4.1) 0 - -# Orthogonalise EV 4 wrt EV 2 -set fmri(ortho4.2) 0 - -# Orthogonalise EV 4 wrt EV 3 -set fmri(ortho4.3) 0 - -# Orthogonalise EV 4 wrt EV 4 -set fmri(ortho4.4) 0 - -# Orthogonalise EV 4 wrt EV 5 -set fmri(ortho4.5) 0 - -# Orthogonalise EV 4 wrt EV 6 -set fmri(ortho4.6) 0 - -# Orthogonalise EV 4 wrt EV 7 -set fmri(ortho4.7) 0 - -# Orthogonalise EV 4 wrt EV 8 -set fmri(ortho4.8) 0 - -# Orthogonalise EV 4 wrt EV 9 -set fmri(ortho4.9) 0 - -# Orthogonalise EV 4 wrt EV 10 -set fmri(ortho4.10) 0 - -# Orthogonalise EV 4 wrt EV 11 -set fmri(ortho4.11) 0 - -# Orthogonalise EV 4 wrt EV 12 -set fmri(ortho4.12) 0 - -# Orthogonalise EV 4 wrt EV 13 -set fmri(ortho4.13) 0 - -# Orthogonalise EV 4 wrt EV 14 -set fmri(ortho4.14) 0 - -# Orthogonalise EV 4 wrt EV 15 -set fmri(ortho4.15) 0 - -# Orthogonalise EV 4 wrt EV 16 -set fmri(ortho4.16) 0 - -# Orthogonalise EV 4 wrt EV 17 -set fmri(ortho4.17) 0 - -# Orthogonalise EV 4 wrt EV 18 -set fmri(ortho4.18) 0 - -# Orthogonalise EV 4 wrt EV 19 -set fmri(ortho4.19) 0 - -# Orthogonalise EV 4 wrt EV 20 -set fmri(ortho4.20) 0 - -# Orthogonalise EV 4 wrt EV 21 -set fmri(ortho4.21) 0 - -# Orthogonalise EV 4 wrt EV 22 -set fmri(ortho4.22) 0 - -# Orthogonalise EV 4 wrt EV 23 -set fmri(ortho4.23) 0 - -# Orthogonalise EV 4 wrt EV 24 -set fmri(ortho4.24) 0 - -# Orthogonalise EV 4 wrt EV 25 -set fmri(ortho4.25) 0 - -# Orthogonalise EV 4 wrt EV 26 -set fmri(ortho4.26) 0 - -# Higher-level EV value for EV 4 and input 1 -set fmri(evg1.4) 0 - -# Higher-level EV value for EV 4 and input 2 -set fmri(evg2.4) 0 - -# Higher-level EV value for EV 4 and input 3 -set fmri(evg3.4) 0 - -# Higher-level EV value for EV 4 and input 4 -set fmri(evg4.4) 0 - -# Higher-level EV value for EV 4 and input 5 -set fmri(evg5.4) 0 - -# Higher-level EV value for EV 4 and input 6 -set fmri(evg6.4) 0 - -# Higher-level EV value for EV 4 and input 7 -set fmri(evg7.4) 1.0 - -# Higher-level EV value for EV 4 and input 8 -set fmri(evg8.4) 1.0 - -# Higher-level EV value for EV 4 and input 9 -set fmri(evg9.4) 0 - -# Higher-level EV value for EV 4 and input 10 -set fmri(evg10.4) 0 - -# Higher-level EV value for EV 4 and input 11 -set fmri(evg11.4) 0 - -# Higher-level EV value for EV 4 and input 12 -set fmri(evg12.4) 0 - -# Higher-level EV value for EV 4 and input 13 -set fmri(evg13.4) 0 - -# Higher-level EV value for EV 4 and input 14 -set fmri(evg14.4) 0 - -# Higher-level EV value for EV 4 and input 15 -set fmri(evg15.4) 0 - -# Higher-level EV value for EV 4 and input 16 -set fmri(evg16.4) 0 - -# Higher-level EV value for EV 4 and input 17 -set fmri(evg17.4) 0 - -# Higher-level EV value for EV 4 and input 18 -set fmri(evg18.4) 0 - -# Higher-level EV value for EV 4 and input 19 -set fmri(evg19.4) 0 - -# Higher-level EV value for EV 4 and input 20 -set fmri(evg20.4) 0 - -# Higher-level EV value for EV 4 and input 21 -set fmri(evg21.4) 0 - -# Higher-level EV value for EV 4 and input 22 -set fmri(evg22.4) 0 - -# Higher-level EV value for EV 4 and input 23 -set fmri(evg23.4) 0 - -# Higher-level EV value for EV 4 and input 24 -set fmri(evg24.4) 0 - -# Higher-level EV value for EV 4 and input 25 -set fmri(evg25.4) 0 - -# Higher-level EV value for EV 4 and input 26 -set fmri(evg26.4) 0 - -# Higher-level EV value for EV 4 and input 27 -set fmri(evg27.4) 0 - -# Higher-level EV value for EV 4 and input 28 -set fmri(evg28.4) 0 - -# Higher-level EV value for EV 4 and input 29 -set fmri(evg29.4) 0 - -# Higher-level EV value for EV 4 and input 30 -set fmri(evg30.4) 0 - -# Higher-level EV value for EV 4 and input 31 -set fmri(evg31.4) 0 - -# Higher-level EV value for EV 4 and input 32 -set fmri(evg32.4) 0 - -# Higher-level EV value for EV 4 and input 33 -set fmri(evg33.4) 0 - -# Higher-level EV value for EV 4 and input 34 -set fmri(evg34.4) 0 - -# Higher-level EV value for EV 4 and input 35 -set fmri(evg35.4) 0 - -# Higher-level EV value for EV 4 and input 36 -set fmri(evg36.4) 0 - -# Higher-level EV value for EV 4 and input 37 -set fmri(evg37.4) 0 - -# Higher-level EV value for EV 4 and input 38 -set fmri(evg38.4) 0 - -# Higher-level EV value for EV 4 and input 39 -set fmri(evg39.4) 0 - -# Higher-level EV value for EV 4 and input 40 -set fmri(evg40.4) 0 - -# Higher-level EV value for EV 4 and input 41 -set fmri(evg41.4) 0 - -# Higher-level EV value for EV 4 and input 42 -set fmri(evg42.4) 0 - -# Higher-level EV value for EV 4 and input 43 -set fmri(evg43.4) 0 - -# Higher-level EV value for EV 4 and input 44 -set fmri(evg44.4) 0 - -# Higher-level EV value for EV 4 and input 45 -set fmri(evg45.4) 0 - -# Higher-level EV value for EV 4 and input 46 -set fmri(evg46.4) 0 - -# Higher-level EV value for EV 4 and input 47 -set fmri(evg47.4) 0 - -# Higher-level EV value for EV 4 and input 48 -set fmri(evg48.4) 0 - -# Higher-level EV value for EV 4 and input 49 -set fmri(evg49.4) 0 - -# Higher-level EV value for EV 4 and input 50 -set fmri(evg50.4) 0 - -# Higher-level EV value for EV 4 and input 51 -set fmri(evg51.4) 0 - -# Higher-level EV value for EV 4 and input 52 -set fmri(evg52.4) 0 - -# EV 5 title -set fmri(evtitle5) "" - -# Basic waveform shape (EV 5) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape5) 2 - -# Convolution (EV 5) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve5) 0 - -# Convolve phase (EV 5) -set fmri(convolve_phase5) 0 - -# Apply temporal filtering (EV 5) -set fmri(tempfilt_yn5) 0 - -# Add temporal derivative (EV 5) -set fmri(deriv_yn5) 0 - -# Custom EV file (EV 5) -set fmri(custom5) "dummy" - -# Orthogonalise EV 5 wrt EV 0 -set fmri(ortho5.0) 0 - -# Orthogonalise EV 5 wrt EV 1 -set fmri(ortho5.1) 0 - -# Orthogonalise EV 5 wrt EV 2 -set fmri(ortho5.2) 0 - -# Orthogonalise EV 5 wrt EV 3 -set fmri(ortho5.3) 0 - -# Orthogonalise EV 5 wrt EV 4 -set fmri(ortho5.4) 0 - -# Orthogonalise EV 5 wrt EV 5 -set fmri(ortho5.5) 0 - -# Orthogonalise EV 5 wrt EV 6 -set fmri(ortho5.6) 0 - -# Orthogonalise EV 5 wrt EV 7 -set fmri(ortho5.7) 0 - -# Orthogonalise EV 5 wrt EV 8 -set fmri(ortho5.8) 0 - -# Orthogonalise EV 5 wrt EV 9 -set fmri(ortho5.9) 0 - -# Orthogonalise EV 5 wrt EV 10 -set fmri(ortho5.10) 0 - -# Orthogonalise EV 5 wrt EV 11 -set fmri(ortho5.11) 0 - -# Orthogonalise EV 5 wrt EV 12 -set fmri(ortho5.12) 0 - -# Orthogonalise EV 5 wrt EV 13 -set fmri(ortho5.13) 0 - -# Orthogonalise EV 5 wrt EV 14 -set fmri(ortho5.14) 0 - -# Orthogonalise EV 5 wrt EV 15 -set fmri(ortho5.15) 0 - -# Orthogonalise EV 5 wrt EV 16 -set fmri(ortho5.16) 0 - -# Orthogonalise EV 5 wrt EV 17 -set fmri(ortho5.17) 0 - -# Orthogonalise EV 5 wrt EV 18 -set fmri(ortho5.18) 0 - -# Orthogonalise EV 5 wrt EV 19 -set fmri(ortho5.19) 0 - -# Orthogonalise EV 5 wrt EV 20 -set fmri(ortho5.20) 0 - -# Orthogonalise EV 5 wrt EV 21 -set fmri(ortho5.21) 0 - -# Orthogonalise EV 5 wrt EV 22 -set fmri(ortho5.22) 0 - -# Orthogonalise EV 5 wrt EV 23 -set fmri(ortho5.23) 0 - -# Orthogonalise EV 5 wrt EV 24 -set fmri(ortho5.24) 0 - -# Orthogonalise EV 5 wrt EV 25 -set fmri(ortho5.25) 0 - -# Orthogonalise EV 5 wrt EV 26 -set fmri(ortho5.26) 0 - -# Higher-level EV value for EV 5 and input 1 -set fmri(evg1.5) 0 - -# Higher-level EV value for EV 5 and input 2 -set fmri(evg2.5) 0 - -# Higher-level EV value for EV 5 and input 3 -set fmri(evg3.5) 0 - -# Higher-level EV value for EV 5 and input 4 -set fmri(evg4.5) 0 - -# Higher-level EV value for EV 5 and input 5 -set fmri(evg5.5) 0 - -# Higher-level EV value for EV 5 and input 6 -set fmri(evg6.5) 0 - -# Higher-level EV value for EV 5 and input 7 -set fmri(evg7.5) 0 - -# Higher-level EV value for EV 5 and input 8 -set fmri(evg8.5) 0 - -# Higher-level EV value for EV 5 and input 9 -set fmri(evg9.5) 1.0 - -# Higher-level EV value for EV 5 and input 10 -set fmri(evg10.5) 1.0 - -# Higher-level EV value for EV 5 and input 11 -set fmri(evg11.5) 0 - -# Higher-level EV value for EV 5 and input 12 -set fmri(evg12.5) 0 - -# Higher-level EV value for EV 5 and input 13 -set fmri(evg13.5) 0 - -# Higher-level EV value for EV 5 and input 14 -set fmri(evg14.5) 0 - -# Higher-level EV value for EV 5 and input 15 -set fmri(evg15.5) 0 - -# Higher-level EV value for EV 5 and input 16 -set fmri(evg16.5) 0 - -# Higher-level EV value for EV 5 and input 17 -set fmri(evg17.5) 0 - -# Higher-level EV value for EV 5 and input 18 -set fmri(evg18.5) 0 - -# Higher-level EV value for EV 5 and input 19 -set fmri(evg19.5) 0 - -# Higher-level EV value for EV 5 and input 20 -set fmri(evg20.5) 0 - -# Higher-level EV value for EV 5 and input 21 -set fmri(evg21.5) 0 - -# Higher-level EV value for EV 5 and input 22 -set fmri(evg22.5) 0 - -# Higher-level EV value for EV 5 and input 23 -set fmri(evg23.5) 0 - -# Higher-level EV value for EV 5 and input 24 -set fmri(evg24.5) 0 - -# Higher-level EV value for EV 5 and input 25 -set fmri(evg25.5) 0 - -# Higher-level EV value for EV 5 and input 26 -set fmri(evg26.5) 0 - -# Higher-level EV value for EV 5 and input 27 -set fmri(evg27.5) 0 - -# Higher-level EV value for EV 5 and input 28 -set fmri(evg28.5) 0 - -# Higher-level EV value for EV 5 and input 29 -set fmri(evg29.5) 0 - -# Higher-level EV value for EV 5 and input 30 -set fmri(evg30.5) 0 - -# Higher-level EV value for EV 5 and input 31 -set fmri(evg31.5) 0 - -# Higher-level EV value for EV 5 and input 32 -set fmri(evg32.5) 0 - -# Higher-level EV value for EV 5 and input 33 -set fmri(evg33.5) 0 - -# Higher-level EV value for EV 5 and input 34 -set fmri(evg34.5) 0 - -# Higher-level EV value for EV 5 and input 35 -set fmri(evg35.5) 0 - -# Higher-level EV value for EV 5 and input 36 -set fmri(evg36.5) 0 - -# Higher-level EV value for EV 5 and input 37 -set fmri(evg37.5) 0 - -# Higher-level EV value for EV 5 and input 38 -set fmri(evg38.5) 0 - -# Higher-level EV value for EV 5 and input 39 -set fmri(evg39.5) 0 - -# Higher-level EV value for EV 5 and input 40 -set fmri(evg40.5) 0 - -# Higher-level EV value for EV 5 and input 41 -set fmri(evg41.5) 0 - -# Higher-level EV value for EV 5 and input 42 -set fmri(evg42.5) 0 - -# Higher-level EV value for EV 5 and input 43 -set fmri(evg43.5) 0 - -# Higher-level EV value for EV 5 and input 44 -set fmri(evg44.5) 0 - -# Higher-level EV value for EV 5 and input 45 -set fmri(evg45.5) 0 - -# Higher-level EV value for EV 5 and input 46 -set fmri(evg46.5) 0 - -# Higher-level EV value for EV 5 and input 47 -set fmri(evg47.5) 0 - -# Higher-level EV value for EV 5 and input 48 -set fmri(evg48.5) 0 - -# Higher-level EV value for EV 5 and input 49 -set fmri(evg49.5) 0 - -# Higher-level EV value for EV 5 and input 50 -set fmri(evg50.5) 0 - -# Higher-level EV value for EV 5 and input 51 -set fmri(evg51.5) 0 - -# Higher-level EV value for EV 5 and input 52 -set fmri(evg52.5) 0 - -# EV 6 title -set fmri(evtitle6) "" - -# Basic waveform shape (EV 6) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape6) 2 - -# Convolution (EV 6) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve6) 0 - -# Convolve phase (EV 6) -set fmri(convolve_phase6) 0 - -# Apply temporal filtering (EV 6) -set fmri(tempfilt_yn6) 0 - -# Add temporal derivative (EV 6) -set fmri(deriv_yn6) 0 - -# Custom EV file (EV 6) -set fmri(custom6) "dummy" - -# Orthogonalise EV 6 wrt EV 0 -set fmri(ortho6.0) 0 - -# Orthogonalise EV 6 wrt EV 1 -set fmri(ortho6.1) 0 - -# Orthogonalise EV 6 wrt EV 2 -set fmri(ortho6.2) 0 - -# Orthogonalise EV 6 wrt EV 3 -set fmri(ortho6.3) 0 - -# Orthogonalise EV 6 wrt EV 4 -set fmri(ortho6.4) 0 - -# Orthogonalise EV 6 wrt EV 5 -set fmri(ortho6.5) 0 - -# Orthogonalise EV 6 wrt EV 6 -set fmri(ortho6.6) 0 - -# Orthogonalise EV 6 wrt EV 7 -set fmri(ortho6.7) 0 - -# Orthogonalise EV 6 wrt EV 8 -set fmri(ortho6.8) 0 - -# Orthogonalise EV 6 wrt EV 9 -set fmri(ortho6.9) 0 - -# Orthogonalise EV 6 wrt EV 10 -set fmri(ortho6.10) 0 - -# Orthogonalise EV 6 wrt EV 11 -set fmri(ortho6.11) 0 - -# Orthogonalise EV 6 wrt EV 12 -set fmri(ortho6.12) 0 - -# Orthogonalise EV 6 wrt EV 13 -set fmri(ortho6.13) 0 - -# Orthogonalise EV 6 wrt EV 14 -set fmri(ortho6.14) 0 - -# Orthogonalise EV 6 wrt EV 15 -set fmri(ortho6.15) 0 - -# Orthogonalise EV 6 wrt EV 16 -set fmri(ortho6.16) 0 - -# Orthogonalise EV 6 wrt EV 17 -set fmri(ortho6.17) 0 - -# Orthogonalise EV 6 wrt EV 18 -set fmri(ortho6.18) 0 - -# Orthogonalise EV 6 wrt EV 19 -set fmri(ortho6.19) 0 - -# Orthogonalise EV 6 wrt EV 20 -set fmri(ortho6.20) 0 - -# Orthogonalise EV 6 wrt EV 21 -set fmri(ortho6.21) 0 - -# Orthogonalise EV 6 wrt EV 22 -set fmri(ortho6.22) 0 - -# Orthogonalise EV 6 wrt EV 23 -set fmri(ortho6.23) 0 - -# Orthogonalise EV 6 wrt EV 24 -set fmri(ortho6.24) 0 - -# Orthogonalise EV 6 wrt EV 25 -set fmri(ortho6.25) 0 - -# Orthogonalise EV 6 wrt EV 26 -set fmri(ortho6.26) 0 - -# Higher-level EV value for EV 6 and input 1 -set fmri(evg1.6) 0 - -# Higher-level EV value for EV 6 and input 2 -set fmri(evg2.6) 0 - -# Higher-level EV value for EV 6 and input 3 -set fmri(evg3.6) 0 - -# Higher-level EV value for EV 6 and input 4 -set fmri(evg4.6) 0 - -# Higher-level EV value for EV 6 and input 5 -set fmri(evg5.6) 0 - -# Higher-level EV value for EV 6 and input 6 -set fmri(evg6.6) 0 - -# Higher-level EV value for EV 6 and input 7 -set fmri(evg7.6) 0 - -# Higher-level EV value for EV 6 and input 8 -set fmri(evg8.6) 0 - -# Higher-level EV value for EV 6 and input 9 -set fmri(evg9.6) 0 - -# Higher-level EV value for EV 6 and input 10 -set fmri(evg10.6) 0 - -# Higher-level EV value for EV 6 and input 11 -set fmri(evg11.6) 1.0 - -# Higher-level EV value for EV 6 and input 12 -set fmri(evg12.6) 1.0 - -# Higher-level EV value for EV 6 and input 13 -set fmri(evg13.6) 0 - -# Higher-level EV value for EV 6 and input 14 -set fmri(evg14.6) 0 - -# Higher-level EV value for EV 6 and input 15 -set fmri(evg15.6) 0 - -# Higher-level EV value for EV 6 and input 16 -set fmri(evg16.6) 0 - -# Higher-level EV value for EV 6 and input 17 -set fmri(evg17.6) 0 - -# Higher-level EV value for EV 6 and input 18 -set fmri(evg18.6) 0 - -# Higher-level EV value for EV 6 and input 19 -set fmri(evg19.6) 0 - -# Higher-level EV value for EV 6 and input 20 -set fmri(evg20.6) 0 - -# Higher-level EV value for EV 6 and input 21 -set fmri(evg21.6) 0 - -# Higher-level EV value for EV 6 and input 22 -set fmri(evg22.6) 0 - -# Higher-level EV value for EV 6 and input 23 -set fmri(evg23.6) 0 - -# Higher-level EV value for EV 6 and input 24 -set fmri(evg24.6) 0 - -# Higher-level EV value for EV 6 and input 25 -set fmri(evg25.6) 0 - -# Higher-level EV value for EV 6 and input 26 -set fmri(evg26.6) 0 - -# Higher-level EV value for EV 6 and input 27 -set fmri(evg27.6) 0 - -# Higher-level EV value for EV 6 and input 28 -set fmri(evg28.6) 0 - -# Higher-level EV value for EV 6 and input 29 -set fmri(evg29.6) 0 - -# Higher-level EV value for EV 6 and input 30 -set fmri(evg30.6) 0 - -# Higher-level EV value for EV 6 and input 31 -set fmri(evg31.6) 0 - -# Higher-level EV value for EV 6 and input 32 -set fmri(evg32.6) 0 - -# Higher-level EV value for EV 6 and input 33 -set fmri(evg33.6) 0 - -# Higher-level EV value for EV 6 and input 34 -set fmri(evg34.6) 0 - -# Higher-level EV value for EV 6 and input 35 -set fmri(evg35.6) 0 - -# Higher-level EV value for EV 6 and input 36 -set fmri(evg36.6) 0 - -# Higher-level EV value for EV 6 and input 37 -set fmri(evg37.6) 0 - -# Higher-level EV value for EV 6 and input 38 -set fmri(evg38.6) 0 - -# Higher-level EV value for EV 6 and input 39 -set fmri(evg39.6) 0 - -# Higher-level EV value for EV 6 and input 40 -set fmri(evg40.6) 0 - -# Higher-level EV value for EV 6 and input 41 -set fmri(evg41.6) 0 - -# Higher-level EV value for EV 6 and input 42 -set fmri(evg42.6) 0 - -# Higher-level EV value for EV 6 and input 43 -set fmri(evg43.6) 0 - -# Higher-level EV value for EV 6 and input 44 -set fmri(evg44.6) 0 - -# Higher-level EV value for EV 6 and input 45 -set fmri(evg45.6) 0 - -# Higher-level EV value for EV 6 and input 46 -set fmri(evg46.6) 0 - -# Higher-level EV value for EV 6 and input 47 -set fmri(evg47.6) 0 - -# Higher-level EV value for EV 6 and input 48 -set fmri(evg48.6) 0 - -# Higher-level EV value for EV 6 and input 49 -set fmri(evg49.6) 0 - -# Higher-level EV value for EV 6 and input 50 -set fmri(evg50.6) 0 - -# Higher-level EV value for EV 6 and input 51 -set fmri(evg51.6) 0 - -# Higher-level EV value for EV 6 and input 52 -set fmri(evg52.6) 0 - -# EV 7 title -set fmri(evtitle7) "" - -# Basic waveform shape (EV 7) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape7) 2 - -# Convolution (EV 7) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve7) 0 - -# Convolve phase (EV 7) -set fmri(convolve_phase7) 0 - -# Apply temporal filtering (EV 7) -set fmri(tempfilt_yn7) 0 - -# Add temporal derivative (EV 7) -set fmri(deriv_yn7) 0 - -# Custom EV file (EV 7) -set fmri(custom7) "dummy" - -# Orthogonalise EV 7 wrt EV 0 -set fmri(ortho7.0) 0 - -# Orthogonalise EV 7 wrt EV 1 -set fmri(ortho7.1) 0 - -# Orthogonalise EV 7 wrt EV 2 -set fmri(ortho7.2) 0 - -# Orthogonalise EV 7 wrt EV 3 -set fmri(ortho7.3) 0 - -# Orthogonalise EV 7 wrt EV 4 -set fmri(ortho7.4) 0 - -# Orthogonalise EV 7 wrt EV 5 -set fmri(ortho7.5) 0 - -# Orthogonalise EV 7 wrt EV 6 -set fmri(ortho7.6) 0 - -# Orthogonalise EV 7 wrt EV 7 -set fmri(ortho7.7) 0 - -# Orthogonalise EV 7 wrt EV 8 -set fmri(ortho7.8) 0 - -# Orthogonalise EV 7 wrt EV 9 -set fmri(ortho7.9) 0 - -# Orthogonalise EV 7 wrt EV 10 -set fmri(ortho7.10) 0 - -# Orthogonalise EV 7 wrt EV 11 -set fmri(ortho7.11) 0 - -# Orthogonalise EV 7 wrt EV 12 -set fmri(ortho7.12) 0 - -# Orthogonalise EV 7 wrt EV 13 -set fmri(ortho7.13) 0 - -# Orthogonalise EV 7 wrt EV 14 -set fmri(ortho7.14) 0 - -# Orthogonalise EV 7 wrt EV 15 -set fmri(ortho7.15) 0 - -# Orthogonalise EV 7 wrt EV 16 -set fmri(ortho7.16) 0 - -# Orthogonalise EV 7 wrt EV 17 -set fmri(ortho7.17) 0 - -# Orthogonalise EV 7 wrt EV 18 -set fmri(ortho7.18) 0 - -# Orthogonalise EV 7 wrt EV 19 -set fmri(ortho7.19) 0 - -# Orthogonalise EV 7 wrt EV 20 -set fmri(ortho7.20) 0 - -# Orthogonalise EV 7 wrt EV 21 -set fmri(ortho7.21) 0 - -# Orthogonalise EV 7 wrt EV 22 -set fmri(ortho7.22) 0 - -# Orthogonalise EV 7 wrt EV 23 -set fmri(ortho7.23) 0 - -# Orthogonalise EV 7 wrt EV 24 -set fmri(ortho7.24) 0 - -# Orthogonalise EV 7 wrt EV 25 -set fmri(ortho7.25) 0 - -# Orthogonalise EV 7 wrt EV 26 -set fmri(ortho7.26) 0 - -# Higher-level EV value for EV 7 and input 1 -set fmri(evg1.7) 0 - -# Higher-level EV value for EV 7 and input 2 -set fmri(evg2.7) 0 - -# Higher-level EV value for EV 7 and input 3 -set fmri(evg3.7) 0 - -# Higher-level EV value for EV 7 and input 4 -set fmri(evg4.7) 0 - -# Higher-level EV value for EV 7 and input 5 -set fmri(evg5.7) 0 - -# Higher-level EV value for EV 7 and input 6 -set fmri(evg6.7) 0 - -# Higher-level EV value for EV 7 and input 7 -set fmri(evg7.7) 0 - -# Higher-level EV value for EV 7 and input 8 -set fmri(evg8.7) 0 - -# Higher-level EV value for EV 7 and input 9 -set fmri(evg9.7) 0 - -# Higher-level EV value for EV 7 and input 10 -set fmri(evg10.7) 0 - -# Higher-level EV value for EV 7 and input 11 -set fmri(evg11.7) 0 - -# Higher-level EV value for EV 7 and input 12 -set fmri(evg12.7) 0 - -# Higher-level EV value for EV 7 and input 13 -set fmri(evg13.7) 1.0 - -# Higher-level EV value for EV 7 and input 14 -set fmri(evg14.7) 1.0 - -# Higher-level EV value for EV 7 and input 15 -set fmri(evg15.7) 0 - -# Higher-level EV value for EV 7 and input 16 -set fmri(evg16.7) 0 - -# Higher-level EV value for EV 7 and input 17 -set fmri(evg17.7) 0 - -# Higher-level EV value for EV 7 and input 18 -set fmri(evg18.7) 0 - -# Higher-level EV value for EV 7 and input 19 -set fmri(evg19.7) 0 - -# Higher-level EV value for EV 7 and input 20 -set fmri(evg20.7) 0 - -# Higher-level EV value for EV 7 and input 21 -set fmri(evg21.7) 0 - -# Higher-level EV value for EV 7 and input 22 -set fmri(evg22.7) 0 - -# Higher-level EV value for EV 7 and input 23 -set fmri(evg23.7) 0 - -# Higher-level EV value for EV 7 and input 24 -set fmri(evg24.7) 0 - -# Higher-level EV value for EV 7 and input 25 -set fmri(evg25.7) 0 - -# Higher-level EV value for EV 7 and input 26 -set fmri(evg26.7) 0 - -# Higher-level EV value for EV 7 and input 27 -set fmri(evg27.7) 0 - -# Higher-level EV value for EV 7 and input 28 -set fmri(evg28.7) 0 - -# Higher-level EV value for EV 7 and input 29 -set fmri(evg29.7) 0 - -# Higher-level EV value for EV 7 and input 30 -set fmri(evg30.7) 0 - -# Higher-level EV value for EV 7 and input 31 -set fmri(evg31.7) 0 - -# Higher-level EV value for EV 7 and input 32 -set fmri(evg32.7) 0 - -# Higher-level EV value for EV 7 and input 33 -set fmri(evg33.7) 0 - -# Higher-level EV value for EV 7 and input 34 -set fmri(evg34.7) 0 - -# Higher-level EV value for EV 7 and input 35 -set fmri(evg35.7) 0 - -# Higher-level EV value for EV 7 and input 36 -set fmri(evg36.7) 0 - -# Higher-level EV value for EV 7 and input 37 -set fmri(evg37.7) 0 - -# Higher-level EV value for EV 7 and input 38 -set fmri(evg38.7) 0 - -# Higher-level EV value for EV 7 and input 39 -set fmri(evg39.7) 0 - -# Higher-level EV value for EV 7 and input 40 -set fmri(evg40.7) 0 - -# Higher-level EV value for EV 7 and input 41 -set fmri(evg41.7) 0 - -# Higher-level EV value for EV 7 and input 42 -set fmri(evg42.7) 0 - -# Higher-level EV value for EV 7 and input 43 -set fmri(evg43.7) 0 - -# Higher-level EV value for EV 7 and input 44 -set fmri(evg44.7) 0 - -# Higher-level EV value for EV 7 and input 45 -set fmri(evg45.7) 0 - -# Higher-level EV value for EV 7 and input 46 -set fmri(evg46.7) 0 - -# Higher-level EV value for EV 7 and input 47 -set fmri(evg47.7) 0 - -# Higher-level EV value for EV 7 and input 48 -set fmri(evg48.7) 0 - -# Higher-level EV value for EV 7 and input 49 -set fmri(evg49.7) 0 - -# Higher-level EV value for EV 7 and input 50 -set fmri(evg50.7) 0 - -# Higher-level EV value for EV 7 and input 51 -set fmri(evg51.7) 0 - -# Higher-level EV value for EV 7 and input 52 -set fmri(evg52.7) 0 - -# EV 8 title -set fmri(evtitle8) "" - -# Basic waveform shape (EV 8) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape8) 2 - -# Convolution (EV 8) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve8) 0 - -# Convolve phase (EV 8) -set fmri(convolve_phase8) 0 - -# Apply temporal filtering (EV 8) -set fmri(tempfilt_yn8) 0 - -# Add temporal derivative (EV 8) -set fmri(deriv_yn8) 0 - -# Custom EV file (EV 8) -set fmri(custom8) "dummy" - -# Orthogonalise EV 8 wrt EV 0 -set fmri(ortho8.0) 0 - -# Orthogonalise EV 8 wrt EV 1 -set fmri(ortho8.1) 0 - -# Orthogonalise EV 8 wrt EV 2 -set fmri(ortho8.2) 0 - -# Orthogonalise EV 8 wrt EV 3 -set fmri(ortho8.3) 0 - -# Orthogonalise EV 8 wrt EV 4 -set fmri(ortho8.4) 0 - -# Orthogonalise EV 8 wrt EV 5 -set fmri(ortho8.5) 0 - -# Orthogonalise EV 8 wrt EV 6 -set fmri(ortho8.6) 0 - -# Orthogonalise EV 8 wrt EV 7 -set fmri(ortho8.7) 0 - -# Orthogonalise EV 8 wrt EV 8 -set fmri(ortho8.8) 0 - -# Orthogonalise EV 8 wrt EV 9 -set fmri(ortho8.9) 0 - -# Orthogonalise EV 8 wrt EV 10 -set fmri(ortho8.10) 0 - -# Orthogonalise EV 8 wrt EV 11 -set fmri(ortho8.11) 0 - -# Orthogonalise EV 8 wrt EV 12 -set fmri(ortho8.12) 0 - -# Orthogonalise EV 8 wrt EV 13 -set fmri(ortho8.13) 0 - -# Orthogonalise EV 8 wrt EV 14 -set fmri(ortho8.14) 0 - -# Orthogonalise EV 8 wrt EV 15 -set fmri(ortho8.15) 0 - -# Orthogonalise EV 8 wrt EV 16 -set fmri(ortho8.16) 0 - -# Orthogonalise EV 8 wrt EV 17 -set fmri(ortho8.17) 0 - -# Orthogonalise EV 8 wrt EV 18 -set fmri(ortho8.18) 0 - -# Orthogonalise EV 8 wrt EV 19 -set fmri(ortho8.19) 0 - -# Orthogonalise EV 8 wrt EV 20 -set fmri(ortho8.20) 0 - -# Orthogonalise EV 8 wrt EV 21 -set fmri(ortho8.21) 0 - -# Orthogonalise EV 8 wrt EV 22 -set fmri(ortho8.22) 0 - -# Orthogonalise EV 8 wrt EV 23 -set fmri(ortho8.23) 0 - -# Orthogonalise EV 8 wrt EV 24 -set fmri(ortho8.24) 0 - -# Orthogonalise EV 8 wrt EV 25 -set fmri(ortho8.25) 0 - -# Orthogonalise EV 8 wrt EV 26 -set fmri(ortho8.26) 0 - -# Higher-level EV value for EV 8 and input 1 -set fmri(evg1.8) 0 - -# Higher-level EV value for EV 8 and input 2 -set fmri(evg2.8) 0 - -# Higher-level EV value for EV 8 and input 3 -set fmri(evg3.8) 0 - -# Higher-level EV value for EV 8 and input 4 -set fmri(evg4.8) 0 - -# Higher-level EV value for EV 8 and input 5 -set fmri(evg5.8) 0 - -# Higher-level EV value for EV 8 and input 6 -set fmri(evg6.8) 0 - -# Higher-level EV value for EV 8 and input 7 -set fmri(evg7.8) 0 - -# Higher-level EV value for EV 8 and input 8 -set fmri(evg8.8) 0 - -# Higher-level EV value for EV 8 and input 9 -set fmri(evg9.8) 0 - -# Higher-level EV value for EV 8 and input 10 -set fmri(evg10.8) 0 - -# Higher-level EV value for EV 8 and input 11 -set fmri(evg11.8) 0 - -# Higher-level EV value for EV 8 and input 12 -set fmri(evg12.8) 0 - -# Higher-level EV value for EV 8 and input 13 -set fmri(evg13.8) 0 - -# Higher-level EV value for EV 8 and input 14 -set fmri(evg14.8) 0 - -# Higher-level EV value for EV 8 and input 15 -set fmri(evg15.8) 1.0 - -# Higher-level EV value for EV 8 and input 16 -set fmri(evg16.8) 1.0 - -# Higher-level EV value for EV 8 and input 17 -set fmri(evg17.8) 0 - -# Higher-level EV value for EV 8 and input 18 -set fmri(evg18.8) 0 - -# Higher-level EV value for EV 8 and input 19 -set fmri(evg19.8) 0 - -# Higher-level EV value for EV 8 and input 20 -set fmri(evg20.8) 0 - -# Higher-level EV value for EV 8 and input 21 -set fmri(evg21.8) 0 - -# Higher-level EV value for EV 8 and input 22 -set fmri(evg22.8) 0 - -# Higher-level EV value for EV 8 and input 23 -set fmri(evg23.8) 0 - -# Higher-level EV value for EV 8 and input 24 -set fmri(evg24.8) 0 - -# Higher-level EV value for EV 8 and input 25 -set fmri(evg25.8) 0 - -# Higher-level EV value for EV 8 and input 26 -set fmri(evg26.8) 0 - -# Higher-level EV value for EV 8 and input 27 -set fmri(evg27.8) 0 - -# Higher-level EV value for EV 8 and input 28 -set fmri(evg28.8) 0 - -# Higher-level EV value for EV 8 and input 29 -set fmri(evg29.8) 0 - -# Higher-level EV value for EV 8 and input 30 -set fmri(evg30.8) 0 - -# Higher-level EV value for EV 8 and input 31 -set fmri(evg31.8) 0 - -# Higher-level EV value for EV 8 and input 32 -set fmri(evg32.8) 0 - -# Higher-level EV value for EV 8 and input 33 -set fmri(evg33.8) 0 - -# Higher-level EV value for EV 8 and input 34 -set fmri(evg34.8) 0 - -# Higher-level EV value for EV 8 and input 35 -set fmri(evg35.8) 0 - -# Higher-level EV value for EV 8 and input 36 -set fmri(evg36.8) 0 - -# Higher-level EV value for EV 8 and input 37 -set fmri(evg37.8) 0 - -# Higher-level EV value for EV 8 and input 38 -set fmri(evg38.8) 0 - -# Higher-level EV value for EV 8 and input 39 -set fmri(evg39.8) 0 - -# Higher-level EV value for EV 8 and input 40 -set fmri(evg40.8) 0 - -# Higher-level EV value for EV 8 and input 41 -set fmri(evg41.8) 0 - -# Higher-level EV value for EV 8 and input 42 -set fmri(evg42.8) 0 - -# Higher-level EV value for EV 8 and input 43 -set fmri(evg43.8) 0 - -# Higher-level EV value for EV 8 and input 44 -set fmri(evg44.8) 0 - -# Higher-level EV value for EV 8 and input 45 -set fmri(evg45.8) 0 - -# Higher-level EV value for EV 8 and input 46 -set fmri(evg46.8) 0 - -# Higher-level EV value for EV 8 and input 47 -set fmri(evg47.8) 0 - -# Higher-level EV value for EV 8 and input 48 -set fmri(evg48.8) 0 - -# Higher-level EV value for EV 8 and input 49 -set fmri(evg49.8) 0 - -# Higher-level EV value for EV 8 and input 50 -set fmri(evg50.8) 0 - -# Higher-level EV value for EV 8 and input 51 -set fmri(evg51.8) 0 - -# Higher-level EV value for EV 8 and input 52 -set fmri(evg52.8) 0 - -# EV 9 title -set fmri(evtitle9) "" - -# Basic waveform shape (EV 9) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape9) 2 - -# Convolution (EV 9) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve9) 0 - -# Convolve phase (EV 9) -set fmri(convolve_phase9) 0 - -# Apply temporal filtering (EV 9) -set fmri(tempfilt_yn9) 0 - -# Add temporal derivative (EV 9) -set fmri(deriv_yn9) 0 - -# Custom EV file (EV 9) -set fmri(custom9) "dummy" - -# Orthogonalise EV 9 wrt EV 0 -set fmri(ortho9.0) 0 - -# Orthogonalise EV 9 wrt EV 1 -set fmri(ortho9.1) 0 - -# Orthogonalise EV 9 wrt EV 2 -set fmri(ortho9.2) 0 - -# Orthogonalise EV 9 wrt EV 3 -set fmri(ortho9.3) 0 - -# Orthogonalise EV 9 wrt EV 4 -set fmri(ortho9.4) 0 - -# Orthogonalise EV 9 wrt EV 5 -set fmri(ortho9.5) 0 - -# Orthogonalise EV 9 wrt EV 6 -set fmri(ortho9.6) 0 - -# Orthogonalise EV 9 wrt EV 7 -set fmri(ortho9.7) 0 - -# Orthogonalise EV 9 wrt EV 8 -set fmri(ortho9.8) 0 - -# Orthogonalise EV 9 wrt EV 9 -set fmri(ortho9.9) 0 - -# Orthogonalise EV 9 wrt EV 10 -set fmri(ortho9.10) 0 - -# Orthogonalise EV 9 wrt EV 11 -set fmri(ortho9.11) 0 - -# Orthogonalise EV 9 wrt EV 12 -set fmri(ortho9.12) 0 - -# Orthogonalise EV 9 wrt EV 13 -set fmri(ortho9.13) 0 - -# Orthogonalise EV 9 wrt EV 14 -set fmri(ortho9.14) 0 - -# Orthogonalise EV 9 wrt EV 15 -set fmri(ortho9.15) 0 - -# Orthogonalise EV 9 wrt EV 16 -set fmri(ortho9.16) 0 - -# Orthogonalise EV 9 wrt EV 17 -set fmri(ortho9.17) 0 - -# Orthogonalise EV 9 wrt EV 18 -set fmri(ortho9.18) 0 - -# Orthogonalise EV 9 wrt EV 19 -set fmri(ortho9.19) 0 - -# Orthogonalise EV 9 wrt EV 20 -set fmri(ortho9.20) 0 - -# Orthogonalise EV 9 wrt EV 21 -set fmri(ortho9.21) 0 - -# Orthogonalise EV 9 wrt EV 22 -set fmri(ortho9.22) 0 - -# Orthogonalise EV 9 wrt EV 23 -set fmri(ortho9.23) 0 - -# Orthogonalise EV 9 wrt EV 24 -set fmri(ortho9.24) 0 - -# Orthogonalise EV 9 wrt EV 25 -set fmri(ortho9.25) 0 - -# Orthogonalise EV 9 wrt EV 26 -set fmri(ortho9.26) 0 - -# Higher-level EV value for EV 9 and input 1 -set fmri(evg1.9) 0 - -# Higher-level EV value for EV 9 and input 2 -set fmri(evg2.9) 0 - -# Higher-level EV value for EV 9 and input 3 -set fmri(evg3.9) 0 - -# Higher-level EV value for EV 9 and input 4 -set fmri(evg4.9) 0 - -# Higher-level EV value for EV 9 and input 5 -set fmri(evg5.9) 0 - -# Higher-level EV value for EV 9 and input 6 -set fmri(evg6.9) 0 - -# Higher-level EV value for EV 9 and input 7 -set fmri(evg7.9) 0 - -# Higher-level EV value for EV 9 and input 8 -set fmri(evg8.9) 0 - -# Higher-level EV value for EV 9 and input 9 -set fmri(evg9.9) 0 - -# Higher-level EV value for EV 9 and input 10 -set fmri(evg10.9) 0 - -# Higher-level EV value for EV 9 and input 11 -set fmri(evg11.9) 0 - -# Higher-level EV value for EV 9 and input 12 -set fmri(evg12.9) 0 - -# Higher-level EV value for EV 9 and input 13 -set fmri(evg13.9) 0 - -# Higher-level EV value for EV 9 and input 14 -set fmri(evg14.9) 0 - -# Higher-level EV value for EV 9 and input 15 -set fmri(evg15.9) 0 - -# Higher-level EV value for EV 9 and input 16 -set fmri(evg16.9) 0 - -# Higher-level EV value for EV 9 and input 17 -set fmri(evg17.9) 1.0 - -# Higher-level EV value for EV 9 and input 18 -set fmri(evg18.9) 1.0 - -# Higher-level EV value for EV 9 and input 19 -set fmri(evg19.9) 0 - -# Higher-level EV value for EV 9 and input 20 -set fmri(evg20.9) 0 - -# Higher-level EV value for EV 9 and input 21 -set fmri(evg21.9) 0 - -# Higher-level EV value for EV 9 and input 22 -set fmri(evg22.9) 0 - -# Higher-level EV value for EV 9 and input 23 -set fmri(evg23.9) 0 - -# Higher-level EV value for EV 9 and input 24 -set fmri(evg24.9) 0 - -# Higher-level EV value for EV 9 and input 25 -set fmri(evg25.9) 0 - -# Higher-level EV value for EV 9 and input 26 -set fmri(evg26.9) 0 - -# Higher-level EV value for EV 9 and input 27 -set fmri(evg27.9) 0 - -# Higher-level EV value for EV 9 and input 28 -set fmri(evg28.9) 0 - -# Higher-level EV value for EV 9 and input 29 -set fmri(evg29.9) 0 - -# Higher-level EV value for EV 9 and input 30 -set fmri(evg30.9) 0 - -# Higher-level EV value for EV 9 and input 31 -set fmri(evg31.9) 0 - -# Higher-level EV value for EV 9 and input 32 -set fmri(evg32.9) 0 - -# Higher-level EV value for EV 9 and input 33 -set fmri(evg33.9) 0 - -# Higher-level EV value for EV 9 and input 34 -set fmri(evg34.9) 0 - -# Higher-level EV value for EV 9 and input 35 -set fmri(evg35.9) 0 - -# Higher-level EV value for EV 9 and input 36 -set fmri(evg36.9) 0 - -# Higher-level EV value for EV 9 and input 37 -set fmri(evg37.9) 0 - -# Higher-level EV value for EV 9 and input 38 -set fmri(evg38.9) 0 - -# Higher-level EV value for EV 9 and input 39 -set fmri(evg39.9) 0 - -# Higher-level EV value for EV 9 and input 40 -set fmri(evg40.9) 0 - -# Higher-level EV value for EV 9 and input 41 -set fmri(evg41.9) 0 - -# Higher-level EV value for EV 9 and input 42 -set fmri(evg42.9) 0 - -# Higher-level EV value for EV 9 and input 43 -set fmri(evg43.9) 0 - -# Higher-level EV value for EV 9 and input 44 -set fmri(evg44.9) 0 - -# Higher-level EV value for EV 9 and input 45 -set fmri(evg45.9) 0 - -# Higher-level EV value for EV 9 and input 46 -set fmri(evg46.9) 0 - -# Higher-level EV value for EV 9 and input 47 -set fmri(evg47.9) 0 - -# Higher-level EV value for EV 9 and input 48 -set fmri(evg48.9) 0 - -# Higher-level EV value for EV 9 and input 49 -set fmri(evg49.9) 0 - -# Higher-level EV value for EV 9 and input 50 -set fmri(evg50.9) 0 - -# Higher-level EV value for EV 9 and input 51 -set fmri(evg51.9) 0 - -# Higher-level EV value for EV 9 and input 52 -set fmri(evg52.9) 0 - -# EV 10 title -set fmri(evtitle10) "" - -# Basic waveform shape (EV 10) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape10) 2 - -# Convolution (EV 10) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve10) 0 - -# Convolve phase (EV 10) -set fmri(convolve_phase10) 0 - -# Apply temporal filtering (EV 10) -set fmri(tempfilt_yn10) 0 - -# Add temporal derivative (EV 10) -set fmri(deriv_yn10) 0 - -# Custom EV file (EV 10) -set fmri(custom10) "dummy" - -# Orthogonalise EV 10 wrt EV 0 -set fmri(ortho10.0) 0 - -# Orthogonalise EV 10 wrt EV 1 -set fmri(ortho10.1) 0 - -# Orthogonalise EV 10 wrt EV 2 -set fmri(ortho10.2) 0 - -# Orthogonalise EV 10 wrt EV 3 -set fmri(ortho10.3) 0 - -# Orthogonalise EV 10 wrt EV 4 -set fmri(ortho10.4) 0 - -# Orthogonalise EV 10 wrt EV 5 -set fmri(ortho10.5) 0 - -# Orthogonalise EV 10 wrt EV 6 -set fmri(ortho10.6) 0 - -# Orthogonalise EV 10 wrt EV 7 -set fmri(ortho10.7) 0 - -# Orthogonalise EV 10 wrt EV 8 -set fmri(ortho10.8) 0 - -# Orthogonalise EV 10 wrt EV 9 -set fmri(ortho10.9) 0 - -# Orthogonalise EV 10 wrt EV 10 -set fmri(ortho10.10) 0 - -# Orthogonalise EV 10 wrt EV 11 -set fmri(ortho10.11) 0 - -# Orthogonalise EV 10 wrt EV 12 -set fmri(ortho10.12) 0 - -# Orthogonalise EV 10 wrt EV 13 -set fmri(ortho10.13) 0 - -# Orthogonalise EV 10 wrt EV 14 -set fmri(ortho10.14) 0 - -# Orthogonalise EV 10 wrt EV 15 -set fmri(ortho10.15) 0 - -# Orthogonalise EV 10 wrt EV 16 -set fmri(ortho10.16) 0 - -# Orthogonalise EV 10 wrt EV 17 -set fmri(ortho10.17) 0 - -# Orthogonalise EV 10 wrt EV 18 -set fmri(ortho10.18) 0 - -# Orthogonalise EV 10 wrt EV 19 -set fmri(ortho10.19) 0 - -# Orthogonalise EV 10 wrt EV 20 -set fmri(ortho10.20) 0 - -# Orthogonalise EV 10 wrt EV 21 -set fmri(ortho10.21) 0 - -# Orthogonalise EV 10 wrt EV 22 -set fmri(ortho10.22) 0 - -# Orthogonalise EV 10 wrt EV 23 -set fmri(ortho10.23) 0 - -# Orthogonalise EV 10 wrt EV 24 -set fmri(ortho10.24) 0 - -# Orthogonalise EV 10 wrt EV 25 -set fmri(ortho10.25) 0 - -# Orthogonalise EV 10 wrt EV 26 -set fmri(ortho10.26) 0 - -# Higher-level EV value for EV 10 and input 1 -set fmri(evg1.10) 0 - -# Higher-level EV value for EV 10 and input 2 -set fmri(evg2.10) 0 - -# Higher-level EV value for EV 10 and input 3 -set fmri(evg3.10) 0 - -# Higher-level EV value for EV 10 and input 4 -set fmri(evg4.10) 0 - -# Higher-level EV value for EV 10 and input 5 -set fmri(evg5.10) 0 - -# Higher-level EV value for EV 10 and input 6 -set fmri(evg6.10) 0 - -# Higher-level EV value for EV 10 and input 7 -set fmri(evg7.10) 0 - -# Higher-level EV value for EV 10 and input 8 -set fmri(evg8.10) 0 - -# Higher-level EV value for EV 10 and input 9 -set fmri(evg9.10) 0 - -# Higher-level EV value for EV 10 and input 10 -set fmri(evg10.10) 0 - -# Higher-level EV value for EV 10 and input 11 -set fmri(evg11.10) 0 - -# Higher-level EV value for EV 10 and input 12 -set fmri(evg12.10) 0 - -# Higher-level EV value for EV 10 and input 13 -set fmri(evg13.10) 0 - -# Higher-level EV value for EV 10 and input 14 -set fmri(evg14.10) 0 - -# Higher-level EV value for EV 10 and input 15 -set fmri(evg15.10) 0 - -# Higher-level EV value for EV 10 and input 16 -set fmri(evg16.10) 0 - -# Higher-level EV value for EV 10 and input 17 -set fmri(evg17.10) 0 - -# Higher-level EV value for EV 10 and input 18 -set fmri(evg18.10) 0 - -# Higher-level EV value for EV 10 and input 19 -set fmri(evg19.10) 1.0 - -# Higher-level EV value for EV 10 and input 20 -set fmri(evg20.10) 1.0 - -# Higher-level EV value for EV 10 and input 21 -set fmri(evg21.10) 0 - -# Higher-level EV value for EV 10 and input 22 -set fmri(evg22.10) 0 - -# Higher-level EV value for EV 10 and input 23 -set fmri(evg23.10) 0 - -# Higher-level EV value for EV 10 and input 24 -set fmri(evg24.10) 0 - -# Higher-level EV value for EV 10 and input 25 -set fmri(evg25.10) 0 - -# Higher-level EV value for EV 10 and input 26 -set fmri(evg26.10) 0 - -# Higher-level EV value for EV 10 and input 27 -set fmri(evg27.10) 0 - -# Higher-level EV value for EV 10 and input 28 -set fmri(evg28.10) 0 - -# Higher-level EV value for EV 10 and input 29 -set fmri(evg29.10) 0 - -# Higher-level EV value for EV 10 and input 30 -set fmri(evg30.10) 0 - -# Higher-level EV value for EV 10 and input 31 -set fmri(evg31.10) 0 - -# Higher-level EV value for EV 10 and input 32 -set fmri(evg32.10) 0 - -# Higher-level EV value for EV 10 and input 33 -set fmri(evg33.10) 0 - -# Higher-level EV value for EV 10 and input 34 -set fmri(evg34.10) 0 - -# Higher-level EV value for EV 10 and input 35 -set fmri(evg35.10) 0 - -# Higher-level EV value for EV 10 and input 36 -set fmri(evg36.10) 0 - -# Higher-level EV value for EV 10 and input 37 -set fmri(evg37.10) 0 - -# Higher-level EV value for EV 10 and input 38 -set fmri(evg38.10) 0 - -# Higher-level EV value for EV 10 and input 39 -set fmri(evg39.10) 0 - -# Higher-level EV value for EV 10 and input 40 -set fmri(evg40.10) 0 - -# Higher-level EV value for EV 10 and input 41 -set fmri(evg41.10) 0 - -# Higher-level EV value for EV 10 and input 42 -set fmri(evg42.10) 0 - -# Higher-level EV value for EV 10 and input 43 -set fmri(evg43.10) 0 - -# Higher-level EV value for EV 10 and input 44 -set fmri(evg44.10) 0 - -# Higher-level EV value for EV 10 and input 45 -set fmri(evg45.10) 0 - -# Higher-level EV value for EV 10 and input 46 -set fmri(evg46.10) 0 - -# Higher-level EV value for EV 10 and input 47 -set fmri(evg47.10) 0 - -# Higher-level EV value for EV 10 and input 48 -set fmri(evg48.10) 0 - -# Higher-level EV value for EV 10 and input 49 -set fmri(evg49.10) 0 - -# Higher-level EV value for EV 10 and input 50 -set fmri(evg50.10) 0 - -# Higher-level EV value for EV 10 and input 51 -set fmri(evg51.10) 0 - -# Higher-level EV value for EV 10 and input 52 -set fmri(evg52.10) 0 - -# EV 11 title -set fmri(evtitle11) "" - -# Basic waveform shape (EV 11) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape11) 2 - -# Convolution (EV 11) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve11) 0 - -# Convolve phase (EV 11) -set fmri(convolve_phase11) 0 - -# Apply temporal filtering (EV 11) -set fmri(tempfilt_yn11) 0 - -# Add temporal derivative (EV 11) -set fmri(deriv_yn11) 0 - -# Custom EV file (EV 11) -set fmri(custom11) "dummy" - -# Orthogonalise EV 11 wrt EV 0 -set fmri(ortho11.0) 0 - -# Orthogonalise EV 11 wrt EV 1 -set fmri(ortho11.1) 0 - -# Orthogonalise EV 11 wrt EV 2 -set fmri(ortho11.2) 0 - -# Orthogonalise EV 11 wrt EV 3 -set fmri(ortho11.3) 0 - -# Orthogonalise EV 11 wrt EV 4 -set fmri(ortho11.4) 0 - -# Orthogonalise EV 11 wrt EV 5 -set fmri(ortho11.5) 0 - -# Orthogonalise EV 11 wrt EV 6 -set fmri(ortho11.6) 0 - -# Orthogonalise EV 11 wrt EV 7 -set fmri(ortho11.7) 0 - -# Orthogonalise EV 11 wrt EV 8 -set fmri(ortho11.8) 0 - -# Orthogonalise EV 11 wrt EV 9 -set fmri(ortho11.9) 0 - -# Orthogonalise EV 11 wrt EV 10 -set fmri(ortho11.10) 0 - -# Orthogonalise EV 11 wrt EV 11 -set fmri(ortho11.11) 0 - -# Orthogonalise EV 11 wrt EV 12 -set fmri(ortho11.12) 0 - -# Orthogonalise EV 11 wrt EV 13 -set fmri(ortho11.13) 0 - -# Orthogonalise EV 11 wrt EV 14 -set fmri(ortho11.14) 0 - -# Orthogonalise EV 11 wrt EV 15 -set fmri(ortho11.15) 0 - -# Orthogonalise EV 11 wrt EV 16 -set fmri(ortho11.16) 0 - -# Orthogonalise EV 11 wrt EV 17 -set fmri(ortho11.17) 0 - -# Orthogonalise EV 11 wrt EV 18 -set fmri(ortho11.18) 0 - -# Orthogonalise EV 11 wrt EV 19 -set fmri(ortho11.19) 0 - -# Orthogonalise EV 11 wrt EV 20 -set fmri(ortho11.20) 0 - -# Orthogonalise EV 11 wrt EV 21 -set fmri(ortho11.21) 0 - -# Orthogonalise EV 11 wrt EV 22 -set fmri(ortho11.22) 0 - -# Orthogonalise EV 11 wrt EV 23 -set fmri(ortho11.23) 0 - -# Orthogonalise EV 11 wrt EV 24 -set fmri(ortho11.24) 0 - -# Orthogonalise EV 11 wrt EV 25 -set fmri(ortho11.25) 0 - -# Orthogonalise EV 11 wrt EV 26 -set fmri(ortho11.26) 0 - -# Higher-level EV value for EV 11 and input 1 -set fmri(evg1.11) 0 - -# Higher-level EV value for EV 11 and input 2 -set fmri(evg2.11) 0 - -# Higher-level EV value for EV 11 and input 3 -set fmri(evg3.11) 0 - -# Higher-level EV value for EV 11 and input 4 -set fmri(evg4.11) 0 - -# Higher-level EV value for EV 11 and input 5 -set fmri(evg5.11) 0 - -# Higher-level EV value for EV 11 and input 6 -set fmri(evg6.11) 0 - -# Higher-level EV value for EV 11 and input 7 -set fmri(evg7.11) 0 - -# Higher-level EV value for EV 11 and input 8 -set fmri(evg8.11) 0 - -# Higher-level EV value for EV 11 and input 9 -set fmri(evg9.11) 0 - -# Higher-level EV value for EV 11 and input 10 -set fmri(evg10.11) 0 - -# Higher-level EV value for EV 11 and input 11 -set fmri(evg11.11) 0 - -# Higher-level EV value for EV 11 and input 12 -set fmri(evg12.11) 0 - -# Higher-level EV value for EV 11 and input 13 -set fmri(evg13.11) 0 - -# Higher-level EV value for EV 11 and input 14 -set fmri(evg14.11) 0 - -# Higher-level EV value for EV 11 and input 15 -set fmri(evg15.11) 0 - -# Higher-level EV value for EV 11 and input 16 -set fmri(evg16.11) 0 - -# Higher-level EV value for EV 11 and input 17 -set fmri(evg17.11) 0 - -# Higher-level EV value for EV 11 and input 18 -set fmri(evg18.11) 0 - -# Higher-level EV value for EV 11 and input 19 -set fmri(evg19.11) 0 - -# Higher-level EV value for EV 11 and input 20 -set fmri(evg20.11) 0 - -# Higher-level EV value for EV 11 and input 21 -set fmri(evg21.11) 1.0 - -# Higher-level EV value for EV 11 and input 22 -set fmri(evg22.11) 1.0 - -# Higher-level EV value for EV 11 and input 23 -set fmri(evg23.11) 0 - -# Higher-level EV value for EV 11 and input 24 -set fmri(evg24.11) 0 - -# Higher-level EV value for EV 11 and input 25 -set fmri(evg25.11) 0 - -# Higher-level EV value for EV 11 and input 26 -set fmri(evg26.11) 0 - -# Higher-level EV value for EV 11 and input 27 -set fmri(evg27.11) 0 - -# Higher-level EV value for EV 11 and input 28 -set fmri(evg28.11) 0 - -# Higher-level EV value for EV 11 and input 29 -set fmri(evg29.11) 0 - -# Higher-level EV value for EV 11 and input 30 -set fmri(evg30.11) 0 - -# Higher-level EV value for EV 11 and input 31 -set fmri(evg31.11) 0 - -# Higher-level EV value for EV 11 and input 32 -set fmri(evg32.11) 0 - -# Higher-level EV value for EV 11 and input 33 -set fmri(evg33.11) 0 - -# Higher-level EV value for EV 11 and input 34 -set fmri(evg34.11) 0 - -# Higher-level EV value for EV 11 and input 35 -set fmri(evg35.11) 0 - -# Higher-level EV value for EV 11 and input 36 -set fmri(evg36.11) 0 - -# Higher-level EV value for EV 11 and input 37 -set fmri(evg37.11) 0 - -# Higher-level EV value for EV 11 and input 38 -set fmri(evg38.11) 0 - -# Higher-level EV value for EV 11 and input 39 -set fmri(evg39.11) 0 - -# Higher-level EV value for EV 11 and input 40 -set fmri(evg40.11) 0 - -# Higher-level EV value for EV 11 and input 41 -set fmri(evg41.11) 0 - -# Higher-level EV value for EV 11 and input 42 -set fmri(evg42.11) 0 - -# Higher-level EV value for EV 11 and input 43 -set fmri(evg43.11) 0 - -# Higher-level EV value for EV 11 and input 44 -set fmri(evg44.11) 0 - -# Higher-level EV value for EV 11 and input 45 -set fmri(evg45.11) 0 - -# Higher-level EV value for EV 11 and input 46 -set fmri(evg46.11) 0 - -# Higher-level EV value for EV 11 and input 47 -set fmri(evg47.11) 0 - -# Higher-level EV value for EV 11 and input 48 -set fmri(evg48.11) 0 - -# Higher-level EV value for EV 11 and input 49 -set fmri(evg49.11) 0 - -# Higher-level EV value for EV 11 and input 50 -set fmri(evg50.11) 0 - -# Higher-level EV value for EV 11 and input 51 -set fmri(evg51.11) 0 - -# Higher-level EV value for EV 11 and input 52 -set fmri(evg52.11) 0 - -# EV 12 title -set fmri(evtitle12) "" - -# Basic waveform shape (EV 12) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape12) 2 - -# Convolution (EV 12) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve12) 0 - -# Convolve phase (EV 12) -set fmri(convolve_phase12) 0 - -# Apply temporal filtering (EV 12) -set fmri(tempfilt_yn12) 0 - -# Add temporal derivative (EV 12) -set fmri(deriv_yn12) 0 - -# Custom EV file (EV 12) -set fmri(custom12) "dummy" - -# Orthogonalise EV 12 wrt EV 0 -set fmri(ortho12.0) 0 - -# Orthogonalise EV 12 wrt EV 1 -set fmri(ortho12.1) 0 - -# Orthogonalise EV 12 wrt EV 2 -set fmri(ortho12.2) 0 - -# Orthogonalise EV 12 wrt EV 3 -set fmri(ortho12.3) 0 - -# Orthogonalise EV 12 wrt EV 4 -set fmri(ortho12.4) 0 - -# Orthogonalise EV 12 wrt EV 5 -set fmri(ortho12.5) 0 - -# Orthogonalise EV 12 wrt EV 6 -set fmri(ortho12.6) 0 - -# Orthogonalise EV 12 wrt EV 7 -set fmri(ortho12.7) 0 - -# Orthogonalise EV 12 wrt EV 8 -set fmri(ortho12.8) 0 - -# Orthogonalise EV 12 wrt EV 9 -set fmri(ortho12.9) 0 - -# Orthogonalise EV 12 wrt EV 10 -set fmri(ortho12.10) 0 - -# Orthogonalise EV 12 wrt EV 11 -set fmri(ortho12.11) 0 - -# Orthogonalise EV 12 wrt EV 12 -set fmri(ortho12.12) 0 - -# Orthogonalise EV 12 wrt EV 13 -set fmri(ortho12.13) 0 - -# Orthogonalise EV 12 wrt EV 14 -set fmri(ortho12.14) 0 - -# Orthogonalise EV 12 wrt EV 15 -set fmri(ortho12.15) 0 - -# Orthogonalise EV 12 wrt EV 16 -set fmri(ortho12.16) 0 - -# Orthogonalise EV 12 wrt EV 17 -set fmri(ortho12.17) 0 - -# Orthogonalise EV 12 wrt EV 18 -set fmri(ortho12.18) 0 - -# Orthogonalise EV 12 wrt EV 19 -set fmri(ortho12.19) 0 - -# Orthogonalise EV 12 wrt EV 20 -set fmri(ortho12.20) 0 - -# Orthogonalise EV 12 wrt EV 21 -set fmri(ortho12.21) 0 - -# Orthogonalise EV 12 wrt EV 22 -set fmri(ortho12.22) 0 - -# Orthogonalise EV 12 wrt EV 23 -set fmri(ortho12.23) 0 - -# Orthogonalise EV 12 wrt EV 24 -set fmri(ortho12.24) 0 - -# Orthogonalise EV 12 wrt EV 25 -set fmri(ortho12.25) 0 - -# Orthogonalise EV 12 wrt EV 26 -set fmri(ortho12.26) 0 - -# Higher-level EV value for EV 12 and input 1 -set fmri(evg1.12) 0 - -# Higher-level EV value for EV 12 and input 2 -set fmri(evg2.12) 0 - -# Higher-level EV value for EV 12 and input 3 -set fmri(evg3.12) 0 - -# Higher-level EV value for EV 12 and input 4 -set fmri(evg4.12) 0 - -# Higher-level EV value for EV 12 and input 5 -set fmri(evg5.12) 0 - -# Higher-level EV value for EV 12 and input 6 -set fmri(evg6.12) 0 - -# Higher-level EV value for EV 12 and input 7 -set fmri(evg7.12) 0 - -# Higher-level EV value for EV 12 and input 8 -set fmri(evg8.12) 0 - -# Higher-level EV value for EV 12 and input 9 -set fmri(evg9.12) 0 - -# Higher-level EV value for EV 12 and input 10 -set fmri(evg10.12) 0 - -# Higher-level EV value for EV 12 and input 11 -set fmri(evg11.12) 0 - -# Higher-level EV value for EV 12 and input 12 -set fmri(evg12.12) 0 - -# Higher-level EV value for EV 12 and input 13 -set fmri(evg13.12) 0 - -# Higher-level EV value for EV 12 and input 14 -set fmri(evg14.12) 0 - -# Higher-level EV value for EV 12 and input 15 -set fmri(evg15.12) 0 - -# Higher-level EV value for EV 12 and input 16 -set fmri(evg16.12) 0 - -# Higher-level EV value for EV 12 and input 17 -set fmri(evg17.12) 0 - -# Higher-level EV value for EV 12 and input 18 -set fmri(evg18.12) 0 - -# Higher-level EV value for EV 12 and input 19 -set fmri(evg19.12) 0 - -# Higher-level EV value for EV 12 and input 20 -set fmri(evg20.12) 0 - -# Higher-level EV value for EV 12 and input 21 -set fmri(evg21.12) 0 - -# Higher-level EV value for EV 12 and input 22 -set fmri(evg22.12) 0 - -# Higher-level EV value for EV 12 and input 23 -set fmri(evg23.12) 1.0 - -# Higher-level EV value for EV 12 and input 24 -set fmri(evg24.12) 1.0 - -# Higher-level EV value for EV 12 and input 25 -set fmri(evg25.12) 0 - -# Higher-level EV value for EV 12 and input 26 -set fmri(evg26.12) 0 - -# Higher-level EV value for EV 12 and input 27 -set fmri(evg27.12) 0 - -# Higher-level EV value for EV 12 and input 28 -set fmri(evg28.12) 0 - -# Higher-level EV value for EV 12 and input 29 -set fmri(evg29.12) 0 - -# Higher-level EV value for EV 12 and input 30 -set fmri(evg30.12) 0 - -# Higher-level EV value for EV 12 and input 31 -set fmri(evg31.12) 0 - -# Higher-level EV value for EV 12 and input 32 -set fmri(evg32.12) 0 - -# Higher-level EV value for EV 12 and input 33 -set fmri(evg33.12) 0 - -# Higher-level EV value for EV 12 and input 34 -set fmri(evg34.12) 0 - -# Higher-level EV value for EV 12 and input 35 -set fmri(evg35.12) 0 - -# Higher-level EV value for EV 12 and input 36 -set fmri(evg36.12) 0 - -# Higher-level EV value for EV 12 and input 37 -set fmri(evg37.12) 0 - -# Higher-level EV value for EV 12 and input 38 -set fmri(evg38.12) 0 - -# Higher-level EV value for EV 12 and input 39 -set fmri(evg39.12) 0 - -# Higher-level EV value for EV 12 and input 40 -set fmri(evg40.12) 0 - -# Higher-level EV value for EV 12 and input 41 -set fmri(evg41.12) 0 - -# Higher-level EV value for EV 12 and input 42 -set fmri(evg42.12) 0 - -# Higher-level EV value for EV 12 and input 43 -set fmri(evg43.12) 0 - -# Higher-level EV value for EV 12 and input 44 -set fmri(evg44.12) 0 - -# Higher-level EV value for EV 12 and input 45 -set fmri(evg45.12) 0 - -# Higher-level EV value for EV 12 and input 46 -set fmri(evg46.12) 0 - -# Higher-level EV value for EV 12 and input 47 -set fmri(evg47.12) 0 - -# Higher-level EV value for EV 12 and input 48 -set fmri(evg48.12) 0 - -# Higher-level EV value for EV 12 and input 49 -set fmri(evg49.12) 0 - -# Higher-level EV value for EV 12 and input 50 -set fmri(evg50.12) 0 - -# Higher-level EV value for EV 12 and input 51 -set fmri(evg51.12) 0 - -# Higher-level EV value for EV 12 and input 52 -set fmri(evg52.12) 0 - -# EV 13 title -set fmri(evtitle13) "" - -# Basic waveform shape (EV 13) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape13) 2 - -# Convolution (EV 13) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve13) 0 - -# Convolve phase (EV 13) -set fmri(convolve_phase13) 0 - -# Apply temporal filtering (EV 13) -set fmri(tempfilt_yn13) 0 - -# Add temporal derivative (EV 13) -set fmri(deriv_yn13) 0 - -# Custom EV file (EV 13) -set fmri(custom13) "dummy" - -# Orthogonalise EV 13 wrt EV 0 -set fmri(ortho13.0) 0 - -# Orthogonalise EV 13 wrt EV 1 -set fmri(ortho13.1) 0 - -# Orthogonalise EV 13 wrt EV 2 -set fmri(ortho13.2) 0 - -# Orthogonalise EV 13 wrt EV 3 -set fmri(ortho13.3) 0 - -# Orthogonalise EV 13 wrt EV 4 -set fmri(ortho13.4) 0 - -# Orthogonalise EV 13 wrt EV 5 -set fmri(ortho13.5) 0 - -# Orthogonalise EV 13 wrt EV 6 -set fmri(ortho13.6) 0 - -# Orthogonalise EV 13 wrt EV 7 -set fmri(ortho13.7) 0 - -# Orthogonalise EV 13 wrt EV 8 -set fmri(ortho13.8) 0 - -# Orthogonalise EV 13 wrt EV 9 -set fmri(ortho13.9) 0 - -# Orthogonalise EV 13 wrt EV 10 -set fmri(ortho13.10) 0 - -# Orthogonalise EV 13 wrt EV 11 -set fmri(ortho13.11) 0 - -# Orthogonalise EV 13 wrt EV 12 -set fmri(ortho13.12) 0 - -# Orthogonalise EV 13 wrt EV 13 -set fmri(ortho13.13) 0 - -# Orthogonalise EV 13 wrt EV 14 -set fmri(ortho13.14) 0 - -# Orthogonalise EV 13 wrt EV 15 -set fmri(ortho13.15) 0 - -# Orthogonalise EV 13 wrt EV 16 -set fmri(ortho13.16) 0 - -# Orthogonalise EV 13 wrt EV 17 -set fmri(ortho13.17) 0 - -# Orthogonalise EV 13 wrt EV 18 -set fmri(ortho13.18) 0 - -# Orthogonalise EV 13 wrt EV 19 -set fmri(ortho13.19) 0 - -# Orthogonalise EV 13 wrt EV 20 -set fmri(ortho13.20) 0 - -# Orthogonalise EV 13 wrt EV 21 -set fmri(ortho13.21) 0 - -# Orthogonalise EV 13 wrt EV 22 -set fmri(ortho13.22) 0 - -# Orthogonalise EV 13 wrt EV 23 -set fmri(ortho13.23) 0 - -# Orthogonalise EV 13 wrt EV 24 -set fmri(ortho13.24) 0 - -# Orthogonalise EV 13 wrt EV 25 -set fmri(ortho13.25) 0 - -# Orthogonalise EV 13 wrt EV 26 -set fmri(ortho13.26) 0 - -# Higher-level EV value for EV 13 and input 1 -set fmri(evg1.13) 0 - -# Higher-level EV value for EV 13 and input 2 -set fmri(evg2.13) 0 - -# Higher-level EV value for EV 13 and input 3 -set fmri(evg3.13) 0 - -# Higher-level EV value for EV 13 and input 4 -set fmri(evg4.13) 0 - -# Higher-level EV value for EV 13 and input 5 -set fmri(evg5.13) 0 - -# Higher-level EV value for EV 13 and input 6 -set fmri(evg6.13) 0 - -# Higher-level EV value for EV 13 and input 7 -set fmri(evg7.13) 0 - -# Higher-level EV value for EV 13 and input 8 -set fmri(evg8.13) 0 - -# Higher-level EV value for EV 13 and input 9 -set fmri(evg9.13) 0 - -# Higher-level EV value for EV 13 and input 10 -set fmri(evg10.13) 0 - -# Higher-level EV value for EV 13 and input 11 -set fmri(evg11.13) 0 - -# Higher-level EV value for EV 13 and input 12 -set fmri(evg12.13) 0 - -# Higher-level EV value for EV 13 and input 13 -set fmri(evg13.13) 0 - -# Higher-level EV value for EV 13 and input 14 -set fmri(evg14.13) 0 - -# Higher-level EV value for EV 13 and input 15 -set fmri(evg15.13) 0 - -# Higher-level EV value for EV 13 and input 16 -set fmri(evg16.13) 0 - -# Higher-level EV value for EV 13 and input 17 -set fmri(evg17.13) 0 - -# Higher-level EV value for EV 13 and input 18 -set fmri(evg18.13) 0 - -# Higher-level EV value for EV 13 and input 19 -set fmri(evg19.13) 0 - -# Higher-level EV value for EV 13 and input 20 -set fmri(evg20.13) 0 - -# Higher-level EV value for EV 13 and input 21 -set fmri(evg21.13) 0 - -# Higher-level EV value for EV 13 and input 22 -set fmri(evg22.13) 0 - -# Higher-level EV value for EV 13 and input 23 -set fmri(evg23.13) 0 - -# Higher-level EV value for EV 13 and input 24 -set fmri(evg24.13) 0 - -# Higher-level EV value for EV 13 and input 25 -set fmri(evg25.13) 1.0 - -# Higher-level EV value for EV 13 and input 26 -set fmri(evg26.13) 1.0 - -# Higher-level EV value for EV 13 and input 27 -set fmri(evg27.13) 0 - -# Higher-level EV value for EV 13 and input 28 -set fmri(evg28.13) 0 - -# Higher-level EV value for EV 13 and input 29 -set fmri(evg29.13) 0 - -# Higher-level EV value for EV 13 and input 30 -set fmri(evg30.13) 0 - -# Higher-level EV value for EV 13 and input 31 -set fmri(evg31.13) 0 - -# Higher-level EV value for EV 13 and input 32 -set fmri(evg32.13) 0 - -# Higher-level EV value for EV 13 and input 33 -set fmri(evg33.13) 0 - -# Higher-level EV value for EV 13 and input 34 -set fmri(evg34.13) 0 - -# Higher-level EV value for EV 13 and input 35 -set fmri(evg35.13) 0 - -# Higher-level EV value for EV 13 and input 36 -set fmri(evg36.13) 0 - -# Higher-level EV value for EV 13 and input 37 -set fmri(evg37.13) 0 - -# Higher-level EV value for EV 13 and input 38 -set fmri(evg38.13) 0 - -# Higher-level EV value for EV 13 and input 39 -set fmri(evg39.13) 0 - -# Higher-level EV value for EV 13 and input 40 -set fmri(evg40.13) 0 - -# Higher-level EV value for EV 13 and input 41 -set fmri(evg41.13) 0 - -# Higher-level EV value for EV 13 and input 42 -set fmri(evg42.13) 0 - -# Higher-level EV value for EV 13 and input 43 -set fmri(evg43.13) 0 - -# Higher-level EV value for EV 13 and input 44 -set fmri(evg44.13) 0 - -# Higher-level EV value for EV 13 and input 45 -set fmri(evg45.13) 0 - -# Higher-level EV value for EV 13 and input 46 -set fmri(evg46.13) 0 - -# Higher-level EV value for EV 13 and input 47 -set fmri(evg47.13) 0 - -# Higher-level EV value for EV 13 and input 48 -set fmri(evg48.13) 0 - -# Higher-level EV value for EV 13 and input 49 -set fmri(evg49.13) 0 - -# Higher-level EV value for EV 13 and input 50 -set fmri(evg50.13) 0 - -# Higher-level EV value for EV 13 and input 51 -set fmri(evg51.13) 0 - -# Higher-level EV value for EV 13 and input 52 -set fmri(evg52.13) 0 - -# EV 14 title -set fmri(evtitle14) "" - -# Basic waveform shape (EV 14) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape14) 2 - -# Convolution (EV 14) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve14) 0 - -# Convolve phase (EV 14) -set fmri(convolve_phase14) 0 - -# Apply temporal filtering (EV 14) -set fmri(tempfilt_yn14) 0 - -# Add temporal derivative (EV 14) -set fmri(deriv_yn14) 0 - -# Custom EV file (EV 14) -set fmri(custom14) "dummy" - -# Orthogonalise EV 14 wrt EV 0 -set fmri(ortho14.0) 0 - -# Orthogonalise EV 14 wrt EV 1 -set fmri(ortho14.1) 0 - -# Orthogonalise EV 14 wrt EV 2 -set fmri(ortho14.2) 0 - -# Orthogonalise EV 14 wrt EV 3 -set fmri(ortho14.3) 0 - -# Orthogonalise EV 14 wrt EV 4 -set fmri(ortho14.4) 0 - -# Orthogonalise EV 14 wrt EV 5 -set fmri(ortho14.5) 0 - -# Orthogonalise EV 14 wrt EV 6 -set fmri(ortho14.6) 0 - -# Orthogonalise EV 14 wrt EV 7 -set fmri(ortho14.7) 0 - -# Orthogonalise EV 14 wrt EV 8 -set fmri(ortho14.8) 0 - -# Orthogonalise EV 14 wrt EV 9 -set fmri(ortho14.9) 0 - -# Orthogonalise EV 14 wrt EV 10 -set fmri(ortho14.10) 0 - -# Orthogonalise EV 14 wrt EV 11 -set fmri(ortho14.11) 0 - -# Orthogonalise EV 14 wrt EV 12 -set fmri(ortho14.12) 0 - -# Orthogonalise EV 14 wrt EV 13 -set fmri(ortho14.13) 0 - -# Orthogonalise EV 14 wrt EV 14 -set fmri(ortho14.14) 0 - -# Orthogonalise EV 14 wrt EV 15 -set fmri(ortho14.15) 0 - -# Orthogonalise EV 14 wrt EV 16 -set fmri(ortho14.16) 0 - -# Orthogonalise EV 14 wrt EV 17 -set fmri(ortho14.17) 0 - -# Orthogonalise EV 14 wrt EV 18 -set fmri(ortho14.18) 0 - -# Orthogonalise EV 14 wrt EV 19 -set fmri(ortho14.19) 0 - -# Orthogonalise EV 14 wrt EV 20 -set fmri(ortho14.20) 0 - -# Orthogonalise EV 14 wrt EV 21 -set fmri(ortho14.21) 0 - -# Orthogonalise EV 14 wrt EV 22 -set fmri(ortho14.22) 0 - -# Orthogonalise EV 14 wrt EV 23 -set fmri(ortho14.23) 0 - -# Orthogonalise EV 14 wrt EV 24 -set fmri(ortho14.24) 0 - -# Orthogonalise EV 14 wrt EV 25 -set fmri(ortho14.25) 0 - -# Orthogonalise EV 14 wrt EV 26 -set fmri(ortho14.26) 0 - -# Higher-level EV value for EV 14 and input 1 -set fmri(evg1.14) 0 - -# Higher-level EV value for EV 14 and input 2 -set fmri(evg2.14) 0 - -# Higher-level EV value for EV 14 and input 3 -set fmri(evg3.14) 0 - -# Higher-level EV value for EV 14 and input 4 -set fmri(evg4.14) 0 - -# Higher-level EV value for EV 14 and input 5 -set fmri(evg5.14) 0 - -# Higher-level EV value for EV 14 and input 6 -set fmri(evg6.14) 0 - -# Higher-level EV value for EV 14 and input 7 -set fmri(evg7.14) 0 - -# Higher-level EV value for EV 14 and input 8 -set fmri(evg8.14) 0 - -# Higher-level EV value for EV 14 and input 9 -set fmri(evg9.14) 0 - -# Higher-level EV value for EV 14 and input 10 -set fmri(evg10.14) 0 - -# Higher-level EV value for EV 14 and input 11 -set fmri(evg11.14) 0 - -# Higher-level EV value for EV 14 and input 12 -set fmri(evg12.14) 0 - -# Higher-level EV value for EV 14 and input 13 -set fmri(evg13.14) 0 - -# Higher-level EV value for EV 14 and input 14 -set fmri(evg14.14) 0 - -# Higher-level EV value for EV 14 and input 15 -set fmri(evg15.14) 0 - -# Higher-level EV value for EV 14 and input 16 -set fmri(evg16.14) 0 - -# Higher-level EV value for EV 14 and input 17 -set fmri(evg17.14) 0 - -# Higher-level EV value for EV 14 and input 18 -set fmri(evg18.14) 0 - -# Higher-level EV value for EV 14 and input 19 -set fmri(evg19.14) 0 - -# Higher-level EV value for EV 14 and input 20 -set fmri(evg20.14) 0 - -# Higher-level EV value for EV 14 and input 21 -set fmri(evg21.14) 0 - -# Higher-level EV value for EV 14 and input 22 -set fmri(evg22.14) 0 - -# Higher-level EV value for EV 14 and input 23 -set fmri(evg23.14) 0 - -# Higher-level EV value for EV 14 and input 24 -set fmri(evg24.14) 0 - -# Higher-level EV value for EV 14 and input 25 -set fmri(evg25.14) 0 - -# Higher-level EV value for EV 14 and input 26 -set fmri(evg26.14) 0 - -# Higher-level EV value for EV 14 and input 27 -set fmri(evg27.14) 1.0 - -# Higher-level EV value for EV 14 and input 28 -set fmri(evg28.14) 1.0 - -# Higher-level EV value for EV 14 and input 29 -set fmri(evg29.14) 0 - -# Higher-level EV value for EV 14 and input 30 -set fmri(evg30.14) 0 - -# Higher-level EV value for EV 14 and input 31 -set fmri(evg31.14) 0 - -# Higher-level EV value for EV 14 and input 32 -set fmri(evg32.14) 0 - -# Higher-level EV value for EV 14 and input 33 -set fmri(evg33.14) 0 - -# Higher-level EV value for EV 14 and input 34 -set fmri(evg34.14) 0 - -# Higher-level EV value for EV 14 and input 35 -set fmri(evg35.14) 0 - -# Higher-level EV value for EV 14 and input 36 -set fmri(evg36.14) 0 - -# Higher-level EV value for EV 14 and input 37 -set fmri(evg37.14) 0 - -# Higher-level EV value for EV 14 and input 38 -set fmri(evg38.14) 0 - -# Higher-level EV value for EV 14 and input 39 -set fmri(evg39.14) 0 - -# Higher-level EV value for EV 14 and input 40 -set fmri(evg40.14) 0 - -# Higher-level EV value for EV 14 and input 41 -set fmri(evg41.14) 0 - -# Higher-level EV value for EV 14 and input 42 -set fmri(evg42.14) 0 - -# Higher-level EV value for EV 14 and input 43 -set fmri(evg43.14) 0 - -# Higher-level EV value for EV 14 and input 44 -set fmri(evg44.14) 0 - -# Higher-level EV value for EV 14 and input 45 -set fmri(evg45.14) 0 - -# Higher-level EV value for EV 14 and input 46 -set fmri(evg46.14) 0 - -# Higher-level EV value for EV 14 and input 47 -set fmri(evg47.14) 0 - -# Higher-level EV value for EV 14 and input 48 -set fmri(evg48.14) 0 - -# Higher-level EV value for EV 14 and input 49 -set fmri(evg49.14) 0 - -# Higher-level EV value for EV 14 and input 50 -set fmri(evg50.14) 0 - -# Higher-level EV value for EV 14 and input 51 -set fmri(evg51.14) 0 - -# Higher-level EV value for EV 14 and input 52 -set fmri(evg52.14) 0 - -# EV 15 title -set fmri(evtitle15) "" - -# Basic waveform shape (EV 15) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape15) 2 - -# Convolution (EV 15) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve15) 0 - -# Convolve phase (EV 15) -set fmri(convolve_phase15) 0 - -# Apply temporal filtering (EV 15) -set fmri(tempfilt_yn15) 0 - -# Add temporal derivative (EV 15) -set fmri(deriv_yn15) 0 - -# Custom EV file (EV 15) -set fmri(custom15) "dummy" - -# Orthogonalise EV 15 wrt EV 0 -set fmri(ortho15.0) 0 - -# Orthogonalise EV 15 wrt EV 1 -set fmri(ortho15.1) 0 - -# Orthogonalise EV 15 wrt EV 2 -set fmri(ortho15.2) 0 - -# Orthogonalise EV 15 wrt EV 3 -set fmri(ortho15.3) 0 - -# Orthogonalise EV 15 wrt EV 4 -set fmri(ortho15.4) 0 - -# Orthogonalise EV 15 wrt EV 5 -set fmri(ortho15.5) 0 - -# Orthogonalise EV 15 wrt EV 6 -set fmri(ortho15.6) 0 - -# Orthogonalise EV 15 wrt EV 7 -set fmri(ortho15.7) 0 - -# Orthogonalise EV 15 wrt EV 8 -set fmri(ortho15.8) 0 - -# Orthogonalise EV 15 wrt EV 9 -set fmri(ortho15.9) 0 - -# Orthogonalise EV 15 wrt EV 10 -set fmri(ortho15.10) 0 - -# Orthogonalise EV 15 wrt EV 11 -set fmri(ortho15.11) 0 - -# Orthogonalise EV 15 wrt EV 12 -set fmri(ortho15.12) 0 - -# Orthogonalise EV 15 wrt EV 13 -set fmri(ortho15.13) 0 - -# Orthogonalise EV 15 wrt EV 14 -set fmri(ortho15.14) 0 - -# Orthogonalise EV 15 wrt EV 15 -set fmri(ortho15.15) 0 - -# Orthogonalise EV 15 wrt EV 16 -set fmri(ortho15.16) 0 - -# Orthogonalise EV 15 wrt EV 17 -set fmri(ortho15.17) 0 - -# Orthogonalise EV 15 wrt EV 18 -set fmri(ortho15.18) 0 - -# Orthogonalise EV 15 wrt EV 19 -set fmri(ortho15.19) 0 - -# Orthogonalise EV 15 wrt EV 20 -set fmri(ortho15.20) 0 - -# Orthogonalise EV 15 wrt EV 21 -set fmri(ortho15.21) 0 - -# Orthogonalise EV 15 wrt EV 22 -set fmri(ortho15.22) 0 - -# Orthogonalise EV 15 wrt EV 23 -set fmri(ortho15.23) 0 - -# Orthogonalise EV 15 wrt EV 24 -set fmri(ortho15.24) 0 - -# Orthogonalise EV 15 wrt EV 25 -set fmri(ortho15.25) 0 - -# Orthogonalise EV 15 wrt EV 26 -set fmri(ortho15.26) 0 - -# Higher-level EV value for EV 15 and input 1 -set fmri(evg1.15) 0 - -# Higher-level EV value for EV 15 and input 2 -set fmri(evg2.15) 0 - -# Higher-level EV value for EV 15 and input 3 -set fmri(evg3.15) 0 - -# Higher-level EV value for EV 15 and input 4 -set fmri(evg4.15) 0 - -# Higher-level EV value for EV 15 and input 5 -set fmri(evg5.15) 0 - -# Higher-level EV value for EV 15 and input 6 -set fmri(evg6.15) 0 - -# Higher-level EV value for EV 15 and input 7 -set fmri(evg7.15) 0 - -# Higher-level EV value for EV 15 and input 8 -set fmri(evg8.15) 0 - -# Higher-level EV value for EV 15 and input 9 -set fmri(evg9.15) 0 - -# Higher-level EV value for EV 15 and input 10 -set fmri(evg10.15) 0 - -# Higher-level EV value for EV 15 and input 11 -set fmri(evg11.15) 0 - -# Higher-level EV value for EV 15 and input 12 -set fmri(evg12.15) 0 - -# Higher-level EV value for EV 15 and input 13 -set fmri(evg13.15) 0 - -# Higher-level EV value for EV 15 and input 14 -set fmri(evg14.15) 0 - -# Higher-level EV value for EV 15 and input 15 -set fmri(evg15.15) 0 - -# Higher-level EV value for EV 15 and input 16 -set fmri(evg16.15) 0 - -# Higher-level EV value for EV 15 and input 17 -set fmri(evg17.15) 0 - -# Higher-level EV value for EV 15 and input 18 -set fmri(evg18.15) 0 - -# Higher-level EV value for EV 15 and input 19 -set fmri(evg19.15) 0 - -# Higher-level EV value for EV 15 and input 20 -set fmri(evg20.15) 0 - -# Higher-level EV value for EV 15 and input 21 -set fmri(evg21.15) 0 - -# Higher-level EV value for EV 15 and input 22 -set fmri(evg22.15) 0 - -# Higher-level EV value for EV 15 and input 23 -set fmri(evg23.15) 0 - -# Higher-level EV value for EV 15 and input 24 -set fmri(evg24.15) 0 - -# Higher-level EV value for EV 15 and input 25 -set fmri(evg25.15) 0 - -# Higher-level EV value for EV 15 and input 26 -set fmri(evg26.15) 0 - -# Higher-level EV value for EV 15 and input 27 -set fmri(evg27.15) 0 - -# Higher-level EV value for EV 15 and input 28 -set fmri(evg28.15) 0 - -# Higher-level EV value for EV 15 and input 29 -set fmri(evg29.15) 1.0 - -# Higher-level EV value for EV 15 and input 30 -set fmri(evg30.15) 1.0 - -# Higher-level EV value for EV 15 and input 31 -set fmri(evg31.15) 0 - -# Higher-level EV value for EV 15 and input 32 -set fmri(evg32.15) 0 - -# Higher-level EV value for EV 15 and input 33 -set fmri(evg33.15) 0 - -# Higher-level EV value for EV 15 and input 34 -set fmri(evg34.15) 0 - -# Higher-level EV value for EV 15 and input 35 -set fmri(evg35.15) 0 - -# Higher-level EV value for EV 15 and input 36 -set fmri(evg36.15) 0 - -# Higher-level EV value for EV 15 and input 37 -set fmri(evg37.15) 0 - -# Higher-level EV value for EV 15 and input 38 -set fmri(evg38.15) 0 - -# Higher-level EV value for EV 15 and input 39 -set fmri(evg39.15) 0 - -# Higher-level EV value for EV 15 and input 40 -set fmri(evg40.15) 0 - -# Higher-level EV value for EV 15 and input 41 -set fmri(evg41.15) 0 - -# Higher-level EV value for EV 15 and input 42 -set fmri(evg42.15) 0 - -# Higher-level EV value for EV 15 and input 43 -set fmri(evg43.15) 0 - -# Higher-level EV value for EV 15 and input 44 -set fmri(evg44.15) 0 - -# Higher-level EV value for EV 15 and input 45 -set fmri(evg45.15) 0 - -# Higher-level EV value for EV 15 and input 46 -set fmri(evg46.15) 0 - -# Higher-level EV value for EV 15 and input 47 -set fmri(evg47.15) 0 - -# Higher-level EV value for EV 15 and input 48 -set fmri(evg48.15) 0 - -# Higher-level EV value for EV 15 and input 49 -set fmri(evg49.15) 0 - -# Higher-level EV value for EV 15 and input 50 -set fmri(evg50.15) 0 - -# Higher-level EV value for EV 15 and input 51 -set fmri(evg51.15) 0 - -# Higher-level EV value for EV 15 and input 52 -set fmri(evg52.15) 0 - -# EV 16 title -set fmri(evtitle16) "" - -# Basic waveform shape (EV 16) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape16) 2 - -# Convolution (EV 16) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve16) 0 - -# Convolve phase (EV 16) -set fmri(convolve_phase16) 0 - -# Apply temporal filtering (EV 16) -set fmri(tempfilt_yn16) 0 - -# Add temporal derivative (EV 16) -set fmri(deriv_yn16) 0 - -# Custom EV file (EV 16) -set fmri(custom16) "dummy" - -# Orthogonalise EV 16 wrt EV 0 -set fmri(ortho16.0) 0 - -# Orthogonalise EV 16 wrt EV 1 -set fmri(ortho16.1) 0 - -# Orthogonalise EV 16 wrt EV 2 -set fmri(ortho16.2) 0 - -# Orthogonalise EV 16 wrt EV 3 -set fmri(ortho16.3) 0 - -# Orthogonalise EV 16 wrt EV 4 -set fmri(ortho16.4) 0 - -# Orthogonalise EV 16 wrt EV 5 -set fmri(ortho16.5) 0 - -# Orthogonalise EV 16 wrt EV 6 -set fmri(ortho16.6) 0 - -# Orthogonalise EV 16 wrt EV 7 -set fmri(ortho16.7) 0 - -# Orthogonalise EV 16 wrt EV 8 -set fmri(ortho16.8) 0 - -# Orthogonalise EV 16 wrt EV 9 -set fmri(ortho16.9) 0 - -# Orthogonalise EV 16 wrt EV 10 -set fmri(ortho16.10) 0 - -# Orthogonalise EV 16 wrt EV 11 -set fmri(ortho16.11) 0 - -# Orthogonalise EV 16 wrt EV 12 -set fmri(ortho16.12) 0 - -# Orthogonalise EV 16 wrt EV 13 -set fmri(ortho16.13) 0 - -# Orthogonalise EV 16 wrt EV 14 -set fmri(ortho16.14) 0 - -# Orthogonalise EV 16 wrt EV 15 -set fmri(ortho16.15) 0 - -# Orthogonalise EV 16 wrt EV 16 -set fmri(ortho16.16) 0 - -# Orthogonalise EV 16 wrt EV 17 -set fmri(ortho16.17) 0 - -# Orthogonalise EV 16 wrt EV 18 -set fmri(ortho16.18) 0 - -# Orthogonalise EV 16 wrt EV 19 -set fmri(ortho16.19) 0 - -# Orthogonalise EV 16 wrt EV 20 -set fmri(ortho16.20) 0 - -# Orthogonalise EV 16 wrt EV 21 -set fmri(ortho16.21) 0 - -# Orthogonalise EV 16 wrt EV 22 -set fmri(ortho16.22) 0 - -# Orthogonalise EV 16 wrt EV 23 -set fmri(ortho16.23) 0 - -# Orthogonalise EV 16 wrt EV 24 -set fmri(ortho16.24) 0 - -# Orthogonalise EV 16 wrt EV 25 -set fmri(ortho16.25) 0 - -# Orthogonalise EV 16 wrt EV 26 -set fmri(ortho16.26) 0 - -# Higher-level EV value for EV 16 and input 1 -set fmri(evg1.16) 0 - -# Higher-level EV value for EV 16 and input 2 -set fmri(evg2.16) 0 - -# Higher-level EV value for EV 16 and input 3 -set fmri(evg3.16) 0 - -# Higher-level EV value for EV 16 and input 4 -set fmri(evg4.16) 0 - -# Higher-level EV value for EV 16 and input 5 -set fmri(evg5.16) 0 - -# Higher-level EV value for EV 16 and input 6 -set fmri(evg6.16) 0 - -# Higher-level EV value for EV 16 and input 7 -set fmri(evg7.16) 0 - -# Higher-level EV value for EV 16 and input 8 -set fmri(evg8.16) 0 - -# Higher-level EV value for EV 16 and input 9 -set fmri(evg9.16) 0 - -# Higher-level EV value for EV 16 and input 10 -set fmri(evg10.16) 0 - -# Higher-level EV value for EV 16 and input 11 -set fmri(evg11.16) 0 - -# Higher-level EV value for EV 16 and input 12 -set fmri(evg12.16) 0 - -# Higher-level EV value for EV 16 and input 13 -set fmri(evg13.16) 0 - -# Higher-level EV value for EV 16 and input 14 -set fmri(evg14.16) 0 - -# Higher-level EV value for EV 16 and input 15 -set fmri(evg15.16) 0 - -# Higher-level EV value for EV 16 and input 16 -set fmri(evg16.16) 0 - -# Higher-level EV value for EV 16 and input 17 -set fmri(evg17.16) 0 - -# Higher-level EV value for EV 16 and input 18 -set fmri(evg18.16) 0 - -# Higher-level EV value for EV 16 and input 19 -set fmri(evg19.16) 0 - -# Higher-level EV value for EV 16 and input 20 -set fmri(evg20.16) 0 - -# Higher-level EV value for EV 16 and input 21 -set fmri(evg21.16) 0 - -# Higher-level EV value for EV 16 and input 22 -set fmri(evg22.16) 0 - -# Higher-level EV value for EV 16 and input 23 -set fmri(evg23.16) 0 - -# Higher-level EV value for EV 16 and input 24 -set fmri(evg24.16) 0 - -# Higher-level EV value for EV 16 and input 25 -set fmri(evg25.16) 0 - -# Higher-level EV value for EV 16 and input 26 -set fmri(evg26.16) 0 - -# Higher-level EV value for EV 16 and input 27 -set fmri(evg27.16) 0 - -# Higher-level EV value for EV 16 and input 28 -set fmri(evg28.16) 0 - -# Higher-level EV value for EV 16 and input 29 -set fmri(evg29.16) 0 - -# Higher-level EV value for EV 16 and input 30 -set fmri(evg30.16) 0 - -# Higher-level EV value for EV 16 and input 31 -set fmri(evg31.16) 1.0 - -# Higher-level EV value for EV 16 and input 32 -set fmri(evg32.16) 1.0 - -# Higher-level EV value for EV 16 and input 33 -set fmri(evg33.16) 0 - -# Higher-level EV value for EV 16 and input 34 -set fmri(evg34.16) 0 - -# Higher-level EV value for EV 16 and input 35 -set fmri(evg35.16) 0 - -# Higher-level EV value for EV 16 and input 36 -set fmri(evg36.16) 0 - -# Higher-level EV value for EV 16 and input 37 -set fmri(evg37.16) 0 - -# Higher-level EV value for EV 16 and input 38 -set fmri(evg38.16) 0 - -# Higher-level EV value for EV 16 and input 39 -set fmri(evg39.16) 0 - -# Higher-level EV value for EV 16 and input 40 -set fmri(evg40.16) 0 - -# Higher-level EV value for EV 16 and input 41 -set fmri(evg41.16) 0 - -# Higher-level EV value for EV 16 and input 42 -set fmri(evg42.16) 0 - -# Higher-level EV value for EV 16 and input 43 -set fmri(evg43.16) 0 - -# Higher-level EV value for EV 16 and input 44 -set fmri(evg44.16) 0 - -# Higher-level EV value for EV 16 and input 45 -set fmri(evg45.16) 0 - -# Higher-level EV value for EV 16 and input 46 -set fmri(evg46.16) 0 - -# Higher-level EV value for EV 16 and input 47 -set fmri(evg47.16) 0 - -# Higher-level EV value for EV 16 and input 48 -set fmri(evg48.16) 0 - -# Higher-level EV value for EV 16 and input 49 -set fmri(evg49.16) 0 - -# Higher-level EV value for EV 16 and input 50 -set fmri(evg50.16) 0 - -# Higher-level EV value for EV 16 and input 51 -set fmri(evg51.16) 0 - -# Higher-level EV value for EV 16 and input 52 -set fmri(evg52.16) 0 - -# EV 17 title -set fmri(evtitle17) "" - -# Basic waveform shape (EV 17) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape17) 2 - -# Convolution (EV 17) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve17) 0 - -# Convolve phase (EV 17) -set fmri(convolve_phase17) 0 - -# Apply temporal filtering (EV 17) -set fmri(tempfilt_yn17) 0 - -# Add temporal derivative (EV 17) -set fmri(deriv_yn17) 0 - -# Custom EV file (EV 17) -set fmri(custom17) "dummy" - -# Orthogonalise EV 17 wrt EV 0 -set fmri(ortho17.0) 0 - -# Orthogonalise EV 17 wrt EV 1 -set fmri(ortho17.1) 0 - -# Orthogonalise EV 17 wrt EV 2 -set fmri(ortho17.2) 0 - -# Orthogonalise EV 17 wrt EV 3 -set fmri(ortho17.3) 0 - -# Orthogonalise EV 17 wrt EV 4 -set fmri(ortho17.4) 0 - -# Orthogonalise EV 17 wrt EV 5 -set fmri(ortho17.5) 0 - -# Orthogonalise EV 17 wrt EV 6 -set fmri(ortho17.6) 0 - -# Orthogonalise EV 17 wrt EV 7 -set fmri(ortho17.7) 0 - -# Orthogonalise EV 17 wrt EV 8 -set fmri(ortho17.8) 0 - -# Orthogonalise EV 17 wrt EV 9 -set fmri(ortho17.9) 0 - -# Orthogonalise EV 17 wrt EV 10 -set fmri(ortho17.10) 0 - -# Orthogonalise EV 17 wrt EV 11 -set fmri(ortho17.11) 0 - -# Orthogonalise EV 17 wrt EV 12 -set fmri(ortho17.12) 0 - -# Orthogonalise EV 17 wrt EV 13 -set fmri(ortho17.13) 0 - -# Orthogonalise EV 17 wrt EV 14 -set fmri(ortho17.14) 0 - -# Orthogonalise EV 17 wrt EV 15 -set fmri(ortho17.15) 0 - -# Orthogonalise EV 17 wrt EV 16 -set fmri(ortho17.16) 0 - -# Orthogonalise EV 17 wrt EV 17 -set fmri(ortho17.17) 0 - -# Orthogonalise EV 17 wrt EV 18 -set fmri(ortho17.18) 0 - -# Orthogonalise EV 17 wrt EV 19 -set fmri(ortho17.19) 0 - -# Orthogonalise EV 17 wrt EV 20 -set fmri(ortho17.20) 0 - -# Orthogonalise EV 17 wrt EV 21 -set fmri(ortho17.21) 0 - -# Orthogonalise EV 17 wrt EV 22 -set fmri(ortho17.22) 0 - -# Orthogonalise EV 17 wrt EV 23 -set fmri(ortho17.23) 0 - -# Orthogonalise EV 17 wrt EV 24 -set fmri(ortho17.24) 0 - -# Orthogonalise EV 17 wrt EV 25 -set fmri(ortho17.25) 0 - -# Orthogonalise EV 17 wrt EV 26 -set fmri(ortho17.26) 0 - -# Higher-level EV value for EV 17 and input 1 -set fmri(evg1.17) 0 - -# Higher-level EV value for EV 17 and input 2 -set fmri(evg2.17) 0 - -# Higher-level EV value for EV 17 and input 3 -set fmri(evg3.17) 0 - -# Higher-level EV value for EV 17 and input 4 -set fmri(evg4.17) 0 - -# Higher-level EV value for EV 17 and input 5 -set fmri(evg5.17) 0 - -# Higher-level EV value for EV 17 and input 6 -set fmri(evg6.17) 0 - -# Higher-level EV value for EV 17 and input 7 -set fmri(evg7.17) 0 - -# Higher-level EV value for EV 17 and input 8 -set fmri(evg8.17) 0 - -# Higher-level EV value for EV 17 and input 9 -set fmri(evg9.17) 0 - -# Higher-level EV value for EV 17 and input 10 -set fmri(evg10.17) 0 - -# Higher-level EV value for EV 17 and input 11 -set fmri(evg11.17) 0 - -# Higher-level EV value for EV 17 and input 12 -set fmri(evg12.17) 0 - -# Higher-level EV value for EV 17 and input 13 -set fmri(evg13.17) 0 - -# Higher-level EV value for EV 17 and input 14 -set fmri(evg14.17) 0 - -# Higher-level EV value for EV 17 and input 15 -set fmri(evg15.17) 0 - -# Higher-level EV value for EV 17 and input 16 -set fmri(evg16.17) 0 - -# Higher-level EV value for EV 17 and input 17 -set fmri(evg17.17) 0 - -# Higher-level EV value for EV 17 and input 18 -set fmri(evg18.17) 0 - -# Higher-level EV value for EV 17 and input 19 -set fmri(evg19.17) 0 - -# Higher-level EV value for EV 17 and input 20 -set fmri(evg20.17) 0 - -# Higher-level EV value for EV 17 and input 21 -set fmri(evg21.17) 0 - -# Higher-level EV value for EV 17 and input 22 -set fmri(evg22.17) 0 - -# Higher-level EV value for EV 17 and input 23 -set fmri(evg23.17) 0 - -# Higher-level EV value for EV 17 and input 24 -set fmri(evg24.17) 0 - -# Higher-level EV value for EV 17 and input 25 -set fmri(evg25.17) 0 - -# Higher-level EV value for EV 17 and input 26 -set fmri(evg26.17) 0 - -# Higher-level EV value for EV 17 and input 27 -set fmri(evg27.17) 0 - -# Higher-level EV value for EV 17 and input 28 -set fmri(evg28.17) 0 - -# Higher-level EV value for EV 17 and input 29 -set fmri(evg29.17) 0 - -# Higher-level EV value for EV 17 and input 30 -set fmri(evg30.17) 0 - -# Higher-level EV value for EV 17 and input 31 -set fmri(evg31.17) 0 - -# Higher-level EV value for EV 17 and input 32 -set fmri(evg32.17) 0 - -# Higher-level EV value for EV 17 and input 33 -set fmri(evg33.17) 1.0 - -# Higher-level EV value for EV 17 and input 34 -set fmri(evg34.17) 1.0 - -# Higher-level EV value for EV 17 and input 35 -set fmri(evg35.17) 0 - -# Higher-level EV value for EV 17 and input 36 -set fmri(evg36.17) 0 - -# Higher-level EV value for EV 17 and input 37 -set fmri(evg37.17) 0 - -# Higher-level EV value for EV 17 and input 38 -set fmri(evg38.17) 0 - -# Higher-level EV value for EV 17 and input 39 -set fmri(evg39.17) 0 - -# Higher-level EV value for EV 17 and input 40 -set fmri(evg40.17) 0 - -# Higher-level EV value for EV 17 and input 41 -set fmri(evg41.17) 0 - -# Higher-level EV value for EV 17 and input 42 -set fmri(evg42.17) 0 - -# Higher-level EV value for EV 17 and input 43 -set fmri(evg43.17) 0 - -# Higher-level EV value for EV 17 and input 44 -set fmri(evg44.17) 0 - -# Higher-level EV value for EV 17 and input 45 -set fmri(evg45.17) 0 - -# Higher-level EV value for EV 17 and input 46 -set fmri(evg46.17) 0 - -# Higher-level EV value for EV 17 and input 47 -set fmri(evg47.17) 0 - -# Higher-level EV value for EV 17 and input 48 -set fmri(evg48.17) 0 - -# Higher-level EV value for EV 17 and input 49 -set fmri(evg49.17) 0 - -# Higher-level EV value for EV 17 and input 50 -set fmri(evg50.17) 0 - -# Higher-level EV value for EV 17 and input 51 -set fmri(evg51.17) 0 - -# Higher-level EV value for EV 17 and input 52 -set fmri(evg52.17) 0 - -# EV 18 title -set fmri(evtitle18) "" - -# Basic waveform shape (EV 18) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape18) 2 - -# Convolution (EV 18) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve18) 0 - -# Convolve phase (EV 18) -set fmri(convolve_phase18) 0 - -# Apply temporal filtering (EV 18) -set fmri(tempfilt_yn18) 0 - -# Add temporal derivative (EV 18) -set fmri(deriv_yn18) 0 - -# Custom EV file (EV 18) -set fmri(custom18) "dummy" - -# Orthogonalise EV 18 wrt EV 0 -set fmri(ortho18.0) 0 - -# Orthogonalise EV 18 wrt EV 1 -set fmri(ortho18.1) 0 - -# Orthogonalise EV 18 wrt EV 2 -set fmri(ortho18.2) 0 - -# Orthogonalise EV 18 wrt EV 3 -set fmri(ortho18.3) 0 - -# Orthogonalise EV 18 wrt EV 4 -set fmri(ortho18.4) 0 - -# Orthogonalise EV 18 wrt EV 5 -set fmri(ortho18.5) 0 - -# Orthogonalise EV 18 wrt EV 6 -set fmri(ortho18.6) 0 - -# Orthogonalise EV 18 wrt EV 7 -set fmri(ortho18.7) 0 - -# Orthogonalise EV 18 wrt EV 8 -set fmri(ortho18.8) 0 - -# Orthogonalise EV 18 wrt EV 9 -set fmri(ortho18.9) 0 - -# Orthogonalise EV 18 wrt EV 10 -set fmri(ortho18.10) 0 - -# Orthogonalise EV 18 wrt EV 11 -set fmri(ortho18.11) 0 - -# Orthogonalise EV 18 wrt EV 12 -set fmri(ortho18.12) 0 - -# Orthogonalise EV 18 wrt EV 13 -set fmri(ortho18.13) 0 - -# Orthogonalise EV 18 wrt EV 14 -set fmri(ortho18.14) 0 - -# Orthogonalise EV 18 wrt EV 15 -set fmri(ortho18.15) 0 - -# Orthogonalise EV 18 wrt EV 16 -set fmri(ortho18.16) 0 - -# Orthogonalise EV 18 wrt EV 17 -set fmri(ortho18.17) 0 - -# Orthogonalise EV 18 wrt EV 18 -set fmri(ortho18.18) 0 - -# Orthogonalise EV 18 wrt EV 19 -set fmri(ortho18.19) 0 - -# Orthogonalise EV 18 wrt EV 20 -set fmri(ortho18.20) 0 - -# Orthogonalise EV 18 wrt EV 21 -set fmri(ortho18.21) 0 - -# Orthogonalise EV 18 wrt EV 22 -set fmri(ortho18.22) 0 - -# Orthogonalise EV 18 wrt EV 23 -set fmri(ortho18.23) 0 - -# Orthogonalise EV 18 wrt EV 24 -set fmri(ortho18.24) 0 - -# Orthogonalise EV 18 wrt EV 25 -set fmri(ortho18.25) 0 - -# Orthogonalise EV 18 wrt EV 26 -set fmri(ortho18.26) 0 - -# Higher-level EV value for EV 18 and input 1 -set fmri(evg1.18) 0 - -# Higher-level EV value for EV 18 and input 2 -set fmri(evg2.18) 0 - -# Higher-level EV value for EV 18 and input 3 -set fmri(evg3.18) 0 - -# Higher-level EV value for EV 18 and input 4 -set fmri(evg4.18) 0 - -# Higher-level EV value for EV 18 and input 5 -set fmri(evg5.18) 0 - -# Higher-level EV value for EV 18 and input 6 -set fmri(evg6.18) 0 - -# Higher-level EV value for EV 18 and input 7 -set fmri(evg7.18) 0 - -# Higher-level EV value for EV 18 and input 8 -set fmri(evg8.18) 0 - -# Higher-level EV value for EV 18 and input 9 -set fmri(evg9.18) 0 - -# Higher-level EV value for EV 18 and input 10 -set fmri(evg10.18) 0 - -# Higher-level EV value for EV 18 and input 11 -set fmri(evg11.18) 0 - -# Higher-level EV value for EV 18 and input 12 -set fmri(evg12.18) 0 - -# Higher-level EV value for EV 18 and input 13 -set fmri(evg13.18) 0 - -# Higher-level EV value for EV 18 and input 14 -set fmri(evg14.18) 0 - -# Higher-level EV value for EV 18 and input 15 -set fmri(evg15.18) 0 - -# Higher-level EV value for EV 18 and input 16 -set fmri(evg16.18) 0 - -# Higher-level EV value for EV 18 and input 17 -set fmri(evg17.18) 0 - -# Higher-level EV value for EV 18 and input 18 -set fmri(evg18.18) 0 - -# Higher-level EV value for EV 18 and input 19 -set fmri(evg19.18) 0 - -# Higher-level EV value for EV 18 and input 20 -set fmri(evg20.18) 0 - -# Higher-level EV value for EV 18 and input 21 -set fmri(evg21.18) 0 - -# Higher-level EV value for EV 18 and input 22 -set fmri(evg22.18) 0 - -# Higher-level EV value for EV 18 and input 23 -set fmri(evg23.18) 0 - -# Higher-level EV value for EV 18 and input 24 -set fmri(evg24.18) 0 - -# Higher-level EV value for EV 18 and input 25 -set fmri(evg25.18) 0 - -# Higher-level EV value for EV 18 and input 26 -set fmri(evg26.18) 0 - -# Higher-level EV value for EV 18 and input 27 -set fmri(evg27.18) 0 - -# Higher-level EV value for EV 18 and input 28 -set fmri(evg28.18) 0 - -# Higher-level EV value for EV 18 and input 29 -set fmri(evg29.18) 0 - -# Higher-level EV value for EV 18 and input 30 -set fmri(evg30.18) 0 - -# Higher-level EV value for EV 18 and input 31 -set fmri(evg31.18) 0 - -# Higher-level EV value for EV 18 and input 32 -set fmri(evg32.18) 0 - -# Higher-level EV value for EV 18 and input 33 -set fmri(evg33.18) 0 - -# Higher-level EV value for EV 18 and input 34 -set fmri(evg34.18) 0 - -# Higher-level EV value for EV 18 and input 35 -set fmri(evg35.18) 1.0 - -# Higher-level EV value for EV 18 and input 36 -set fmri(evg36.18) 1.0 - -# Higher-level EV value for EV 18 and input 37 -set fmri(evg37.18) 0 - -# Higher-level EV value for EV 18 and input 38 -set fmri(evg38.18) 0 - -# Higher-level EV value for EV 18 and input 39 -set fmri(evg39.18) 0 - -# Higher-level EV value for EV 18 and input 40 -set fmri(evg40.18) 0 - -# Higher-level EV value for EV 18 and input 41 -set fmri(evg41.18) 0 - -# Higher-level EV value for EV 18 and input 42 -set fmri(evg42.18) 0 - -# Higher-level EV value for EV 18 and input 43 -set fmri(evg43.18) 0 - -# Higher-level EV value for EV 18 and input 44 -set fmri(evg44.18) 0 - -# Higher-level EV value for EV 18 and input 45 -set fmri(evg45.18) 0 - -# Higher-level EV value for EV 18 and input 46 -set fmri(evg46.18) 0 - -# Higher-level EV value for EV 18 and input 47 -set fmri(evg47.18) 0 - -# Higher-level EV value for EV 18 and input 48 -set fmri(evg48.18) 0 - -# Higher-level EV value for EV 18 and input 49 -set fmri(evg49.18) 0 - -# Higher-level EV value for EV 18 and input 50 -set fmri(evg50.18) 0 - -# Higher-level EV value for EV 18 and input 51 -set fmri(evg51.18) 0 - -# Higher-level EV value for EV 18 and input 52 -set fmri(evg52.18) 0 - -# EV 19 title -set fmri(evtitle19) "" - -# Basic waveform shape (EV 19) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape19) 2 - -# Convolution (EV 19) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve19) 0 - -# Convolve phase (EV 19) -set fmri(convolve_phase19) 0 - -# Apply temporal filtering (EV 19) -set fmri(tempfilt_yn19) 0 - -# Add temporal derivative (EV 19) -set fmri(deriv_yn19) 0 - -# Custom EV file (EV 19) -set fmri(custom19) "dummy" - -# Orthogonalise EV 19 wrt EV 0 -set fmri(ortho19.0) 0 - -# Orthogonalise EV 19 wrt EV 1 -set fmri(ortho19.1) 0 - -# Orthogonalise EV 19 wrt EV 2 -set fmri(ortho19.2) 0 - -# Orthogonalise EV 19 wrt EV 3 -set fmri(ortho19.3) 0 - -# Orthogonalise EV 19 wrt EV 4 -set fmri(ortho19.4) 0 - -# Orthogonalise EV 19 wrt EV 5 -set fmri(ortho19.5) 0 - -# Orthogonalise EV 19 wrt EV 6 -set fmri(ortho19.6) 0 - -# Orthogonalise EV 19 wrt EV 7 -set fmri(ortho19.7) 0 - -# Orthogonalise EV 19 wrt EV 8 -set fmri(ortho19.8) 0 - -# Orthogonalise EV 19 wrt EV 9 -set fmri(ortho19.9) 0 - -# Orthogonalise EV 19 wrt EV 10 -set fmri(ortho19.10) 0 - -# Orthogonalise EV 19 wrt EV 11 -set fmri(ortho19.11) 0 - -# Orthogonalise EV 19 wrt EV 12 -set fmri(ortho19.12) 0 - -# Orthogonalise EV 19 wrt EV 13 -set fmri(ortho19.13) 0 - -# Orthogonalise EV 19 wrt EV 14 -set fmri(ortho19.14) 0 - -# Orthogonalise EV 19 wrt EV 15 -set fmri(ortho19.15) 0 - -# Orthogonalise EV 19 wrt EV 16 -set fmri(ortho19.16) 0 - -# Orthogonalise EV 19 wrt EV 17 -set fmri(ortho19.17) 0 - -# Orthogonalise EV 19 wrt EV 18 -set fmri(ortho19.18) 0 - -# Orthogonalise EV 19 wrt EV 19 -set fmri(ortho19.19) 0 - -# Orthogonalise EV 19 wrt EV 20 -set fmri(ortho19.20) 0 - -# Orthogonalise EV 19 wrt EV 21 -set fmri(ortho19.21) 0 - -# Orthogonalise EV 19 wrt EV 22 -set fmri(ortho19.22) 0 - -# Orthogonalise EV 19 wrt EV 23 -set fmri(ortho19.23) 0 - -# Orthogonalise EV 19 wrt EV 24 -set fmri(ortho19.24) 0 - -# Orthogonalise EV 19 wrt EV 25 -set fmri(ortho19.25) 0 - -# Orthogonalise EV 19 wrt EV 26 -set fmri(ortho19.26) 0 - -# Higher-level EV value for EV 19 and input 1 -set fmri(evg1.19) 0 - -# Higher-level EV value for EV 19 and input 2 -set fmri(evg2.19) 0 - -# Higher-level EV value for EV 19 and input 3 -set fmri(evg3.19) 0 - -# Higher-level EV value for EV 19 and input 4 -set fmri(evg4.19) 0 - -# Higher-level EV value for EV 19 and input 5 -set fmri(evg5.19) 0 - -# Higher-level EV value for EV 19 and input 6 -set fmri(evg6.19) 0 - -# Higher-level EV value for EV 19 and input 7 -set fmri(evg7.19) 0 - -# Higher-level EV value for EV 19 and input 8 -set fmri(evg8.19) 0 - -# Higher-level EV value for EV 19 and input 9 -set fmri(evg9.19) 0 - -# Higher-level EV value for EV 19 and input 10 -set fmri(evg10.19) 0 - -# Higher-level EV value for EV 19 and input 11 -set fmri(evg11.19) 0 - -# Higher-level EV value for EV 19 and input 12 -set fmri(evg12.19) 0 - -# Higher-level EV value for EV 19 and input 13 -set fmri(evg13.19) 0 - -# Higher-level EV value for EV 19 and input 14 -set fmri(evg14.19) 0 - -# Higher-level EV value for EV 19 and input 15 -set fmri(evg15.19) 0 - -# Higher-level EV value for EV 19 and input 16 -set fmri(evg16.19) 0 - -# Higher-level EV value for EV 19 and input 17 -set fmri(evg17.19) 0 - -# Higher-level EV value for EV 19 and input 18 -set fmri(evg18.19) 0 - -# Higher-level EV value for EV 19 and input 19 -set fmri(evg19.19) 0 - -# Higher-level EV value for EV 19 and input 20 -set fmri(evg20.19) 0 - -# Higher-level EV value for EV 19 and input 21 -set fmri(evg21.19) 0 - -# Higher-level EV value for EV 19 and input 22 -set fmri(evg22.19) 0 - -# Higher-level EV value for EV 19 and input 23 -set fmri(evg23.19) 0 - -# Higher-level EV value for EV 19 and input 24 -set fmri(evg24.19) 0 - -# Higher-level EV value for EV 19 and input 25 -set fmri(evg25.19) 0 - -# Higher-level EV value for EV 19 and input 26 -set fmri(evg26.19) 0 - -# Higher-level EV value for EV 19 and input 27 -set fmri(evg27.19) 0 - -# Higher-level EV value for EV 19 and input 28 -set fmri(evg28.19) 0 - -# Higher-level EV value for EV 19 and input 29 -set fmri(evg29.19) 0 - -# Higher-level EV value for EV 19 and input 30 -set fmri(evg30.19) 0 - -# Higher-level EV value for EV 19 and input 31 -set fmri(evg31.19) 0 - -# Higher-level EV value for EV 19 and input 32 -set fmri(evg32.19) 0 - -# Higher-level EV value for EV 19 and input 33 -set fmri(evg33.19) 0 - -# Higher-level EV value for EV 19 and input 34 -set fmri(evg34.19) 0 - -# Higher-level EV value for EV 19 and input 35 -set fmri(evg35.19) 0 - -# Higher-level EV value for EV 19 and input 36 -set fmri(evg36.19) 0 - -# Higher-level EV value for EV 19 and input 37 -set fmri(evg37.19) 1.0 - -# Higher-level EV value for EV 19 and input 38 -set fmri(evg38.19) 1.0 - -# Higher-level EV value for EV 19 and input 39 -set fmri(evg39.19) 0 - -# Higher-level EV value for EV 19 and input 40 -set fmri(evg40.19) 0 - -# Higher-level EV value for EV 19 and input 41 -set fmri(evg41.19) 0 - -# Higher-level EV value for EV 19 and input 42 -set fmri(evg42.19) 0 - -# Higher-level EV value for EV 19 and input 43 -set fmri(evg43.19) 0 - -# Higher-level EV value for EV 19 and input 44 -set fmri(evg44.19) 0 - -# Higher-level EV value for EV 19 and input 45 -set fmri(evg45.19) 0 - -# Higher-level EV value for EV 19 and input 46 -set fmri(evg46.19) 0 - -# Higher-level EV value for EV 19 and input 47 -set fmri(evg47.19) 0 - -# Higher-level EV value for EV 19 and input 48 -set fmri(evg48.19) 0 - -# Higher-level EV value for EV 19 and input 49 -set fmri(evg49.19) 0 - -# Higher-level EV value for EV 19 and input 50 -set fmri(evg50.19) 0 - -# Higher-level EV value for EV 19 and input 51 -set fmri(evg51.19) 0 - -# Higher-level EV value for EV 19 and input 52 -set fmri(evg52.19) 0 - -# EV 20 title -set fmri(evtitle20) "" - -# Basic waveform shape (EV 20) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape20) 2 - -# Convolution (EV 20) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve20) 0 - -# Convolve phase (EV 20) -set fmri(convolve_phase20) 0 - -# Apply temporal filtering (EV 20) -set fmri(tempfilt_yn20) 0 - -# Add temporal derivative (EV 20) -set fmri(deriv_yn20) 0 - -# Custom EV file (EV 20) -set fmri(custom20) "dummy" - -# Orthogonalise EV 20 wrt EV 0 -set fmri(ortho20.0) 0 - -# Orthogonalise EV 20 wrt EV 1 -set fmri(ortho20.1) 0 - -# Orthogonalise EV 20 wrt EV 2 -set fmri(ortho20.2) 0 - -# Orthogonalise EV 20 wrt EV 3 -set fmri(ortho20.3) 0 - -# Orthogonalise EV 20 wrt EV 4 -set fmri(ortho20.4) 0 - -# Orthogonalise EV 20 wrt EV 5 -set fmri(ortho20.5) 0 - -# Orthogonalise EV 20 wrt EV 6 -set fmri(ortho20.6) 0 - -# Orthogonalise EV 20 wrt EV 7 -set fmri(ortho20.7) 0 - -# Orthogonalise EV 20 wrt EV 8 -set fmri(ortho20.8) 0 - -# Orthogonalise EV 20 wrt EV 9 -set fmri(ortho20.9) 0 - -# Orthogonalise EV 20 wrt EV 10 -set fmri(ortho20.10) 0 - -# Orthogonalise EV 20 wrt EV 11 -set fmri(ortho20.11) 0 - -# Orthogonalise EV 20 wrt EV 12 -set fmri(ortho20.12) 0 - -# Orthogonalise EV 20 wrt EV 13 -set fmri(ortho20.13) 0 - -# Orthogonalise EV 20 wrt EV 14 -set fmri(ortho20.14) 0 - -# Orthogonalise EV 20 wrt EV 15 -set fmri(ortho20.15) 0 - -# Orthogonalise EV 20 wrt EV 16 -set fmri(ortho20.16) 0 - -# Orthogonalise EV 20 wrt EV 17 -set fmri(ortho20.17) 0 - -# Orthogonalise EV 20 wrt EV 18 -set fmri(ortho20.18) 0 - -# Orthogonalise EV 20 wrt EV 19 -set fmri(ortho20.19) 0 - -# Orthogonalise EV 20 wrt EV 20 -set fmri(ortho20.20) 0 - -# Orthogonalise EV 20 wrt EV 21 -set fmri(ortho20.21) 0 - -# Orthogonalise EV 20 wrt EV 22 -set fmri(ortho20.22) 0 - -# Orthogonalise EV 20 wrt EV 23 -set fmri(ortho20.23) 0 - -# Orthogonalise EV 20 wrt EV 24 -set fmri(ortho20.24) 0 - -# Orthogonalise EV 20 wrt EV 25 -set fmri(ortho20.25) 0 - -# Orthogonalise EV 20 wrt EV 26 -set fmri(ortho20.26) 0 - -# Higher-level EV value for EV 20 and input 1 -set fmri(evg1.20) 0 - -# Higher-level EV value for EV 20 and input 2 -set fmri(evg2.20) 0 - -# Higher-level EV value for EV 20 and input 3 -set fmri(evg3.20) 0 - -# Higher-level EV value for EV 20 and input 4 -set fmri(evg4.20) 0 - -# Higher-level EV value for EV 20 and input 5 -set fmri(evg5.20) 0 - -# Higher-level EV value for EV 20 and input 6 -set fmri(evg6.20) 0 - -# Higher-level EV value for EV 20 and input 7 -set fmri(evg7.20) 0 - -# Higher-level EV value for EV 20 and input 8 -set fmri(evg8.20) 0 - -# Higher-level EV value for EV 20 and input 9 -set fmri(evg9.20) 0 - -# Higher-level EV value for EV 20 and input 10 -set fmri(evg10.20) 0 - -# Higher-level EV value for EV 20 and input 11 -set fmri(evg11.20) 0 - -# Higher-level EV value for EV 20 and input 12 -set fmri(evg12.20) 0 - -# Higher-level EV value for EV 20 and input 13 -set fmri(evg13.20) 0 - -# Higher-level EV value for EV 20 and input 14 -set fmri(evg14.20) 0 - -# Higher-level EV value for EV 20 and input 15 -set fmri(evg15.20) 0 - -# Higher-level EV value for EV 20 and input 16 -set fmri(evg16.20) 0 - -# Higher-level EV value for EV 20 and input 17 -set fmri(evg17.20) 0 - -# Higher-level EV value for EV 20 and input 18 -set fmri(evg18.20) 0 - -# Higher-level EV value for EV 20 and input 19 -set fmri(evg19.20) 0 - -# Higher-level EV value for EV 20 and input 20 -set fmri(evg20.20) 0 - -# Higher-level EV value for EV 20 and input 21 -set fmri(evg21.20) 0 - -# Higher-level EV value for EV 20 and input 22 -set fmri(evg22.20) 0 - -# Higher-level EV value for EV 20 and input 23 -set fmri(evg23.20) 0 - -# Higher-level EV value for EV 20 and input 24 -set fmri(evg24.20) 0 - -# Higher-level EV value for EV 20 and input 25 -set fmri(evg25.20) 0 - -# Higher-level EV value for EV 20 and input 26 -set fmri(evg26.20) 0 - -# Higher-level EV value for EV 20 and input 27 -set fmri(evg27.20) 0 - -# Higher-level EV value for EV 20 and input 28 -set fmri(evg28.20) 0 - -# Higher-level EV value for EV 20 and input 29 -set fmri(evg29.20) 0 - -# Higher-level EV value for EV 20 and input 30 -set fmri(evg30.20) 0 - -# Higher-level EV value for EV 20 and input 31 -set fmri(evg31.20) 0 - -# Higher-level EV value for EV 20 and input 32 -set fmri(evg32.20) 0 - -# Higher-level EV value for EV 20 and input 33 -set fmri(evg33.20) 0 - -# Higher-level EV value for EV 20 and input 34 -set fmri(evg34.20) 0 - -# Higher-level EV value for EV 20 and input 35 -set fmri(evg35.20) 0 - -# Higher-level EV value for EV 20 and input 36 -set fmri(evg36.20) 0 - -# Higher-level EV value for EV 20 and input 37 -set fmri(evg37.20) 0 - -# Higher-level EV value for EV 20 and input 38 -set fmri(evg38.20) 0 - -# Higher-level EV value for EV 20 and input 39 -set fmri(evg39.20) 1.0 - -# Higher-level EV value for EV 20 and input 40 -set fmri(evg40.20) 1.0 - -# Higher-level EV value for EV 20 and input 41 -set fmri(evg41.20) 0 - -# Higher-level EV value for EV 20 and input 42 -set fmri(evg42.20) 0 - -# Higher-level EV value for EV 20 and input 43 -set fmri(evg43.20) 0 - -# Higher-level EV value for EV 20 and input 44 -set fmri(evg44.20) 0 - -# Higher-level EV value for EV 20 and input 45 -set fmri(evg45.20) 0 - -# Higher-level EV value for EV 20 and input 46 -set fmri(evg46.20) 0 - -# Higher-level EV value for EV 20 and input 47 -set fmri(evg47.20) 0 - -# Higher-level EV value for EV 20 and input 48 -set fmri(evg48.20) 0 - -# Higher-level EV value for EV 20 and input 49 -set fmri(evg49.20) 0 - -# Higher-level EV value for EV 20 and input 50 -set fmri(evg50.20) 0 - -# Higher-level EV value for EV 20 and input 51 -set fmri(evg51.20) 0 - -# Higher-level EV value for EV 20 and input 52 -set fmri(evg52.20) 0 - -# EV 21 title -set fmri(evtitle21) "" - -# Basic waveform shape (EV 21) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape21) 2 - -# Convolution (EV 21) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve21) 0 - -# Convolve phase (EV 21) -set fmri(convolve_phase21) 0 - -# Apply temporal filtering (EV 21) -set fmri(tempfilt_yn21) 0 - -# Add temporal derivative (EV 21) -set fmri(deriv_yn21) 0 - -# Custom EV file (EV 21) -set fmri(custom21) "dummy" - -# Orthogonalise EV 21 wrt EV 0 -set fmri(ortho21.0) 0 - -# Orthogonalise EV 21 wrt EV 1 -set fmri(ortho21.1) 0 - -# Orthogonalise EV 21 wrt EV 2 -set fmri(ortho21.2) 0 - -# Orthogonalise EV 21 wrt EV 3 -set fmri(ortho21.3) 0 - -# Orthogonalise EV 21 wrt EV 4 -set fmri(ortho21.4) 0 - -# Orthogonalise EV 21 wrt EV 5 -set fmri(ortho21.5) 0 - -# Orthogonalise EV 21 wrt EV 6 -set fmri(ortho21.6) 0 - -# Orthogonalise EV 21 wrt EV 7 -set fmri(ortho21.7) 0 - -# Orthogonalise EV 21 wrt EV 8 -set fmri(ortho21.8) 0 - -# Orthogonalise EV 21 wrt EV 9 -set fmri(ortho21.9) 0 - -# Orthogonalise EV 21 wrt EV 10 -set fmri(ortho21.10) 0 - -# Orthogonalise EV 21 wrt EV 11 -set fmri(ortho21.11) 0 - -# Orthogonalise EV 21 wrt EV 12 -set fmri(ortho21.12) 0 - -# Orthogonalise EV 21 wrt EV 13 -set fmri(ortho21.13) 0 - -# Orthogonalise EV 21 wrt EV 14 -set fmri(ortho21.14) 0 - -# Orthogonalise EV 21 wrt EV 15 -set fmri(ortho21.15) 0 - -# Orthogonalise EV 21 wrt EV 16 -set fmri(ortho21.16) 0 - -# Orthogonalise EV 21 wrt EV 17 -set fmri(ortho21.17) 0 - -# Orthogonalise EV 21 wrt EV 18 -set fmri(ortho21.18) 0 - -# Orthogonalise EV 21 wrt EV 19 -set fmri(ortho21.19) 0 - -# Orthogonalise EV 21 wrt EV 20 -set fmri(ortho21.20) 0 - -# Orthogonalise EV 21 wrt EV 21 -set fmri(ortho21.21) 0 - -# Orthogonalise EV 21 wrt EV 22 -set fmri(ortho21.22) 0 - -# Orthogonalise EV 21 wrt EV 23 -set fmri(ortho21.23) 0 - -# Orthogonalise EV 21 wrt EV 24 -set fmri(ortho21.24) 0 - -# Orthogonalise EV 21 wrt EV 25 -set fmri(ortho21.25) 0 - -# Orthogonalise EV 21 wrt EV 26 -set fmri(ortho21.26) 0 - -# Higher-level EV value for EV 21 and input 1 -set fmri(evg1.21) 0 - -# Higher-level EV value for EV 21 and input 2 -set fmri(evg2.21) 0 - -# Higher-level EV value for EV 21 and input 3 -set fmri(evg3.21) 0 - -# Higher-level EV value for EV 21 and input 4 -set fmri(evg4.21) 0 - -# Higher-level EV value for EV 21 and input 5 -set fmri(evg5.21) 0 - -# Higher-level EV value for EV 21 and input 6 -set fmri(evg6.21) 0 - -# Higher-level EV value for EV 21 and input 7 -set fmri(evg7.21) 0 - -# Higher-level EV value for EV 21 and input 8 -set fmri(evg8.21) 0 - -# Higher-level EV value for EV 21 and input 9 -set fmri(evg9.21) 0 - -# Higher-level EV value for EV 21 and input 10 -set fmri(evg10.21) 0 - -# Higher-level EV value for EV 21 and input 11 -set fmri(evg11.21) 0 - -# Higher-level EV value for EV 21 and input 12 -set fmri(evg12.21) 0 - -# Higher-level EV value for EV 21 and input 13 -set fmri(evg13.21) 0 - -# Higher-level EV value for EV 21 and input 14 -set fmri(evg14.21) 0 - -# Higher-level EV value for EV 21 and input 15 -set fmri(evg15.21) 0 - -# Higher-level EV value for EV 21 and input 16 -set fmri(evg16.21) 0 - -# Higher-level EV value for EV 21 and input 17 -set fmri(evg17.21) 0 - -# Higher-level EV value for EV 21 and input 18 -set fmri(evg18.21) 0 - -# Higher-level EV value for EV 21 and input 19 -set fmri(evg19.21) 0 - -# Higher-level EV value for EV 21 and input 20 -set fmri(evg20.21) 0 - -# Higher-level EV value for EV 21 and input 21 -set fmri(evg21.21) 0 - -# Higher-level EV value for EV 21 and input 22 -set fmri(evg22.21) 0 - -# Higher-level EV value for EV 21 and input 23 -set fmri(evg23.21) 0 - -# Higher-level EV value for EV 21 and input 24 -set fmri(evg24.21) 0 - -# Higher-level EV value for EV 21 and input 25 -set fmri(evg25.21) 0 - -# Higher-level EV value for EV 21 and input 26 -set fmri(evg26.21) 0 - -# Higher-level EV value for EV 21 and input 27 -set fmri(evg27.21) 0 - -# Higher-level EV value for EV 21 and input 28 -set fmri(evg28.21) 0 - -# Higher-level EV value for EV 21 and input 29 -set fmri(evg29.21) 0 - -# Higher-level EV value for EV 21 and input 30 -set fmri(evg30.21) 0 - -# Higher-level EV value for EV 21 and input 31 -set fmri(evg31.21) 0 - -# Higher-level EV value for EV 21 and input 32 -set fmri(evg32.21) 0 - -# Higher-level EV value for EV 21 and input 33 -set fmri(evg33.21) 0 - -# Higher-level EV value for EV 21 and input 34 -set fmri(evg34.21) 0 - -# Higher-level EV value for EV 21 and input 35 -set fmri(evg35.21) 0 - -# Higher-level EV value for EV 21 and input 36 -set fmri(evg36.21) 0 - -# Higher-level EV value for EV 21 and input 37 -set fmri(evg37.21) 0 - -# Higher-level EV value for EV 21 and input 38 -set fmri(evg38.21) 0 - -# Higher-level EV value for EV 21 and input 39 -set fmri(evg39.21) 0 - -# Higher-level EV value for EV 21 and input 40 -set fmri(evg40.21) 0 - -# Higher-level EV value for EV 21 and input 41 -set fmri(evg41.21) 1.0 - -# Higher-level EV value for EV 21 and input 42 -set fmri(evg42.21) 1.0 - -# Higher-level EV value for EV 21 and input 43 -set fmri(evg43.21) 0 - -# Higher-level EV value for EV 21 and input 44 -set fmri(evg44.21) 0 - -# Higher-level EV value for EV 21 and input 45 -set fmri(evg45.21) 0 - -# Higher-level EV value for EV 21 and input 46 -set fmri(evg46.21) 0 - -# Higher-level EV value for EV 21 and input 47 -set fmri(evg47.21) 0 - -# Higher-level EV value for EV 21 and input 48 -set fmri(evg48.21) 0 - -# Higher-level EV value for EV 21 and input 49 -set fmri(evg49.21) 0 - -# Higher-level EV value for EV 21 and input 50 -set fmri(evg50.21) 0 - -# Higher-level EV value for EV 21 and input 51 -set fmri(evg51.21) 0 - -# Higher-level EV value for EV 21 and input 52 -set fmri(evg52.21) 0 - -# EV 22 title -set fmri(evtitle22) "" - -# Basic waveform shape (EV 22) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape22) 2 - -# Convolution (EV 22) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve22) 0 - -# Convolve phase (EV 22) -set fmri(convolve_phase22) 0 - -# Apply temporal filtering (EV 22) -set fmri(tempfilt_yn22) 0 - -# Add temporal derivative (EV 22) -set fmri(deriv_yn22) 0 - -# Custom EV file (EV 22) -set fmri(custom22) "dummy" - -# Orthogonalise EV 22 wrt EV 0 -set fmri(ortho22.0) 0 - -# Orthogonalise EV 22 wrt EV 1 -set fmri(ortho22.1) 0 - -# Orthogonalise EV 22 wrt EV 2 -set fmri(ortho22.2) 0 - -# Orthogonalise EV 22 wrt EV 3 -set fmri(ortho22.3) 0 - -# Orthogonalise EV 22 wrt EV 4 -set fmri(ortho22.4) 0 - -# Orthogonalise EV 22 wrt EV 5 -set fmri(ortho22.5) 0 - -# Orthogonalise EV 22 wrt EV 6 -set fmri(ortho22.6) 0 - -# Orthogonalise EV 22 wrt EV 7 -set fmri(ortho22.7) 0 - -# Orthogonalise EV 22 wrt EV 8 -set fmri(ortho22.8) 0 - -# Orthogonalise EV 22 wrt EV 9 -set fmri(ortho22.9) 0 - -# Orthogonalise EV 22 wrt EV 10 -set fmri(ortho22.10) 0 - -# Orthogonalise EV 22 wrt EV 11 -set fmri(ortho22.11) 0 - -# Orthogonalise EV 22 wrt EV 12 -set fmri(ortho22.12) 0 - -# Orthogonalise EV 22 wrt EV 13 -set fmri(ortho22.13) 0 - -# Orthogonalise EV 22 wrt EV 14 -set fmri(ortho22.14) 0 - -# Orthogonalise EV 22 wrt EV 15 -set fmri(ortho22.15) 0 - -# Orthogonalise EV 22 wrt EV 16 -set fmri(ortho22.16) 0 - -# Orthogonalise EV 22 wrt EV 17 -set fmri(ortho22.17) 0 - -# Orthogonalise EV 22 wrt EV 18 -set fmri(ortho22.18) 0 - -# Orthogonalise EV 22 wrt EV 19 -set fmri(ortho22.19) 0 - -# Orthogonalise EV 22 wrt EV 20 -set fmri(ortho22.20) 0 - -# Orthogonalise EV 22 wrt EV 21 -set fmri(ortho22.21) 0 - -# Orthogonalise EV 22 wrt EV 22 -set fmri(ortho22.22) 0 - -# Orthogonalise EV 22 wrt EV 23 -set fmri(ortho22.23) 0 - -# Orthogonalise EV 22 wrt EV 24 -set fmri(ortho22.24) 0 - -# Orthogonalise EV 22 wrt EV 25 -set fmri(ortho22.25) 0 - -# Orthogonalise EV 22 wrt EV 26 -set fmri(ortho22.26) 0 - -# Higher-level EV value for EV 22 and input 1 -set fmri(evg1.22) 0 - -# Higher-level EV value for EV 22 and input 2 -set fmri(evg2.22) 0 - -# Higher-level EV value for EV 22 and input 3 -set fmri(evg3.22) 0 - -# Higher-level EV value for EV 22 and input 4 -set fmri(evg4.22) 0 - -# Higher-level EV value for EV 22 and input 5 -set fmri(evg5.22) 0 - -# Higher-level EV value for EV 22 and input 6 -set fmri(evg6.22) 0 - -# Higher-level EV value for EV 22 and input 7 -set fmri(evg7.22) 0 - -# Higher-level EV value for EV 22 and input 8 -set fmri(evg8.22) 0 - -# Higher-level EV value for EV 22 and input 9 -set fmri(evg9.22) 0 - -# Higher-level EV value for EV 22 and input 10 -set fmri(evg10.22) 0 - -# Higher-level EV value for EV 22 and input 11 -set fmri(evg11.22) 0 - -# Higher-level EV value for EV 22 and input 12 -set fmri(evg12.22) 0 - -# Higher-level EV value for EV 22 and input 13 -set fmri(evg13.22) 0 - -# Higher-level EV value for EV 22 and input 14 -set fmri(evg14.22) 0 - -# Higher-level EV value for EV 22 and input 15 -set fmri(evg15.22) 0 - -# Higher-level EV value for EV 22 and input 16 -set fmri(evg16.22) 0 - -# Higher-level EV value for EV 22 and input 17 -set fmri(evg17.22) 0 - -# Higher-level EV value for EV 22 and input 18 -set fmri(evg18.22) 0 - -# Higher-level EV value for EV 22 and input 19 -set fmri(evg19.22) 0 - -# Higher-level EV value for EV 22 and input 20 -set fmri(evg20.22) 0 - -# Higher-level EV value for EV 22 and input 21 -set fmri(evg21.22) 0 - -# Higher-level EV value for EV 22 and input 22 -set fmri(evg22.22) 0 - -# Higher-level EV value for EV 22 and input 23 -set fmri(evg23.22) 0 - -# Higher-level EV value for EV 22 and input 24 -set fmri(evg24.22) 0 - -# Higher-level EV value for EV 22 and input 25 -set fmri(evg25.22) 0 - -# Higher-level EV value for EV 22 and input 26 -set fmri(evg26.22) 0 - -# Higher-level EV value for EV 22 and input 27 -set fmri(evg27.22) 0 - -# Higher-level EV value for EV 22 and input 28 -set fmri(evg28.22) 0 - -# Higher-level EV value for EV 22 and input 29 -set fmri(evg29.22) 0 - -# Higher-level EV value for EV 22 and input 30 -set fmri(evg30.22) 0 - -# Higher-level EV value for EV 22 and input 31 -set fmri(evg31.22) 0 - -# Higher-level EV value for EV 22 and input 32 -set fmri(evg32.22) 0 - -# Higher-level EV value for EV 22 and input 33 -set fmri(evg33.22) 0 - -# Higher-level EV value for EV 22 and input 34 -set fmri(evg34.22) 0 - -# Higher-level EV value for EV 22 and input 35 -set fmri(evg35.22) 0 - -# Higher-level EV value for EV 22 and input 36 -set fmri(evg36.22) 0 - -# Higher-level EV value for EV 22 and input 37 -set fmri(evg37.22) 0 - -# Higher-level EV value for EV 22 and input 38 -set fmri(evg38.22) 0 - -# Higher-level EV value for EV 22 and input 39 -set fmri(evg39.22) 0 - -# Higher-level EV value for EV 22 and input 40 -set fmri(evg40.22) 0 - -# Higher-level EV value for EV 22 and input 41 -set fmri(evg41.22) 0 - -# Higher-level EV value for EV 22 and input 42 -set fmri(evg42.22) 0 - -# Higher-level EV value for EV 22 and input 43 -set fmri(evg43.22) 1.0 - -# Higher-level EV value for EV 22 and input 44 -set fmri(evg44.22) 1.0 - -# Higher-level EV value for EV 22 and input 45 -set fmri(evg45.22) 0 - -# Higher-level EV value for EV 22 and input 46 -set fmri(evg46.22) 0 - -# Higher-level EV value for EV 22 and input 47 -set fmri(evg47.22) 0 - -# Higher-level EV value for EV 22 and input 48 -set fmri(evg48.22) 0 - -# Higher-level EV value for EV 22 and input 49 -set fmri(evg49.22) 0 - -# Higher-level EV value for EV 22 and input 50 -set fmri(evg50.22) 0 - -# Higher-level EV value for EV 22 and input 51 -set fmri(evg51.22) 0 - -# Higher-level EV value for EV 22 and input 52 -set fmri(evg52.22) 0 - -# EV 23 title -set fmri(evtitle23) "" - -# Basic waveform shape (EV 23) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape23) 2 - -# Convolution (EV 23) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve23) 0 - -# Convolve phase (EV 23) -set fmri(convolve_phase23) 0 - -# Apply temporal filtering (EV 23) -set fmri(tempfilt_yn23) 0 - -# Add temporal derivative (EV 23) -set fmri(deriv_yn23) 0 - -# Custom EV file (EV 23) -set fmri(custom23) "dummy" - -# Orthogonalise EV 23 wrt EV 0 -set fmri(ortho23.0) 0 - -# Orthogonalise EV 23 wrt EV 1 -set fmri(ortho23.1) 0 - -# Orthogonalise EV 23 wrt EV 2 -set fmri(ortho23.2) 0 - -# Orthogonalise EV 23 wrt EV 3 -set fmri(ortho23.3) 0 - -# Orthogonalise EV 23 wrt EV 4 -set fmri(ortho23.4) 0 - -# Orthogonalise EV 23 wrt EV 5 -set fmri(ortho23.5) 0 - -# Orthogonalise EV 23 wrt EV 6 -set fmri(ortho23.6) 0 - -# Orthogonalise EV 23 wrt EV 7 -set fmri(ortho23.7) 0 - -# Orthogonalise EV 23 wrt EV 8 -set fmri(ortho23.8) 0 - -# Orthogonalise EV 23 wrt EV 9 -set fmri(ortho23.9) 0 - -# Orthogonalise EV 23 wrt EV 10 -set fmri(ortho23.10) 0 - -# Orthogonalise EV 23 wrt EV 11 -set fmri(ortho23.11) 0 - -# Orthogonalise EV 23 wrt EV 12 -set fmri(ortho23.12) 0 - -# Orthogonalise EV 23 wrt EV 13 -set fmri(ortho23.13) 0 - -# Orthogonalise EV 23 wrt EV 14 -set fmri(ortho23.14) 0 - -# Orthogonalise EV 23 wrt EV 15 -set fmri(ortho23.15) 0 - -# Orthogonalise EV 23 wrt EV 16 -set fmri(ortho23.16) 0 - -# Orthogonalise EV 23 wrt EV 17 -set fmri(ortho23.17) 0 - -# Orthogonalise EV 23 wrt EV 18 -set fmri(ortho23.18) 0 - -# Orthogonalise EV 23 wrt EV 19 -set fmri(ortho23.19) 0 - -# Orthogonalise EV 23 wrt EV 20 -set fmri(ortho23.20) 0 - -# Orthogonalise EV 23 wrt EV 21 -set fmri(ortho23.21) 0 - -# Orthogonalise EV 23 wrt EV 22 -set fmri(ortho23.22) 0 - -# Orthogonalise EV 23 wrt EV 23 -set fmri(ortho23.23) 0 - -# Orthogonalise EV 23 wrt EV 24 -set fmri(ortho23.24) 0 - -# Orthogonalise EV 23 wrt EV 25 -set fmri(ortho23.25) 0 - -# Orthogonalise EV 23 wrt EV 26 -set fmri(ortho23.26) 0 - -# Higher-level EV value for EV 23 and input 1 -set fmri(evg1.23) 0 - -# Higher-level EV value for EV 23 and input 2 -set fmri(evg2.23) 0 - -# Higher-level EV value for EV 23 and input 3 -set fmri(evg3.23) 0 - -# Higher-level EV value for EV 23 and input 4 -set fmri(evg4.23) 0 - -# Higher-level EV value for EV 23 and input 5 -set fmri(evg5.23) 0 - -# Higher-level EV value for EV 23 and input 6 -set fmri(evg6.23) 0 - -# Higher-level EV value for EV 23 and input 7 -set fmri(evg7.23) 0 - -# Higher-level EV value for EV 23 and input 8 -set fmri(evg8.23) 0 - -# Higher-level EV value for EV 23 and input 9 -set fmri(evg9.23) 0 - -# Higher-level EV value for EV 23 and input 10 -set fmri(evg10.23) 0 - -# Higher-level EV value for EV 23 and input 11 -set fmri(evg11.23) 0 - -# Higher-level EV value for EV 23 and input 12 -set fmri(evg12.23) 0 - -# Higher-level EV value for EV 23 and input 13 -set fmri(evg13.23) 0 - -# Higher-level EV value for EV 23 and input 14 -set fmri(evg14.23) 0 - -# Higher-level EV value for EV 23 and input 15 -set fmri(evg15.23) 0 - -# Higher-level EV value for EV 23 and input 16 -set fmri(evg16.23) 0 - -# Higher-level EV value for EV 23 and input 17 -set fmri(evg17.23) 0 - -# Higher-level EV value for EV 23 and input 18 -set fmri(evg18.23) 0 - -# Higher-level EV value for EV 23 and input 19 -set fmri(evg19.23) 0 - -# Higher-level EV value for EV 23 and input 20 -set fmri(evg20.23) 0 - -# Higher-level EV value for EV 23 and input 21 -set fmri(evg21.23) 0 - -# Higher-level EV value for EV 23 and input 22 -set fmri(evg22.23) 0 - -# Higher-level EV value for EV 23 and input 23 -set fmri(evg23.23) 0 - -# Higher-level EV value for EV 23 and input 24 -set fmri(evg24.23) 0 - -# Higher-level EV value for EV 23 and input 25 -set fmri(evg25.23) 0 - -# Higher-level EV value for EV 23 and input 26 -set fmri(evg26.23) 0 - -# Higher-level EV value for EV 23 and input 27 -set fmri(evg27.23) 0 - -# Higher-level EV value for EV 23 and input 28 -set fmri(evg28.23) 0 - -# Higher-level EV value for EV 23 and input 29 -set fmri(evg29.23) 0 - -# Higher-level EV value for EV 23 and input 30 -set fmri(evg30.23) 0 - -# Higher-level EV value for EV 23 and input 31 -set fmri(evg31.23) 0 - -# Higher-level EV value for EV 23 and input 32 -set fmri(evg32.23) 0 - -# Higher-level EV value for EV 23 and input 33 -set fmri(evg33.23) 0 - -# Higher-level EV value for EV 23 and input 34 -set fmri(evg34.23) 0 - -# Higher-level EV value for EV 23 and input 35 -set fmri(evg35.23) 0 - -# Higher-level EV value for EV 23 and input 36 -set fmri(evg36.23) 0 - -# Higher-level EV value for EV 23 and input 37 -set fmri(evg37.23) 0 - -# Higher-level EV value for EV 23 and input 38 -set fmri(evg38.23) 0 - -# Higher-level EV value for EV 23 and input 39 -set fmri(evg39.23) 0 - -# Higher-level EV value for EV 23 and input 40 -set fmri(evg40.23) 0 - -# Higher-level EV value for EV 23 and input 41 -set fmri(evg41.23) 0 - -# Higher-level EV value for EV 23 and input 42 -set fmri(evg42.23) 0 - -# Higher-level EV value for EV 23 and input 43 -set fmri(evg43.23) 0 - -# Higher-level EV value for EV 23 and input 44 -set fmri(evg44.23) 0 - -# Higher-level EV value for EV 23 and input 45 -set fmri(evg45.23) 1.0 - -# Higher-level EV value for EV 23 and input 46 -set fmri(evg46.23) 1.0 - -# Higher-level EV value for EV 23 and input 47 -set fmri(evg47.23) 0 - -# Higher-level EV value for EV 23 and input 48 -set fmri(evg48.23) 0 - -# Higher-level EV value for EV 23 and input 49 -set fmri(evg49.23) 0 - -# Higher-level EV value for EV 23 and input 50 -set fmri(evg50.23) 0 - -# Higher-level EV value for EV 23 and input 51 -set fmri(evg51.23) 0 - -# Higher-level EV value for EV 23 and input 52 -set fmri(evg52.23) 0 - -# EV 24 title -set fmri(evtitle24) "" - -# Basic waveform shape (EV 24) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape24) 2 - -# Convolution (EV 24) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve24) 0 - -# Convolve phase (EV 24) -set fmri(convolve_phase24) 0 - -# Apply temporal filtering (EV 24) -set fmri(tempfilt_yn24) 0 - -# Add temporal derivative (EV 24) -set fmri(deriv_yn24) 0 - -# Custom EV file (EV 24) -set fmri(custom24) "dummy" - -# Orthogonalise EV 24 wrt EV 0 -set fmri(ortho24.0) 0 - -# Orthogonalise EV 24 wrt EV 1 -set fmri(ortho24.1) 0 - -# Orthogonalise EV 24 wrt EV 2 -set fmri(ortho24.2) 0 - -# Orthogonalise EV 24 wrt EV 3 -set fmri(ortho24.3) 0 - -# Orthogonalise EV 24 wrt EV 4 -set fmri(ortho24.4) 0 - -# Orthogonalise EV 24 wrt EV 5 -set fmri(ortho24.5) 0 - -# Orthogonalise EV 24 wrt EV 6 -set fmri(ortho24.6) 0 - -# Orthogonalise EV 24 wrt EV 7 -set fmri(ortho24.7) 0 - -# Orthogonalise EV 24 wrt EV 8 -set fmri(ortho24.8) 0 - -# Orthogonalise EV 24 wrt EV 9 -set fmri(ortho24.9) 0 - -# Orthogonalise EV 24 wrt EV 10 -set fmri(ortho24.10) 0 - -# Orthogonalise EV 24 wrt EV 11 -set fmri(ortho24.11) 0 - -# Orthogonalise EV 24 wrt EV 12 -set fmri(ortho24.12) 0 - -# Orthogonalise EV 24 wrt EV 13 -set fmri(ortho24.13) 0 - -# Orthogonalise EV 24 wrt EV 14 -set fmri(ortho24.14) 0 - -# Orthogonalise EV 24 wrt EV 15 -set fmri(ortho24.15) 0 - -# Orthogonalise EV 24 wrt EV 16 -set fmri(ortho24.16) 0 - -# Orthogonalise EV 24 wrt EV 17 -set fmri(ortho24.17) 0 - -# Orthogonalise EV 24 wrt EV 18 -set fmri(ortho24.18) 0 - -# Orthogonalise EV 24 wrt EV 19 -set fmri(ortho24.19) 0 - -# Orthogonalise EV 24 wrt EV 20 -set fmri(ortho24.20) 0 - -# Orthogonalise EV 24 wrt EV 21 -set fmri(ortho24.21) 0 - -# Orthogonalise EV 24 wrt EV 22 -set fmri(ortho24.22) 0 - -# Orthogonalise EV 24 wrt EV 23 -set fmri(ortho24.23) 0 - -# Orthogonalise EV 24 wrt EV 24 -set fmri(ortho24.24) 0 - -# Orthogonalise EV 24 wrt EV 25 -set fmri(ortho24.25) 0 - -# Orthogonalise EV 24 wrt EV 26 -set fmri(ortho24.26) 0 - -# Higher-level EV value for EV 24 and input 1 -set fmri(evg1.24) 0 - -# Higher-level EV value for EV 24 and input 2 -set fmri(evg2.24) 0 - -# Higher-level EV value for EV 24 and input 3 -set fmri(evg3.24) 0 - -# Higher-level EV value for EV 24 and input 4 -set fmri(evg4.24) 0 - -# Higher-level EV value for EV 24 and input 5 -set fmri(evg5.24) 0 - -# Higher-level EV value for EV 24 and input 6 -set fmri(evg6.24) 0 - -# Higher-level EV value for EV 24 and input 7 -set fmri(evg7.24) 0 - -# Higher-level EV value for EV 24 and input 8 -set fmri(evg8.24) 0 - -# Higher-level EV value for EV 24 and input 9 -set fmri(evg9.24) 0 - -# Higher-level EV value for EV 24 and input 10 -set fmri(evg10.24) 0 - -# Higher-level EV value for EV 24 and input 11 -set fmri(evg11.24) 0 - -# Higher-level EV value for EV 24 and input 12 -set fmri(evg12.24) 0 - -# Higher-level EV value for EV 24 and input 13 -set fmri(evg13.24) 0 - -# Higher-level EV value for EV 24 and input 14 -set fmri(evg14.24) 0 - -# Higher-level EV value for EV 24 and input 15 -set fmri(evg15.24) 0 - -# Higher-level EV value for EV 24 and input 16 -set fmri(evg16.24) 0 - -# Higher-level EV value for EV 24 and input 17 -set fmri(evg17.24) 0 - -# Higher-level EV value for EV 24 and input 18 -set fmri(evg18.24) 0 - -# Higher-level EV value for EV 24 and input 19 -set fmri(evg19.24) 0 - -# Higher-level EV value for EV 24 and input 20 -set fmri(evg20.24) 0 - -# Higher-level EV value for EV 24 and input 21 -set fmri(evg21.24) 0 - -# Higher-level EV value for EV 24 and input 22 -set fmri(evg22.24) 0 - -# Higher-level EV value for EV 24 and input 23 -set fmri(evg23.24) 0 - -# Higher-level EV value for EV 24 and input 24 -set fmri(evg24.24) 0 - -# Higher-level EV value for EV 24 and input 25 -set fmri(evg25.24) 0 - -# Higher-level EV value for EV 24 and input 26 -set fmri(evg26.24) 0 - -# Higher-level EV value for EV 24 and input 27 -set fmri(evg27.24) 0 - -# Higher-level EV value for EV 24 and input 28 -set fmri(evg28.24) 0 - -# Higher-level EV value for EV 24 and input 29 -set fmri(evg29.24) 0 - -# Higher-level EV value for EV 24 and input 30 -set fmri(evg30.24) 0 - -# Higher-level EV value for EV 24 and input 31 -set fmri(evg31.24) 0 - -# Higher-level EV value for EV 24 and input 32 -set fmri(evg32.24) 0 - -# Higher-level EV value for EV 24 and input 33 -set fmri(evg33.24) 0 - -# Higher-level EV value for EV 24 and input 34 -set fmri(evg34.24) 0 - -# Higher-level EV value for EV 24 and input 35 -set fmri(evg35.24) 0 - -# Higher-level EV value for EV 24 and input 36 -set fmri(evg36.24) 0 - -# Higher-level EV value for EV 24 and input 37 -set fmri(evg37.24) 0 - -# Higher-level EV value for EV 24 and input 38 -set fmri(evg38.24) 0 - -# Higher-level EV value for EV 24 and input 39 -set fmri(evg39.24) 0 - -# Higher-level EV value for EV 24 and input 40 -set fmri(evg40.24) 0 - -# Higher-level EV value for EV 24 and input 41 -set fmri(evg41.24) 0 - -# Higher-level EV value for EV 24 and input 42 -set fmri(evg42.24) 0 - -# Higher-level EV value for EV 24 and input 43 -set fmri(evg43.24) 0 - -# Higher-level EV value for EV 24 and input 44 -set fmri(evg44.24) 0 - -# Higher-level EV value for EV 24 and input 45 -set fmri(evg45.24) 0 - -# Higher-level EV value for EV 24 and input 46 -set fmri(evg46.24) 0 - -# Higher-level EV value for EV 24 and input 47 -set fmri(evg47.24) 1.0 - -# Higher-level EV value for EV 24 and input 48 -set fmri(evg48.24) 1.0 - -# Higher-level EV value for EV 24 and input 49 -set fmri(evg49.24) 0 - -# Higher-level EV value for EV 24 and input 50 -set fmri(evg50.24) 0 - -# Higher-level EV value for EV 24 and input 51 -set fmri(evg51.24) 0 - -# Higher-level EV value for EV 24 and input 52 -set fmri(evg52.24) 0 - -# EV 25 title -set fmri(evtitle25) "" - -# Basic waveform shape (EV 25) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape25) 2 - -# Convolution (EV 25) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve25) 0 - -# Convolve phase (EV 25) -set fmri(convolve_phase25) 0 - -# Apply temporal filtering (EV 25) -set fmri(tempfilt_yn25) 0 - -# Add temporal derivative (EV 25) -set fmri(deriv_yn25) 0 - -# Custom EV file (EV 25) -set fmri(custom25) "dummy" - -# Orthogonalise EV 25 wrt EV 0 -set fmri(ortho25.0) 0 - -# Orthogonalise EV 25 wrt EV 1 -set fmri(ortho25.1) 0 - -# Orthogonalise EV 25 wrt EV 2 -set fmri(ortho25.2) 0 - -# Orthogonalise EV 25 wrt EV 3 -set fmri(ortho25.3) 0 - -# Orthogonalise EV 25 wrt EV 4 -set fmri(ortho25.4) 0 - -# Orthogonalise EV 25 wrt EV 5 -set fmri(ortho25.5) 0 - -# Orthogonalise EV 25 wrt EV 6 -set fmri(ortho25.6) 0 - -# Orthogonalise EV 25 wrt EV 7 -set fmri(ortho25.7) 0 - -# Orthogonalise EV 25 wrt EV 8 -set fmri(ortho25.8) 0 - -# Orthogonalise EV 25 wrt EV 9 -set fmri(ortho25.9) 0 - -# Orthogonalise EV 25 wrt EV 10 -set fmri(ortho25.10) 0 - -# Orthogonalise EV 25 wrt EV 11 -set fmri(ortho25.11) 0 - -# Orthogonalise EV 25 wrt EV 12 -set fmri(ortho25.12) 0 - -# Orthogonalise EV 25 wrt EV 13 -set fmri(ortho25.13) 0 - -# Orthogonalise EV 25 wrt EV 14 -set fmri(ortho25.14) 0 - -# Orthogonalise EV 25 wrt EV 15 -set fmri(ortho25.15) 0 - -# Orthogonalise EV 25 wrt EV 16 -set fmri(ortho25.16) 0 - -# Orthogonalise EV 25 wrt EV 17 -set fmri(ortho25.17) 0 - -# Orthogonalise EV 25 wrt EV 18 -set fmri(ortho25.18) 0 - -# Orthogonalise EV 25 wrt EV 19 -set fmri(ortho25.19) 0 - -# Orthogonalise EV 25 wrt EV 20 -set fmri(ortho25.20) 0 - -# Orthogonalise EV 25 wrt EV 21 -set fmri(ortho25.21) 0 - -# Orthogonalise EV 25 wrt EV 22 -set fmri(ortho25.22) 0 - -# Orthogonalise EV 25 wrt EV 23 -set fmri(ortho25.23) 0 - -# Orthogonalise EV 25 wrt EV 24 -set fmri(ortho25.24) 0 - -# Orthogonalise EV 25 wrt EV 25 -set fmri(ortho25.25) 0 - -# Orthogonalise EV 25 wrt EV 26 -set fmri(ortho25.26) 0 - -# Higher-level EV value for EV 25 and input 1 -set fmri(evg1.25) 0 - -# Higher-level EV value for EV 25 and input 2 -set fmri(evg2.25) 0 - -# Higher-level EV value for EV 25 and input 3 -set fmri(evg3.25) 0 - -# Higher-level EV value for EV 25 and input 4 -set fmri(evg4.25) 0 - -# Higher-level EV value for EV 25 and input 5 -set fmri(evg5.25) 0 - -# Higher-level EV value for EV 25 and input 6 -set fmri(evg6.25) 0 - -# Higher-level EV value for EV 25 and input 7 -set fmri(evg7.25) 0 - -# Higher-level EV value for EV 25 and input 8 -set fmri(evg8.25) 0 - -# Higher-level EV value for EV 25 and input 9 -set fmri(evg9.25) 0 - -# Higher-level EV value for EV 25 and input 10 -set fmri(evg10.25) 0 - -# Higher-level EV value for EV 25 and input 11 -set fmri(evg11.25) 0 - -# Higher-level EV value for EV 25 and input 12 -set fmri(evg12.25) 0 - -# Higher-level EV value for EV 25 and input 13 -set fmri(evg13.25) 0 - -# Higher-level EV value for EV 25 and input 14 -set fmri(evg14.25) 0 - -# Higher-level EV value for EV 25 and input 15 -set fmri(evg15.25) 0 - -# Higher-level EV value for EV 25 and input 16 -set fmri(evg16.25) 0 - -# Higher-level EV value for EV 25 and input 17 -set fmri(evg17.25) 0 - -# Higher-level EV value for EV 25 and input 18 -set fmri(evg18.25) 0 - -# Higher-level EV value for EV 25 and input 19 -set fmri(evg19.25) 0 - -# Higher-level EV value for EV 25 and input 20 -set fmri(evg20.25) 0 - -# Higher-level EV value for EV 25 and input 21 -set fmri(evg21.25) 0 - -# Higher-level EV value for EV 25 and input 22 -set fmri(evg22.25) 0 - -# Higher-level EV value for EV 25 and input 23 -set fmri(evg23.25) 0 - -# Higher-level EV value for EV 25 and input 24 -set fmri(evg24.25) 0 - -# Higher-level EV value for EV 25 and input 25 -set fmri(evg25.25) 0 - -# Higher-level EV value for EV 25 and input 26 -set fmri(evg26.25) 0 - -# Higher-level EV value for EV 25 and input 27 -set fmri(evg27.25) 0 - -# Higher-level EV value for EV 25 and input 28 -set fmri(evg28.25) 0 - -# Higher-level EV value for EV 25 and input 29 -set fmri(evg29.25) 0 - -# Higher-level EV value for EV 25 and input 30 -set fmri(evg30.25) 0 - -# Higher-level EV value for EV 25 and input 31 -set fmri(evg31.25) 0 - -# Higher-level EV value for EV 25 and input 32 -set fmri(evg32.25) 0 - -# Higher-level EV value for EV 25 and input 33 -set fmri(evg33.25) 0 - -# Higher-level EV value for EV 25 and input 34 -set fmri(evg34.25) 0 - -# Higher-level EV value for EV 25 and input 35 -set fmri(evg35.25) 0 - -# Higher-level EV value for EV 25 and input 36 -set fmri(evg36.25) 0 - -# Higher-level EV value for EV 25 and input 37 -set fmri(evg37.25) 0 - -# Higher-level EV value for EV 25 and input 38 -set fmri(evg38.25) 0 - -# Higher-level EV value for EV 25 and input 39 -set fmri(evg39.25) 0 - -# Higher-level EV value for EV 25 and input 40 -set fmri(evg40.25) 0 - -# Higher-level EV value for EV 25 and input 41 -set fmri(evg41.25) 0 - -# Higher-level EV value for EV 25 and input 42 -set fmri(evg42.25) 0 - -# Higher-level EV value for EV 25 and input 43 -set fmri(evg43.25) 0 - -# Higher-level EV value for EV 25 and input 44 -set fmri(evg44.25) 0 - -# Higher-level EV value for EV 25 and input 45 -set fmri(evg45.25) 0 - -# Higher-level EV value for EV 25 and input 46 -set fmri(evg46.25) 0 - -# Higher-level EV value for EV 25 and input 47 -set fmri(evg47.25) 0 - -# Higher-level EV value for EV 25 and input 48 -set fmri(evg48.25) 0 - -# Higher-level EV value for EV 25 and input 49 -set fmri(evg49.25) 1.0 - -# Higher-level EV value for EV 25 and input 50 -set fmri(evg50.25) 1.0 - -# Higher-level EV value for EV 25 and input 51 -set fmri(evg51.25) 0 - -# Higher-level EV value for EV 25 and input 52 -set fmri(evg52.25) 0 - -# EV 26 title -set fmri(evtitle26) "" - -# Basic waveform shape (EV 26) -# 0 : Square -# 1 : Sinusoid -# 2 : Custom (1 entry per volume) -# 3 : Custom (3 column format) -# 4 : Interaction -# 10 : Empty (all zeros) -set fmri(shape26) 2 - -# Convolution (EV 26) -# 0 : None -# 1 : Gaussian -# 2 : Gamma -# 3 : Double-Gamma HRF -# 4 : Gamma basis functions -# 5 : Sine basis functions -# 6 : FIR basis functions -# 8 : Alternate Double-Gamma -set fmri(convolve26) 0 - -# Convolve phase (EV 26) -set fmri(convolve_phase26) 0 - -# Apply temporal filtering (EV 26) -set fmri(tempfilt_yn26) 0 - -# Add temporal derivative (EV 26) -set fmri(deriv_yn26) 0 - -# Custom EV file (EV 26) -set fmri(custom26) "dummy" - -# Orthogonalise EV 26 wrt EV 0 -set fmri(ortho26.0) 0 - -# Orthogonalise EV 26 wrt EV 1 -set fmri(ortho26.1) 0 - -# Orthogonalise EV 26 wrt EV 2 -set fmri(ortho26.2) 0 - -# Orthogonalise EV 26 wrt EV 3 -set fmri(ortho26.3) 0 - -# Orthogonalise EV 26 wrt EV 4 -set fmri(ortho26.4) 0 - -# Orthogonalise EV 26 wrt EV 5 -set fmri(ortho26.5) 0 - -# Orthogonalise EV 26 wrt EV 6 -set fmri(ortho26.6) 0 - -# Orthogonalise EV 26 wrt EV 7 -set fmri(ortho26.7) 0 - -# Orthogonalise EV 26 wrt EV 8 -set fmri(ortho26.8) 0 - -# Orthogonalise EV 26 wrt EV 9 -set fmri(ortho26.9) 0 - -# Orthogonalise EV 26 wrt EV 10 -set fmri(ortho26.10) 0 - -# Orthogonalise EV 26 wrt EV 11 -set fmri(ortho26.11) 0 - -# Orthogonalise EV 26 wrt EV 12 -set fmri(ortho26.12) 0 - -# Orthogonalise EV 26 wrt EV 13 -set fmri(ortho26.13) 0 - -# Orthogonalise EV 26 wrt EV 14 -set fmri(ortho26.14) 0 - -# Orthogonalise EV 26 wrt EV 15 -set fmri(ortho26.15) 0 - -# Orthogonalise EV 26 wrt EV 16 -set fmri(ortho26.16) 0 - -# Orthogonalise EV 26 wrt EV 17 -set fmri(ortho26.17) 0 - -# Orthogonalise EV 26 wrt EV 18 -set fmri(ortho26.18) 0 - -# Orthogonalise EV 26 wrt EV 19 -set fmri(ortho26.19) 0 - -# Orthogonalise EV 26 wrt EV 20 -set fmri(ortho26.20) 0 - -# Orthogonalise EV 26 wrt EV 21 -set fmri(ortho26.21) 0 - -# Orthogonalise EV 26 wrt EV 22 -set fmri(ortho26.22) 0 - -# Orthogonalise EV 26 wrt EV 23 -set fmri(ortho26.23) 0 - -# Orthogonalise EV 26 wrt EV 24 -set fmri(ortho26.24) 0 - -# Orthogonalise EV 26 wrt EV 25 -set fmri(ortho26.25) 0 - -# Orthogonalise EV 26 wrt EV 26 -set fmri(ortho26.26) 0 - -# Higher-level EV value for EV 26 and input 1 -set fmri(evg1.26) 0 - -# Higher-level EV value for EV 26 and input 2 -set fmri(evg2.26) 0 - -# Higher-level EV value for EV 26 and input 3 -set fmri(evg3.26) 0 - -# Higher-level EV value for EV 26 and input 4 -set fmri(evg4.26) 0 - -# Higher-level EV value for EV 26 and input 5 -set fmri(evg5.26) 0 - -# Higher-level EV value for EV 26 and input 6 -set fmri(evg6.26) 0 - -# Higher-level EV value for EV 26 and input 7 -set fmri(evg7.26) 0 - -# Higher-level EV value for EV 26 and input 8 -set fmri(evg8.26) 0 - -# Higher-level EV value for EV 26 and input 9 -set fmri(evg9.26) 0 - -# Higher-level EV value for EV 26 and input 10 -set fmri(evg10.26) 0 - -# Higher-level EV value for EV 26 and input 11 -set fmri(evg11.26) 0 - -# Higher-level EV value for EV 26 and input 12 -set fmri(evg12.26) 0 - -# Higher-level EV value for EV 26 and input 13 -set fmri(evg13.26) 0 - -# Higher-level EV value for EV 26 and input 14 -set fmri(evg14.26) 0 - -# Higher-level EV value for EV 26 and input 15 -set fmri(evg15.26) 0 - -# Higher-level EV value for EV 26 and input 16 -set fmri(evg16.26) 0 - -# Higher-level EV value for EV 26 and input 17 -set fmri(evg17.26) 0 - -# Higher-level EV value for EV 26 and input 18 -set fmri(evg18.26) 0 - -# Higher-level EV value for EV 26 and input 19 -set fmri(evg19.26) 0 - -# Higher-level EV value for EV 26 and input 20 -set fmri(evg20.26) 0 - -# Higher-level EV value for EV 26 and input 21 -set fmri(evg21.26) 0 - -# Higher-level EV value for EV 26 and input 22 -set fmri(evg22.26) 0 - -# Higher-level EV value for EV 26 and input 23 -set fmri(evg23.26) 0 - -# Higher-level EV value for EV 26 and input 24 -set fmri(evg24.26) 0 - -# Higher-level EV value for EV 26 and input 25 -set fmri(evg25.26) 0 - -# Higher-level EV value for EV 26 and input 26 -set fmri(evg26.26) 0 - -# Higher-level EV value for EV 26 and input 27 -set fmri(evg27.26) 0 - -# Higher-level EV value for EV 26 and input 28 -set fmri(evg28.26) 0 - -# Higher-level EV value for EV 26 and input 29 -set fmri(evg29.26) 0 - -# Higher-level EV value for EV 26 and input 30 -set fmri(evg30.26) 0 - -# Higher-level EV value for EV 26 and input 31 -set fmri(evg31.26) 0 - -# Higher-level EV value for EV 26 and input 32 -set fmri(evg32.26) 0 - -# Higher-level EV value for EV 26 and input 33 -set fmri(evg33.26) 0 - -# Higher-level EV value for EV 26 and input 34 -set fmri(evg34.26) 0 - -# Higher-level EV value for EV 26 and input 35 -set fmri(evg35.26) 0 - -# Higher-level EV value for EV 26 and input 36 -set fmri(evg36.26) 0 - -# Higher-level EV value for EV 26 and input 37 -set fmri(evg37.26) 0 - -# Higher-level EV value for EV 26 and input 38 -set fmri(evg38.26) 0 - -# Higher-level EV value for EV 26 and input 39 -set fmri(evg39.26) 0 - -# Higher-level EV value for EV 26 and input 40 -set fmri(evg40.26) 0 - -# Higher-level EV value for EV 26 and input 41 -set fmri(evg41.26) 0 - -# Higher-level EV value for EV 26 and input 42 -set fmri(evg42.26) 0 - -# Higher-level EV value for EV 26 and input 43 -set fmri(evg43.26) 0 - -# Higher-level EV value for EV 26 and input 44 -set fmri(evg44.26) 0 - -# Higher-level EV value for EV 26 and input 45 -set fmri(evg45.26) 0 - -# Higher-level EV value for EV 26 and input 46 -set fmri(evg46.26) 0 - -# Higher-level EV value for EV 26 and input 47 -set fmri(evg47.26) 0 - -# Higher-level EV value for EV 26 and input 48 -set fmri(evg48.26) 0 - -# Higher-level EV value for EV 26 and input 49 -set fmri(evg49.26) 0 - -# Higher-level EV value for EV 26 and input 50 -set fmri(evg50.26) 0 - -# Higher-level EV value for EV 26 and input 51 -set fmri(evg51.26) 1.0 - -# Higher-level EV value for EV 26 and input 52 -set fmri(evg52.26) 1.0 - -# Setup Orthogonalisation at higher level? -set fmri(level2orth) 0 - -# Group membership for input 1 -set fmri(groupmem.1) 1 - -# Group membership for input 2 -set fmri(groupmem.2) 1 - -# Group membership for input 3 -set fmri(groupmem.3) 1 - -# Group membership for input 4 -set fmri(groupmem.4) 1 - -# Group membership for input 5 -set fmri(groupmem.5) 1 - -# Group membership for input 6 -set fmri(groupmem.6) 1 - -# Group membership for input 7 -set fmri(groupmem.7) 1 - -# Group membership for input 8 -set fmri(groupmem.8) 1 - -# Group membership for input 9 -set fmri(groupmem.9) 1 - -# Group membership for input 10 -set fmri(groupmem.10) 1 - -# Group membership for input 11 -set fmri(groupmem.11) 1 - -# Group membership for input 12 -set fmri(groupmem.12) 1 - -# Group membership for input 13 -set fmri(groupmem.13) 1 - -# Group membership for input 14 -set fmri(groupmem.14) 1 - -# Group membership for input 15 -set fmri(groupmem.15) 1 - -# Group membership for input 16 -set fmri(groupmem.16) 1 - -# Group membership for input 17 -set fmri(groupmem.17) 1 - -# Group membership for input 18 -set fmri(groupmem.18) 1 - -# Group membership for input 19 -set fmri(groupmem.19) 1 - -# Group membership for input 20 -set fmri(groupmem.20) 1 - -# Group membership for input 21 -set fmri(groupmem.21) 1 - -# Group membership for input 22 -set fmri(groupmem.22) 1 - -# Group membership for input 23 -set fmri(groupmem.23) 1 - -# Group membership for input 24 -set fmri(groupmem.24) 1 - -# Group membership for input 25 -set fmri(groupmem.25) 1 - -# Group membership for input 26 -set fmri(groupmem.26) 1 - -# Group membership for input 27 -set fmri(groupmem.27) 1 - -# Group membership for input 28 -set fmri(groupmem.28) 1 - -# Group membership for input 29 -set fmri(groupmem.29) 1 - -# Group membership for input 30 -set fmri(groupmem.30) 1 - -# Group membership for input 31 -set fmri(groupmem.31) 1 - -# Group membership for input 32 -set fmri(groupmem.32) 1 - -# Group membership for input 33 -set fmri(groupmem.33) 1 - -# Group membership for input 34 -set fmri(groupmem.34) 1 - -# Group membership for input 35 -set fmri(groupmem.35) 1 - -# Group membership for input 36 -set fmri(groupmem.36) 1 - -# Group membership for input 37 -set fmri(groupmem.37) 1 - -# Group membership for input 38 -set fmri(groupmem.38) 1 - -# Group membership for input 39 -set fmri(groupmem.39) 1 - -# Group membership for input 40 -set fmri(groupmem.40) 1 - -# Group membership for input 41 -set fmri(groupmem.41) 1 - -# Group membership for input 42 -set fmri(groupmem.42) 1 - -# Group membership for input 43 -set fmri(groupmem.43) 1 - -# Group membership for input 44 -set fmri(groupmem.44) 1 - -# Group membership for input 45 -set fmri(groupmem.45) 1 - -# Group membership for input 46 -set fmri(groupmem.46) 1 - -# Group membership for input 47 -set fmri(groupmem.47) 1 - -# Group membership for input 48 -set fmri(groupmem.48) 1 - -# Group membership for input 49 -set fmri(groupmem.49) 1 - -# Group membership for input 50 -set fmri(groupmem.50) 1 - -# Group membership for input 51 -set fmri(groupmem.51) 1 - -# Group membership for input 52 -set fmri(groupmem.52) 1 - -# Contrast & F-tests mode -# real : control real EVs -# orig : control original EVs -set fmri(con_mode_old) real -set fmri(con_mode) real - -# Display images for contrast_real 1 -set fmri(conpic_real.1) 1 - -# Title for contrast_real 1 -set fmri(conname_real.1) "" - -# Real contrast_real vector 1 element 1 -set fmri(con_real1.1) 1 - -# Real contrast_real vector 1 element 2 -set fmri(con_real1.2) 0 - -# Real contrast_real vector 1 element 3 -set fmri(con_real1.3) 0 - -# Real contrast_real vector 1 element 4 -set fmri(con_real1.4) 0 - -# Real contrast_real vector 1 element 5 -set fmri(con_real1.5) 0 - -# Real contrast_real vector 1 element 6 -set fmri(con_real1.6) 0 - -# Real contrast_real vector 1 element 7 -set fmri(con_real1.7) 0 - -# Real contrast_real vector 1 element 8 -set fmri(con_real1.8) 0 - -# Real contrast_real vector 1 element 9 -set fmri(con_real1.9) 0 - -# Real contrast_real vector 1 element 10 -set fmri(con_real1.10) 0 - -# Real contrast_real vector 1 element 11 -set fmri(con_real1.11) 0 - -# Real contrast_real vector 1 element 12 -set fmri(con_real1.12) 0 - -# Real contrast_real vector 1 element 13 -set fmri(con_real1.13) 0 - -# Real contrast_real vector 1 element 14 -set fmri(con_real1.14) 0 - -# Real contrast_real vector 1 element 15 -set fmri(con_real1.15) 0 - -# Real contrast_real vector 1 element 16 -set fmri(con_real1.16) 0 - -# Real contrast_real vector 1 element 17 -set fmri(con_real1.17) 0 - -# Real contrast_real vector 1 element 18 -set fmri(con_real1.18) 0 - -# Real contrast_real vector 1 element 19 -set fmri(con_real1.19) 0 - -# Real contrast_real vector 1 element 20 -set fmri(con_real1.20) 0 - -# Real contrast_real vector 1 element 21 -set fmri(con_real1.21) 0 - -# Real contrast_real vector 1 element 22 -set fmri(con_real1.22) 0 - -# Real contrast_real vector 1 element 23 -set fmri(con_real1.23) 0 - -# Real contrast_real vector 1 element 24 -set fmri(con_real1.24) 0 - -# Real contrast_real vector 1 element 25 -set fmri(con_real1.25) 0 - -# Real contrast_real vector 1 element 26 -set fmri(con_real1.26) 0 - -# Display images for contrast_real 2 -set fmri(conpic_real.2) 1 - -# Title for contrast_real 2 -set fmri(conname_real.2) "" - -# Real contrast_real vector 2 element 1 -set fmri(con_real2.1) 0 - -# Real contrast_real vector 2 element 2 -set fmri(con_real2.2) 1.0 - -# Real contrast_real vector 2 element 3 -set fmri(con_real2.3) 0 - -# Real contrast_real vector 2 element 4 -set fmri(con_real2.4) 0 - -# Real contrast_real vector 2 element 5 -set fmri(con_real2.5) 0 - -# Real contrast_real vector 2 element 6 -set fmri(con_real2.6) 0 - -# Real contrast_real vector 2 element 7 -set fmri(con_real2.7) 0 - -# Real contrast_real vector 2 element 8 -set fmri(con_real2.8) 0 - -# Real contrast_real vector 2 element 9 -set fmri(con_real2.9) 0 - -# Real contrast_real vector 2 element 10 -set fmri(con_real2.10) 0 - -# Real contrast_real vector 2 element 11 -set fmri(con_real2.11) 0 - -# Real contrast_real vector 2 element 12 -set fmri(con_real2.12) 0 - -# Real contrast_real vector 2 element 13 -set fmri(con_real2.13) 0 - -# Real contrast_real vector 2 element 14 -set fmri(con_real2.14) 0 - -# Real contrast_real vector 2 element 15 -set fmri(con_real2.15) 0 - -# Real contrast_real vector 2 element 16 -set fmri(con_real2.16) 0 - -# Real contrast_real vector 2 element 17 -set fmri(con_real2.17) 0 - -# Real contrast_real vector 2 element 18 -set fmri(con_real2.18) 0 - -# Real contrast_real vector 2 element 19 -set fmri(con_real2.19) 0 - -# Real contrast_real vector 2 element 20 -set fmri(con_real2.20) 0 - -# Real contrast_real vector 2 element 21 -set fmri(con_real2.21) 0 - -# Real contrast_real vector 2 element 22 -set fmri(con_real2.22) 0 - -# Real contrast_real vector 2 element 23 -set fmri(con_real2.23) 0 - -# Real contrast_real vector 2 element 24 -set fmri(con_real2.24) 0 - -# Real contrast_real vector 2 element 25 -set fmri(con_real2.25) 0 - -# Real contrast_real vector 2 element 26 -set fmri(con_real2.26) 0 - -# Display images for contrast_real 3 -set fmri(conpic_real.3) 1 - -# Title for contrast_real 3 -set fmri(conname_real.3) "" - -# Real contrast_real vector 3 element 1 -set fmri(con_real3.1) 0 - -# Real contrast_real vector 3 element 2 -set fmri(con_real3.2) 0 - -# Real contrast_real vector 3 element 3 -set fmri(con_real3.3) 1.0 - -# Real contrast_real vector 3 element 4 -set fmri(con_real3.4) 0 - -# Real contrast_real vector 3 element 5 -set fmri(con_real3.5) 0 - -# Real contrast_real vector 3 element 6 -set fmri(con_real3.6) 0 - -# Real contrast_real vector 3 element 7 -set fmri(con_real3.7) 0 - -# Real contrast_real vector 3 element 8 -set fmri(con_real3.8) 0 - -# Real contrast_real vector 3 element 9 -set fmri(con_real3.9) 0 - -# Real contrast_real vector 3 element 10 -set fmri(con_real3.10) 0 - -# Real contrast_real vector 3 element 11 -set fmri(con_real3.11) 0 - -# Real contrast_real vector 3 element 12 -set fmri(con_real3.12) 0 - -# Real contrast_real vector 3 element 13 -set fmri(con_real3.13) 0 - -# Real contrast_real vector 3 element 14 -set fmri(con_real3.14) 0 - -# Real contrast_real vector 3 element 15 -set fmri(con_real3.15) 0 - -# Real contrast_real vector 3 element 16 -set fmri(con_real3.16) 0 - -# Real contrast_real vector 3 element 17 -set fmri(con_real3.17) 0 - -# Real contrast_real vector 3 element 18 -set fmri(con_real3.18) 0 - -# Real contrast_real vector 3 element 19 -set fmri(con_real3.19) 0 - -# Real contrast_real vector 3 element 20 -set fmri(con_real3.20) 0 - -# Real contrast_real vector 3 element 21 -set fmri(con_real3.21) 0 - -# Real contrast_real vector 3 element 22 -set fmri(con_real3.22) 0 - -# Real contrast_real vector 3 element 23 -set fmri(con_real3.23) 0 - -# Real contrast_real vector 3 element 24 -set fmri(con_real3.24) 0 - -# Real contrast_real vector 3 element 25 -set fmri(con_real3.25) 0 - -# Real contrast_real vector 3 element 26 -set fmri(con_real3.26) 0 - -# Display images for contrast_real 4 -set fmri(conpic_real.4) 1 - -# Title for contrast_real 4 -set fmri(conname_real.4) "" - -# Real contrast_real vector 4 element 1 -set fmri(con_real4.1) 0 - -# Real contrast_real vector 4 element 2 -set fmri(con_real4.2) 0 - -# Real contrast_real vector 4 element 3 -set fmri(con_real4.3) 0 - -# Real contrast_real vector 4 element 4 -set fmri(con_real4.4) 1.0 - -# Real contrast_real vector 4 element 5 -set fmri(con_real4.5) 0 - -# Real contrast_real vector 4 element 6 -set fmri(con_real4.6) 0 - -# Real contrast_real vector 4 element 7 -set fmri(con_real4.7) 0 - -# Real contrast_real vector 4 element 8 -set fmri(con_real4.8) 0 - -# Real contrast_real vector 4 element 9 -set fmri(con_real4.9) 0 - -# Real contrast_real vector 4 element 10 -set fmri(con_real4.10) 0 - -# Real contrast_real vector 4 element 11 -set fmri(con_real4.11) 0 - -# Real contrast_real vector 4 element 12 -set fmri(con_real4.12) 0 - -# Real contrast_real vector 4 element 13 -set fmri(con_real4.13) 0 - -# Real contrast_real vector 4 element 14 -set fmri(con_real4.14) 0 - -# Real contrast_real vector 4 element 15 -set fmri(con_real4.15) 0 - -# Real contrast_real vector 4 element 16 -set fmri(con_real4.16) 0 - -# Real contrast_real vector 4 element 17 -set fmri(con_real4.17) 0 - -# Real contrast_real vector 4 element 18 -set fmri(con_real4.18) 0 - -# Real contrast_real vector 4 element 19 -set fmri(con_real4.19) 0 - -# Real contrast_real vector 4 element 20 -set fmri(con_real4.20) 0 - -# Real contrast_real vector 4 element 21 -set fmri(con_real4.21) 0 - -# Real contrast_real vector 4 element 22 -set fmri(con_real4.22) 0 - -# Real contrast_real vector 4 element 23 -set fmri(con_real4.23) 0 - -# Real contrast_real vector 4 element 24 -set fmri(con_real4.24) 0 - -# Real contrast_real vector 4 element 25 -set fmri(con_real4.25) 0 - -# Real contrast_real vector 4 element 26 -set fmri(con_real4.26) 0 - -# Display images for contrast_real 5 -set fmri(conpic_real.5) 1 - -# Title for contrast_real 5 -set fmri(conname_real.5) "" - -# Real contrast_real vector 5 element 1 -set fmri(con_real5.1) 0 - -# Real contrast_real vector 5 element 2 -set fmri(con_real5.2) 0 - -# Real contrast_real vector 5 element 3 -set fmri(con_real5.3) 0 - -# Real contrast_real vector 5 element 4 -set fmri(con_real5.4) 0 - -# Real contrast_real vector 5 element 5 -set fmri(con_real5.5) 1.0 - -# Real contrast_real vector 5 element 6 -set fmri(con_real5.6) 0 - -# Real contrast_real vector 5 element 7 -set fmri(con_real5.7) 0 - -# Real contrast_real vector 5 element 8 -set fmri(con_real5.8) 0 - -# Real contrast_real vector 5 element 9 -set fmri(con_real5.9) 0 - -# Real contrast_real vector 5 element 10 -set fmri(con_real5.10) 0 - -# Real contrast_real vector 5 element 11 -set fmri(con_real5.11) 0 - -# Real contrast_real vector 5 element 12 -set fmri(con_real5.12) 0 - -# Real contrast_real vector 5 element 13 -set fmri(con_real5.13) 0 - -# Real contrast_real vector 5 element 14 -set fmri(con_real5.14) 0 - -# Real contrast_real vector 5 element 15 -set fmri(con_real5.15) 0 - -# Real contrast_real vector 5 element 16 -set fmri(con_real5.16) 0 - -# Real contrast_real vector 5 element 17 -set fmri(con_real5.17) 0 - -# Real contrast_real vector 5 element 18 -set fmri(con_real5.18) 0 - -# Real contrast_real vector 5 element 19 -set fmri(con_real5.19) 0 - -# Real contrast_real vector 5 element 20 -set fmri(con_real5.20) 0 - -# Real contrast_real vector 5 element 21 -set fmri(con_real5.21) 0 - -# Real contrast_real vector 5 element 22 -set fmri(con_real5.22) 0 - -# Real contrast_real vector 5 element 23 -set fmri(con_real5.23) 0 - -# Real contrast_real vector 5 element 24 -set fmri(con_real5.24) 0 - -# Real contrast_real vector 5 element 25 -set fmri(con_real5.25) 0 - -# Real contrast_real vector 5 element 26 -set fmri(con_real5.26) 0 - -# Display images for contrast_real 6 -set fmri(conpic_real.6) 1 - -# Title for contrast_real 6 -set fmri(conname_real.6) "" - -# Real contrast_real vector 6 element 1 -set fmri(con_real6.1) 0 - -# Real contrast_real vector 6 element 2 -set fmri(con_real6.2) 0 - -# Real contrast_real vector 6 element 3 -set fmri(con_real6.3) 0 - -# Real contrast_real vector 6 element 4 -set fmri(con_real6.4) 0 - -# Real contrast_real vector 6 element 5 -set fmri(con_real6.5) 0 - -# Real contrast_real vector 6 element 6 -set fmri(con_real6.6) 1.0 - -# Real contrast_real vector 6 element 7 -set fmri(con_real6.7) 0 - -# Real contrast_real vector 6 element 8 -set fmri(con_real6.8) 0 - -# Real contrast_real vector 6 element 9 -set fmri(con_real6.9) 0 - -# Real contrast_real vector 6 element 10 -set fmri(con_real6.10) 0 - -# Real contrast_real vector 6 element 11 -set fmri(con_real6.11) 0 - -# Real contrast_real vector 6 element 12 -set fmri(con_real6.12) 0 - -# Real contrast_real vector 6 element 13 -set fmri(con_real6.13) 0 - -# Real contrast_real vector 6 element 14 -set fmri(con_real6.14) 0 - -# Real contrast_real vector 6 element 15 -set fmri(con_real6.15) 0 - -# Real contrast_real vector 6 element 16 -set fmri(con_real6.16) 0 - -# Real contrast_real vector 6 element 17 -set fmri(con_real6.17) 0 - -# Real contrast_real vector 6 element 18 -set fmri(con_real6.18) 0 - -# Real contrast_real vector 6 element 19 -set fmri(con_real6.19) 0 - -# Real contrast_real vector 6 element 20 -set fmri(con_real6.20) 0 - -# Real contrast_real vector 6 element 21 -set fmri(con_real6.21) 0 - -# Real contrast_real vector 6 element 22 -set fmri(con_real6.22) 0 - -# Real contrast_real vector 6 element 23 -set fmri(con_real6.23) 0 - -# Real contrast_real vector 6 element 24 -set fmri(con_real6.24) 0 - -# Real contrast_real vector 6 element 25 -set fmri(con_real6.25) 0 - -# Real contrast_real vector 6 element 26 -set fmri(con_real6.26) 0 - -# Display images for contrast_real 7 -set fmri(conpic_real.7) 1 - -# Title for contrast_real 7 -set fmri(conname_real.7) "" - -# Real contrast_real vector 7 element 1 -set fmri(con_real7.1) 0 - -# Real contrast_real vector 7 element 2 -set fmri(con_real7.2) 0 - -# Real contrast_real vector 7 element 3 -set fmri(con_real7.3) 0 - -# Real contrast_real vector 7 element 4 -set fmri(con_real7.4) 0 - -# Real contrast_real vector 7 element 5 -set fmri(con_real7.5) 0 - -# Real contrast_real vector 7 element 6 -set fmri(con_real7.6) 0 - -# Real contrast_real vector 7 element 7 -set fmri(con_real7.7) 1.0 - -# Real contrast_real vector 7 element 8 -set fmri(con_real7.8) 0 - -# Real contrast_real vector 7 element 9 -set fmri(con_real7.9) 0 - -# Real contrast_real vector 7 element 10 -set fmri(con_real7.10) 0 - -# Real contrast_real vector 7 element 11 -set fmri(con_real7.11) 0 - -# Real contrast_real vector 7 element 12 -set fmri(con_real7.12) 0 - -# Real contrast_real vector 7 element 13 -set fmri(con_real7.13) 0 - -# Real contrast_real vector 7 element 14 -set fmri(con_real7.14) 0 - -# Real contrast_real vector 7 element 15 -set fmri(con_real7.15) 0 - -# Real contrast_real vector 7 element 16 -set fmri(con_real7.16) 0 - -# Real contrast_real vector 7 element 17 -set fmri(con_real7.17) 0 - -# Real contrast_real vector 7 element 18 -set fmri(con_real7.18) 0 - -# Real contrast_real vector 7 element 19 -set fmri(con_real7.19) 0 - -# Real contrast_real vector 7 element 20 -set fmri(con_real7.20) 0 - -# Real contrast_real vector 7 element 21 -set fmri(con_real7.21) 0 - -# Real contrast_real vector 7 element 22 -set fmri(con_real7.22) 0 - -# Real contrast_real vector 7 element 23 -set fmri(con_real7.23) 0 - -# Real contrast_real vector 7 element 24 -set fmri(con_real7.24) 0 - -# Real contrast_real vector 7 element 25 -set fmri(con_real7.25) 0 - -# Real contrast_real vector 7 element 26 -set fmri(con_real7.26) 0 - -# Display images for contrast_real 8 -set fmri(conpic_real.8) 1 - -# Title for contrast_real 8 -set fmri(conname_real.8) "" - -# Real contrast_real vector 8 element 1 -set fmri(con_real8.1) 0 - -# Real contrast_real vector 8 element 2 -set fmri(con_real8.2) 0 - -# Real contrast_real vector 8 element 3 -set fmri(con_real8.3) 0 - -# Real contrast_real vector 8 element 4 -set fmri(con_real8.4) 0 - -# Real contrast_real vector 8 element 5 -set fmri(con_real8.5) 0 - -# Real contrast_real vector 8 element 6 -set fmri(con_real8.6) 0 - -# Real contrast_real vector 8 element 7 -set fmri(con_real8.7) 0 - -# Real contrast_real vector 8 element 8 -set fmri(con_real8.8) 1.0 - -# Real contrast_real vector 8 element 9 -set fmri(con_real8.9) 0 - -# Real contrast_real vector 8 element 10 -set fmri(con_real8.10) 0 - -# Real contrast_real vector 8 element 11 -set fmri(con_real8.11) 0 - -# Real contrast_real vector 8 element 12 -set fmri(con_real8.12) 0 - -# Real contrast_real vector 8 element 13 -set fmri(con_real8.13) 0 - -# Real contrast_real vector 8 element 14 -set fmri(con_real8.14) 0 - -# Real contrast_real vector 8 element 15 -set fmri(con_real8.15) 0 - -# Real contrast_real vector 8 element 16 -set fmri(con_real8.16) 0 - -# Real contrast_real vector 8 element 17 -set fmri(con_real8.17) 0 - -# Real contrast_real vector 8 element 18 -set fmri(con_real8.18) 0 - -# Real contrast_real vector 8 element 19 -set fmri(con_real8.19) 0 - -# Real contrast_real vector 8 element 20 -set fmri(con_real8.20) 0 - -# Real contrast_real vector 8 element 21 -set fmri(con_real8.21) 0 - -# Real contrast_real vector 8 element 22 -set fmri(con_real8.22) 0 - -# Real contrast_real vector 8 element 23 -set fmri(con_real8.23) 0 - -# Real contrast_real vector 8 element 24 -set fmri(con_real8.24) 0 - -# Real contrast_real vector 8 element 25 -set fmri(con_real8.25) 0 - -# Real contrast_real vector 8 element 26 -set fmri(con_real8.26) 0 - -# Display images for contrast_real 9 -set fmri(conpic_real.9) 1 - -# Title for contrast_real 9 -set fmri(conname_real.9) "" - -# Real contrast_real vector 9 element 1 -set fmri(con_real9.1) 0 - -# Real contrast_real vector 9 element 2 -set fmri(con_real9.2) 0 - -# Real contrast_real vector 9 element 3 -set fmri(con_real9.3) 0 - -# Real contrast_real vector 9 element 4 -set fmri(con_real9.4) 0 - -# Real contrast_real vector 9 element 5 -set fmri(con_real9.5) 0 - -# Real contrast_real vector 9 element 6 -set fmri(con_real9.6) 0 - -# Real contrast_real vector 9 element 7 -set fmri(con_real9.7) 0 - -# Real contrast_real vector 9 element 8 -set fmri(con_real9.8) 0 - -# Real contrast_real vector 9 element 9 -set fmri(con_real9.9) 1.0 - -# Real contrast_real vector 9 element 10 -set fmri(con_real9.10) 0 - -# Real contrast_real vector 9 element 11 -set fmri(con_real9.11) 0 - -# Real contrast_real vector 9 element 12 -set fmri(con_real9.12) 0 - -# Real contrast_real vector 9 element 13 -set fmri(con_real9.13) 0 - -# Real contrast_real vector 9 element 14 -set fmri(con_real9.14) 0 - -# Real contrast_real vector 9 element 15 -set fmri(con_real9.15) 0 - -# Real contrast_real vector 9 element 16 -set fmri(con_real9.16) 0 - -# Real contrast_real vector 9 element 17 -set fmri(con_real9.17) 0 - -# Real contrast_real vector 9 element 18 -set fmri(con_real9.18) 0 - -# Real contrast_real vector 9 element 19 -set fmri(con_real9.19) 0 - -# Real contrast_real vector 9 element 20 -set fmri(con_real9.20) 0 - -# Real contrast_real vector 9 element 21 -set fmri(con_real9.21) 0 - -# Real contrast_real vector 9 element 22 -set fmri(con_real9.22) 0 - -# Real contrast_real vector 9 element 23 -set fmri(con_real9.23) 0 - -# Real contrast_real vector 9 element 24 -set fmri(con_real9.24) 0 - -# Real contrast_real vector 9 element 25 -set fmri(con_real9.25) 0 - -# Real contrast_real vector 9 element 26 -set fmri(con_real9.26) 0 - -# Display images for contrast_real 10 -set fmri(conpic_real.10) 1 - -# Title for contrast_real 10 -set fmri(conname_real.10) "" - -# Real contrast_real vector 10 element 1 -set fmri(con_real10.1) 0 - -# Real contrast_real vector 10 element 2 -set fmri(con_real10.2) 0 - -# Real contrast_real vector 10 element 3 -set fmri(con_real10.3) 0 - -# Real contrast_real vector 10 element 4 -set fmri(con_real10.4) 0 - -# Real contrast_real vector 10 element 5 -set fmri(con_real10.5) 0 - -# Real contrast_real vector 10 element 6 -set fmri(con_real10.6) 0 - -# Real contrast_real vector 10 element 7 -set fmri(con_real10.7) 0 - -# Real contrast_real vector 10 element 8 -set fmri(con_real10.8) 0 - -# Real contrast_real vector 10 element 9 -set fmri(con_real10.9) 0 - -# Real contrast_real vector 10 element 10 -set fmri(con_real10.10) 1.0 - -# Real contrast_real vector 10 element 11 -set fmri(con_real10.11) 0 - -# Real contrast_real vector 10 element 12 -set fmri(con_real10.12) 0 - -# Real contrast_real vector 10 element 13 -set fmri(con_real10.13) 0 - -# Real contrast_real vector 10 element 14 -set fmri(con_real10.14) 0 - -# Real contrast_real vector 10 element 15 -set fmri(con_real10.15) 0 - -# Real contrast_real vector 10 element 16 -set fmri(con_real10.16) 0 - -# Real contrast_real vector 10 element 17 -set fmri(con_real10.17) 0 - -# Real contrast_real vector 10 element 18 -set fmri(con_real10.18) 0 - -# Real contrast_real vector 10 element 19 -set fmri(con_real10.19) 0 - -# Real contrast_real vector 10 element 20 -set fmri(con_real10.20) 0 - -# Real contrast_real vector 10 element 21 -set fmri(con_real10.21) 0 - -# Real contrast_real vector 10 element 22 -set fmri(con_real10.22) 0 - -# Real contrast_real vector 10 element 23 -set fmri(con_real10.23) 0 - -# Real contrast_real vector 10 element 24 -set fmri(con_real10.24) 0 - -# Real contrast_real vector 10 element 25 -set fmri(con_real10.25) 0 - -# Real contrast_real vector 10 element 26 -set fmri(con_real10.26) 0 - -# Display images for contrast_real 11 -set fmri(conpic_real.11) 1 - -# Title for contrast_real 11 -set fmri(conname_real.11) "" - -# Real contrast_real vector 11 element 1 -set fmri(con_real11.1) 0 - -# Real contrast_real vector 11 element 2 -set fmri(con_real11.2) 0 - -# Real contrast_real vector 11 element 3 -set fmri(con_real11.3) 0 - -# Real contrast_real vector 11 element 4 -set fmri(con_real11.4) 0 - -# Real contrast_real vector 11 element 5 -set fmri(con_real11.5) 0 - -# Real contrast_real vector 11 element 6 -set fmri(con_real11.6) 0 - -# Real contrast_real vector 11 element 7 -set fmri(con_real11.7) 0 - -# Real contrast_real vector 11 element 8 -set fmri(con_real11.8) 0 - -# Real contrast_real vector 11 element 9 -set fmri(con_real11.9) 0 - -# Real contrast_real vector 11 element 10 -set fmri(con_real11.10) 0 - -# Real contrast_real vector 11 element 11 -set fmri(con_real11.11) 1.0 - -# Real contrast_real vector 11 element 12 -set fmri(con_real11.12) 0 - -# Real contrast_real vector 11 element 13 -set fmri(con_real11.13) 0 - -# Real contrast_real vector 11 element 14 -set fmri(con_real11.14) 0 - -# Real contrast_real vector 11 element 15 -set fmri(con_real11.15) 0 - -# Real contrast_real vector 11 element 16 -set fmri(con_real11.16) 0 - -# Real contrast_real vector 11 element 17 -set fmri(con_real11.17) 0 - -# Real contrast_real vector 11 element 18 -set fmri(con_real11.18) 0 - -# Real contrast_real vector 11 element 19 -set fmri(con_real11.19) 0 - -# Real contrast_real vector 11 element 20 -set fmri(con_real11.20) 0 - -# Real contrast_real vector 11 element 21 -set fmri(con_real11.21) 0 - -# Real contrast_real vector 11 element 22 -set fmri(con_real11.22) 0 - -# Real contrast_real vector 11 element 23 -set fmri(con_real11.23) 0 - -# Real contrast_real vector 11 element 24 -set fmri(con_real11.24) 0 - -# Real contrast_real vector 11 element 25 -set fmri(con_real11.25) 0 - -# Real contrast_real vector 11 element 26 -set fmri(con_real11.26) 0 - -# Display images for contrast_real 12 -set fmri(conpic_real.12) 1 - -# Title for contrast_real 12 -set fmri(conname_real.12) "" - -# Real contrast_real vector 12 element 1 -set fmri(con_real12.1) 0 - -# Real contrast_real vector 12 element 2 -set fmri(con_real12.2) 0 - -# Real contrast_real vector 12 element 3 -set fmri(con_real12.3) 0 - -# Real contrast_real vector 12 element 4 -set fmri(con_real12.4) 0 - -# Real contrast_real vector 12 element 5 -set fmri(con_real12.5) 0 - -# Real contrast_real vector 12 element 6 -set fmri(con_real12.6) 0 - -# Real contrast_real vector 12 element 7 -set fmri(con_real12.7) 0 - -# Real contrast_real vector 12 element 8 -set fmri(con_real12.8) 0 - -# Real contrast_real vector 12 element 9 -set fmri(con_real12.9) 0 - -# Real contrast_real vector 12 element 10 -set fmri(con_real12.10) 0 - -# Real contrast_real vector 12 element 11 -set fmri(con_real12.11) 0 - -# Real contrast_real vector 12 element 12 -set fmri(con_real12.12) 1.0 - -# Real contrast_real vector 12 element 13 -set fmri(con_real12.13) 0 - -# Real contrast_real vector 12 element 14 -set fmri(con_real12.14) 0 - -# Real contrast_real vector 12 element 15 -set fmri(con_real12.15) 0 - -# Real contrast_real vector 12 element 16 -set fmri(con_real12.16) 0 - -# Real contrast_real vector 12 element 17 -set fmri(con_real12.17) 0 - -# Real contrast_real vector 12 element 18 -set fmri(con_real12.18) 0 - -# Real contrast_real vector 12 element 19 -set fmri(con_real12.19) 0 - -# Real contrast_real vector 12 element 20 -set fmri(con_real12.20) 0 - -# Real contrast_real vector 12 element 21 -set fmri(con_real12.21) 0 - -# Real contrast_real vector 12 element 22 -set fmri(con_real12.22) 0 - -# Real contrast_real vector 12 element 23 -set fmri(con_real12.23) 0 - -# Real contrast_real vector 12 element 24 -set fmri(con_real12.24) 0 - -# Real contrast_real vector 12 element 25 -set fmri(con_real12.25) 0 - -# Real contrast_real vector 12 element 26 -set fmri(con_real12.26) 0 - -# Display images for contrast_real 13 -set fmri(conpic_real.13) 1 - -# Title for contrast_real 13 -set fmri(conname_real.13) "" - -# Real contrast_real vector 13 element 1 -set fmri(con_real13.1) 0 - -# Real contrast_real vector 13 element 2 -set fmri(con_real13.2) 0 - -# Real contrast_real vector 13 element 3 -set fmri(con_real13.3) 0 - -# Real contrast_real vector 13 element 4 -set fmri(con_real13.4) 0 - -# Real contrast_real vector 13 element 5 -set fmri(con_real13.5) 0 - -# Real contrast_real vector 13 element 6 -set fmri(con_real13.6) 0 - -# Real contrast_real vector 13 element 7 -set fmri(con_real13.7) 0 - -# Real contrast_real vector 13 element 8 -set fmri(con_real13.8) 0 - -# Real contrast_real vector 13 element 9 -set fmri(con_real13.9) 0 - -# Real contrast_real vector 13 element 10 -set fmri(con_real13.10) 0 - -# Real contrast_real vector 13 element 11 -set fmri(con_real13.11) 0 - -# Real contrast_real vector 13 element 12 -set fmri(con_real13.12) 0 - -# Real contrast_real vector 13 element 13 -set fmri(con_real13.13) 1.0 - -# Real contrast_real vector 13 element 14 -set fmri(con_real13.14) 0 - -# Real contrast_real vector 13 element 15 -set fmri(con_real13.15) 0 - -# Real contrast_real vector 13 element 16 -set fmri(con_real13.16) 0 - -# Real contrast_real vector 13 element 17 -set fmri(con_real13.17) 0 - -# Real contrast_real vector 13 element 18 -set fmri(con_real13.18) 0 - -# Real contrast_real vector 13 element 19 -set fmri(con_real13.19) 0 - -# Real contrast_real vector 13 element 20 -set fmri(con_real13.20) 0 - -# Real contrast_real vector 13 element 21 -set fmri(con_real13.21) 0 - -# Real contrast_real vector 13 element 22 -set fmri(con_real13.22) 0 - -# Real contrast_real vector 13 element 23 -set fmri(con_real13.23) 0 - -# Real contrast_real vector 13 element 24 -set fmri(con_real13.24) 0 - -# Real contrast_real vector 13 element 25 -set fmri(con_real13.25) 0 - -# Real contrast_real vector 13 element 26 -set fmri(con_real13.26) 0 - -# Display images for contrast_real 14 -set fmri(conpic_real.14) 1 - -# Title for contrast_real 14 -set fmri(conname_real.14) "" - -# Real contrast_real vector 14 element 1 -set fmri(con_real14.1) 0 - -# Real contrast_real vector 14 element 2 -set fmri(con_real14.2) 0 - -# Real contrast_real vector 14 element 3 -set fmri(con_real14.3) 0 - -# Real contrast_real vector 14 element 4 -set fmri(con_real14.4) 0 - -# Real contrast_real vector 14 element 5 -set fmri(con_real14.5) 0 - -# Real contrast_real vector 14 element 6 -set fmri(con_real14.6) 0 - -# Real contrast_real vector 14 element 7 -set fmri(con_real14.7) 0 - -# Real contrast_real vector 14 element 8 -set fmri(con_real14.8) 0 - -# Real contrast_real vector 14 element 9 -set fmri(con_real14.9) 0 - -# Real contrast_real vector 14 element 10 -set fmri(con_real14.10) 0 - -# Real contrast_real vector 14 element 11 -set fmri(con_real14.11) 0 - -# Real contrast_real vector 14 element 12 -set fmri(con_real14.12) 0 - -# Real contrast_real vector 14 element 13 -set fmri(con_real14.13) 0 - -# Real contrast_real vector 14 element 14 -set fmri(con_real14.14) 1.0 - -# Real contrast_real vector 14 element 15 -set fmri(con_real14.15) 0 - -# Real contrast_real vector 14 element 16 -set fmri(con_real14.16) 0 - -# Real contrast_real vector 14 element 17 -set fmri(con_real14.17) 0 - -# Real contrast_real vector 14 element 18 -set fmri(con_real14.18) 0 - -# Real contrast_real vector 14 element 19 -set fmri(con_real14.19) 0 - -# Real contrast_real vector 14 element 20 -set fmri(con_real14.20) 0 - -# Real contrast_real vector 14 element 21 -set fmri(con_real14.21) 0 - -# Real contrast_real vector 14 element 22 -set fmri(con_real14.22) 0 - -# Real contrast_real vector 14 element 23 -set fmri(con_real14.23) 0 - -# Real contrast_real vector 14 element 24 -set fmri(con_real14.24) 0 - -# Real contrast_real vector 14 element 25 -set fmri(con_real14.25) 0 - -# Real contrast_real vector 14 element 26 -set fmri(con_real14.26) 0 - -# Display images for contrast_real 15 -set fmri(conpic_real.15) 1 - -# Title for contrast_real 15 -set fmri(conname_real.15) "" - -# Real contrast_real vector 15 element 1 -set fmri(con_real15.1) 0 - -# Real contrast_real vector 15 element 2 -set fmri(con_real15.2) 0 - -# Real contrast_real vector 15 element 3 -set fmri(con_real15.3) 0 - -# Real contrast_real vector 15 element 4 -set fmri(con_real15.4) 0 - -# Real contrast_real vector 15 element 5 -set fmri(con_real15.5) 0 - -# Real contrast_real vector 15 element 6 -set fmri(con_real15.6) 0 - -# Real contrast_real vector 15 element 7 -set fmri(con_real15.7) 0 - -# Real contrast_real vector 15 element 8 -set fmri(con_real15.8) 0 - -# Real contrast_real vector 15 element 9 -set fmri(con_real15.9) 0 - -# Real contrast_real vector 15 element 10 -set fmri(con_real15.10) 0 - -# Real contrast_real vector 15 element 11 -set fmri(con_real15.11) 0 - -# Real contrast_real vector 15 element 12 -set fmri(con_real15.12) 0 - -# Real contrast_real vector 15 element 13 -set fmri(con_real15.13) 0 - -# Real contrast_real vector 15 element 14 -set fmri(con_real15.14) 0 - -# Real contrast_real vector 15 element 15 -set fmri(con_real15.15) 1.0 - -# Real contrast_real vector 15 element 16 -set fmri(con_real15.16) 0 - -# Real contrast_real vector 15 element 17 -set fmri(con_real15.17) 0 - -# Real contrast_real vector 15 element 18 -set fmri(con_real15.18) 0 - -# Real contrast_real vector 15 element 19 -set fmri(con_real15.19) 0 - -# Real contrast_real vector 15 element 20 -set fmri(con_real15.20) 0 - -# Real contrast_real vector 15 element 21 -set fmri(con_real15.21) 0 - -# Real contrast_real vector 15 element 22 -set fmri(con_real15.22) 0 - -# Real contrast_real vector 15 element 23 -set fmri(con_real15.23) 0 - -# Real contrast_real vector 15 element 24 -set fmri(con_real15.24) 0 - -# Real contrast_real vector 15 element 25 -set fmri(con_real15.25) 0 - -# Real contrast_real vector 15 element 26 -set fmri(con_real15.26) 0 - -# Display images for contrast_real 16 -set fmri(conpic_real.16) 1 - -# Title for contrast_real 16 -set fmri(conname_real.16) "" - -# Real contrast_real vector 16 element 1 -set fmri(con_real16.1) 0 - -# Real contrast_real vector 16 element 2 -set fmri(con_real16.2) 0 - -# Real contrast_real vector 16 element 3 -set fmri(con_real16.3) 0 - -# Real contrast_real vector 16 element 4 -set fmri(con_real16.4) 0 - -# Real contrast_real vector 16 element 5 -set fmri(con_real16.5) 0 - -# Real contrast_real vector 16 element 6 -set fmri(con_real16.6) 0 - -# Real contrast_real vector 16 element 7 -set fmri(con_real16.7) 0 - -# Real contrast_real vector 16 element 8 -set fmri(con_real16.8) 0 - -# Real contrast_real vector 16 element 9 -set fmri(con_real16.9) 0 - -# Real contrast_real vector 16 element 10 -set fmri(con_real16.10) 0 - -# Real contrast_real vector 16 element 11 -set fmri(con_real16.11) 0 - -# Real contrast_real vector 16 element 12 -set fmri(con_real16.12) 0 - -# Real contrast_real vector 16 element 13 -set fmri(con_real16.13) 0 - -# Real contrast_real vector 16 element 14 -set fmri(con_real16.14) 0 - -# Real contrast_real vector 16 element 15 -set fmri(con_real16.15) 0 - -# Real contrast_real vector 16 element 16 -set fmri(con_real16.16) 1.0 - -# Real contrast_real vector 16 element 17 -set fmri(con_real16.17) 0 - -# Real contrast_real vector 16 element 18 -set fmri(con_real16.18) 0 - -# Real contrast_real vector 16 element 19 -set fmri(con_real16.19) 0 - -# Real contrast_real vector 16 element 20 -set fmri(con_real16.20) 0 - -# Real contrast_real vector 16 element 21 -set fmri(con_real16.21) 0 - -# Real contrast_real vector 16 element 22 -set fmri(con_real16.22) 0 - -# Real contrast_real vector 16 element 23 -set fmri(con_real16.23) 0 - -# Real contrast_real vector 16 element 24 -set fmri(con_real16.24) 0 - -# Real contrast_real vector 16 element 25 -set fmri(con_real16.25) 0 - -# Real contrast_real vector 16 element 26 -set fmri(con_real16.26) 0 - -# Display images for contrast_real 17 -set fmri(conpic_real.17) 1 - -# Title for contrast_real 17 -set fmri(conname_real.17) "" - -# Real contrast_real vector 17 element 1 -set fmri(con_real17.1) 0 - -# Real contrast_real vector 17 element 2 -set fmri(con_real17.2) 0 - -# Real contrast_real vector 17 element 3 -set fmri(con_real17.3) 0 - -# Real contrast_real vector 17 element 4 -set fmri(con_real17.4) 0 - -# Real contrast_real vector 17 element 5 -set fmri(con_real17.5) 0 - -# Real contrast_real vector 17 element 6 -set fmri(con_real17.6) 0 - -# Real contrast_real vector 17 element 7 -set fmri(con_real17.7) 0 - -# Real contrast_real vector 17 element 8 -set fmri(con_real17.8) 0 - -# Real contrast_real vector 17 element 9 -set fmri(con_real17.9) 0 - -# Real contrast_real vector 17 element 10 -set fmri(con_real17.10) 0 - -# Real contrast_real vector 17 element 11 -set fmri(con_real17.11) 0 - -# Real contrast_real vector 17 element 12 -set fmri(con_real17.12) 0 - -# Real contrast_real vector 17 element 13 -set fmri(con_real17.13) 0 - -# Real contrast_real vector 17 element 14 -set fmri(con_real17.14) 0 - -# Real contrast_real vector 17 element 15 -set fmri(con_real17.15) 0 - -# Real contrast_real vector 17 element 16 -set fmri(con_real17.16) 0 - -# Real contrast_real vector 17 element 17 -set fmri(con_real17.17) 1.0 - -# Real contrast_real vector 17 element 18 -set fmri(con_real17.18) 0 - -# Real contrast_real vector 17 element 19 -set fmri(con_real17.19) 0 - -# Real contrast_real vector 17 element 20 -set fmri(con_real17.20) 0 - -# Real contrast_real vector 17 element 21 -set fmri(con_real17.21) 0 - -# Real contrast_real vector 17 element 22 -set fmri(con_real17.22) 0 - -# Real contrast_real vector 17 element 23 -set fmri(con_real17.23) 0 - -# Real contrast_real vector 17 element 24 -set fmri(con_real17.24) 0 - -# Real contrast_real vector 17 element 25 -set fmri(con_real17.25) 0 - -# Real contrast_real vector 17 element 26 -set fmri(con_real17.26) 0 - -# Display images for contrast_real 18 -set fmri(conpic_real.18) 1 - -# Title for contrast_real 18 -set fmri(conname_real.18) "" - -# Real contrast_real vector 18 element 1 -set fmri(con_real18.1) 0 - -# Real contrast_real vector 18 element 2 -set fmri(con_real18.2) 0 - -# Real contrast_real vector 18 element 3 -set fmri(con_real18.3) 0 - -# Real contrast_real vector 18 element 4 -set fmri(con_real18.4) 0 - -# Real contrast_real vector 18 element 5 -set fmri(con_real18.5) 0 - -# Real contrast_real vector 18 element 6 -set fmri(con_real18.6) 0 - -# Real contrast_real vector 18 element 7 -set fmri(con_real18.7) 0 - -# Real contrast_real vector 18 element 8 -set fmri(con_real18.8) 0 - -# Real contrast_real vector 18 element 9 -set fmri(con_real18.9) 0 - -# Real contrast_real vector 18 element 10 -set fmri(con_real18.10) 0 - -# Real contrast_real vector 18 element 11 -set fmri(con_real18.11) 0 - -# Real contrast_real vector 18 element 12 -set fmri(con_real18.12) 0 - -# Real contrast_real vector 18 element 13 -set fmri(con_real18.13) 0 - -# Real contrast_real vector 18 element 14 -set fmri(con_real18.14) 0 - -# Real contrast_real vector 18 element 15 -set fmri(con_real18.15) 0 - -# Real contrast_real vector 18 element 16 -set fmri(con_real18.16) 0 - -# Real contrast_real vector 18 element 17 -set fmri(con_real18.17) 0 - -# Real contrast_real vector 18 element 18 -set fmri(con_real18.18) 1.0 - -# Real contrast_real vector 18 element 19 -set fmri(con_real18.19) 0 - -# Real contrast_real vector 18 element 20 -set fmri(con_real18.20) 0 - -# Real contrast_real vector 18 element 21 -set fmri(con_real18.21) 0 - -# Real contrast_real vector 18 element 22 -set fmri(con_real18.22) 0 - -# Real contrast_real vector 18 element 23 -set fmri(con_real18.23) 0 - -# Real contrast_real vector 18 element 24 -set fmri(con_real18.24) 0 - -# Real contrast_real vector 18 element 25 -set fmri(con_real18.25) 0 - -# Real contrast_real vector 18 element 26 -set fmri(con_real18.26) 0 - -# Display images for contrast_real 19 -set fmri(conpic_real.19) 1 - -# Title for contrast_real 19 -set fmri(conname_real.19) "" - -# Real contrast_real vector 19 element 1 -set fmri(con_real19.1) 0 - -# Real contrast_real vector 19 element 2 -set fmri(con_real19.2) 0 - -# Real contrast_real vector 19 element 3 -set fmri(con_real19.3) 0 - -# Real contrast_real vector 19 element 4 -set fmri(con_real19.4) 0 - -# Real contrast_real vector 19 element 5 -set fmri(con_real19.5) 0 - -# Real contrast_real vector 19 element 6 -set fmri(con_real19.6) 0 - -# Real contrast_real vector 19 element 7 -set fmri(con_real19.7) 0 - -# Real contrast_real vector 19 element 8 -set fmri(con_real19.8) 0 - -# Real contrast_real vector 19 element 9 -set fmri(con_real19.9) 0 - -# Real contrast_real vector 19 element 10 -set fmri(con_real19.10) 0 - -# Real contrast_real vector 19 element 11 -set fmri(con_real19.11) 0 - -# Real contrast_real vector 19 element 12 -set fmri(con_real19.12) 0 - -# Real contrast_real vector 19 element 13 -set fmri(con_real19.13) 0 - -# Real contrast_real vector 19 element 14 -set fmri(con_real19.14) 0 - -# Real contrast_real vector 19 element 15 -set fmri(con_real19.15) 0 - -# Real contrast_real vector 19 element 16 -set fmri(con_real19.16) 0 - -# Real contrast_real vector 19 element 17 -set fmri(con_real19.17) 0 - -# Real contrast_real vector 19 element 18 -set fmri(con_real19.18) 0 - -# Real contrast_real vector 19 element 19 -set fmri(con_real19.19) 1.0 - -# Real contrast_real vector 19 element 20 -set fmri(con_real19.20) 0 - -# Real contrast_real vector 19 element 21 -set fmri(con_real19.21) 0 - -# Real contrast_real vector 19 element 22 -set fmri(con_real19.22) 0 - -# Real contrast_real vector 19 element 23 -set fmri(con_real19.23) 0 - -# Real contrast_real vector 19 element 24 -set fmri(con_real19.24) 0 - -# Real contrast_real vector 19 element 25 -set fmri(con_real19.25) 0 - -# Real contrast_real vector 19 element 26 -set fmri(con_real19.26) 0 - -# Display images for contrast_real 20 -set fmri(conpic_real.20) 1 - -# Title for contrast_real 20 -set fmri(conname_real.20) "" - -# Real contrast_real vector 20 element 1 -set fmri(con_real20.1) 0 - -# Real contrast_real vector 20 element 2 -set fmri(con_real20.2) 0 - -# Real contrast_real vector 20 element 3 -set fmri(con_real20.3) 0 - -# Real contrast_real vector 20 element 4 -set fmri(con_real20.4) 0 - -# Real contrast_real vector 20 element 5 -set fmri(con_real20.5) 0 - -# Real contrast_real vector 20 element 6 -set fmri(con_real20.6) 0 - -# Real contrast_real vector 20 element 7 -set fmri(con_real20.7) 0 - -# Real contrast_real vector 20 element 8 -set fmri(con_real20.8) 0 - -# Real contrast_real vector 20 element 9 -set fmri(con_real20.9) 0 - -# Real contrast_real vector 20 element 10 -set fmri(con_real20.10) 0 - -# Real contrast_real vector 20 element 11 -set fmri(con_real20.11) 0 - -# Real contrast_real vector 20 element 12 -set fmri(con_real20.12) 0 - -# Real contrast_real vector 20 element 13 -set fmri(con_real20.13) 0 - -# Real contrast_real vector 20 element 14 -set fmri(con_real20.14) 0 - -# Real contrast_real vector 20 element 15 -set fmri(con_real20.15) 0 - -# Real contrast_real vector 20 element 16 -set fmri(con_real20.16) 0 - -# Real contrast_real vector 20 element 17 -set fmri(con_real20.17) 0 - -# Real contrast_real vector 20 element 18 -set fmri(con_real20.18) 0 - -# Real contrast_real vector 20 element 19 -set fmri(con_real20.19) 0 - -# Real contrast_real vector 20 element 20 -set fmri(con_real20.20) 1.0 - -# Real contrast_real vector 20 element 21 -set fmri(con_real20.21) 0 - -# Real contrast_real vector 20 element 22 -set fmri(con_real20.22) 0 - -# Real contrast_real vector 20 element 23 -set fmri(con_real20.23) 0 - -# Real contrast_real vector 20 element 24 -set fmri(con_real20.24) 0 - -# Real contrast_real vector 20 element 25 -set fmri(con_real20.25) 0 - -# Real contrast_real vector 20 element 26 -set fmri(con_real20.26) 0 - -# Display images for contrast_real 21 -set fmri(conpic_real.21) 1 - -# Title for contrast_real 21 -set fmri(conname_real.21) "" - -# Real contrast_real vector 21 element 1 -set fmri(con_real21.1) 0 - -# Real contrast_real vector 21 element 2 -set fmri(con_real21.2) 0 - -# Real contrast_real vector 21 element 3 -set fmri(con_real21.3) 0 - -# Real contrast_real vector 21 element 4 -set fmri(con_real21.4) 0 - -# Real contrast_real vector 21 element 5 -set fmri(con_real21.5) 0 - -# Real contrast_real vector 21 element 6 -set fmri(con_real21.6) 0 - -# Real contrast_real vector 21 element 7 -set fmri(con_real21.7) 0 - -# Real contrast_real vector 21 element 8 -set fmri(con_real21.8) 0 - -# Real contrast_real vector 21 element 9 -set fmri(con_real21.9) 0 - -# Real contrast_real vector 21 element 10 -set fmri(con_real21.10) 0 - -# Real contrast_real vector 21 element 11 -set fmri(con_real21.11) 0 - -# Real contrast_real vector 21 element 12 -set fmri(con_real21.12) 0 - -# Real contrast_real vector 21 element 13 -set fmri(con_real21.13) 0 - -# Real contrast_real vector 21 element 14 -set fmri(con_real21.14) 0 - -# Real contrast_real vector 21 element 15 -set fmri(con_real21.15) 0 - -# Real contrast_real vector 21 element 16 -set fmri(con_real21.16) 0 - -# Real contrast_real vector 21 element 17 -set fmri(con_real21.17) 0 - -# Real contrast_real vector 21 element 18 -set fmri(con_real21.18) 0 - -# Real contrast_real vector 21 element 19 -set fmri(con_real21.19) 0 - -# Real contrast_real vector 21 element 20 -set fmri(con_real21.20) 0 - -# Real contrast_real vector 21 element 21 -set fmri(con_real21.21) 1.0 - -# Real contrast_real vector 21 element 22 -set fmri(con_real21.22) 0 - -# Real contrast_real vector 21 element 23 -set fmri(con_real21.23) 0 - -# Real contrast_real vector 21 element 24 -set fmri(con_real21.24) 0 - -# Real contrast_real vector 21 element 25 -set fmri(con_real21.25) 0 - -# Real contrast_real vector 21 element 26 -set fmri(con_real21.26) 0 - -# Display images for contrast_real 22 -set fmri(conpic_real.22) 1 - -# Title for contrast_real 22 -set fmri(conname_real.22) "" - -# Real contrast_real vector 22 element 1 -set fmri(con_real22.1) 0 - -# Real contrast_real vector 22 element 2 -set fmri(con_real22.2) 0 - -# Real contrast_real vector 22 element 3 -set fmri(con_real22.3) 0 - -# Real contrast_real vector 22 element 4 -set fmri(con_real22.4) 0 - -# Real contrast_real vector 22 element 5 -set fmri(con_real22.5) 0 - -# Real contrast_real vector 22 element 6 -set fmri(con_real22.6) 0 - -# Real contrast_real vector 22 element 7 -set fmri(con_real22.7) 0 - -# Real contrast_real vector 22 element 8 -set fmri(con_real22.8) 0 - -# Real contrast_real vector 22 element 9 -set fmri(con_real22.9) 0 - -# Real contrast_real vector 22 element 10 -set fmri(con_real22.10) 0 - -# Real contrast_real vector 22 element 11 -set fmri(con_real22.11) 0 - -# Real contrast_real vector 22 element 12 -set fmri(con_real22.12) 0 - -# Real contrast_real vector 22 element 13 -set fmri(con_real22.13) 0 - -# Real contrast_real vector 22 element 14 -set fmri(con_real22.14) 0 - -# Real contrast_real vector 22 element 15 -set fmri(con_real22.15) 0 - -# Real contrast_real vector 22 element 16 -set fmri(con_real22.16) 0 - -# Real contrast_real vector 22 element 17 -set fmri(con_real22.17) 0 - -# Real contrast_real vector 22 element 18 -set fmri(con_real22.18) 0 - -# Real contrast_real vector 22 element 19 -set fmri(con_real22.19) 0 - -# Real contrast_real vector 22 element 20 -set fmri(con_real22.20) 0 - -# Real contrast_real vector 22 element 21 -set fmri(con_real22.21) 0 - -# Real contrast_real vector 22 element 22 -set fmri(con_real22.22) 1.0 - -# Real contrast_real vector 22 element 23 -set fmri(con_real22.23) 0 - -# Real contrast_real vector 22 element 24 -set fmri(con_real22.24) 0 - -# Real contrast_real vector 22 element 25 -set fmri(con_real22.25) 0 - -# Real contrast_real vector 22 element 26 -set fmri(con_real22.26) 0 - -# Display images for contrast_real 23 -set fmri(conpic_real.23) 1 - -# Title for contrast_real 23 -set fmri(conname_real.23) "" - -# Real contrast_real vector 23 element 1 -set fmri(con_real23.1) 0 - -# Real contrast_real vector 23 element 2 -set fmri(con_real23.2) 0 - -# Real contrast_real vector 23 element 3 -set fmri(con_real23.3) 0 - -# Real contrast_real vector 23 element 4 -set fmri(con_real23.4) 0 - -# Real contrast_real vector 23 element 5 -set fmri(con_real23.5) 0 - -# Real contrast_real vector 23 element 6 -set fmri(con_real23.6) 0 - -# Real contrast_real vector 23 element 7 -set fmri(con_real23.7) 0 - -# Real contrast_real vector 23 element 8 -set fmri(con_real23.8) 0 - -# Real contrast_real vector 23 element 9 -set fmri(con_real23.9) 0 - -# Real contrast_real vector 23 element 10 -set fmri(con_real23.10) 0 - -# Real contrast_real vector 23 element 11 -set fmri(con_real23.11) 0 - -# Real contrast_real vector 23 element 12 -set fmri(con_real23.12) 0 - -# Real contrast_real vector 23 element 13 -set fmri(con_real23.13) 0 - -# Real contrast_real vector 23 element 14 -set fmri(con_real23.14) 0 - -# Real contrast_real vector 23 element 15 -set fmri(con_real23.15) 0 - -# Real contrast_real vector 23 element 16 -set fmri(con_real23.16) 0 - -# Real contrast_real vector 23 element 17 -set fmri(con_real23.17) 0 - -# Real contrast_real vector 23 element 18 -set fmri(con_real23.18) 0 - -# Real contrast_real vector 23 element 19 -set fmri(con_real23.19) 0 - -# Real contrast_real vector 23 element 20 -set fmri(con_real23.20) 0 - -# Real contrast_real vector 23 element 21 -set fmri(con_real23.21) 0 - -# Real contrast_real vector 23 element 22 -set fmri(con_real23.22) 0 - -# Real contrast_real vector 23 element 23 -set fmri(con_real23.23) 1.0 - -# Real contrast_real vector 23 element 24 -set fmri(con_real23.24) 0 - -# Real contrast_real vector 23 element 25 -set fmri(con_real23.25) 0 - -# Real contrast_real vector 23 element 26 -set fmri(con_real23.26) 0 - -# Display images for contrast_real 24 -set fmri(conpic_real.24) 1 - -# Title for contrast_real 24 -set fmri(conname_real.24) "" - -# Real contrast_real vector 24 element 1 -set fmri(con_real24.1) 0 - -# Real contrast_real vector 24 element 2 -set fmri(con_real24.2) 0 - -# Real contrast_real vector 24 element 3 -set fmri(con_real24.3) 0 - -# Real contrast_real vector 24 element 4 -set fmri(con_real24.4) 0 - -# Real contrast_real vector 24 element 5 -set fmri(con_real24.5) 0 - -# Real contrast_real vector 24 element 6 -set fmri(con_real24.6) 0 - -# Real contrast_real vector 24 element 7 -set fmri(con_real24.7) 0 - -# Real contrast_real vector 24 element 8 -set fmri(con_real24.8) 0 - -# Real contrast_real vector 24 element 9 -set fmri(con_real24.9) 0 - -# Real contrast_real vector 24 element 10 -set fmri(con_real24.10) 0 - -# Real contrast_real vector 24 element 11 -set fmri(con_real24.11) 0 - -# Real contrast_real vector 24 element 12 -set fmri(con_real24.12) 0 - -# Real contrast_real vector 24 element 13 -set fmri(con_real24.13) 0 - -# Real contrast_real vector 24 element 14 -set fmri(con_real24.14) 0 - -# Real contrast_real vector 24 element 15 -set fmri(con_real24.15) 0 - -# Real contrast_real vector 24 element 16 -set fmri(con_real24.16) 0 - -# Real contrast_real vector 24 element 17 -set fmri(con_real24.17) 0 - -# Real contrast_real vector 24 element 18 -set fmri(con_real24.18) 0 - -# Real contrast_real vector 24 element 19 -set fmri(con_real24.19) 0 - -# Real contrast_real vector 24 element 20 -set fmri(con_real24.20) 0 - -# Real contrast_real vector 24 element 21 -set fmri(con_real24.21) 0 - -# Real contrast_real vector 24 element 22 -set fmri(con_real24.22) 0 - -# Real contrast_real vector 24 element 23 -set fmri(con_real24.23) 0 - -# Real contrast_real vector 24 element 24 -set fmri(con_real24.24) 1.0 - -# Real contrast_real vector 24 element 25 -set fmri(con_real24.25) 0 - -# Real contrast_real vector 24 element 26 -set fmri(con_real24.26) 0 - -# Display images for contrast_real 25 -set fmri(conpic_real.25) 1 - -# Title for contrast_real 25 -set fmri(conname_real.25) "" - -# Real contrast_real vector 25 element 1 -set fmri(con_real25.1) 0 - -# Real contrast_real vector 25 element 2 -set fmri(con_real25.2) 0 - -# Real contrast_real vector 25 element 3 -set fmri(con_real25.3) 0 - -# Real contrast_real vector 25 element 4 -set fmri(con_real25.4) 0 - -# Real contrast_real vector 25 element 5 -set fmri(con_real25.5) 0 - -# Real contrast_real vector 25 element 6 -set fmri(con_real25.6) 0 - -# Real contrast_real vector 25 element 7 -set fmri(con_real25.7) 0 - -# Real contrast_real vector 25 element 8 -set fmri(con_real25.8) 0 - -# Real contrast_real vector 25 element 9 -set fmri(con_real25.9) 0 - -# Real contrast_real vector 25 element 10 -set fmri(con_real25.10) 0 - -# Real contrast_real vector 25 element 11 -set fmri(con_real25.11) 0 - -# Real contrast_real vector 25 element 12 -set fmri(con_real25.12) 0 - -# Real contrast_real vector 25 element 13 -set fmri(con_real25.13) 0 - -# Real contrast_real vector 25 element 14 -set fmri(con_real25.14) 0 - -# Real contrast_real vector 25 element 15 -set fmri(con_real25.15) 0 - -# Real contrast_real vector 25 element 16 -set fmri(con_real25.16) 0 - -# Real contrast_real vector 25 element 17 -set fmri(con_real25.17) 0 - -# Real contrast_real vector 25 element 18 -set fmri(con_real25.18) 0 - -# Real contrast_real vector 25 element 19 -set fmri(con_real25.19) 0 - -# Real contrast_real vector 25 element 20 -set fmri(con_real25.20) 0 - -# Real contrast_real vector 25 element 21 -set fmri(con_real25.21) 0 - -# Real contrast_real vector 25 element 22 -set fmri(con_real25.22) 0 - -# Real contrast_real vector 25 element 23 -set fmri(con_real25.23) 0 - -# Real contrast_real vector 25 element 24 -set fmri(con_real25.24) 0 - -# Real contrast_real vector 25 element 25 -set fmri(con_real25.25) 1.0 - -# Real contrast_real vector 25 element 26 -set fmri(con_real25.26) 0 - -# Display images for contrast_real 26 -set fmri(conpic_real.26) 1 - -# Title for contrast_real 26 -set fmri(conname_real.26) "" - -# Real contrast_real vector 26 element 1 -set fmri(con_real26.1) 0 - -# Real contrast_real vector 26 element 2 -set fmri(con_real26.2) 0 - -# Real contrast_real vector 26 element 3 -set fmri(con_real26.3) 0 - -# Real contrast_real vector 26 element 4 -set fmri(con_real26.4) 0 - -# Real contrast_real vector 26 element 5 -set fmri(con_real26.5) 0 - -# Real contrast_real vector 26 element 6 -set fmri(con_real26.6) 0 - -# Real contrast_real vector 26 element 7 -set fmri(con_real26.7) 0 - -# Real contrast_real vector 26 element 8 -set fmri(con_real26.8) 0 - -# Real contrast_real vector 26 element 9 -set fmri(con_real26.9) 0 - -# Real contrast_real vector 26 element 10 -set fmri(con_real26.10) 0 - -# Real contrast_real vector 26 element 11 -set fmri(con_real26.11) 0 - -# Real contrast_real vector 26 element 12 -set fmri(con_real26.12) 0 - -# Real contrast_real vector 26 element 13 -set fmri(con_real26.13) 0 - -# Real contrast_real vector 26 element 14 -set fmri(con_real26.14) 0 - -# Real contrast_real vector 26 element 15 -set fmri(con_real26.15) 0 - -# Real contrast_real vector 26 element 16 -set fmri(con_real26.16) 0 - -# Real contrast_real vector 26 element 17 -set fmri(con_real26.17) 0 - -# Real contrast_real vector 26 element 18 -set fmri(con_real26.18) 0 - -# Real contrast_real vector 26 element 19 -set fmri(con_real26.19) 0 - -# Real contrast_real vector 26 element 20 -set fmri(con_real26.20) 0 - -# Real contrast_real vector 26 element 21 -set fmri(con_real26.21) 0 - -# Real contrast_real vector 26 element 22 -set fmri(con_real26.22) 0 - -# Real contrast_real vector 26 element 23 -set fmri(con_real26.23) 0 - -# Real contrast_real vector 26 element 24 -set fmri(con_real26.24) 0 - -# Real contrast_real vector 26 element 25 -set fmri(con_real26.25) 0 - -# Real contrast_real vector 26 element 26 -set fmri(con_real26.26) 1.0 - -# Contrast masking - use >0 instead of thresholding? -set fmri(conmask_zerothresh_yn) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 2? -set fmri(conmask1_2) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 3? -set fmri(conmask1_3) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 4? -set fmri(conmask1_4) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 5? -set fmri(conmask1_5) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 6? -set fmri(conmask1_6) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 7? -set fmri(conmask1_7) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 8? -set fmri(conmask1_8) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 9? -set fmri(conmask1_9) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 10? -set fmri(conmask1_10) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 11? -set fmri(conmask1_11) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 12? -set fmri(conmask1_12) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 13? -set fmri(conmask1_13) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 14? -set fmri(conmask1_14) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 15? -set fmri(conmask1_15) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 16? -set fmri(conmask1_16) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 17? -set fmri(conmask1_17) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 18? -set fmri(conmask1_18) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 19? -set fmri(conmask1_19) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 20? -set fmri(conmask1_20) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 21? -set fmri(conmask1_21) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 22? -set fmri(conmask1_22) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 23? -set fmri(conmask1_23) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 24? -set fmri(conmask1_24) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 25? -set fmri(conmask1_25) 0 - -# Mask real contrast/F-test 1 with real contrast/F-test 26? -set fmri(conmask1_26) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 1? -set fmri(conmask2_1) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 3? -set fmri(conmask2_3) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 4? -set fmri(conmask2_4) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 5? -set fmri(conmask2_5) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 6? -set fmri(conmask2_6) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 7? -set fmri(conmask2_7) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 8? -set fmri(conmask2_8) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 9? -set fmri(conmask2_9) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 10? -set fmri(conmask2_10) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 11? -set fmri(conmask2_11) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 12? -set fmri(conmask2_12) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 13? -set fmri(conmask2_13) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 14? -set fmri(conmask2_14) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 15? -set fmri(conmask2_15) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 16? -set fmri(conmask2_16) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 17? -set fmri(conmask2_17) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 18? -set fmri(conmask2_18) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 19? -set fmri(conmask2_19) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 20? -set fmri(conmask2_20) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 21? -set fmri(conmask2_21) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 22? -set fmri(conmask2_22) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 23? -set fmri(conmask2_23) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 24? -set fmri(conmask2_24) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 25? -set fmri(conmask2_25) 0 - -# Mask real contrast/F-test 2 with real contrast/F-test 26? -set fmri(conmask2_26) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 1? -set fmri(conmask3_1) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 2? -set fmri(conmask3_2) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 4? -set fmri(conmask3_4) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 5? -set fmri(conmask3_5) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 6? -set fmri(conmask3_6) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 7? -set fmri(conmask3_7) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 8? -set fmri(conmask3_8) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 9? -set fmri(conmask3_9) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 10? -set fmri(conmask3_10) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 11? -set fmri(conmask3_11) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 12? -set fmri(conmask3_12) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 13? -set fmri(conmask3_13) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 14? -set fmri(conmask3_14) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 15? -set fmri(conmask3_15) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 16? -set fmri(conmask3_16) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 17? -set fmri(conmask3_17) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 18? -set fmri(conmask3_18) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 19? -set fmri(conmask3_19) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 20? -set fmri(conmask3_20) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 21? -set fmri(conmask3_21) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 22? -set fmri(conmask3_22) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 23? -set fmri(conmask3_23) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 24? -set fmri(conmask3_24) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 25? -set fmri(conmask3_25) 0 - -# Mask real contrast/F-test 3 with real contrast/F-test 26? -set fmri(conmask3_26) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 1? -set fmri(conmask4_1) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 2? -set fmri(conmask4_2) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 3? -set fmri(conmask4_3) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 5? -set fmri(conmask4_5) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 6? -set fmri(conmask4_6) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 7? -set fmri(conmask4_7) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 8? -set fmri(conmask4_8) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 9? -set fmri(conmask4_9) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 10? -set fmri(conmask4_10) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 11? -set fmri(conmask4_11) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 12? -set fmri(conmask4_12) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 13? -set fmri(conmask4_13) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 14? -set fmri(conmask4_14) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 15? -set fmri(conmask4_15) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 16? -set fmri(conmask4_16) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 17? -set fmri(conmask4_17) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 18? -set fmri(conmask4_18) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 19? -set fmri(conmask4_19) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 20? -set fmri(conmask4_20) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 21? -set fmri(conmask4_21) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 22? -set fmri(conmask4_22) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 23? -set fmri(conmask4_23) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 24? -set fmri(conmask4_24) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 25? -set fmri(conmask4_25) 0 - -# Mask real contrast/F-test 4 with real contrast/F-test 26? -set fmri(conmask4_26) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 1? -set fmri(conmask5_1) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 2? -set fmri(conmask5_2) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 3? -set fmri(conmask5_3) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 4? -set fmri(conmask5_4) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 6? -set fmri(conmask5_6) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 7? -set fmri(conmask5_7) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 8? -set fmri(conmask5_8) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 9? -set fmri(conmask5_9) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 10? -set fmri(conmask5_10) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 11? -set fmri(conmask5_11) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 12? -set fmri(conmask5_12) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 13? -set fmri(conmask5_13) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 14? -set fmri(conmask5_14) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 15? -set fmri(conmask5_15) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 16? -set fmri(conmask5_16) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 17? -set fmri(conmask5_17) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 18? -set fmri(conmask5_18) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 19? -set fmri(conmask5_19) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 20? -set fmri(conmask5_20) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 21? -set fmri(conmask5_21) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 22? -set fmri(conmask5_22) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 23? -set fmri(conmask5_23) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 24? -set fmri(conmask5_24) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 25? -set fmri(conmask5_25) 0 - -# Mask real contrast/F-test 5 with real contrast/F-test 26? -set fmri(conmask5_26) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 1? -set fmri(conmask6_1) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 2? -set fmri(conmask6_2) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 3? -set fmri(conmask6_3) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 4? -set fmri(conmask6_4) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 5? -set fmri(conmask6_5) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 7? -set fmri(conmask6_7) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 8? -set fmri(conmask6_8) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 9? -set fmri(conmask6_9) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 10? -set fmri(conmask6_10) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 11? -set fmri(conmask6_11) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 12? -set fmri(conmask6_12) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 13? -set fmri(conmask6_13) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 14? -set fmri(conmask6_14) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 15? -set fmri(conmask6_15) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 16? -set fmri(conmask6_16) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 17? -set fmri(conmask6_17) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 18? -set fmri(conmask6_18) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 19? -set fmri(conmask6_19) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 20? -set fmri(conmask6_20) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 21? -set fmri(conmask6_21) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 22? -set fmri(conmask6_22) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 23? -set fmri(conmask6_23) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 24? -set fmri(conmask6_24) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 25? -set fmri(conmask6_25) 0 - -# Mask real contrast/F-test 6 with real contrast/F-test 26? -set fmri(conmask6_26) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 1? -set fmri(conmask7_1) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 2? -set fmri(conmask7_2) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 3? -set fmri(conmask7_3) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 4? -set fmri(conmask7_4) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 5? -set fmri(conmask7_5) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 6? -set fmri(conmask7_6) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 8? -set fmri(conmask7_8) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 9? -set fmri(conmask7_9) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 10? -set fmri(conmask7_10) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 11? -set fmri(conmask7_11) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 12? -set fmri(conmask7_12) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 13? -set fmri(conmask7_13) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 14? -set fmri(conmask7_14) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 15? -set fmri(conmask7_15) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 16? -set fmri(conmask7_16) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 17? -set fmri(conmask7_17) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 18? -set fmri(conmask7_18) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 19? -set fmri(conmask7_19) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 20? -set fmri(conmask7_20) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 21? -set fmri(conmask7_21) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 22? -set fmri(conmask7_22) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 23? -set fmri(conmask7_23) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 24? -set fmri(conmask7_24) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 25? -set fmri(conmask7_25) 0 - -# Mask real contrast/F-test 7 with real contrast/F-test 26? -set fmri(conmask7_26) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 1? -set fmri(conmask8_1) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 2? -set fmri(conmask8_2) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 3? -set fmri(conmask8_3) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 4? -set fmri(conmask8_4) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 5? -set fmri(conmask8_5) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 6? -set fmri(conmask8_6) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 7? -set fmri(conmask8_7) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 9? -set fmri(conmask8_9) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 10? -set fmri(conmask8_10) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 11? -set fmri(conmask8_11) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 12? -set fmri(conmask8_12) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 13? -set fmri(conmask8_13) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 14? -set fmri(conmask8_14) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 15? -set fmri(conmask8_15) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 16? -set fmri(conmask8_16) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 17? -set fmri(conmask8_17) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 18? -set fmri(conmask8_18) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 19? -set fmri(conmask8_19) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 20? -set fmri(conmask8_20) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 21? -set fmri(conmask8_21) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 22? -set fmri(conmask8_22) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 23? -set fmri(conmask8_23) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 24? -set fmri(conmask8_24) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 25? -set fmri(conmask8_25) 0 - -# Mask real contrast/F-test 8 with real contrast/F-test 26? -set fmri(conmask8_26) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 1? -set fmri(conmask9_1) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 2? -set fmri(conmask9_2) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 3? -set fmri(conmask9_3) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 4? -set fmri(conmask9_4) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 5? -set fmri(conmask9_5) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 6? -set fmri(conmask9_6) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 7? -set fmri(conmask9_7) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 8? -set fmri(conmask9_8) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 10? -set fmri(conmask9_10) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 11? -set fmri(conmask9_11) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 12? -set fmri(conmask9_12) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 13? -set fmri(conmask9_13) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 14? -set fmri(conmask9_14) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 15? -set fmri(conmask9_15) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 16? -set fmri(conmask9_16) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 17? -set fmri(conmask9_17) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 18? -set fmri(conmask9_18) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 19? -set fmri(conmask9_19) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 20? -set fmri(conmask9_20) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 21? -set fmri(conmask9_21) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 22? -set fmri(conmask9_22) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 23? -set fmri(conmask9_23) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 24? -set fmri(conmask9_24) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 25? -set fmri(conmask9_25) 0 - -# Mask real contrast/F-test 9 with real contrast/F-test 26? -set fmri(conmask9_26) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 1? -set fmri(conmask10_1) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 2? -set fmri(conmask10_2) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 3? -set fmri(conmask10_3) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 4? -set fmri(conmask10_4) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 5? -set fmri(conmask10_5) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 6? -set fmri(conmask10_6) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 7? -set fmri(conmask10_7) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 8? -set fmri(conmask10_8) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 9? -set fmri(conmask10_9) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 11? -set fmri(conmask10_11) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 12? -set fmri(conmask10_12) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 13? -set fmri(conmask10_13) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 14? -set fmri(conmask10_14) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 15? -set fmri(conmask10_15) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 16? -set fmri(conmask10_16) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 17? -set fmri(conmask10_17) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 18? -set fmri(conmask10_18) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 19? -set fmri(conmask10_19) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 20? -set fmri(conmask10_20) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 21? -set fmri(conmask10_21) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 22? -set fmri(conmask10_22) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 23? -set fmri(conmask10_23) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 24? -set fmri(conmask10_24) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 25? -set fmri(conmask10_25) 0 - -# Mask real contrast/F-test 10 with real contrast/F-test 26? -set fmri(conmask10_26) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 1? -set fmri(conmask11_1) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 2? -set fmri(conmask11_2) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 3? -set fmri(conmask11_3) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 4? -set fmri(conmask11_4) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 5? -set fmri(conmask11_5) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 6? -set fmri(conmask11_6) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 7? -set fmri(conmask11_7) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 8? -set fmri(conmask11_8) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 9? -set fmri(conmask11_9) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 10? -set fmri(conmask11_10) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 12? -set fmri(conmask11_12) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 13? -set fmri(conmask11_13) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 14? -set fmri(conmask11_14) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 15? -set fmri(conmask11_15) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 16? -set fmri(conmask11_16) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 17? -set fmri(conmask11_17) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 18? -set fmri(conmask11_18) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 19? -set fmri(conmask11_19) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 20? -set fmri(conmask11_20) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 21? -set fmri(conmask11_21) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 22? -set fmri(conmask11_22) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 23? -set fmri(conmask11_23) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 24? -set fmri(conmask11_24) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 25? -set fmri(conmask11_25) 0 - -# Mask real contrast/F-test 11 with real contrast/F-test 26? -set fmri(conmask11_26) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 1? -set fmri(conmask12_1) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 2? -set fmri(conmask12_2) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 3? -set fmri(conmask12_3) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 4? -set fmri(conmask12_4) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 5? -set fmri(conmask12_5) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 6? -set fmri(conmask12_6) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 7? -set fmri(conmask12_7) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 8? -set fmri(conmask12_8) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 9? -set fmri(conmask12_9) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 10? -set fmri(conmask12_10) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 11? -set fmri(conmask12_11) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 13? -set fmri(conmask12_13) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 14? -set fmri(conmask12_14) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 15? -set fmri(conmask12_15) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 16? -set fmri(conmask12_16) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 17? -set fmri(conmask12_17) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 18? -set fmri(conmask12_18) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 19? -set fmri(conmask12_19) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 20? -set fmri(conmask12_20) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 21? -set fmri(conmask12_21) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 22? -set fmri(conmask12_22) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 23? -set fmri(conmask12_23) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 24? -set fmri(conmask12_24) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 25? -set fmri(conmask12_25) 0 - -# Mask real contrast/F-test 12 with real contrast/F-test 26? -set fmri(conmask12_26) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 1? -set fmri(conmask13_1) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 2? -set fmri(conmask13_2) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 3? -set fmri(conmask13_3) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 4? -set fmri(conmask13_4) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 5? -set fmri(conmask13_5) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 6? -set fmri(conmask13_6) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 7? -set fmri(conmask13_7) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 8? -set fmri(conmask13_8) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 9? -set fmri(conmask13_9) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 10? -set fmri(conmask13_10) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 11? -set fmri(conmask13_11) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 12? -set fmri(conmask13_12) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 14? -set fmri(conmask13_14) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 15? -set fmri(conmask13_15) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 16? -set fmri(conmask13_16) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 17? -set fmri(conmask13_17) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 18? -set fmri(conmask13_18) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 19? -set fmri(conmask13_19) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 20? -set fmri(conmask13_20) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 21? -set fmri(conmask13_21) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 22? -set fmri(conmask13_22) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 23? -set fmri(conmask13_23) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 24? -set fmri(conmask13_24) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 25? -set fmri(conmask13_25) 0 - -# Mask real contrast/F-test 13 with real contrast/F-test 26? -set fmri(conmask13_26) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 1? -set fmri(conmask14_1) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 2? -set fmri(conmask14_2) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 3? -set fmri(conmask14_3) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 4? -set fmri(conmask14_4) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 5? -set fmri(conmask14_5) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 6? -set fmri(conmask14_6) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 7? -set fmri(conmask14_7) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 8? -set fmri(conmask14_8) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 9? -set fmri(conmask14_9) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 10? -set fmri(conmask14_10) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 11? -set fmri(conmask14_11) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 12? -set fmri(conmask14_12) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 13? -set fmri(conmask14_13) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 15? -set fmri(conmask14_15) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 16? -set fmri(conmask14_16) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 17? -set fmri(conmask14_17) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 18? -set fmri(conmask14_18) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 19? -set fmri(conmask14_19) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 20? -set fmri(conmask14_20) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 21? -set fmri(conmask14_21) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 22? -set fmri(conmask14_22) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 23? -set fmri(conmask14_23) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 24? -set fmri(conmask14_24) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 25? -set fmri(conmask14_25) 0 - -# Mask real contrast/F-test 14 with real contrast/F-test 26? -set fmri(conmask14_26) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 1? -set fmri(conmask15_1) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 2? -set fmri(conmask15_2) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 3? -set fmri(conmask15_3) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 4? -set fmri(conmask15_4) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 5? -set fmri(conmask15_5) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 6? -set fmri(conmask15_6) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 7? -set fmri(conmask15_7) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 8? -set fmri(conmask15_8) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 9? -set fmri(conmask15_9) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 10? -set fmri(conmask15_10) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 11? -set fmri(conmask15_11) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 12? -set fmri(conmask15_12) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 13? -set fmri(conmask15_13) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 14? -set fmri(conmask15_14) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 16? -set fmri(conmask15_16) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 17? -set fmri(conmask15_17) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 18? -set fmri(conmask15_18) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 19? -set fmri(conmask15_19) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 20? -set fmri(conmask15_20) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 21? -set fmri(conmask15_21) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 22? -set fmri(conmask15_22) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 23? -set fmri(conmask15_23) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 24? -set fmri(conmask15_24) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 25? -set fmri(conmask15_25) 0 - -# Mask real contrast/F-test 15 with real contrast/F-test 26? -set fmri(conmask15_26) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 1? -set fmri(conmask16_1) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 2? -set fmri(conmask16_2) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 3? -set fmri(conmask16_3) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 4? -set fmri(conmask16_4) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 5? -set fmri(conmask16_5) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 6? -set fmri(conmask16_6) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 7? -set fmri(conmask16_7) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 8? -set fmri(conmask16_8) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 9? -set fmri(conmask16_9) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 10? -set fmri(conmask16_10) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 11? -set fmri(conmask16_11) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 12? -set fmri(conmask16_12) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 13? -set fmri(conmask16_13) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 14? -set fmri(conmask16_14) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 15? -set fmri(conmask16_15) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 17? -set fmri(conmask16_17) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 18? -set fmri(conmask16_18) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 19? -set fmri(conmask16_19) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 20? -set fmri(conmask16_20) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 21? -set fmri(conmask16_21) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 22? -set fmri(conmask16_22) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 23? -set fmri(conmask16_23) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 24? -set fmri(conmask16_24) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 25? -set fmri(conmask16_25) 0 - -# Mask real contrast/F-test 16 with real contrast/F-test 26? -set fmri(conmask16_26) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 1? -set fmri(conmask17_1) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 2? -set fmri(conmask17_2) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 3? -set fmri(conmask17_3) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 4? -set fmri(conmask17_4) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 5? -set fmri(conmask17_5) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 6? -set fmri(conmask17_6) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 7? -set fmri(conmask17_7) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 8? -set fmri(conmask17_8) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 9? -set fmri(conmask17_9) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 10? -set fmri(conmask17_10) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 11? -set fmri(conmask17_11) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 12? -set fmri(conmask17_12) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 13? -set fmri(conmask17_13) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 14? -set fmri(conmask17_14) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 15? -set fmri(conmask17_15) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 16? -set fmri(conmask17_16) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 18? -set fmri(conmask17_18) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 19? -set fmri(conmask17_19) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 20? -set fmri(conmask17_20) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 21? -set fmri(conmask17_21) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 22? -set fmri(conmask17_22) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 23? -set fmri(conmask17_23) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 24? -set fmri(conmask17_24) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 25? -set fmri(conmask17_25) 0 - -# Mask real contrast/F-test 17 with real contrast/F-test 26? -set fmri(conmask17_26) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 1? -set fmri(conmask18_1) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 2? -set fmri(conmask18_2) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 3? -set fmri(conmask18_3) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 4? -set fmri(conmask18_4) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 5? -set fmri(conmask18_5) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 6? -set fmri(conmask18_6) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 7? -set fmri(conmask18_7) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 8? -set fmri(conmask18_8) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 9? -set fmri(conmask18_9) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 10? -set fmri(conmask18_10) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 11? -set fmri(conmask18_11) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 12? -set fmri(conmask18_12) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 13? -set fmri(conmask18_13) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 14? -set fmri(conmask18_14) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 15? -set fmri(conmask18_15) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 16? -set fmri(conmask18_16) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 17? -set fmri(conmask18_17) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 19? -set fmri(conmask18_19) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 20? -set fmri(conmask18_20) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 21? -set fmri(conmask18_21) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 22? -set fmri(conmask18_22) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 23? -set fmri(conmask18_23) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 24? -set fmri(conmask18_24) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 25? -set fmri(conmask18_25) 0 - -# Mask real contrast/F-test 18 with real contrast/F-test 26? -set fmri(conmask18_26) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 1? -set fmri(conmask19_1) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 2? -set fmri(conmask19_2) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 3? -set fmri(conmask19_3) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 4? -set fmri(conmask19_4) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 5? -set fmri(conmask19_5) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 6? -set fmri(conmask19_6) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 7? -set fmri(conmask19_7) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 8? -set fmri(conmask19_8) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 9? -set fmri(conmask19_9) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 10? -set fmri(conmask19_10) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 11? -set fmri(conmask19_11) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 12? -set fmri(conmask19_12) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 13? -set fmri(conmask19_13) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 14? -set fmri(conmask19_14) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 15? -set fmri(conmask19_15) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 16? -set fmri(conmask19_16) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 17? -set fmri(conmask19_17) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 18? -set fmri(conmask19_18) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 20? -set fmri(conmask19_20) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 21? -set fmri(conmask19_21) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 22? -set fmri(conmask19_22) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 23? -set fmri(conmask19_23) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 24? -set fmri(conmask19_24) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 25? -set fmri(conmask19_25) 0 - -# Mask real contrast/F-test 19 with real contrast/F-test 26? -set fmri(conmask19_26) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 1? -set fmri(conmask20_1) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 2? -set fmri(conmask20_2) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 3? -set fmri(conmask20_3) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 4? -set fmri(conmask20_4) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 5? -set fmri(conmask20_5) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 6? -set fmri(conmask20_6) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 7? -set fmri(conmask20_7) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 8? -set fmri(conmask20_8) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 9? -set fmri(conmask20_9) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 10? -set fmri(conmask20_10) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 11? -set fmri(conmask20_11) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 12? -set fmri(conmask20_12) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 13? -set fmri(conmask20_13) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 14? -set fmri(conmask20_14) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 15? -set fmri(conmask20_15) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 16? -set fmri(conmask20_16) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 17? -set fmri(conmask20_17) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 18? -set fmri(conmask20_18) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 19? -set fmri(conmask20_19) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 21? -set fmri(conmask20_21) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 22? -set fmri(conmask20_22) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 23? -set fmri(conmask20_23) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 24? -set fmri(conmask20_24) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 25? -set fmri(conmask20_25) 0 - -# Mask real contrast/F-test 20 with real contrast/F-test 26? -set fmri(conmask20_26) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 1? -set fmri(conmask21_1) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 2? -set fmri(conmask21_2) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 3? -set fmri(conmask21_3) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 4? -set fmri(conmask21_4) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 5? -set fmri(conmask21_5) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 6? -set fmri(conmask21_6) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 7? -set fmri(conmask21_7) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 8? -set fmri(conmask21_8) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 9? -set fmri(conmask21_9) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 10? -set fmri(conmask21_10) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 11? -set fmri(conmask21_11) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 12? -set fmri(conmask21_12) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 13? -set fmri(conmask21_13) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 14? -set fmri(conmask21_14) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 15? -set fmri(conmask21_15) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 16? -set fmri(conmask21_16) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 17? -set fmri(conmask21_17) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 18? -set fmri(conmask21_18) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 19? -set fmri(conmask21_19) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 20? -set fmri(conmask21_20) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 22? -set fmri(conmask21_22) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 23? -set fmri(conmask21_23) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 24? -set fmri(conmask21_24) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 25? -set fmri(conmask21_25) 0 - -# Mask real contrast/F-test 21 with real contrast/F-test 26? -set fmri(conmask21_26) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 1? -set fmri(conmask22_1) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 2? -set fmri(conmask22_2) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 3? -set fmri(conmask22_3) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 4? -set fmri(conmask22_4) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 5? -set fmri(conmask22_5) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 6? -set fmri(conmask22_6) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 7? -set fmri(conmask22_7) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 8? -set fmri(conmask22_8) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 9? -set fmri(conmask22_9) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 10? -set fmri(conmask22_10) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 11? -set fmri(conmask22_11) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 12? -set fmri(conmask22_12) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 13? -set fmri(conmask22_13) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 14? -set fmri(conmask22_14) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 15? -set fmri(conmask22_15) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 16? -set fmri(conmask22_16) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 17? -set fmri(conmask22_17) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 18? -set fmri(conmask22_18) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 19? -set fmri(conmask22_19) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 20? -set fmri(conmask22_20) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 21? -set fmri(conmask22_21) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 23? -set fmri(conmask22_23) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 24? -set fmri(conmask22_24) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 25? -set fmri(conmask22_25) 0 - -# Mask real contrast/F-test 22 with real contrast/F-test 26? -set fmri(conmask22_26) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 1? -set fmri(conmask23_1) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 2? -set fmri(conmask23_2) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 3? -set fmri(conmask23_3) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 4? -set fmri(conmask23_4) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 5? -set fmri(conmask23_5) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 6? -set fmri(conmask23_6) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 7? -set fmri(conmask23_7) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 8? -set fmri(conmask23_8) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 9? -set fmri(conmask23_9) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 10? -set fmri(conmask23_10) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 11? -set fmri(conmask23_11) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 12? -set fmri(conmask23_12) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 13? -set fmri(conmask23_13) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 14? -set fmri(conmask23_14) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 15? -set fmri(conmask23_15) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 16? -set fmri(conmask23_16) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 17? -set fmri(conmask23_17) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 18? -set fmri(conmask23_18) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 19? -set fmri(conmask23_19) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 20? -set fmri(conmask23_20) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 21? -set fmri(conmask23_21) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 22? -set fmri(conmask23_22) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 24? -set fmri(conmask23_24) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 25? -set fmri(conmask23_25) 0 - -# Mask real contrast/F-test 23 with real contrast/F-test 26? -set fmri(conmask23_26) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 1? -set fmri(conmask24_1) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 2? -set fmri(conmask24_2) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 3? -set fmri(conmask24_3) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 4? -set fmri(conmask24_4) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 5? -set fmri(conmask24_5) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 6? -set fmri(conmask24_6) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 7? -set fmri(conmask24_7) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 8? -set fmri(conmask24_8) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 9? -set fmri(conmask24_9) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 10? -set fmri(conmask24_10) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 11? -set fmri(conmask24_11) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 12? -set fmri(conmask24_12) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 13? -set fmri(conmask24_13) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 14? -set fmri(conmask24_14) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 15? -set fmri(conmask24_15) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 16? -set fmri(conmask24_16) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 17? -set fmri(conmask24_17) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 18? -set fmri(conmask24_18) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 19? -set fmri(conmask24_19) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 20? -set fmri(conmask24_20) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 21? -set fmri(conmask24_21) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 22? -set fmri(conmask24_22) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 23? -set fmri(conmask24_23) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 25? -set fmri(conmask24_25) 0 - -# Mask real contrast/F-test 24 with real contrast/F-test 26? -set fmri(conmask24_26) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 1? -set fmri(conmask25_1) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 2? -set fmri(conmask25_2) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 3? -set fmri(conmask25_3) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 4? -set fmri(conmask25_4) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 5? -set fmri(conmask25_5) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 6? -set fmri(conmask25_6) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 7? -set fmri(conmask25_7) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 8? -set fmri(conmask25_8) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 9? -set fmri(conmask25_9) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 10? -set fmri(conmask25_10) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 11? -set fmri(conmask25_11) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 12? -set fmri(conmask25_12) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 13? -set fmri(conmask25_13) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 14? -set fmri(conmask25_14) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 15? -set fmri(conmask25_15) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 16? -set fmri(conmask25_16) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 17? -set fmri(conmask25_17) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 18? -set fmri(conmask25_18) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 19? -set fmri(conmask25_19) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 20? -set fmri(conmask25_20) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 21? -set fmri(conmask25_21) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 22? -set fmri(conmask25_22) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 23? -set fmri(conmask25_23) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 24? -set fmri(conmask25_24) 0 - -# Mask real contrast/F-test 25 with real contrast/F-test 26? -set fmri(conmask25_26) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 1? -set fmri(conmask26_1) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 2? -set fmri(conmask26_2) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 3? -set fmri(conmask26_3) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 4? -set fmri(conmask26_4) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 5? -set fmri(conmask26_5) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 6? -set fmri(conmask26_6) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 7? -set fmri(conmask26_7) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 8? -set fmri(conmask26_8) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 9? -set fmri(conmask26_9) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 10? -set fmri(conmask26_10) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 11? -set fmri(conmask26_11) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 12? -set fmri(conmask26_12) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 13? -set fmri(conmask26_13) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 14? -set fmri(conmask26_14) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 15? -set fmri(conmask26_15) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 16? -set fmri(conmask26_16) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 17? -set fmri(conmask26_17) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 18? -set fmri(conmask26_18) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 19? -set fmri(conmask26_19) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 20? -set fmri(conmask26_20) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 21? -set fmri(conmask26_21) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 22? -set fmri(conmask26_22) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 23? -set fmri(conmask26_23) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 24? -set fmri(conmask26_24) 0 - -# Mask real contrast/F-test 26 with real contrast/F-test 25? -set fmri(conmask26_25) 0 - -# Do contrast masking at all? -set fmri(conmask1_1) 0 - -########################################################## -# Now options that don't appear in the GUI - -# Alternative (to BETting) mask image -set fmri(alternative_mask) "" - -# Initial structural space registration initialisation transform -set fmri(init_initial_highres) "" - -# Structural space registration initialisation transform -set fmri(init_highres) "" - -# Standard space registration initialisation transform -set fmri(init_standard) "" - -# For full FEAT analysis: overwrite existing .feat output dir? -set fmri(overwrite_yn) 0 diff --git a/pydra/tasks/fsl/tests/data/test.nii.gz b/pydra/tasks/fsl/tests/data/test.nii.gz deleted file mode 100644 index a25d016..0000000 --- a/pydra/tasks/fsl/tests/data/test.nii.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:05271ea95146ecc19af198d7052cdfa5ef98a6796b2179c6789422447978974a -size 28061534 diff --git a/pydra/tasks/fsl/tests/data/test2.nii b/pydra/tasks/fsl/tests/data/test2.nii deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/test3.nii b/pydra/tasks/fsl/tests/data/test3.nii deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/test_film_gls.nii.gz b/pydra/tasks/fsl/tests/data/test_film_gls.nii.gz deleted file mode 100644 index 75ee73d..0000000 --- a/pydra/tasks/fsl/tests/data/test_film_gls.nii.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f164986665ec302f7d09ebfb3fe8047df8787e24394e680d513e180e6a25df30 -size 27889429 diff --git a/pydra/tasks/fsl/tests/data/test_warpcoef.nii.gz b/pydra/tasks/fsl/tests/data/test_warpcoef.nii.gz deleted file mode 100644 index 0991c88..0000000 --- a/pydra/tasks/fsl/tests/data/test_warpcoef.nii.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bb3d96bd875f3bd3ccb37caa761336c7e9f52779d19cd21a059d777b04885785 -size 325 diff --git a/pydra/tasks/fsl/tests/data/timeDesign.con b/pydra/tasks/fsl/tests/data/timeDesign.con deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/timeDesign.mat b/pydra/tasks/fsl/tests/data/timeDesign.mat deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/varcope_merged.nii.gz b/pydra/tasks/fsl/tests/data/varcope_merged.nii.gz deleted file mode 100644 index d777854..0000000 --- a/pydra/tasks/fsl/tests/data/varcope_merged.nii.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:67fd15e24c00fd6736ca6a5492fb2b51672e20dde9aa693bc75a910f8c2ed4ca -size 23935446 diff --git a/pydra/tasks/fsl/tests/data/warpfield.nii b/pydra/tasks/fsl/tests/data/warpfield.nii deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/tests/data/warpfield.nii.gz b/pydra/tasks/fsl/tests/data/warpfield.nii.gz deleted file mode 100644 index a25d016..0000000 --- a/pydra/tasks/fsl/tests/data/warpfield.nii.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:05271ea95146ecc19af198d7052cdfa5ef98a6796b2179c6789422447978974a -size 28061534 diff --git a/pydra/tasks/fsl/tests/data/zstat1.nii.gz b/pydra/tasks/fsl/tests/data/zstat1.nii.gz deleted file mode 100644 index 246c3e4..0000000 --- a/pydra/tasks/fsl/tests/data/zstat1.nii.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:217ee66ca638ee732b7e82c16ff841f38aa7dd19b7a473d6e94b7de2fdb685e0 -size 961353 diff --git a/pydra/tasks/fsl/utils/__init__.py b/pydra/tasks/fsl/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/utils/complex.py b/pydra/tasks/fsl/utils/complex.py deleted file mode 100644 index 0170b06..0000000 --- a/pydra/tasks/fsl/utils/complex.py +++ /dev/null @@ -1,267 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def Complex_output(inputs): - import attr - - if inputs.complex_cartesian: - in_file = inputs.real_in_file - elif inputs.complex_polar: - in_file = inputs.magnitude_in_file - elif inputs.complex_split or inputs.complex_merge: - in_file = inputs.complex_in_file - else: - return None - return f"{in_file}_cplx" - - -input_fields = [ - ( - "complex_in_file", - specs.File, - {"help_string": "", "argstr": "{complex_in_file}", "position": 2}, - ), - ( - "complex_in_file2", - specs.File, - {"help_string": "", "argstr": "{complex_in_file2}", "position": 3}, - ), - ( - "real_in_file", - specs.File, - {"help_string": "", "argstr": "{real_in_file}", "position": 2}, - ), - ( - "imaginary_in_file", - specs.File, - {"help_string": "", "argstr": "{imaginary_in_file}", "position": 3}, - ), - ( - "magnitude_in_file", - specs.File, - {"help_string": "", "argstr": "{magnitude_in_file}", "position": 2}, - ), - ( - "phase_in_file", - specs.File, - {"help_string": "", "argstr": "{phase_in_file}", "position": 3}, - ), - ( - "complex_out_file", - str, - { - "help_string": "", - "argstr": "{complex_out_file}", - "position": -3, - "xor": [ - "complex_out_file", - "magnitude_out_file", - "phase_out_file", - "real_out_file", - "imaginary_out_file", - "real_polar", - "real_cartesian", - ], - }, - ), - ( - "magnitude_out_file", - str, - { - "help_string": "", - "argstr": "{magnitude_out_file}", - "position": -4, - "xor": [ - "complex_out_file", - "real_out_file", - "imaginary_out_file", - "real_cartesian", - "complex_cartesian", - "complex_polar", - "complex_split", - "complex_merge", - ], - "output_file_template": "{in_file}_mag", - }, - ), - ( - "phase_out_file", - str, - { - "help_string": "", - "argstr": "{phase_out_file}", - "position": -3, - "xor": [ - "complex_out_file", - "real_out_file", - "imaginary_out_file", - "real_cartesian", - "complex_cartesian", - "complex_polar", - "complex_split", - "complex_merge", - ], - "output_file_template": "{in_file}_phase", - }, - ), - ( - "real_out_file", - str, - { - "help_string": "", - "argstr": "{real_out_file}", - "position": -4, - "xor": [ - "complex_out_file", - "magnitude_out_file", - "phase_out_file", - "real_polar", - "complex_cartesian", - "complex_polar", - "complex_split", - "complex_merge", - ], - "output_file_template": "{in_file}_real", - }, - ), - ( - "imaginary_out_file", - str, - { - "help_string": "", - "argstr": "{imaginary_out_file}", - "position": -3, - "xor": [ - "complex_out_file", - "magnitude_out_file", - "phase_out_file", - "real_polar", - "complex_cartesian", - "complex_polar", - "complex_split", - "complex_merge", - ], - "output_file_template": "{in_file}_imag", - }, - ), - ("start_vol", int, {"help_string": "", "argstr": "{start_vol}", "position": -2}), - ("end_vol", int, {"help_string": "", "argstr": "{end_vol}", "position": -1}), - ( - "real_polar", - bool, - { - "help_string": "", - "argstr": "-realpolar", - "position": 1, - "xor": [ - "real_polar", - "real_cartesian", - "complex_cartesian", - "complex_polar", - "complex_split", - "complex_merge", - ], - }, - ), - ( - "real_cartesian", - bool, - { - "help_string": "", - "argstr": "-realcartesian", - "position": 1, - "xor": [ - "real_polar", - "real_cartesian", - "complex_cartesian", - "complex_polar", - "complex_split", - "complex_merge", - ], - }, - ), - ( - "complex_cartesian", - bool, - { - "help_string": "", - "argstr": "-complex", - "position": 1, - "xor": [ - "real_polar", - "real_cartesian", - "complex_cartesian", - "complex_polar", - "complex_split", - "complex_merge", - ], - }, - ), - ( - "complex_polar", - bool, - { - "help_string": "", - "argstr": "-complexpolar", - "position": 1, - "xor": [ - "real_polar", - "real_cartesian", - "complex_cartesian", - "complex_polar", - "complex_split", - "complex_merge", - ], - }, - ), - ( - "complex_split", - bool, - { - "help_string": "", - "argstr": "-complexsplit", - "position": 1, - "xor": [ - "real_polar", - "real_cartesian", - "complex_cartesian", - "complex_polar", - "complex_split", - "complex_merge", - ], - }, - ), - ( - "complex_merge", - bool, - { - "help_string": "", - "argstr": "-complexmerge", - "position": 1, - "xor": [ - "real_polar", - "real_cartesian", - "complex_cartesian", - "complex_polar", - "complex_split", - "complex_merge", - "start_vol", - "end_vol", - ], - }, - ), -] -Complex_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -Complex_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class Complex(ShellCommandTask): - input_spec = Complex_input_spec - output_spec = Complex_output_spec - executable = "fslcomplex" diff --git a/pydra/tasks/fsl/utils/convertwarp.py b/pydra/tasks/fsl/utils/convertwarp.py deleted file mode 100644 index 5d8ab40..0000000 --- a/pydra/tasks/fsl/utils/convertwarp.py +++ /dev/null @@ -1,169 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "reference", - specs.File, - { - "help_string": "Name of a file in target space of the full transform.", - "argstr": "--ref={reference}", - "mandatory": True, - "position": 1, - }, - ), - ( - "out_file", - str, - { - "help_string": "Name of output file, containing warps that are the combination of all those given as arguments. The format of this will be a field-file (rather than spline coefficients) with any affine components included.", - "argstr": "--out={out_file}", - "position": -1, - "output_file_template": "{reference}_concatwarp", - }, - ), - ( - "premat", - specs.File, - { - "help_string": "filename for pre-transform (affine matrix)", - "argstr": "--premat={premat}", - }, - ), - ( - "warp1", - specs.File, - { - "help_string": "Name of file containing initial warp-fields/coefficients (follows premat). This could e.g. be a fnirt-transform from a subjects structural scan to an average of a group of subjects.", - "argstr": "--warp1={warp1}", - }, - ), - ( - "midmat", - specs.File, - { - "help_string": "Name of file containing mid-warp-affine transform", - "argstr": "--midmat={midmat}", - }, - ), - ( - "warp2", - specs.File, - { - "help_string": "Name of file containing secondary warp-fields/coefficients (after warp1/midmat but before postmat). This could e.g. be a fnirt-transform from the average of a group of subjects to some standard space (e.g. MNI152).", - "argstr": "--warp2={warp2}", - }, - ), - ( - "postmat", - specs.File, - { - "help_string": "Name of file containing an affine transform (applied last). It could e.g. be an affine transform that maps the MNI152-space into a better approximation to the Talairach-space (if indeed there is one).", - "argstr": "--postmat={postmat}", - }, - ), - ( - "shift_in_file", - specs.File, - { - "help_string": 'Name of file containing a "shiftmap", a non-linear transform with displacements only in one direction (applied first, before premat). This would typically be a fieldmap that has been pre-processed using fugue that maps a subjects functional (EPI) data onto an undistorted space (i.e. a space that corresponds to his/her true anatomy).', - "argstr": "--shiftmap={shift_in_file}", - }, - ), - ( - "shift_direction", - ty.Any, - { - "help_string": "Indicates the direction that the distortions from --shiftmap goes. It depends on the direction and polarity of the phase-encoding in the EPI sequence.", - "argstr": "--shiftdir={shift_direction}", - "requires": ["shift_in_file"], - }, - ), - ( - "cons_jacobian", - bool, - { - "help_string": "Constrain the Jacobian of the warpfield to lie within specified min/max limits.", - "argstr": "--constrainj", - }, - ), - ( - "jacobian_min", - float, - { - "help_string": "Minimum acceptable Jacobian value for constraint (default 0.01)", - "argstr": "--jmin={jacobian_min}", - }, - ), - ( - "jacobian_max", - float, - { - "help_string": "Maximum acceptable Jacobian value for constraint (default 100.0)", - "argstr": "--jmax={jacobian_max}", - }, - ), - ( - "abswarp", - bool, - { - "help_string": "If set it indicates that the warps in --warp1 and --warp2 should be interpreted as absolute. I.e. the values in --warp1/2 are the coordinates in the next space, rather than displacements. This flag is ignored if --warp1/2 was created by fnirt, which always creates relative displacements.", - "argstr": "--abs", - "xor": ["relwarp"], - }, - ), - ( - "relwarp", - bool, - { - "help_string": "If set it indicates that the warps in --warp1/2 should be interpreted as relative. I.e. the values in --warp1/2 are displacements from the coordinates in the next space.", - "argstr": "--rel", - "xor": ["abswarp"], - }, - ), - ( - "out_abswarp", - bool, - { - "help_string": "If set it indicates that the warps in --out should be absolute, i.e. the values in --out are displacements from the coordinates in --ref.", - "argstr": "--absout", - "xor": ["out_relwarp"], - }, - ), - ( - "out_relwarp", - bool, - { - "help_string": "If set it indicates that the warps in --out should be relative, i.e. the values in --out are displacements from the coordinates in --ref.", - "argstr": "--relout", - "xor": ["out_abswarp"], - }, - ), -] -ConvertWarp_input_spec = specs.SpecInfo( - name="Input", fields=input_fields, bases=(specs.ShellSpec,) -) - -output_fields = [] -ConvertWarp_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class ConvertWarp(ShellCommandTask): - """ - Example - ------- - >>> task = ConvertWarp() - >>> task.inputs.warp1 = "warpfield.nii" - >>> task.inputs.reference = "test.nii.gz" - >>> task.inputs.relwarp = True - >>> task.inputs.out_file = "test_concatwarp.nii.gz" - >>> task.cmdline - 'convertwarp --ref=test.nii.gz --warp1=warpfield.nii --rel --out=test_concatwarp.nii.gz' - """ - - input_spec = ConvertWarp_input_spec - output_spec = ConvertWarp_output_spec - executable = "convertwarp" diff --git a/pydra/tasks/fsl/utils/convertxfm.py b/pydra/tasks/fsl/utils/convertxfm.py deleted file mode 100644 index 48dc601..0000000 --- a/pydra/tasks/fsl/utils/convertxfm.py +++ /dev/null @@ -1,110 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def ConvertXFM_output(inputs): - import attr - - in_file = inputs.in_file - if inputs.invert_xfm: - return f"{in_file}_inv" - elif inputs.concat_xfm: - if inputs.in_file2.exists(): - in_file2 = inputs.in_file2 - return f"{in_file}_{in_file2}" - else: - raise Exception("in_file2 is needed to use concat_xfm") - - elif inputs.fix_scale_skew: - return f"{in_file}_fix" - else: - raise Exception("this function requires invert_xfm, or concat_xfm," "or fix_scale_skew") - - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input transformation matrix", - "argstr": "{in_file}", - "mandatory": True, - "position": -1, - }, - ), - ( - "in_file2", - specs.File, - { - "help_string": "second input matrix (for use with fix_scale_skew or concat_xfm)", - "argstr": "{in_file2}", - "position": -2, - }, - ), - ( - "invert_xfm", - bool, - { - "help_string": "invert input transformation", - "argstr": "-inverse", - "position": -3, - "xor": ["invert_xfm", "concat_xfm", "fix_scale_skew"], - }, - ), - ( - "concat_xfm", - bool, - { - "help_string": "write joint transformation of two input matrices", - "argstr": "-concat", - "position": -3, - "requires": ["in_file2"], - "xor": ["invert_xfm", "concat_xfm", "fix_scale_skew"], - }, - ), - ( - "fix_scale_skew", - bool, - { - "help_string": "use secondary matrix to fix scale and skew", - "argstr": "-fixscaleskew", - "position": -3, - "requires": ["in_file2"], - "xor": ["invert_xfm", "concat_xfm", "fix_scale_skew"], - }, - ), - ( - "out_file", - str, - { - "help_string": "final transformation matrix", - "argstr": "-omat {out_file}", - "position": 1, - "output_file_template": ConvertXFM_output, - }, - ), -] -ConvertXFM_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -ConvertXFM_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class ConvertXFM(ShellCommandTask): - """ - Example - ------- - >>> task = ConvertXFM() - >>> task.inputs.in_file = "flirt.mat" - >>> task.inputs.invert_xfm = True - >>> task.inputs.out_file = "flirt_inv.mat" - >>> task.cmdline - 'convert_xfm -omat flirt_inv.mat -inverse flirt.mat' - """ - - input_spec = ConvertXFM_input_spec - output_spec = ConvertXFM_output_spec - executable = "convert_xfm" diff --git a/pydra/tasks/fsl/utils/copygeom.py b/pydra/tasks/fsl/utils/copygeom.py deleted file mode 100644 index 11b94c7..0000000 --- a/pydra/tasks/fsl/utils/copygeom.py +++ /dev/null @@ -1,69 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "source image", - "argstr": "{in_file}", - "mandatory": True, - "position": 0, - }, - ), - ( - "dest_file", - str, - { - "help_string": "destination image", - "argstr": "{dest_file}", - "copyfile": True, - "mandatory": True, - "position": 1, - "output_file_template": "{dest_file}", - }, - ), - ( - "ignore_dims", - bool, - { - "help_string": "Do not copy image dimensions", - "argstr": "-d", - "position": "-1", - }, - ), -] -CopyGeom_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "out_file", - specs.File, - { - "help_string": "image with new geometry header", - "requires": ["in_file", "dest_file"], - "output_file_template": "{dest_file}", - }, - ) -] -CopyGeom_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class CopyGeom(ShellCommandTask): - """ - Example - ------- - >>> task = CopyGeom() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.dest_file = "dest.nii.gz" - >>> task.cmdline - 'fslcpgeom test.nii.gz dest.nii.gz' - """ - - input_spec = CopyGeom_input_spec - output_spec = CopyGeom_output_spec - executable = "fslcpgeom" diff --git a/pydra/tasks/fsl/utils/extractroi.py b/pydra/tasks/fsl/utils/extractroi.py deleted file mode 100644 index da34f08..0000000 --- a/pydra/tasks/fsl/utils/extractroi.py +++ /dev/null @@ -1,58 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input file", - "argstr": "{in_file}", - "mandatory": True, - "position": 0, - }, - ), - ( - "roi_file", - str, - { - "help_string": "output file", - "argstr": "{roi_file}", - "position": 1, - "output_file_template": "{in_file}_trim", - }, - ), - ("x_min", int, {"help_string": "", "argstr": "{x_min}", "position": 2}), - ("x_size", int, {"help_string": "", "argstr": "{x_size}", "position": 3}), - ("y_min", int, {"help_string": "", "argstr": "{y_min}", "position": 4}), - ("y_size", int, {"help_string": "", "argstr": "{y_size}", "position": 5}), - ("z_min", int, {"help_string": "", "argstr": "{z_min}", "position": 6}), - ("z_size", int, {"help_string": "", "argstr": "{z_size}", "position": 7}), - ("t_min", int, {"help_string": "", "argstr": "{t_min}", "position": 8}), - ("t_size", int, {"help_string": "", "argstr": "{t_size}", "position": 9}), -] -ExtractROI_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -ExtractROI_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class ExtractROI(ShellCommandTask): - """ - Example - ------- - >>> task = ExtractROI() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.t_min = 0 - >>> task.inputs.t_size = 3 - >>> task.inputs.roi_file = "test_trim.nii.gz" - >>> task.cmdline - 'fslroi test.nii.gz test_trim.nii.gz 0 3' - """ - - input_spec = ExtractROI_input_spec - output_spec = ExtractROI_output_spec - executable = "fslroi" diff --git a/pydra/tasks/fsl/utils/filterregressor.py b/pydra/tasks/fsl/utils/filterregressor.py deleted file mode 100644 index 21985d0..0000000 --- a/pydra/tasks/fsl/utils/filterregressor.py +++ /dev/null @@ -1,91 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input file name (4D image)", - "argstr": "-i {in_file}", - "mandatory": True, - "position": 1, - }, - ), - ( - "out_file", - str, - { - "help_string": "output file name for the filtered data", - "argstr": "-o {out_file}", - "position": 2, - "output_file_template": "{in_file}_filtered", - }, - ), - ( - "design_file", - specs.File, - { - "help_string": "name of the matrix with time courses (e.g. GLM design or MELODIC mixing matrix)", - "argstr": "-d {design_file}", - "mandatory": True, - "position": 3, - }, - ), - ( - "filter_columns", - list, - { - "help_string": "(1-based) column indices to filter out of the data", - "argstr": "-f '{filter_columns}'", - "mandatory": True, - "position": 4, - "xor": ["filter_all"], - }, - ), - ( - "mask", - specs.File, - {"help_string": "mask image file name", "argstr": "-m {mask}"}, - ), - ( - "var_norm", - bool, - {"help_string": "perform variance-normalization on data", "argstr": "--vn"}, - ), - ( - "out_vnscales", - bool, - { - "help_string": "output scaling factors for variance normalization", - "argstr": "--out_vnscales", - }, - ), -] -FilterRegressor_input_spec = specs.SpecInfo( - name="Input", fields=input_fields, bases=(specs.ShellSpec,) -) - -output_fields = [] -FilterRegressor_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class FilterRegressor(ShellCommandTask): - """ - Example - ------- - >>> task = FilterRegressor() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.design_file = "design" - >>> task.inputs.filter_columns = "1,2,3" - >>> task.inputs.out_file = "test_filtered.nii.gz" - >>> task.cmdline - 'fsl_regfilt -i test.nii.gz -o test_filtered.nii.gz -d design -f 1,2,3' - """ - - input_spec = FilterRegressor_input_spec - output_spec = FilterRegressor_output_spec - executable = "fsl_regfilt" diff --git a/pydra/tasks/fsl/utils/imagemaths.py b/pydra/tasks/fsl/utils/imagemaths.py deleted file mode 100644 index 7cdf89e..0000000 --- a/pydra/tasks/fsl/utils/imagemaths.py +++ /dev/null @@ -1,75 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - {"help_string": "", "argstr": "{in_file}", "mandatory": True, "position": 1}, - ), - ( - "in_file2", - specs.File, - {"help_string": "", "argstr": "{in_file2}", "position": 3}, - ), - ( - "mask_file", - specs.File, - { - "help_string": "use (following image>0) to mask current image", - "argstr": "-mas {mask_file}", - }, - ), - ( - "out_file", - str, - { - "help_string": "", - "argstr": "{out_file}", - "position": -2, - "output_file_template": "{in_file}_maths", - }, - ), - ( - "op_string", - str, - { - "help_string": "string defining the operation, i. e. -add", - "argstr": "{op_string}", - "position": 2, - }, - ), - ( - "out_data_type", - ty.Any, - { - "help_string": "output datatype, one of (char, short, int, float, double, input)", - "argstr": "-odt {out_data_type}", - "position": -1, - }, - ), -] -ImageMaths_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -ImageMaths_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class ImageMaths(ShellCommandTask): - """ - Example - ------- - >>> task = ImageMaths() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.op_string = "-add 5" - >>> task.inputs.out_file = "test_maths.nii.gz" - >>> task.cmdline - 'fslmaths test.nii.gz -add 5 test_maths.nii.gz' - """ - - input_spec = ImageMaths_input_spec - output_spec = ImageMaths_output_spec - executable = "fslmaths" diff --git a/pydra/tasks/fsl/utils/imagemeants.py b/pydra/tasks/fsl/utils/imagemeants.py deleted file mode 100644 index 64b0eef..0000000 --- a/pydra/tasks/fsl/utils/imagemeants.py +++ /dev/null @@ -1,105 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input file for computing the average timeseries", - "argstr": "-i {in_file}", - "mandatory": True, - "position": 0, - }, - ), - ( - "out_file", - str, - { - "help_string": "name of output text matrix", - "argstr": "-o {out_file}", - "output_file_template": "{in_file}_meants.txt", - }, - ), - ("mask", specs.File, {"help_string": "input 3D mask", "argstr": "-m {mask}"}), - ( - "spatial_coord", - list, - { - "help_string": " requested spatial coordinate (instead of mask)", - "argstr": "-c {spatial_coord}", - }, - ), - ( - "use_mm", - bool, - { - "help_string": "use mm instead of voxel coordinates (for -c option)", - "argstr": "--usemm", - }, - ), - ( - "show_all", - bool, - { - "help_string": "show all voxel time series (within mask) instead of averaging", - "argstr": "--showall", - }, - ), - ( - "eig", - bool, - { - "help_string": "calculate Eigenvariate(s) instead of mean (output will have 0 mean)", - "argstr": "--eig", - }, - ), - ( - "order", - int, - 1, - {"help_string": "select number of Eigenvariates", "argstr": "--order={order}"}, - ), - ( - "nobin", - bool, - { - "help_string": "do not binarise the mask for calculation of Eigenvariates", - "argstr": "--no_bin", - }, - ), - ( - "transpose", - bool, - { - "help_string": "output results in transpose format (one row per voxel/mean)", - "argstr": "--transpose", - }, - ), -] -ImageMeants_input_spec = specs.SpecInfo( - name="Input", fields=input_fields, bases=(specs.ShellSpec,) -) - -output_fields = [] -ImageMeants_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class ImageMeants(ShellCommandTask): - """ - Example - ------- - >>> task = ImageMeants() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.mask = "mask.nii.gz" - >>> task.inputs.out_file = "test_meants.txt" - >>> task.cmdline - 'fslmeants -i test.nii.gz -o test_meants.txt -m mask.nii.gz --order=1' - """ - - input_spec = ImageMeants_input_spec - output_spec = ImageMeants_output_spec - executable = "fslmeants" diff --git a/pydra/tasks/fsl/utils/imagestats.py b/pydra/tasks/fsl/utils/imagestats.py deleted file mode 100644 index 54a6438..0000000 --- a/pydra/tasks/fsl/utils/imagestats.py +++ /dev/null @@ -1,77 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "split_4d", - bool, - { - "help_string": "give a separate output line for each 3D volume of a 4D timeseries", - "argstr": "-t", - "position": 1, - }, - ), - ( - "in_file", - specs.File, - { - "help_string": "input file to generate stats of", - "argstr": "{in_file}", - "mandatory": True, - "position": 3, - }, - ), - ( - "op_string", - str, - { - "help_string": "string defining the operation, options are applied in order, e.g. -M -l 10 -M will report the non-zero mean, apply a threshold and then report the new nonzero mean", - "argstr": "{op_string}", - "mandatory": True, - "position": 4, - }, - ), - ( - "mask_file", - specs.File, - {"help_string": "mask file used for option -k %s", "argstr": ""}, - ), - ( - "index_mask_file", - specs.File, - { - "help_string": "generate seperate n submasks from indexMask, for indexvalues 1..n where n is the maximum index value in indexMask, and generate statistics for each submask", - "argstr": "-K {index_mask_file}", - "position": 2, - }, - ), -] -ImageStats_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "out_stat", - ty.Any, - {"help_string": "stats output", "requires": ["in_file", "op_string"]}, - ) -] -ImageStats_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class ImageStats(ShellCommandTask): - """ - Example - ------- - >>> task = ImageStats() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.op_string = "-M" - >>> task.cmdline - 'fslstats test.nii.gz -M' - """ - - input_spec = ImageStats_input_spec - output_spec = ImageStats_output_spec - executable = "fslstats" diff --git a/pydra/tasks/fsl/utils/invwarp.py b/pydra/tasks/fsl/utils/invwarp.py deleted file mode 100644 index 26b77c5..0000000 --- a/pydra/tasks/fsl/utils/invwarp.py +++ /dev/null @@ -1,111 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "warp", - specs.File, - { - "help_string": "Name of file containing warp-coefficients/fields. This would typically be the output from the --cout switch of fnirt (but can also use fields, like the output from --fout).", - "argstr": "--warp={warp}", - "mandatory": True, - }, - ), - ( - "reference", - specs.File, - { - "help_string": "Name of a file in target space. Note that the target space is now different from the target space that was used to create the --warp file. It would typically be the file that was specified with the --in argument when running fnirt.", - "argstr": "--ref={reference}", - "mandatory": True, - }, - ), - ( - "inverse_warp", - str, - { - "help_string": 'Name of output file, containing warps that are the "reverse" of those in --warp. This will be a field-file (rather than a file of spline coefficients), and it will have any affine component included as part of the displacements.', - "argstr": "--out={inverse_warp}", - "output_file_template": "{warp}_inverse", - }, - ), - ( - "absolute", - bool, - { - "help_string": "If set it indicates that the warps in --warp should be interpreted as absolute, provided that it is not created by fnirt (which always uses relative warps). If set it also indicates that the output --out should be absolute.", - "argstr": "--abs", - "xor": ["relative"], - }, - ), - ( - "relative", - bool, - { - "help_string": "If set it indicates that the warps in --warp should be interpreted as relative. I.e. the values in --warp are displacements from the coordinates in the --ref space. If set it also indicates that the output --out should be relative.", - "argstr": "--rel", - "xor": ["absolute"], - }, - ), - ( - "niter", - int, - { - "help_string": "Determines how many iterations of the gradient-descent search that should be run.", - "argstr": "--niter={niter}", - }, - ), - ( - "regularise", - float, - { - "help_string": "Regularization strength (deafult=1.0).", - "argstr": "--regularise={regularise}", - }, - ), - ( - "noconstraint", - bool, - {"help_string": "Do not apply Jacobian constraint", "argstr": "--noconstraint"}, - ), - ( - "jacobian_min", - float, - { - "help_string": "Minimum acceptable Jacobian value for constraint (default 0.01)", - "argstr": "--jmin={jacobian_min}", - }, - ), - ( - "jacobian_max", - float, - { - "help_string": "Maximum acceptable Jacobian value for constraint (default 100.0)", - "argstr": "--jmax={jacobian_max}", - }, - ), -] -InvWarp_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -InvWarp_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class InvWarp(ShellCommandTask): - """ - Example - ------- - >>> task = InvWarp() - >>> task.inputs.reference = "anatomical.nii" - >>> task.inputs.warp = "struct2mni.nii" - >>> task.inputs.inverse_warp = "struct2mni_inverse.nii.gz" - >>> task.cmdline - 'invwarp --warp=struct2mni.nii --ref=anatomical.nii --out=struct2mni_inverse.nii.gz' - """ - - input_spec = InvWarp_input_spec - output_spec = InvWarp_output_spec - executable = "invwarp" diff --git a/pydra/tasks/fsl/utils/slice.py b/pydra/tasks/fsl/utils/slice.py deleted file mode 100644 index f728857..0000000 --- a/pydra/tasks/fsl/utils/slice.py +++ /dev/null @@ -1,44 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input filename", - "argstr": "{in_file}", - "copyfile": False, - "mandatory": True, - "position": 0, - }, - ), - ( - "out_base_name", - str, - {"help_string": "outputs prefix", "argstr": "{out_base_name}", "position": 1}, - ), -] -Slice_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -Slice_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class Slice(ShellCommandTask): - """ - Example - ------- - >>> task = Slice() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.out_base_name = "sl" - >>> task.cmdline - 'fslslice test.nii.gz sl' - """ - - input_spec = Slice_input_spec - output_spec = Slice_output_spec - executable = "fslslice" diff --git a/pydra/tasks/fsl/utils/smooth.py b/pydra/tasks/fsl/utils/smooth.py deleted file mode 100644 index cc24ae7..0000000 --- a/pydra/tasks/fsl/utils/smooth.py +++ /dev/null @@ -1,55 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - {"help_string": "", "argstr": "{in_file}", "mandatory": True, "position": 0}, - ), - ( - "sigma", - float, - { - "help_string": "gaussian kernel sigma in mm (not voxels)", - "argstr": "-kernel gauss {sigma:.03f} -fmean", - "mandatory": True, - "position": 1, - "xor": ["fwhm"], - }, - ), - ( - "smoothed_file", - str, - { - "help_string": "", - "argstr": "{smoothed_file}", - "position": 2, - "output_file_template": "{in_file}_smooth", - }, - ), -] -Smooth_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [] -Smooth_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class Smooth(ShellCommandTask): - """ - Example - ------- - >>> task = Smooth() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.sigma = 3.397 - >>> task.inputs.smoothed_file = "test_smooth.nii.gz" - >>> task.cmdline - 'fslmaths test.nii.gz -kernel gauss 3.397 -fmean test_smooth.nii.gz' - """ - - input_spec = Smooth_input_spec - output_spec = Smooth_output_spec - executable = "fslmaths" diff --git a/pydra/tasks/fsl/utils/split.py b/pydra/tasks/fsl/utils/split.py deleted file mode 100644 index cc001c6..0000000 --- a/pydra/tasks/fsl/utils/split.py +++ /dev/null @@ -1,72 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - - -def Split_output(inputs): - import os, glob - - output_dir = os.getcwd() - return sorted(glob.glob(os.path.join(output_dir, f"{inputs.output_basename}*.*"))) - - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input filename", - "argstr": "{in_file}", - "mandatory": True, - "position": 0, - }, - ), - ( - "output_basename", - str, - {"help_string": "outputs prefix", "argstr": "{output_basename}", "position": 1}, - ), - ( - "dimension", - ty.Any, - { - "help_string": "dimension along which the file will be split", - "argstr": "-{dimension}", - "mandatory": True, - "position": 2, - }, - ), -] -Split_input_spec = specs.SpecInfo(name="Input", fields=input_fields, bases=(specs.ShellSpec,)) - -output_fields = [ - ( - "out_files", - specs.MultiOutputFile, - { - "help_string": "output files", - "requires": ["in_file", "output_basename", "dimension"], - "callable": Split_output, - }, - ) -] -Split_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class Split(ShellCommandTask): - """ - Example - ------- - >>> task = Split() - >>> task.inputs.in_file = "test.nii.gz" - >>> task.inputs.output_basename = "test_split" - >>> task.inputs.dimension = "t" - >>> task.cmdline - 'fslsplit test.nii.gz test_split -t' - """ - - input_spec = Split_input_spec - output_spec = Split_output_spec - executable = "fslsplit" diff --git a/pydra/tasks/fsl/utils/swapdimensions.py b/pydra/tasks/fsl/utils/swapdimensions.py deleted file mode 100644 index 9731072..0000000 --- a/pydra/tasks/fsl/utils/swapdimensions.py +++ /dev/null @@ -1,48 +0,0 @@ -from pydra.engine import specs -from pydra import ShellCommandTask -import typing as ty - -input_fields = [ - ( - "in_file", - specs.File, - { - "help_string": "input image", - "argstr": "{in_file}", - "mandatory": True, - "position": "1", - }, - ), - ( - "new_dims", - ty.Any, - { - "help_string": "3-tuple of new dimension order", - "argstr": "{new_dims} {new_dims} {new_dims}", - "mandatory": True, - }, - ), - ( - "out_file", - str, - { - "help_string": "image to write", - "argstr": "{out_file}", - "output_file_template": "{in_file}_newdims", - }, - ), -] -SwapDimensions_input_spec = specs.SpecInfo( - name="Input", fields=input_fields, bases=(specs.ShellSpec,) -) - -output_fields = [] -SwapDimensions_output_spec = specs.SpecInfo( - name="Output", fields=output_fields, bases=(specs.ShellOutSpec,) -) - - -class SwapDimensions(ShellCommandTask): - input_spec = SwapDimensions_input_spec - output_spec = SwapDimensions_output_spec - executable = "fslswapdim" diff --git a/pydra/tasks/fsl/utils/tests/__init__.py b/pydra/tasks/fsl/utils/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pydra/tasks/fsl/utils/tests/test_run_complex.py b/pydra/tasks/fsl/utils/tests/test_run_complex.py deleted file mode 100644 index 3b8279a..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_complex.py +++ /dev/null @@ -1,72 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..complex import Complex - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_Complex(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = Complex(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = Complex(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_Complex_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = Complex(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = Complex(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_run_convertwarp.py b/pydra/tasks/fsl/utils/tests/test_run_convertwarp.py deleted file mode 100644 index cb2ab5a..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_convertwarp.py +++ /dev/null @@ -1,72 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..convertwarp import ConvertWarp - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_ConvertWarp(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ConvertWarp(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ConvertWarp(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_ConvertWarp_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ConvertWarp(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ConvertWarp(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_run_convertxfm.py b/pydra/tasks/fsl/utils/tests/test_run_convertxfm.py deleted file mode 100644 index ea9abea..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_convertxfm.py +++ /dev/null @@ -1,43 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..convertxfm import ConvertXFM - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", [({"in_file": "flirt.mat", "invert_xfm": True}, ["out_file"])] -) -def test_ConvertXFM(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ConvertXFM(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ConvertXFM(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) diff --git a/pydra/tasks/fsl/utils/tests/test_run_copygeom.py b/pydra/tasks/fsl/utils/tests/test_run_copygeom.py deleted file mode 100644 index 9ee77fd..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_copygeom.py +++ /dev/null @@ -1,72 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..copygeom import CopyGeom - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_CopyGeom(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = CopyGeom(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = CopyGeom(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_CopyGeom_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = CopyGeom(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = CopyGeom(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_run_extractroi.py b/pydra/tasks/fsl/utils/tests/test_run_extractroi.py deleted file mode 100644 index e3bddd8..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_extractroi.py +++ /dev/null @@ -1,44 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..extractroi import ExtractROI - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", - [({"in_file": "test.nii.gz", "t_min": 0, "t_size": 1}, ["roi_file"])], -) -def test_ExtractROI(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ExtractROI(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ExtractROI(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) diff --git a/pydra/tasks/fsl/utils/tests/test_run_filterregressor.py b/pydra/tasks/fsl/utils/tests/test_run_filterregressor.py deleted file mode 100644 index 27e9983..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_filterregressor.py +++ /dev/null @@ -1,72 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..filterregressor import FilterRegressor - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_FilterRegressor(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FilterRegressor(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FilterRegressor(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FilterRegressor_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FilterRegressor(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FilterRegressor(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_run_imagemaths.py b/pydra/tasks/fsl/utils/tests/test_run_imagemaths.py deleted file mode 100644 index ef0dd5a..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_imagemaths.py +++ /dev/null @@ -1,41 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..imagemaths import ImageMaths - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", [(None, ["out_file"])]) -def test_ImageMaths(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ImageMaths(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ImageMaths(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) diff --git a/pydra/tasks/fsl/utils/tests/test_run_imagemeants.py b/pydra/tasks/fsl/utils/tests/test_run_imagemeants.py deleted file mode 100644 index 240d2bf..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_imagemeants.py +++ /dev/null @@ -1,41 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..imagemeants import ImageMeants - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", [(None, ["out_file"])]) -def test_ImageMeants(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ImageMeants(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ImageMeants(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) diff --git a/pydra/tasks/fsl/utils/tests/test_run_imagestats.py b/pydra/tasks/fsl/utils/tests/test_run_imagestats.py deleted file mode 100644 index 59023c2..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_imagestats.py +++ /dev/null @@ -1,72 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..imagestats import ImageStats - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_ImageStats(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ImageStats(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ImageStats(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_ImageStats_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ImageStats(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ImageStats(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_run_invwarp.py b/pydra/tasks/fsl/utils/tests/test_run_invwarp.py deleted file mode 100644 index 9933a37..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_invwarp.py +++ /dev/null @@ -1,72 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..invwarp import InvWarp - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_InvWarp(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = InvWarp(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = InvWarp(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_InvWarp_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = InvWarp(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = InvWarp(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_run_slice.py b/pydra/tasks/fsl/utils/tests/test_run_slice.py deleted file mode 100644 index cfe8272..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_slice.py +++ /dev/null @@ -1,22 +0,0 @@ -import os, pytest -from pathlib import Path -from ..slice import Slice - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", [(None, [])]) -def test_Slice(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = Slice(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - assert getattr(res.output, out_nm).exists() diff --git a/pydra/tasks/fsl/utils/tests/test_run_smooth.py b/pydra/tasks/fsl/utils/tests/test_run_smooth.py deleted file mode 100644 index e6b34a5..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_smooth.py +++ /dev/null @@ -1,43 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..smooth import Smooth - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", [({"in_file": "test.nii.gz", "sigma": 3.397}, ["smoothed_file"])] -) -def test_Smooth(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = Smooth(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = Smooth(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) diff --git a/pydra/tasks/fsl/utils/tests/test_run_split.py b/pydra/tasks/fsl/utils/tests/test_run_split.py deleted file mode 100644 index 970a85e..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_split.py +++ /dev/null @@ -1,53 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..split import Split - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize( - "inputs, outputs", - [ - ( - { - "in_file": "test.nii.gz", - "output_basename": "test_split", - "dimension": "t", - }, - ["out_files"], - ) - ], -) -def test_Split(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = Split(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = Split(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) diff --git a/pydra/tasks/fsl/utils/tests/test_run_swapdimensions.py b/pydra/tasks/fsl/utils/tests/test_run_swapdimensions.py deleted file mode 100644 index fd8b523..0000000 --- a/pydra/tasks/fsl/utils/tests/test_run_swapdimensions.py +++ /dev/null @@ -1,72 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..swapdimensions import SwapDimensions - - -@pytest.mark.xfail("FSLDIR" not in os.environ, reason="no FSL found", raises=FileNotFoundError) -@pytest.mark.parametrize("inputs, outputs", []) -def test_SwapDimensions(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = SwapDimensions(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = SwapDimensions(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - res = task() - print("RESULT: ", res) - for out_nm in outputs: - if isinstance(getattr(res.output, out_nm), list): - assert [os.path.exists(x) for x in getattr(res.output, out_nm)] - else: - assert os.path.exists(getattr(res.output, out_nm)) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_SwapDimensions_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = SwapDimensions(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = SwapDimensions(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_spec_complex.py b/pydra/tasks/fsl/utils/tests/test_spec_complex.py deleted file mode 100644 index 2ab9134..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_complex.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..complex import Complex - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_Complex(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = Complex(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = Complex(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_Complex_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = Complex(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = Complex(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_spec_convertwarp.py b/pydra/tasks/fsl/utils/tests/test_spec_convertwarp.py deleted file mode 100644 index d89b807..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_convertwarp.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..convertwarp import ConvertWarp - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_ConvertWarp(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ConvertWarp(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ConvertWarp(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_ConvertWarp_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ConvertWarp(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ConvertWarp(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_spec_convertxfm.py b/pydra/tasks/fsl/utils/tests/test_spec_convertxfm.py deleted file mode 100644 index 456096a..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_convertxfm.py +++ /dev/null @@ -1,35 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..convertxfm import ConvertXFM - - -@pytest.mark.parametrize( - "inputs, outputs", [({"in_file": "flirt.mat", "invert_xfm": True}, ["out_file"])] -) -def test_ConvertXFM(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ConvertXFM(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ConvertXFM(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/utils/tests/test_spec_copygeom.py b/pydra/tasks/fsl/utils/tests/test_spec_copygeom.py deleted file mode 100644 index 4e6b5bb..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_copygeom.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..copygeom import CopyGeom - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_CopyGeom(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = CopyGeom(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = CopyGeom(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_CopyGeom_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = CopyGeom(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = CopyGeom(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_spec_extractroi.py b/pydra/tasks/fsl/utils/tests/test_spec_extractroi.py deleted file mode 100644 index 3496f3f..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_extractroi.py +++ /dev/null @@ -1,36 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..extractroi import ExtractROI - - -@pytest.mark.parametrize( - "inputs, outputs", - [({"in_file": "test.nii.gz", "t_min": 0, "t_size": 1}, ["roi_file"])], -) -def test_ExtractROI(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ExtractROI(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ExtractROI(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/utils/tests/test_spec_filterregressor.py b/pydra/tasks/fsl/utils/tests/test_spec_filterregressor.py deleted file mode 100644 index 4a55c64..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_filterregressor.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..filterregressor import FilterRegressor - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_FilterRegressor(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FilterRegressor(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FilterRegressor(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_FilterRegressor_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = FilterRegressor(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = FilterRegressor(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_spec_imagemaths.py b/pydra/tasks/fsl/utils/tests/test_spec_imagemaths.py deleted file mode 100644 index 8ec0bb2..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_imagemaths.py +++ /dev/null @@ -1,33 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..imagemaths import ImageMaths - - -@pytest.mark.parametrize("inputs, outputs", [(None, ["out_file"])]) -def test_ImageMaths(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ImageMaths(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ImageMaths(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/utils/tests/test_spec_imagemeants.py b/pydra/tasks/fsl/utils/tests/test_spec_imagemeants.py deleted file mode 100644 index 4d4d0d0..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_imagemeants.py +++ /dev/null @@ -1,33 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..imagemeants import ImageMeants - - -@pytest.mark.parametrize("inputs, outputs", [(None, ["out_file"])]) -def test_ImageMeants(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ImageMeants(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ImageMeants(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/utils/tests/test_spec_imagestats.py b/pydra/tasks/fsl/utils/tests/test_spec_imagestats.py deleted file mode 100644 index 7db868d..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_imagestats.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..imagestats import ImageStats - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_ImageStats(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ImageStats(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ImageStats(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_ImageStats_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = ImageStats(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = ImageStats(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_spec_invwarp.py b/pydra/tasks/fsl/utils/tests/test_spec_invwarp.py deleted file mode 100644 index 4cc3ca9..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_invwarp.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..invwarp import InvWarp - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_InvWarp(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = InvWarp(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = InvWarp(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_InvWarp_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = InvWarp(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = InvWarp(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/utils/tests/test_spec_slice.py b/pydra/tasks/fsl/utils/tests/test_spec_slice.py deleted file mode 100644 index 1933828..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_slice.py +++ /dev/null @@ -1,17 +0,0 @@ -import os, pytest -from pathlib import Path -from ..slice import Slice - - -@pytest.mark.parametrize("inputs, outputs", [(None, [])]) -def test_Slice(test_data, inputs, outputs): - in_file = Path(test_data) / "test.nii.gz" - if inputs is None: - inputs = {} - for key, val in inputs.items(): - try: - inputs[key] = eval(val) - except: - pass - task = Slice(in_file=in_file, **inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/utils/tests/test_spec_smooth.py b/pydra/tasks/fsl/utils/tests/test_spec_smooth.py deleted file mode 100644 index cec0b9c..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_smooth.py +++ /dev/null @@ -1,35 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..smooth import Smooth - - -@pytest.mark.parametrize( - "inputs, outputs", [({"in_file": "test.nii.gz", "sigma": 3.397}, ["smoothed_file"])] -) -def test_Smooth(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = Smooth(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = Smooth(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/utils/tests/test_spec_split.py b/pydra/tasks/fsl/utils/tests/test_spec_split.py deleted file mode 100644 index af3704b..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_split.py +++ /dev/null @@ -1,45 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..split import Split - - -@pytest.mark.parametrize( - "inputs, outputs", - [ - ( - { - "in_file": "test.nii.gz", - "output_basename": "test_split", - "dimension": "t", - }, - ["out_files"], - ) - ], -) -def test_Split(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = Split(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = Split(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) diff --git a/pydra/tasks/fsl/utils/tests/test_spec_swapdimensions.py b/pydra/tasks/fsl/utils/tests/test_spec_swapdimensions.py deleted file mode 100644 index f1dbbfa..0000000 --- a/pydra/tasks/fsl/utils/tests/test_spec_swapdimensions.py +++ /dev/null @@ -1,64 +0,0 @@ -import re, os, shutil, pytest -from pathlib import Path -from ..swapdimensions import SwapDimensions - - -@pytest.mark.parametrize("inputs, outputs", []) -def test_SwapDimensions(test_data, inputs, outputs): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = SwapDimensions(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = SwapDimensions(**inputs) - assert set(task.generated_output_names) == set(["return_code", "stdout", "stderr"] + outputs) - - -@pytest.mark.parametrize("inputs, error", [(None, "AttributeError")]) -def test_SwapDimensions_exception(test_data, inputs, error): - if inputs is None: - in_file = Path(test_data) / "test.nii.gz" - task = SwapDimensions(in_file=in_file) - else: - for key, val in inputs.items(): - try: - pattern = r"\.[a-zA-Z]*" - if isinstance(val, str): - if re.findall(pattern, val) != []: - inputs[key] = Path(test_data) / val - elif "_dir" in key: - dirpath = Path(test_data) / val - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - inputs[key] = Path(test_data) / val - else: - inputs[key] = eval(val) - elif isinstance(val, list): - if all(re.findall(pattern, _) != [] for _ in val): - inputs[key] = [Path(test_data) / _ for _ in val] - else: - inputs[key] = eval(val) - except: - pass - task = SwapDimensions(**inputs) - with pytest.raises(eval(error)): - task.generated_output_names diff --git a/pydra/tasks/fsl/v6_0/__init__.py b/pydra/tasks/fsl/v6_0/__init__.py new file mode 100644 index 0000000..8d155ce --- /dev/null +++ b/pydra/tasks/fsl/v6_0/__init__.py @@ -0,0 +1,69 @@ +""" +This is a basic doctest demonstrating that the package and pydra can both be successfully +imported. + +FSL interfaces are available within the `pydra.tasks.fsl` package. + +>>> from pydra.tasks import fsl + +.. automodule:: pydra.tasks.fsl.bet +.. automodule:: pydra.tasks.fsl.eddy +.. automodule:: pydra.tasks.fsl.fast +.. automodule:: pydra.tasks.fsl.flirt +.. automodule:: pydra.tasks.fsl.fnirt +.. automodule:: pydra.tasks.fsl.fslmaths +.. automodule:: pydra.tasks.fsl.fugue +.. automodule:: pydra.tasks.fsl.susan +.. automodule:: pydra.tasks.fsl.utils +""" + +from . import maths +from .bet import BET, RobustFOV +from .eddy import ApplyTopup, Eddy, Topup +from .fast import FAST +from .flirt import ( + FLIRT, + ApplyXFM, + ConcatXFM, + ConvertXFM, + FixScaleSkew, + Img2ImgCoord, + Img2StdCoord, + InvertXFM, + Std2ImgCoord, +) +from .fnirt import FNIRT, ApplyWarp, ConvertWarp, FNIRTFileUtils, InvWarp +from .fugue import FUGUE, Prelude, PrepareFieldmap, SigLoss +from .susan import SUSAN +from .utils import ( + FFT, + ROI, + ChFileType, + Info, + Interleave, + Merge, + Orient, + Reorient2Std, + SelectVols, + Slice, + SmoothFill, + Split, + SwapDim, +) + +# TODO: Drop compatibility aliases when 0.x is released. +FSLFFT = FFT +FSLROI = ROI +FSLChFileType = ChFileType +FSLInfo = Info +FSLInterleave = Interleave +FSLMerge = Merge +FSLOrient = Orient +FSLPrepareFieldmap = PrepareFieldmap +FSLReorient2Std = Reorient2Std +FSLSelectVols = SelectVols +FSLSlice = Slice +FSLSmoothFill = SmoothFill +FSLSplit = Split +FSLSwapDim = SwapDim +fslmaths = maths diff --git a/pydra/tasks/fsl/v6_0/bet/__init__.py b/pydra/tasks/fsl/v6_0/bet/__init__.py new file mode 100644 index 0000000..9762648 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/bet/__init__.py @@ -0,0 +1,10 @@ +""" +BET +=== + +.. automodule:: pydra.tasks.fsl.bet.bet +.. automodule:: pydra.tasks.fsl.bet.robustfov +""" + +from .bet import BET +from .robustfov import RobustFOV diff --git a/pydra/tasks/fsl/v6_0/bet/bet.py b/pydra/tasks/fsl/v6_0/bet/bet.py new file mode 100644 index 0000000..1247886 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/bet/bet.py @@ -0,0 +1,207 @@ +""" +Brain Extraction Tool (BET) +=========================== + +BET removes non-brain tissues from whole-head images. +It can also estimate the inner and outer skull surfaces, and outer scalp surface, +when provided with good quality T1 and T2 input images. +""" + +__all__ = ["BET"] + +import os +import typing as ty + +import attrs + +import pydra + + +@attrs.define(slots=False, kw_only=True) +class BETSpec(pydra.specs.ShellSpec): + """Specifications for BET.""" + + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "", + } + ) + + output_image: str = attrs.field( + metadata={ + "help_string": "output image", + "argstr": "", + "output_file_template": "{input_image}_bet", + } + ) + + save_brain_surface_outline: bool = attrs.field( + metadata={"help_string": "save brain surface outline", "argstr": "-o"} + ) + + save_brain_mask: bool = attrs.field( + metadata={"help_string": "save binary brain mask", "argstr": "-m"} + ) + + save_skull_image: bool = attrs.field( + metadata={"help_string": "save approximate skull image", "argstr": "-s"} + ) + + save_brain_surface_mesh: bool = attrs.field( + metadata={ + "help_string": "save brain surface as mesh in .vtk format", + "argstr": "-e", + } + ) + + fractional_intensity_threshold: float = attrs.field( + metadata={ + "help_string": ( + "Fractional intensity threshold (between 0 and 1). Default is 0.5. " + "Smaller values give larger brain outline estimates." + ), + "argstr": "-f", + } + ) + + vertical_gradient: float = attrs.field( + metadata={ + "help_string": ( + "Vertical gradient in fractional intensity threshold (between -1 and 1)." + " Default is 0. Positive values give larger brain outlines." + ), + "argstr": "-g", + } + ) + + head_radius: float = attrs.field( + metadata={ + "help_string": "Head radius (in millimeters)." + " Initial surface sphere is set to half of this value.", + "argstr": "-r", + } + ) + + center_of_gravity: ty.Tuple[int, int, int] = attrs.field( + metadata={ + "help_string": "centre-of-gravity (in voxel coordinates) of initial mesh surface", + "argstr": "-c", + } + ) + + apply_thresholding: bool = attrs.field( + metadata={ + "help_string": "apply thresholding to segmented brain image and mask", + "argstr": "-t", + } + ) + + verbose: bool = attrs.field( + metadata={ + "help_string": "enable verbose logging", + "argstr": "-v", + } + ) + + +@attrs.define(slots=False, kw_only=True) +class BETVariationsSpec(pydra.specs.ShellSpec): + """Specifications for BET variations.""" + + _xor = { + "with_robust_brain_center_estimation", + "with_eye_and_optic_nerve_cleanup", + "with_bias_field_and_neck_cleanup", + "with_small_fov_in_z", + "with_4d_fmri_data", + } + + with_robust_brain_center_estimation: bool = attrs.field( + metadata={ + "help_string": "iterate BET several times to improve robustness", + "argstr": "-R", + "xor": _xor, + } + ) + + with_eye_and_optic_nerve_cleanup: bool = attrs.field( + metadata={ + "help_string": "remove eye and optic nerve", + "argstr": "-S", + "xor": _xor | {"save_brain_surface_outline"}, + } + ) + + with_bias_field_and_neck_cleanup: bool = attrs.field( + metadata={ + "help_string": "remove bias field and neck", + "argstr": "-B", + "xor": _xor, + } + ) + + with_small_fov_in_z: bool = attrs.field( + metadata={ + "help_string": "improve BET for very small FOV in Z", + "argstr": "-Z", + "xor": _xor, + } + ) + + with_4d_fmri_data: bool = attrs.field( + metadata={ + "help_string": "apply BET to 4D FMRI data", + "argstr": "-F", + "xor": _xor | {"fractional_intensity_threshold"}, + } + ) + + +@attrs.define(slots=False, kw_only=True) +class BETOutSpec(pydra.specs.ShellOutSpec): + """Output specifications for BET.""" + + brain_surface_outline: pydra.specs.File = attrs.field( + metadata={ + "help_string": "brain surface outline", + "output_file_template": "{output_image}_overlay", + "requires": ["save_brain_surface_outline"], + } + ) + + brain_mask: pydra.specs.File = attrs.field( + metadata={ + "help_string": "brain mask", + "output_file_template": "{output_image}_mask", + "requires": ["save_brain_mask"], + } + ) + + skull_image: pydra.specs.File = attrs.field( + metadata={ + "help_string": "skull image", + "output_file_template": "{output_image}_skull", + "requires": ["save_skull_image"], + } + ) + + brain_surface_mesh: pydra.specs.File = attrs.field( + metadata={ + "help_string": "brain surface mesh", + "output_file_template": "{output_image}_mesh.vtk", + "keep_extension": False, + "requires": ["save_brain_surface_mesh"], + } + ) + + +class BET(pydra.engine.ShellCommandTask): + """Task definition for BET.""" + + executable = "bet" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(BETSpec, BETVariationsSpec)) + + output_spec = pydra.specs.SpecInfo(name="Output", bases=(BETOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/bet/robustfov.py b/pydra/tasks/fsl/v6_0/bet/robustfov.py new file mode 100644 index 0000000..7dbaf6c --- /dev/null +++ b/pydra/tasks/fsl/v6_0/bet/robustfov.py @@ -0,0 +1,68 @@ +""" +RobustFOV +========= + +Automatic FOV reduction to remove the neck and lower part of the head +from structural brain images. + +Examples +-------- + +>>> task = RobustFOV(input_image="image.nii") +>>> task.cmdline # doctest: +ELLIPSIS +'robustfov -i image.nii -r ...image_rfov.nii -b 170 -m ...image_rfov.mat' +""" + +__all__ = ["RobustFOV"] + +import os + +import attrs + +import pydra + + +@attrs.define(slots=False, kw_only=True) +class RobustFOVSpec(pydra.specs.ShellSpec): + """Specifications for robustfov.""" + + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "-i", + } + ) + + output_image: str = attrs.field( + metadata={ + "help_string": "output image with reduced FOV", + "argstr": "-r", + "output_file_template": "{input_image}_rfov", + } + ) + + brain_size: int = attrs.field( + default=170, + metadata={ + "help_string": "size of the brain in z-axis", + "argstr": "-b", + }, + ) + + output_matrix: str = attrs.field( + metadata={ + "help_string": "output transformation matrix", + "argstr": "-m", + "output_file_template": "{input_image}_rfov.mat", + "keep_extension": False, + } + ) + + +class RobustFOV(pydra.engine.ShellCommandTask): + """Task definition for robustfov.""" + + executable = "robustfov" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(RobustFOVSpec,)) diff --git a/pydra/tasks/fsl/v6_0/eddy/__init__.py b/pydra/tasks/fsl/v6_0/eddy/__init__.py new file mode 100644 index 0000000..60dd623 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/eddy/__init__.py @@ -0,0 +1,12 @@ +""" +Eddy +==== + +.. automodule:: pydra.tasks.fsl.eddy.eddy +.. automodule:: pydra.tasks.fsl.eddy.topup +.. automodule:: pydra.tasks.fsl.eddy.applytopup +""" + +from .applytopup import ApplyTopup +from .eddy import Eddy +from .topup import Topup diff --git a/pydra/tasks/fsl/v6_0/eddy/applytopup.py b/pydra/tasks/fsl/v6_0/eddy/applytopup.py new file mode 100644 index 0000000..bc974d7 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/eddy/applytopup.py @@ -0,0 +1,193 @@ +""" +ApplyTopup +========== + +Examples +-------- + +>>> task = ApplyTopup( +... input_image="blipup.nii", +... encoding_file="parameters.txt", +... input_index=1, +... fieldmap_image="fieldmap.nii", +... method="jac", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'applytopup --imain=blipup.nii --datain=parameters.txt --inindex=1 \ +--topup=fieldmap --out=blipup_topup.nii --method=jac ...' + +>>> task = ApplyTopup( +... input_image=["blipup.nii", "blipdown.nii"], +... encoding_file="parameters.txt", +... input_index=[1, 2, 3], +... field_coefficients_image="topup_fieldcoef.nii", +... movement_parameters_file="topup_movpar.txt", +... output_image="corrected.nii", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'applytopup --imain=blipup.nii,blipdown.nii --datain=parameters.txt \ +--inindex=1,2,3 --topup=topup --out=corrected.nii ...' +""" + +__all__ = ["ApplyTopup"] + +from os import PathLike +from pathlib import PurePath +from typing import Sequence, Union + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +def _to_input_image(field: Union[PathLike, Sequence[PathLike]]) -> str: + try: + paths = [PurePath(field)] + except TypeError: + paths = [PurePath(path) for path in field] + + return f"--imain={','.join(str(path) for path in paths)}" + + +def _to_input_index(field: Union[int, Sequence[int]]) -> str: + try: + indexes = list(field) + except TypeError: + indexes = [field] + + return f"--inindex={','.join(str(index) for index in indexes)}" + + +def _to_topup_basename( + fieldmap_image: PathLike, field_coefficients_image: PathLike +) -> str: + if field_coefficients_image: + path = PurePath(field_coefficients_image) + basename = path.parent / path.name.split("_fieldcoef", 1)[0] + else: + path = PurePath(fieldmap_image) + basename = path.parent / path.name.split(".", 1)[0] + + return f"--topup={str(basename)}" + + +def _to_output_image( + output_image: PathLike, + input_image: Union[PathLike, Sequence[PathLike]], +) -> str: + if output_image: + path = PurePath(output_image) + else: + try: + path = PurePath(input_image) + except TypeError: + path = PurePath(input_image[0]) + name, ext = path.name.split(".", 1) + path = path.with_name(f"{name}_topup.{ext}") + + return f"--out={path}" + + +@define(slots=False, kw_only=True) +class ApplyTopupSpec(ShellSpec): + """Specifications for applytopup.""" + + input_image: Union[PathLike, Sequence[PathLike]] = field( + metadata={ + "help_string": "input image", + "mandatory": True, + "formatter": _to_input_image, + } + ) + + encoding_file: PathLike = field( + metadata={ + "help_string": "text file containing phase encoding directions and timings", + "mandatory": True, + "argstr": "--datain={encoding_file}", + } + ) + + input_index: Union[int, Sequence[int]] = field( + metadata={ + "help_string": "indices mapping each input image to a row of the encoding file", + "mandatory": True, + "formatter": _to_input_index, + } + ) + + topup_basename: str = field( + metadata={ + "help_string": "basename for fieldmap or topup output files", + "formatter": _to_topup_basename, + "readonly": True, + } + ) + + fieldmap_image: PathLike = field( + metadata={ + "help_string": "fieldmap image", + "mandatory": True, + "xor": {"field_coefficients_image"}, + } + ) + + field_coefficients_image: PathLike = field( + metadata={ + "help_string": "field coefficients image computed by topup", + "mandatory": True, + "xor": {"fieldmap_image"}, + "requires": {"movement_parameters_file"}, + } + ) + + movement_parameters_file: PathLike = field( + metadata={"help_string": "movement parameters file computed by topup"} + ) + + output_image: PathLike = field( + metadata={ + "help_string": "output image", + "argstr": "--out", + "formatter": _to_output_image, + } + ) + + method: str = field( + default="lsr", + metadata={ + "help_string": "resampling method", + "argstr": "--method={method}", + "allowed_values": {"jac", "lsr", "vb2D", "vb3D", "vb4D"}, + }, + ) + + interpolation: str = field( + default="spline", + metadata={ + "help_string": "interpolation model", + "argstr": "--interp={interpolation}", + "allowed_values": {"spline", "trilinear"}, + }, + ) + + datatype: str = field( + default="preserve", + metadata={ + "help_string": "force output datatype", + "argstr": "--datatype={datatype}", + "allowed_values": {"preserve", "char", "short", "int", "float", "double"}, + }, + ) + + verbose: bool = field( + metadata={"help_string": "enable verbose logging", "argstr": "--verbose"} + ) + + +class ApplyTopup(ShellCommandTask): + """Task definition for applytopup.""" + + executable = "applytopup" + + input_spec = SpecInfo(name="Input", bases=(ApplyTopupSpec,)) diff --git a/pydra/tasks/fsl/v6_0/eddy/eddy.py b/pydra/tasks/fsl/v6_0/eddy/eddy.py new file mode 100644 index 0000000..38335d4 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/eddy/eddy.py @@ -0,0 +1,429 @@ +""" +Eddy +==== + +Correct for artifacts induced by Eddy currents and subject motion. + +Examples +-------- + +>>> task = Eddy( +... input_image="input.nii", +... brain_mask="brain.nii", +... encoding_file="params.txt", +... index_file="index.txt", +... bvec_file="input.bvec", +... bval_file="input.bval", +... fieldmap_image="fieldmap.nii", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'eddy --imain=input.nii --mask=brain.nii --acqp=params.txt --index=index.txt \ +--bvecs=input.bvec --bvals=input.bval --field=fieldmap.nii --out=eddy ...' +""" + +__all__ = ["Eddy"] + +from os import PathLike +from pathlib import PurePath + +from attrs import define, field +from pydra.engine.specs import File, ShellOutSpec, ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(slots=False, kw_only=True) +class EddySpec(ShellSpec): + """Specifications for eddy.""" + + # Parameters that specify input files. + input_image: PathLike = field( + metadata={ + "help_string": "input image as a 4D volume", + "mandatory": True, + "argstr": "--imain={input_image}", + } + ) + + brain_mask: PathLike = field( + metadata={ + "help_string": "brain mask as a single volume image", + "mandatory": True, + "argstr": "--mask={brain_mask}", + } + ) + + encoding_file: PathLike = field( + metadata={ + "help_string": "acquisition parameters for the diffusion protocol", + "mandatory": True, + "argstr": "--acqp={encoding_file}", + } + ) + + index_file: PathLike = field( + metadata={ + "help_string": "mapping from volume index to encoding parameters", + "mandatory": True, + "argstr": "--index={index_file}", + } + ) + + bvec_file: PathLike = field( + metadata={ + "help_string": "diffusion directions", + "mandatory": True, + "argstr": "--bvecs={bvec_file}", + } + ) + + bval_file: PathLike = field( + metadata={ + "help_string": "diffusion weighting", + "mandatory": True, + "argstr": "--bvals={bval_file}", + } + ) + + fieldmap_image: PathLike = field( + metadata={"help_string": "fieldmap image", "argstr": "--field={fieldmap_image}"} + ) + + fieldmap_matrix: PathLike = field( + metadata={ + "help_string": "rigid-body transformation matrix from fieldmap to first input volume", + "argstr": "--field_mat={fieldmap_matrix}", + "requires": {"fieldmap_image"}, + } + ) + + no_peas: bool = field( + metadata={ + "help_string": "do not perform post-Eddy alignment of shells", + "argstr": "--dont_peas", + } + ) + + # Parameters specifying names of output-files. + output_basename: str = field( + default="eddy", + metadata={ + "help_string": "basename for output files", + "argstr": "--out={output_basename}", + }, + ) + + # Parameters specifying how eddy should be run. + first_level_model: str = field( + default="quadratic", + metadata={ + "help_string": "model for the magnetic field generated by Eddy currents", + "argstr": "--flm={first_level_model}", + "allowed_values": {"movement", "linear", "quadratic", "cubic"}, + }, + ) + + second_level_model: str = field( + default="none", + metadata={ + "help_string": "model for how diffusion gradients generate Eddy currents", + "argstr": "--slm={second_level_model}", + "allowed_values": {"none", "linear", "quadratic"}, + }, + ) + + fwhm: float = field( + default=0, + metadata={ + "help_string": "filter width used for pre-conditioning data prior to estimating distortions", + "argstr": "--fwhm={fwhm}", + }, + ) + + num_iterations: int = field( + default=5, + metadata={ + "help_string": "number of iterations for eddy", + "argstr": "--niter={num_iterations}", + }, + ) + + fill_empty_planes: bool = field( + metadata={"help_string": "detect and fill empty planes", "argstr": "--fep"} + ) + + interpolation: str = field( + default="spline", + metadata={ + "help_string": "interpolation method for the estimation phase", + "argstr": "--interp={interpolation}", + "allowed_values": {"spline", "trilinear"}, + }, + ) + + resampling: str = field( + default="jac", + metadata={ + "help_string": "final resampling strategy", + "argstr": "--resamp={resampling}", + "allowed_values": {"jac", "lsr"}, + }, + ) + + num_voxels: int = field( + default=1000, + metadata={ + "help_string": "number of voxels to use for GP hyperparameter estimation", + "argstr": "--nvoxhp={num_voxels}", + }, + ) + + fudge_factor: int = field( + default=10, + metadata={ + "help_string": "fudge factor for Q-space smoothing during estimation", + "argstr": "--ff={fudge_factor}", + }, + ) + + # Parameters for outlier replacement (ol) + replace_outliers: bool = field( + metadata={"help_string": "replace outliers", "argstr": "--repol"} + ) + + outlier_num_stdevs: int = field( + metadata={ + "help_string": "number of times off the standard deviation to qualify as outlier", + "argstr": "--ol_nstd={outlier_num_stdevs}", + "requires": {"replace_outliers"}, + } + ) + + outlier_num_voxels: int = field( + metadata={ + "help_string": "minimum number of voxels in a slice to qualify for outlier detection", + "argstr": "--ol_nvox={outlier_num_voxels}", + "requires": {"replace_outliers"}, + } + ) + + outlier_type: str = field( + metadata={ + "help_string": "type of outliers detected", + "argstr": "--ol_type={outlier_type}", + "allowed_values": {"both", "gw", "sw"}, + "requires": {"replace_outliers"}, + } + ) + + multiband_factor: int = field( + metadata={ + "help_string": "multiband factor", + "argstr": "--mb={multiband_factor}", + } + ) + + multiband_offset: int = field( + metadata={ + "help_string": "multiband slice offset", + "argstr": "--mb_offs={multiband_offset}", + "requires": {"multiband_factor"}, + } + ) + + # Parameters for intra-volume movement correction (s2v) + movement_prediction_order: int = field( + default=0, + metadata={ + "help_string": "order of movement prediction model", + "argstr": "--mporder={movement_prediction_order}", + }, + ) + + s2v_num_iterations: int = field( + metadata={ + "help_string": "number of iterations for s2v movement estimation", + "argstr": "--s2v_niter={s2v_num_iterations}", + } + ) + + s2v_lambda: float = field( + metadata={ + "help_string": "weighting of regularization for s2v movement estimation", + "argstr": "--s2v_lambda={s2v_lambda}", + } + ) + + s2v_interpolation: str = field( + metadata={ + "help_string": "interpolation method for s2v movement estimation.", + "argstr": "--s2v_interp={s2v_interpolation}", + "allowed_values": {"spline", "trilinear"}, + } + ) + + slice_grouping_file: PathLike = field( + metadata={ + "help_string": "file containing slice grouping information", + "argstr": "--slspec={slice_grouping_file}", + "xor": {"slice_timing_file"}, + } + ) + + slice_timing_file: PathLike = field( + metadata={ + "help_string": "file containing slice timing information", + "argstr": "--json={slice_timing_file}", + "xor": {"slice_grouping_file"}, + } + ) + + # Parameters for move-by-susceptibility correction (mbs) + estimate_move_by_susceptibility: bool = field( + metadata={ + "help_string": "estimate susceptibility-induced field changes due to subject motion", + "argstr": "--estimate_move_by_susceptibility", + } + ) + + mbs_num_iterations: int = field( + metadata={ + "help_string": "number of iterations for MBS field estimation", + "argstr": "--mbs_niter={mbs_num_iterations}", + "requires": {"estimate_move_by_susceptibility"}, + } + ) + + mbs_lambda: int = field( + metadata={ + "help_string": "weighting of regularization for MBS field estimation", + "argstr": "--mbs_lambda={mbs_lambda}", + "requires": {"estimate_move_by_susceptibility"}, + } + ) + + mbs_knot_spacing: int = field( + metadata={ + "help_string": "knot-spacing for MBS field estimation", + "argstr": "--mbs_ksp={mbs_knot_spacing}", + "requires": {"estimate_move_by_susceptibility"}, + } + ) + + # Miscellaneous parameters. + data_is_shelled: bool = field( + metadata={ + "help_string": "bypass checks for data shelling", + "argstr": "--data_is_shelled", + } + ) + + random_seed: int = field( + metadata={ + "help_string": "random seed for voxel selection", + "argstr": "--initrand={random_seed}", + } + ) + + save_cnr_maps: bool = field( + metadata={"help_string": "save shell-wise CNR maps", "argstr": "--cnr_maps"} + ) + + save_residuals: bool = field( + metadata={ + "help_string": "save residuals for all scans", + "argstr": "--residuals", + } + ) + + verbose: bool = field( + metadata={"help_string": "enable verbose logging", "argstr": "--verbose"} + ) + + +@define(slots=False, kw_only=True) +class EddyOutSpec(ShellOutSpec): + """Output specification for eddy.""" + + corrected_image: File = field( + metadata={ + "help_string": "input image corrected for distortions", + "output_file_template": "{output_basename}.nii.gz", + } + ) + + parameters_file: File = field( + metadata={ + "help_string": "registration parameters for movement and EC", + "output_file_template": "{output_basename}.eddy_parameters", + } + ) + + rotated_bvec_file: File = field( + metadata={ + "help_string": "rotated b-vecs", + "output_file_template": "{output_basename}.eddy_rotated_bvecs", + } + ) + + movement_rms_matrix: File = field( + metadata={ + "help_string": "movement induced RMS", + "output_file_template": "{output_basename}.eddy_movement_rms", + } + ) + + restricted_movement_rms_matrix: File = field( + metadata={ + "help_string": "movement induced RMS without translation in the PE direction", + "output_file_template": "{output_basename}.eddy_restricted_movement_rms", + } + ) + + displacement_fields_image: File = field( + metadata={ + "help_string": "displacement fields in millimeters", + "output_file_template": "{output_basename}.eddy_displacement_fields", + } + ) + + outlier_free_image: File = field( + metadata={ + "help_string": "input image with outliers replaced by predictions", + "output_file_template": "{output_basename}.eddy_outlier_free_data", + "requires": ["replace_outliers"], + } + ) + + movement_over_time_file: File = field( + metadata={ + "help_string": "movement parameters per time-point (slice or group)", + "output_file_template": "{output_basename}.eddy_movement_over_time", + "requires": ["movement_prediction_order"], + } + ) + + cnr_maps_image: File = field( + metadata={ + "help_string": "path to optional CNR maps image", + "output_file_template": "{output_basename}.eddy_cnr_maps", + "requires": ["save_cnr_maps"], + } + ) + + residuals_image: File = field( + metadata={ + "help_string": "path to optional residuals image", + "output_file_template": "{output_basename}.eddy_residuals", + "requires": ["save_residuals"], + } + ) + + +class Eddy(ShellCommandTask): + """Task definition for eddy.""" + + executable = "eddy" + + input_spec = SpecInfo(name="Input", bases=(EddySpec,)) + + output_spec = SpecInfo(name="Output", bases=(EddyOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/eddy/topup.py b/pydra/tasks/fsl/v6_0/eddy/topup.py new file mode 100644 index 0000000..54f51f7 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/eddy/topup.py @@ -0,0 +1,249 @@ +""" +Topup +===== + +Examples +-------- + +Minimal call to `topup`: + +>>> task = Topup(input_image="input.nii", encoding_file="encoding.txt") +>>> task.cmdline # doctest: +ELLIPSIS +'topup --imain=input.nii --datain=encoding.txt --out=input_topup \ +--fout=...input_fieldmap.nii --iout=...input_unwarped.nii ...' + +Using a multiple resolution approach: + +>>> task = Topup( +... input_image="input.nii", +... encoding_file="encoding.txt", +... subsampling_per_level=(4, 2, 1), +... smoothing_per_level=(8.0, 4.0, 0.0), +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'topup --imain=input.nii --datain=encoding.txt ... --subsamp=4,2,1 --fwhm=8.0,4.0,0.0 ...' +""" + +__all__ = ["Topup"] + +from os import PathLike +from pathlib import PurePath +from typing import Iterable + +from attrs import define, field +from pydra.engine.specs import File, ShellOutSpec, ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +def to_field_per_level(field, param) -> str: + return f"--{param}={','.join([str(elem) for elem in field])}" + + +def to_output_basename(field, input_image) -> str: + return f"--out={field or PurePath(input_image).name.split('.', 1)[0] + '_topup'}" + + +@define(slots=False, kw_only=True) +class TopupSpec(ShellSpec): + """Specifications for topup.""" + + input_image: PathLike = field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "--imain={input_image}", + } + ) + + encoding_file: PathLike = field( + metadata={ + "help_string": "text file containing phase encoding directions and timings", + "mandatory": True, + "argstr": "--datain={encoding_file}", + } + ) + + output_basename: str = field( + metadata={ + "help_string": "output basename for field coefficients and movement parameters", + "formatter": to_output_basename, + }, + ) + + output_fieldmap_image: str = field( + metadata={ + "help_string": "output fieldmap image", + "argstr": "--fout={output_fieldmap_image}", + "output_file_template": "{input_image}_fieldmap", + } + ) + + output_unwarped_image: str = field( + metadata={ + "help_string": "output unwarped image", + "argstr": "--iout={output_unwarped_image}", + "output_file_template": "{input_image}_unwarped", + } + ) + + warp_resolution_per_level: Iterable[float] = field( + default=(10.0,), + metadata={ + "help_string": "resolution of warp basis in millimeters for a given level", + "formatter": lambda field: to_field_per_level(field, "warpres"), + }, + ) + + subsampling_per_level: Iterable[int] = field( + default=(1,), + metadata={ + "help_string": "subsampling factor for a given level", + "formatter": lambda field: to_field_per_level(field, "subsamp"), + }, + ) + + smoothing_per_level: Iterable[float] = field( + default=(8.0,), + metadata={ + "help_string": "FWHM of smoothing kernel in millimeters for a given level", + "formatter": lambda field: to_field_per_level(field, "fwhm"), + }, + ) + + max_iterations_per_level: Iterable[int] = field( + default=(5,), + metadata={ + "help_string": "maximum number of non-linear iterations for a given level", + "formatter": lambda field: to_field_per_level(field, "miter"), + }, + ) + + regularisation_per_level: Iterable[float] = field( + default=(0.0,), + metadata={ + "help_string": "weight of regularisation for a given level", + "formatter": lambda field: to_field_per_level(field, "lambda"), + }, + ) + + estimate_movement_per_level: Iterable[int] = field( + default=(1,), + metadata={ + "help_string": "wether to estimate (1) or keep movement parameters constant (0) for a given level", + "formatter": lambda field: to_field_per_level(field, "estmov"), + "allowed_values": {0, 1}, + }, + ) + + minimisation_method_per_level: Iterable[int] = field( + default=(0,), + metadata={ + "help_string": ( + "which minimisation method to use for a given level " + "(0: Levenberg-Marquardt, 1: Scaled Conjugate Gradient)" + ), + "formatter": lambda field: to_field_per_level(field, "minmet"), + "allowed_values": {0, 1}, + }, + ) + + weight_regularisation_by_ssq: bool = field( + default=True, + metadata={ + "help_string": "weight regularisation by sum-of-squares", + "formatter": lambda field: f"--ssqlambda={field:d}", + }, + ) + + regularisation_model: str = field( + default="bending_energy", + metadata={ + "help_string": "regularisation model", + "argstr": "--regmod={regularisation_model}", + "allowed_values": {"bending_energy", "membrane_energy"}, + }, + ) + + spline_order: int = field( + default=3, + metadata={ + "help_string": "use quadratic (2) or cubic (3) splines", + "argstr": "--splineorder={spline_order}", + "allowed_values": {2, 3}, + }, + ) + + precision: str = field( + default="double", + metadata={ + "help_string": "numerical precision", + "argstr": "--numprec={precision}", + "allowed_values": {"float", "double"}, + }, + ) + + interpolation: str = field( + default="spline", + metadata={ + "help_string": "interpolation model", + "argstr": "--interp={interpolation}", + "allowed_values": {"linear", "spline"}, + }, + ) + + scale: bool = field( + default=False, + metadata={ + "help_string": "scale images to a common mean", + "formatter": lambda field: f"--scale={field:d}", + }, + ) + + regrid: bool = field( + default=True, + metadata={ + "help_string": "perform calculations on a different grid", + "formatter": lambda field: f"--regrid={field:d}", + }, + ) + + num_threads: int = field( + default=1, + metadata={ + "help_string": "number of threads to use", + "argstr": "--nthr={num_threads}", + }, + ) + + verbose: bool = field( + metadata={"help_string": "enable verbose logging", "argstr": "--verbose"} + ) + + +@define(slots=False, kw_only=True) +class TopupOutSpec(ShellOutSpec): + """Output specifications for topup.""" + + field_coefficients_image: File = field( + metadata={ + "help_string": "output field coefficients", + "output_file_template": "{output_basename}_fieldcoef.nii.gz", + } + ) + + movement_parameters_file: File = field( + metadata={ + "help_string": "output movement parameters", + "output_file_template": "{output_basename}_movpar.txt", + } + ) + + +class Topup(ShellCommandTask): + """Task definition for topup.""" + + executable = "topup" + + input_spec = SpecInfo(name="Input", bases=(TopupSpec,)) + + output_spec = SpecInfo(name="Output", bases=(TopupOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/fast.py b/pydra/tasks/fsl/v6_0/fast.py new file mode 100644 index 0000000..ed3a010 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fast.py @@ -0,0 +1,215 @@ +""" +FAST +==== + +Automatic segmentation of 3D images of the brain. +""" + +__all__ = ["FAST"] + +import os + +import attrs + +import pydra + + +@attrs.define(slots=False, kw_only=True) +class FASTSpec(pydra.specs.ShellSpec): + """Specifications for FAST.""" + + # Input parameters. + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input image (single-channel mode)", + "mandatory": True, + "argstr": "", + "position": -1, + } + ) + + image_type: str = attrs.field( + default="T1", + metadata={ + "help_string": "type of input image (T1, T2 or PD)", + "argstr": "-t", + "allowed_values": {"T1", "T2", "PD"}, + "formatter": lambda image_type: "-t {:d}".format( + {"T1": 1, "T2": 2, "PD": 3}.get(image_type) + ), + }, + ) + + # Output parameters. + output_basename: str = attrs.field( + default="fast", + metadata={ + "help_string": "basename used for output files", + "argstr": "-o", + }, + ) + + num_classes: int = attrs.field( + default=3, + metadata={ + "help_string": "number of tissue-type classes", + "argstr": "-n", + }, + ) + + save_probability_maps: bool = attrs.field( + metadata={ + "help_string": "save probability map for each class", + "argstr": "-p", + } + ) + + save_bias_field_image: bool = attrs.field( + metadata={ + "help_string": "save estimated bias field", + "argstr": "-b", + } + ) + + save_bias_corrected_image: bool = attrs.field( + metadata={ + "help_string": "save restored image after bias field correction", + "argstr": "-B", + } + ) + + save_segmentation_masks: bool = attrs.field( + metadata={ + "help_string": "save segmentation mask for each class", + "argstr": "-g", + } + ) + + # Advanced parameters. + main_mrf_parameter: float = attrs.field( + default=0.1, + metadata={ + "help_string": "", + "argstr": "-H", + }, + ) + + bias_field_iterations: int = attrs.field( + default=4, + metadata={ + "help_string": "number of iterations for bias field removal", + "argstr": "-I", + }, + ) + + bias_field_smoothing: float = attrs.field( + default=20, + metadata={ + "help_string": "bias field smoothing (FWHM in millimeters)", + "argstr": "-l", + }, + ) + + no_partial_volume_estimation: bool = attrs.field( + metadata={ + "help_string": "do not perform partial volume estimation", + "argstr": "--nopve", + } + ) + + verbose: bool = attrs.field( + metadata={ + "help_string": "enable verbose logging", + "argstr": "-v", + } + ) + + +def get_segmentation_image(output_basename): + return f"{output_basename}_seg" + + +def get_segmentation_masks(output_basename, num_classes): + return [f"{output_basename}_seg_{i}" for i in range(num_classes)] + + +def get_probability_maps(output_basename, num_classes): + return [f"{output_basename}_prob_{i}" for i in range(num_classes)] + + +def get_partial_volume_maps(output_basename, num_classes): + return [f"{output_basename}_pve_{i}" for i in range(num_classes)] + + +def get_bias_field_image(output_basename): + return f"{output_basename}_bias" + + +def get_bias_corrected_image(output_basename): + return f"{output_basename}_restore" + + +@attrs.define(slots=False, kw_only=True) +class FASTOutSpec(pydra.specs.ShellOutSpec): + """Ouput specifications for FAST.""" + + segmentation_image: pydra.specs.File = attrs.field( + metadata={ + "help_string": "segmentation image with each voxel assigned a class", + "mandatory": True, + "callable": get_segmentation_image, + } + ) + + segmentation_masks: pydra.specs.MultiOutputFile = attrs.field( + metadata={ + "help_string": ( + "one segmentation mask per class, each voxel is assigned a value of " + "1 if belonging to the class 0 otherwise." + ), + "requires": ["save_segmentation_masks"], + "callable": get_segmentation_masks, + } + ) + + probability_maps: pydra.specs.MultiOutputFile = attrs.field( + metadata={ + "help_string": "posterior probability mapping for each class", + "requires": ["save_probability_maps"], + "callable": get_probability_maps, + } + ) + + partial_volume_maps: pydra.specs.MultiOutputFile = attrs.field( + metadata={ + "help_string": "partial volume mapping for each class", + "requires": [("no_partial_volume_estimation", False)], + "callable": get_partial_volume_maps, + } + ) + + bias_field_image: pydra.specs.File = attrs.field( + metadata={ + "help_string": "estimated bias field", + "requires": ["save_bias_field_image"], + "callable": get_bias_field_image, + } + ) + + bias_corrected_image: pydra.specs.File = attrs.field( + metadata={ + "help_string": "restored input image after bias field correction", + "requires": ["save_bias_corrected_image"], + "callable": get_bias_corrected_image, + } + ) + + +class FAST(pydra.engine.ShellCommandTask): + """Task definition for FAST.""" + + executable = "fast" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(FASTSpec,)) + + output_spec = pydra.specs.SpecInfo(name="Ouput", bases=(FASTOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/flirt/__init__.py b/pydra/tasks/fsl/v6_0/flirt/__init__.py new file mode 100644 index 0000000..76fee01 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/flirt/__init__.py @@ -0,0 +1,16 @@ +""" +FLIRT +===== + +.. automodule:: pydra.tasks.fsl.flirt.flirt +.. automodule:: pydra.tasks.fsl.flirt.convertxfm +.. automodule:: pydra.tasks.fsl.flirt.img2imgcoord +.. automodule:: pydra.tasks.fsl.flirt.img2stdcoord +.. automodule:: pydra.tasks.fsl.flirt.std2imgcoord +""" + +from .convertxfm import ConcatXFM, ConvertXFM, FixScaleSkew, InvertXFM +from .flirt import FLIRT, ApplyXFM +from .img2imgcoord import Img2ImgCoord +from .img2stdcoord import Img2StdCoord +from .std2imgcoord import Std2ImgCoord diff --git a/pydra/tasks/fsl/v6_0/flirt/convertxfm.py b/pydra/tasks/fsl/v6_0/flirt/convertxfm.py new file mode 100644 index 0000000..680ac08 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/flirt/convertxfm.py @@ -0,0 +1,143 @@ +""" +ConvertXFM +========== + +Examples +-------- + +Concatenate transformation matrix: + +>>> task = ConcatXFM(input_matrix="AtoB.mat", concat_matrix="BtoC.mat", output_matrix="AtoC.mat") +>>> task.cmdline +'convert_xfm -omat AtoC.mat -concat BtoC.mat AtoB.mat' + +Invert transformation matrix: + +>>> task = InvertXFM(input_matrix="AtoB.mat", output_matrix="BtoA.mat") +>>> task.cmdline +'convert_xfm -omat BtoA.mat -inverse AtoB.mat' + +Fix scaling and skewness with additional matrix: + +>>> task = FixScaleSkew(input_matrix="A.mat", fixscaleskew_matrix="B.mat") +>>> task.cmdline +'convert_xfm -omat ...A_cxfm.mat -fixscaleskew B.mat A.mat' + +Use ConvertXFM to combine multiple operations at once, such as concatenation and inversion: + +>>> task = ConvertXFM(input_matrix="AtoB.mat", concat_matrix="BtoC.mat", inverse=True, output_matrix="CtoA.mat") +>>> task.cmdline +'convert_xfm -omat CtoA.mat -concat BtoC.mat -inverse AtoB.mat' +""" + +__all__ = ["ConvertXFM", "ConcatXFM", "InvertXFM", "FixScaleSkew"] + +import os + +import attrs + +import pydra + + +@attrs.define(slots=False, kw_only=True) +class BaseSpec(pydra.specs.ShellSpec): + """Base specifications for all tasks using convert_xfm.""" + + input_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": "input matrix in 4x4 ASCII format", + "mandatory": True, + "argstr": "", + "position": -1, + } + ) + + output_matrix: str = attrs.field( + metadata={ + "help_string": "output matrix in 4x4 ASCII format", + "argstr": "-omat", + "output_file_template": "{input_matrix}_cxfm", + } + ) + + +@attrs.define(slots=False, kw_only=True) +class ConvertXFMSpec(BaseSpec): + """Specifications for convert_xfm.""" + + fixscaleskew_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": " fix scaling and skewness with this matrix", + "argstr": "-fixscaleskew", + } + ) + + concat_matrix: os.PathLike = attrs.field( + metadata={"help_string": "concatenate with this matrix", "argstr": "-concat"} + ) + + inverse: bool = attrs.field( + metadata={"help_string": "invert the resulting matrix", "argstr": "-inverse"} + ) + + +class ConvertXFM(pydra.engine.ShellCommandTask): + """Task definition for convert_xfm.""" + + executable = "convert_xfm" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(ConvertXFMSpec,)) + + +@attrs.define(slots=False, kw_only=True) +class ConcatXFMSpec(BaseSpec): + """Specifications for concat_xfm.""" + + concat_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": "concatenate with this matrix", + "mandatory": True, + "argstr": "-concat", + } + ) + + +class ConcatXFM(ConvertXFM): + """Task definition for matrix concatenation using convert_xfm.""" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(ConcatXFMSpec,)) + + +@attrs.define(slots=False, kw_only=True) +class InvertXFMSpec(BaseSpec): + """Specifications for invert_xfm.""" + + inverse: bool = attrs.field( + default=True, + metadata={"help_string": "invert the input matrix", "argstr": "-inverse"}, + ) + + +class InvertXFM(ConvertXFM): + """Task definition for matrix inversion using convert_xfm.""" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(InvertXFMSpec,)) + + +@attrs.define(slots=False, kw_only=True) +class FixScaleSkewSpec(BaseSpec): + """Specifications for fixing matrix scaling and skewness using convert_xfm.""" + + fixscaleskew_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": " fix scaling and skewness with this matrix", + "mandatory": True, + "argstr": "-fixscaleskew", + } + ) + + +class FixScaleSkew(ConvertXFM): + """Task definition for fixing matrix scaling and skewness using convert_xfm.""" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(FixScaleSkewSpec,)) diff --git a/pydra/tasks/fsl/v6_0/flirt/flirt.py b/pydra/tasks/fsl/v6_0/flirt/flirt.py new file mode 100644 index 0000000..8fe7a6a --- /dev/null +++ b/pydra/tasks/fsl/v6_0/flirt/flirt.py @@ -0,0 +1,203 @@ +""" +FLIRT +===== + +FLIRT (FMRIB's Linear Image Registration Tool) is a robust and accurate tool +for affine registration of intra- and inter-modal brain images. + +Examples +-------- + +Register two images together: + +>>> task = FLIRT( +... input_image="invol.nii", +... reference_image="refvol.nii", +... output_matrix="invol2refvol.mat", +... cost_function="mutualinfo", +... degrees_of_freedom=6, +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'flirt -in invol.nii -ref refvol.nii -out ...invol_flirt.nii -omat invol2refvol.mat ... -cost mutualinfo ...' + +Perform a single slice registration: + +>>> task = FLIRT( +... input_image="inslice.nii", +... reference_image="refslice.nii", +... output_image="outslice.nii", +... output_matrix="i2r.mat", +... interpolation="nearestneighbour", +... use_2d_registration=True, +... no_search=True, +... ) +>>> task.cmdline +'flirt -in inslice.nii -ref refslice.nii -out outslice.nii -omat i2r.mat -2D -nosearch ... -interp nearestneighbour' + +Apply a transformation: + +>>> task = ApplyXFM( +... input_image="invol.nii", +... output_image="outvol.nii", +... reference_image="refvol.nii", +... initial_matrix="affine.mat", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'flirt -in invol.nii -ref refvol.nii -out outvol.nii -init affine.mat -applyxfm ...' + +Apply a trasnformation and force isotropic resampling to 1 mm: + +>>> task = ApplyXFM( +... input_image="invol.nii", +... output_image="outvol.nii", +... reference_image="refvol.nii", +... initial_matrix="affine.mat", +... isotropic_resolution=1, +... padding_size=5, +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'flirt -in invol.nii -ref refvol.nii -out outvol.nii -init affine.mat -applyisoxfm 1 -paddingsize 5 ...' +""" + +__all__ = ["FLIRT", "ApplyXFM"] + +from os import PathLike + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + +from . import specs + + +@define(slots=False, kw_only=True) +class BaseSpec(ShellSpec): + """Common specifications for FLIRT-based tasks.""" + + input_image: PathLike = field( + metadata={"help_string": "input image", "mandatory": True, "argstr": "-in"} + ) + + reference_image: PathLike = field( + metadata={"help_string": "reference image", "mandatory": True, "argstr": "-ref"} + ) + + output_image: str = field( + metadata={ + "help_string": "output image", + "argstr": "-out", + "output_file_template": "{input_image}_flirt", + } + ) + + output_datatype: str = field( + metadata={ + "help_string": "output datatype", + "argstr": "-datatype", + "allowed_values": {"char", "short", "int", "float", "double"}, + } + ) + + +@define(slots=False, kw_only=True) +class FLIRTSpec(BaseSpec): + """Specifications for FLIRT.""" + + input_weights: PathLike = field( + metadata={ + "help_string": "voxel-wise weighting for input image", + "argstr": "-inweight", + } + ) + + reference_weights: PathLike = field( + metadata={ + "help_string": "voxel-wise weighting for reference image", + "argstr": "-refweight", + } + ) + + initial_matrix: PathLike = field( + metadata={"help_string": "initial transformation matrix", "argstr": "-init"} + ) + + output_matrix: str = field( + metadata={ + "help_string": "output transformation matrix", + "argstr": "-omat", + "output_file_template": "{input_image}_flirt.mat", + "keep_extension": False, + } + ) + + degrees_of_freedom: int = field( + metadata={ + "help_string": "degrees of freedom for the registration model", + "argstr": "-dof", + "allowed_values": {3, 6, 7, 9, 12}, + "xor": {"use_2d_registration"}, + } + ) + + use_2d_registration: bool = field( + metadata={ + "help_string": "use rigid-body registration model in 2D", + "argstr": "-2D", + "xor": {"degrees_of_freedom"}, + } + ) + + +class FLIRT(ShellCommandTask): + """Task definition for FLIRT.""" + + executable = "flirt" + + input_spec = SpecInfo( + name="Input", + bases=( + FLIRTSpec, + specs.SearchSpec, + specs.CostFunctionSpec, + specs.InterpolationSpec, + specs.WeightingSpec, + specs.VerboseSpec, + ), + ) + + +@define(slots=False, kw_only=True) +class ApplyXFMSpec(BaseSpec): + """Specifications for ApplyXFM.""" + + initial_matrix: PathLike = field( + metadata={ + "help_string": "initial transformation matrix", + "mandatory": True, + "argstr": "-init", + } + ) + + isotropic_resolution: float = field( + default=0.0, + metadata={ + "help_string": "force resampling to isotropic resolution", + "formatter": lambda isotropic_resolution: ( + f"-applyisoxfm {isotropic_resolution}" + if isotropic_resolution + else "-applyxfm" + ), + }, + ) + + padding_size: float = field( + metadata={"help_string": "padding size in voxels", "argstr": "-paddingsize"} + ) + + +class ApplyXFM(FLIRT): + """Task definition for ApplyXFM.""" + + input_spec = SpecInfo( + name="Input", bases=(ApplyXFMSpec, specs.InterpolationSpec, specs.VerboseSpec) + ) diff --git a/pydra/tasks/fsl/v6_0/flirt/img2imgcoord.py b/pydra/tasks/fsl/v6_0/flirt/img2imgcoord.py new file mode 100644 index 0000000..d4794ec --- /dev/null +++ b/pydra/tasks/fsl/v6_0/flirt/img2imgcoord.py @@ -0,0 +1,63 @@ +""" +Img2ImgCoord +============ + +Examples +-------- + +>>> task = Img2ImgCoord( +... input_coordinates="coordinates.txt", +... source_image="source.nii", +... destination_image="target.nii", +... affine_matrix="affine.mat", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'img2imgcoord -xfm affine.mat ... -src source.nii -dest target.nii coordinates.txt' +""" + +__all__ = ["Img2ImgCoord"] + +import os + +import attrs + +import pydra + +from . import specs + + +@attrs.define(slots=False, kw_only=True) +class Img2ImgCoordSpec(specs.BaseCoordSpec): + """Specifications for img2imgcoord.""" + + source_image: os.PathLike = attrs.field( + metadata={ + "help_string": "source image", + "mandatory": True, + "argstr": "-src", + } + ) + + destination_image: os.PathLike = attrs.field( + metadata={ + "help_string": "destination image", + "mandatory": True, + "argstr": "-dest", + } + ) + + +class Img2ImgCoordOutSpec(specs.CoordOutSpec): + """Output specifications for img2imgcoord.""" + + +class Img2ImgCoord(pydra.engine.ShellCommandTask): + """Task definition for img2imgcoord.""" + + executable = "img2imgcoord" + + input_spec = pydra.specs.SpecInfo( + name="Input", bases=(Img2ImgCoordSpec, specs.VerboseSpec) + ) + + output_spec = pydra.specs.SpecInfo(name="Output", bases=(Img2ImgCoordOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/flirt/img2stdcoord.py b/pydra/tasks/fsl/v6_0/flirt/img2stdcoord.py new file mode 100644 index 0000000..3bfb396 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/flirt/img2stdcoord.py @@ -0,0 +1,62 @@ +""" +Img2StdCoord +============ + +Examples +-------- + +>>> task = Img2StdCoord( +... input_coordinates="coordinates.txt", +... input_image="input.nii", +... standard_image="standard.nii", +... affine_matrix="affine.mat", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'img2stdcoord -xfm affine.mat ... -img input.nii -std standard.nii coordinates.txt' +""" + +__all__ = ["Img2StdCoord"] + +import os + +import attrs + +import pydra + +from . import specs + + +@attrs.define(slots=False, kw_only=True) +class Img2StdCoordSpec(specs.BaseCoordSpec): + """Specifications for img2stdcoord.""" + + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "-img", + } + ) + + standard_image: os.PathLike = attrs.field( + metadata={ + "help_string": "standard-space image", + "argstr": "-std", + } + ) + + +class Img2StdCoordOutSpec(specs.CoordOutSpec): + """Output specifications for img2stdcoord.""" + + +class Img2StdCoord(pydra.engine.ShellCommandTask): + """Task definition for img2stdcoord.""" + + executable = "img2stdcoord" + + input_spec = pydra.specs.SpecInfo( + name="Input", bases=(Img2StdCoordSpec, specs.VerboseSpec) + ) + + output_spec = pydra.specs.SpecInfo(name="Output", bases=(Img2StdCoordOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/flirt/specs.py b/pydra/tasks/fsl/v6_0/flirt/specs.py new file mode 100644 index 0000000..fe1afe6 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/flirt/specs.py @@ -0,0 +1,190 @@ +"""Common specifications for FLIRT.""" + +__all__ = [ + "CostFunctionSpec", + "InterpolationSpec", + "SearchSpec", + "WeightingSpec", +] + +import os +import pathlib +import typing as ty + +import attrs + +import pydra + + +@attrs.define(slots=False, kw_only=True) +class CostFunctionSpec(pydra.specs.ShellSpec): + cost_function: str = attrs.field( + default="corratio", + metadata={ + "help_string": "cost function", + "argstr": "-cost", + "allowed_values": { + "corratio", + "mutualinfo", + "normmi", + "normcorr", + "leastsq", + }, + }, + ) + + num_bins: int = attrs.field( + default=256, + metadata={ + "help_string": "number of histogram bins", + "argstr": "-bins", + }, + ) + + +@attrs.define(slots=False, kw_only=True) +class InterpolationSpec(pydra.specs.ShellSpec): + interpolation: str = attrs.field( + default="trilinear", + metadata={ + "help_string": "interpolation method", + "argstr": "-interp", + "allowed_values": { + "trilinear", + "nearestneighbour", + "spline", + "sinc", + }, + }, + ) + + +@attrs.define(slots=False, kw_only=True) +class SearchSpec(pydra.specs.ShellSpec): + # TODO: Change to Tuple[int, int] with pydra >=0.23 + SearchRange = ty.List[int] + + no_search: bool = attrs.field( + metadata={ + "help_string": "set all angular search ranges to 0", + "argstr": "-nosearch", + } + ) + + search_range_x: SearchRange = attrs.field( + default=[-90, 90], + metadata={ + "help_string": "range of search angles in x", + "formatter": lambda field, no_search: ( + "" if no_search else f"-searchrx {field[0]} {field[1]}" + ), + }, + ) + + search_range_y: SearchRange = attrs.field( + default=[-90, 90], + metadata={ + "help_string": "range of search angles in y", + "formatter": lambda field, no_search: ( + "" if no_search else f"-searchry {field[0]} {field[1]}" + ), + }, + ) + + search_range_z: SearchRange = attrs.field( + default=[-90, 90], + metadata={ + "help_string": "range of search angles in z", + "formatter": lambda field, no_search: ( + "" if no_search else f"-searchrz {field[0]} {field[1]}" + ), + }, + ) + + +@attrs.define(slots=False, kw_only=True) +class WeightingSpec(pydra.specs.ShellSpec): + reference_weighting_image: os.PathLike = attrs.field( + metadata={ + "help_string": "weights for reference image", + "argstr": "-refweight", + } + ) + + input_weighting_image: os.PathLike = attrs.field( + metadata={ + "help_string": "weights for input image", + "argstr": "-inweight", + } + ) + + +@attrs.define(slots=False, kw_only=True) +class VerboseSpec(pydra.specs.ShellSpec): + verbose: bool = attrs.field( + metadata={ + "help_string": "enable verbose logging", + "argstr": "-v", + } + ) + + +@attrs.define(slots=False, kw_only=True) +class BaseCoordSpec(pydra.specs.ShellSpec): + input_coordinates: os.PathLike = attrs.field( + metadata={ + "help_string": "input coordinates", + "mandatory": True, + "argstr": "", + "position": -1, + } + ) + + output_coordinates: str = attrs.field( + metadata={ + "help_string": "output coordinates", + "output_file_template": "{input_coordinates}_out", + } + ) + + affine_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": "affine transformation matrix", + "argstr": "-xfm", + } + ) + + input_warpfield: os.PathLike = attrs.field( + metadata={ + "help_string": "input warpfield image", + "argstr": "-warp", + } + ) + + unit: str = attrs.field( + default="vox", + metadata={ + "help_string": "unit of coordinates: voxels (vox) or millimeters (mm)", + "argstr": "-{unit}", + "allowed_values": {"vox", "mm"}, + }, + ) + + +def _get_output_coordinates(output_coordinates: str, stdout): + output_coordinates = pathlib.Path.cwd() / output_coordinates + + with open(output_coordinates, mode="w") as f: + f.write(stdout) + + return output_coordinates + + +@attrs.define(slots=False, kw_only=True) +class CoordOutSpec(pydra.specs.ShellOutSpec): + output_coordinates: os.PathLike = attrs.field( + metadata={ + "help_string": "output coordinates", + "callable": _get_output_coordinates, + } + ) diff --git a/pydra/tasks/fsl/v6_0/flirt/std2imgcoord.py b/pydra/tasks/fsl/v6_0/flirt/std2imgcoord.py new file mode 100644 index 0000000..f45e707 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/flirt/std2imgcoord.py @@ -0,0 +1,62 @@ +""" +Std2ImgCoord +============ + +Examples +-------- + +>>> task = Std2ImgCoord( +... input_coordinates="coordinates.txt", +... input_image="input.nii", +... standard_image="standard.nii", +... affine_matrix="affine.mat", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'std2imgcoord -xfm affine.mat ... -std standard.nii -img input.nii coordinates.txt' +""" + +__all__ = ["Std2ImgCoord"] + +import os + +import attrs + +import pydra + +from . import specs + + +@attrs.define(slots=False, kw_only=True) +class Std2ImgCoordSpec(specs.BaseCoordSpec): + """Specifications for std2imgcoord.""" + + standard_image: os.PathLike = attrs.field( + metadata={ + "help_string": "standard-space image", + "argstr": "-std", + } + ) + + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "-img", + } + ) + + +class Std2ImgCoordOutSpec(specs.CoordOutSpec): + """Output specifications for std2imgcoord.""" + + +class Std2ImgCoord(pydra.engine.ShellCommandTask): + """Task definition for std2imgcoord.""" + + executable = "std2imgcoord" + + input_spec = pydra.specs.SpecInfo( + name="Input", bases=(Std2ImgCoordSpec, specs.VerboseSpec) + ) + + output_spec = pydra.specs.SpecInfo(name="Output", bases=(Std2ImgCoordOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/fnirt/__init__.py b/pydra/tasks/fsl/v6_0/fnirt/__init__.py new file mode 100644 index 0000000..2dae811 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fnirt/__init__.py @@ -0,0 +1,16 @@ +""" +FNIRT +===== + +.. automodule:: pydra.tasks.fsl.fnirt.fnirt +.. automodule:: pydra.tasks.fsl.fnirt.fnirtfileutils +.. automodule:: pydra.tasks.fsl.fnirt.applywarp +.. automodule:: pydra.tasks.fsl.fnirt.convertwarp +.. automodule:: pydra.tasks.fsl.fnirt.invwarp +""" + +from .applywarp import ApplyWarp +from .convertwarp import ConvertWarp +from .fnirt import FNIRT +from .fnirtfileutils import FNIRTFileUtils +from .invwarp import InvWarp diff --git a/pydra/tasks/fsl/v6_0/fnirt/applywarp.py b/pydra/tasks/fsl/v6_0/fnirt/applywarp.py new file mode 100644 index 0000000..c14e640 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fnirt/applywarp.py @@ -0,0 +1,152 @@ +""" +ApplyWarp +========= + +Examples +-------- + +>>> task = ApplyWarp( +... input_image="invol.nii", +... reference_image="refvol.nii", +... input_warpfield="warpvol.nii", +... warpfield_as="abs", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'applywarp --in invol.nii --ref refvol.nii --out ...invol_warped.nii \ +--warp warpvol.nii --abs ...' + +>>> task = ApplyWarp( +... input_image="invol.nii", +... reference_image="refvol.nii", +... output_image="outvol.nii", +... use_sqform=True, +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'applywarp --in invol.nii --ref refvol.nii --out outvol.nii ... --usesqform' +""" + +__all__ = ["ApplyWarp"] + +import os +import typing as ty + +import attrs + +import pydra + +from . import specs + + +@attrs.define(slots=False, kw_only=True) +class ApplyWarpSpec(pydra.specs.ShellSpec): + """Specifications for applywarp.""" + + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "--in", + } + ) + + reference_image: os.PathLike = attrs.field( + metadata={ + "help_string": "reference image", + "mandatory": True, + "argstr": "--ref", + } + ) + + output_image: str = attrs.field( + metadata={ + "help_string": "output image", + "argstr": "--out", + "output_file_template": "{input_image}_warped", + } + ) + + input_warpfield: os.PathLike = attrs.field( + metadata={ + "help_string": "deformation field or coefficients", + "argstr": "--warp", + } + ) + + warpfield_as: str = attrs.field( + metadata={ + "help_string": "treat deformation field as absolute (abs) or relative (rel)", + "argstr": "--{warpfield_as}", + "allowed_values": {"abs", "rel"}, + "requires": {"input_warpfield"}, + } + ) + + output_datatype: str = attrs.field( + metadata={ + "help_string": "force output datatype", + "argstr": "--datatype", + "allowed_values": {"char", "short", "int", "float", "double"}, + } + ) + + supersampling_level: ty.Union[str, int] = attrs.field( + metadata={ + "help_string": "level of intermediate supersampling", + "argstr": "--super --superlevel", + } + ) + + pre_affine_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": "pre-affine matrix", + "argstr": "--premat", + } + ) + + post_affine_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": "post-affine matrix", + "argstr": "--postmat", + } + ) + + reference_mask: os.PathLike = attrs.field( + metadata={ + "help_string": "mask image in reference space", + "argstr": "--mask", + } + ) + + interpolation: str = attrs.field( + default="trilinear", + metadata={ + "help_string": "interpolation method", + "argstr": "--interp", + "allowed_values": {"nn", "trilinear", "sinc", "spline"}, + }, + ) + + padding_size: float = attrs.field( + metadata={ + "help_string": "padding size in voxels", + "argstr": "--paddingsize", + } + ) + + use_sqform: bool = attrs.field( + metadata={ + "help_string": "use sform and qform from reference and input images", + "argstr": "--usesqform", + "requires": {"input_image", "reference_image"}, + } + ) + + +class ApplyWarp(pydra.engine.ShellCommandTask): + """Task definition for applywarp.""" + + executable = "applywarp" + + input_spec = pydra.specs.SpecInfo( + name="Input", bases=(ApplyWarpSpec, specs.VerboseSpec) + ) diff --git a/pydra/tasks/fsl/v6_0/fnirt/convertwarp.py b/pydra/tasks/fsl/v6_0/fnirt/convertwarp.py new file mode 100644 index 0000000..37a038f --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fnirt/convertwarp.py @@ -0,0 +1,176 @@ +""" +ConvertWarp +=========== + +Examples +-------- + +>>> task = ConvertWarp( +... reference_image="refvol.nii", +... pre_affine_matrix="affine.mat", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'convertwarp --ref refvol.nii --out ...refvol_warp.nii --premat affine.mat \ +--jacobian ...refvol_jac.nii' + +>>> task = ConvertWarp( +... reference_image="refvol.nii", +... output_warpfield="outwarp.nii", +... pre_affine_matrix="pre.mat", +... pre_warpfield="warp1.nii", +... post_warpfield="warp2.nii", +... post_affine_matrix="post.mat", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'convertwarp --ref refvol.nii --out outwarp.nii --premat pre.mat \ +--warp1 warp1.nii --warp2 warp2.nii --postmat post.mat --jacobian \ +...refvol_jac.nii' + +>>> task = ConvertWarp( +... reference_image="refvol.nii", +... input_shiftmap="shiftmap.nii", +... shift_direction="y-", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'convertwarp --ref refvol.nii --out .../refvol_warp.nii --shiftmap shiftmap.nii \ +--shiftdir y- --jacobian .../refvol_jac.nii' +""" + +__all__ = ["ConvertWarp"] + +import os + +import attrs + +import pydra + +from . import specs + + +@attrs.define(slots=False, kw_only=True) +class ConvertWarpSpec(pydra.specs.ShellSpec): + """Specifications for convertwrap.""" + + reference_image: os.PathLike = attrs.field( + metadata={ + "help_string": "reference image", + "mandatory": True, + "argstr": "--ref", + } + ) + + output_warpfield: str = attrs.field( + metadata={ + "help_string": "output deformation field image", + "argstr": "--out", + "output_file_template": "{reference_image}_warp", + } + ) + + pre_affine_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": "pre-affine matrix", + "argstr": "--premat", + } + ) + + pre_warpfield: os.PathLike = attrs.field( + metadata={ + "help_string": "warp following pre-affine transform", + "argstr": "--warp1", + } + ) + + mid_affine_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": "mid-warp affine matrix", + "argstr": "--midmat", + } + ) + + post_warpfield: os.PathLike = attrs.field( + metadata={ + "help_string": "warp preceding post-affine transform", + "argstr": "--warp2", + } + ) + + post_affine_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": "post-affine matrix", + "argstr": "--postmat", + } + ) + + input_shiftmap: os.PathLike = attrs.field( + metadata={ + "help_string": "shiftmap image (applied first)", + "argstr": "--shiftmap", + } + ) + + shift_direction: str = attrs.field( + metadata={ + "help_string": "direction to apply shiftmap", + "argstr": "--shiftdir", + "requires": {"input_shiftmap"}, + "allowed_values": {"x", "y", "z", "x-", "y-", "z-"}, + } + ) + + output_jacobian_image: str = attrs.field( + metadata={ + "help_string": "constrain the limits of the Jacobian of the deformation field", + "argstr": "--jacobian", + "output_file_template": "{reference_image}_jac", + } + ) + + constrain_jacobian: bool = attrs.field( + metadata={ + "help_string": "constrain the Jacobian of the deformation field", + "argstr": "--constrainj", + } + ) + + min_jacobian: float = attrs.field( + metadata={ + "help_string": "minimum Jacobian value", + "argstr": "--jmin", + "requires": {"constain_jacobian"}, + } + ) + + max_jacobian: float = attrs.field( + metadata={ + "help_string": "maximum Jacobian value", + "argstr": "--jmax", + "requires": {"constain_jacobian"}, + } + ) + + warpfield_as: str = attrs.field( + metadata={ + "help_string": "treat deformation field as absolute (abs) or relative (rel)", + "argstr": "--{warpfield_as}", + "allowed_values": {"abs", "rel"}, + } + ) + + output_warpfield_as: str = attrs.field( + metadata={ + "help_string": "save output deformation field as absolute (abs) or relative (rel)", + "argstr": "--{output_warpfield_as}out", + "allowed_values": {"abs", "rel"}, + } + ) + + +class ConvertWarp(pydra.engine.ShellCommandTask): + """Task definition for convertwarp.""" + + executable = "convertwarp" + + input_spec = pydra.specs.SpecInfo( + name="Input", bases=(ConvertWarpSpec, specs.VerboseSpec) + ) diff --git a/pydra/tasks/fsl/v6_0/fnirt/fnirt.py b/pydra/tasks/fsl/v6_0/fnirt/fnirt.py new file mode 100644 index 0000000..314f2b2 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fnirt/fnirt.py @@ -0,0 +1,267 @@ +""" +FNIRT +===== + +FNIRT (FSL Non-linear Image Registration Tool) performs non-linear registration of brain images. + +Examples +-------- + +>>> task = FNIRT( +... reference_image="template.nii", +... input_image="input.nii", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'fnirt --ref template.nii --in input.nii --cout ...input_warpcoef.nii \ +--iout ...input_warped.nii --fout ...input_warpfield.nii \ +--jout ...input_jac.nii ...' + +>>> task = FNIRT( +... reference_image="template.nii", +... input_image="input.nii", +... subsampling=[4, 2, 1], +... warp_resolution=[8, 8, 8], +... input_fwhm=[8, 4, 2], +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'fnirt --ref template.nii --in input.nii ... --subsamp 4,2,1 \ +--warpres 8,8,8 ... --infwhm 8,4,2 ...' +""" + +__all__ = ["FNIRT"] + +import os +import typing as ty + +import attrs + +import pydra + +from . import specs + + +def _format_list(field: list): + return f"{','.join(map(str, field))}" + + +@attrs.define(slots=False, kw_only=True) +class FNIRTSpec(pydra.specs.ShellSpec): + """Task specifications for FNIRT.""" + + reference_image: os.PathLike = attrs.field( + metadata={ + "help_string": "reference image", + "mandatory": True, + "argstr": "--ref", + } + ) + + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "--in", + } + ) + + affine_matrix: os.PathLike = attrs.field( + metadata={ + "help_string": "affine matrix", + "argstr": "--aff", + } + ) + + input_warpfield: os.PathLike = attrs.field( + metadata={ + "help_string": "input warpfield", + "argstr": "--inwarp", + } + ) + + output_warpcoef: str = attrs.field( + metadata={ + "help_string": "output file containing the field coefficients", + "argstr": "--cout", + "output_file_template": "{input_image}_warpcoef", + } + ) + + output_image: str = attrs.field( + metadata={ + "help_string": "output image", + "argstr": "--iout", + "output_file_template": "{input_image}_warped", + } + ) + + output_warpfield: str = attrs.field( + metadata={ + "help_string": "output deformation field", + "argstr": "--fout", + "output_file_template": "{input_image}_warpfield", + } + ) + + output_jacobian_image: str = attrs.field( + metadata={ + "help_string": "output Jacobian determinant map", + "argstr": "--jout", + "output_file_template": "{input_image}_jac", + } + ) + + reference_mask: os.PathLike = attrs.field( + metadata={ + "help_string": "mask in reference space", + "argstr": "--applyrefmask --refmask", + } + ) + + input_mask: os.PathLike = attrs.field( + metadata={ + "help_string": "mask in input image space", + "argstr": "--applyinmask --inmask", + } + ) + + max_iterations: ty.Iterable[int] = attrs.field( + default=(5, 5, 5, 5), + metadata={ + "help_string": "maximum number of non-linear iterations", + "formatter": lambda field: f"--miter {_format_list(field)}", + }, + ) + + subsampling: ty.Iterable[int] = attrs.field( + default=(4, 2, 1, 1), + metadata={ + "help_string": "sub-sampling scheme", + "formatter": lambda field: f"--subsamp {_format_list(field)}", + }, + ) + + warp_resolution: ty.Tuple[float, float, float] = attrs.field( + default=(10, 10, 10), + metadata={ + "help_string": "resolution of warp basis in x, y and z (in millimeters)", + "formatter": lambda field: f"--warpres {_format_list(field)}", + }, + ) + + spline_order: int = attrs.field( + default=3, + metadata={ + "help_string": "use quadratic (2) or cubic (3) splines", + "argstr": "--splineorder", + "allowed_values": {2, 3}, + }, + ) + + input_fwhm: ty.Iterable[float] = attrs.field( + default=(6.0, 4.0, 2.0, 2.0), + metadata={ + "help_string": "FWHM for Gaussian kernel applied to input image (in millimeters)", + "formatter": lambda field: f"--infwhm {_format_list(field)}", + }, + ) + + reference_fwhm: ty.Iterable[float] = attrs.field( + default=(4.0, 2.0, 0.0, 0.0), + metadata={ + "help_string": "FWHM for Gaussian kernel applied to reference image (in millimeters)", + "formatter": lambda field: f"--reffwhm {_format_list(field)}", + }, + ) + + warp_model: str = attrs.field( + default="bending_energy", + metadata={ + "help_string": "model for warpfield regularisation", + "argstr": "--regmod", + "allowed_values": {"bending_energy", "membrane_energy"}, + }, + ) + + warp_lambda: ty.Iterable[float] = attrs.field( + default=(300, 75, 30, 30), + metadata={ + "help_string": "weight of warpfield regularisation", + "argstr": "--lambda", + }, + ) + + jacobian_range: ty.Tuple[float, float] = attrs.field( + default=(1e-2, 1e2), + metadata={ + "help_string": "range of Jacobian determinants", + "formatter": lambda field: f"--jacrange {_format_list(field)}", + }, + ) + + intensity_model: str = attrs.field( + default="global_non_linear_with_bias", + metadata={ + "help_string": "model for intensity mapping", + "argstr": "--intmod", + "allowed_values": { + "none", + "global_linear", + "global_non_linear", + "local_linear", + "global_non_linear_with_bias", + "local_non_linear", + }, + }, + ) + + intensity_order: int = attrs.field( + default=5, + metadata={ + "help_string": "polynomial order for intensity mapping", + "argstr": "--intorder", + }, + ) + + bias_resolution: ty.Tuple[float, float, float] = attrs.field( + default=(50, 50, 50), + metadata={ + "help_string": "resolution for bias field modelling (in millimeters)", + "formatter": lambda field: f"--biasres {_format_list(field)}", + }, + ) + + bias_lambda: float = attrs.field( + default=10000, + metadata={ + "help_string": "regularisation parameter for bias field modelling", + "argstr": "--biaslambda", + }, + ) + + precision: str = attrs.field( + default="double", + metadata={ + "help_string": "numerical precision for Hessian computation (float or double)", + "argstr": "--numprec", + "allowed_values": {"float", "double"}, + }, + ) + + interpolation: str = attrs.field( + default="linear", + metadata={ + "help_string": "interpolation model (linear or spline)", + "argstr": "--interp", + "allowed_values": {"linear", "spline"}, + }, + ) + + +class FNIRT(pydra.engine.ShellCommandTask): + """Task definition for FNIRT.""" + + executable = "fnirt" + + input_spec = pydra.specs.SpecInfo( + name="Input", bases=(FNIRTSpec, specs.VerboseSpec) + ) diff --git a/pydra/tasks/fsl/v6_0/fnirt/fnirtfileutils.py b/pydra/tasks/fsl/v6_0/fnirt/fnirtfileutils.py new file mode 100644 index 0000000..d066e37 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fnirt/fnirtfileutils.py @@ -0,0 +1,120 @@ +""" +FNIRTFileUtils +============== + +Examples +-------- + +>>> task = FNIRTFileUtils( +... input_image="input.nii", +... reference_image="reference.nii", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'fnirtfileutils --in input.nii --ref reference.nii --out ...input_field.nii \ +--outformat field ...' + +>>> task = FNIRTFileUtils( +... input_image="input.nii", +... reference_image="reference.nii", +... output_jacobian_image="jacobian.nii", +... with_affine_transform=True, +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'fnirtfileutils --in input.nii --ref reference.nii ... --jac jacobian.nii \ +... --withaff' +""" + +__all__ = ["FNIRTFileUtils"] + +import os + +import attrs + +import pydra + +from . import specs + + +@attrs.define(slots=False, kw_only=True) +class FNIRTFileUtilsSpec(pydra.specs.ShellSpec): + """Specifications for fnirtfileutils.""" + + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input image with FNIRT coefficients", + "argstr": "--in", + } + ) + + reference_image: os.PathLike = attrs.field( + metadata={ + "help_string": "reference image", + "argstr": "--ref", + } + ) + + output_image: str = attrs.field( + metadata={ + "help_string": "output field or coefficient image", + "argstr": "--out", + "output_file_template": "{input_image}_{output_format}", + } + ) + + output_format: str = attrs.field( + default="field", + metadata={ + "help_string": "output format (field or spline)", + "argstr": "--outformat", + "allowed_values": {"field", "spline"}, + }, + ) + + warp_resolution: float = attrs.field( + metadata={ + "help_string": "warp resolution in millimeters", + "argstr": "--warpres", + # "requires": {("output_format", "spline")}, # TODO + } + ) + + knot_spacing: float = attrs.field( + metadata={ + "help_string": "knot spacing in voxels", + "argstr": "--knotspace", + # "requires": {("output_format", "spline")}, # TODO + } + ) + + output_jacobian_image: str = attrs.field( + metadata={ + "help_string": "output Jacobian determinant map", + "argstr": "--jac", + "output_file_template": "{input_image}_jac", + } + ) + + output_jacobian_matrix: str = attrs.field( + metadata={ + "help_string": "output Jacobian matrix map", + "argstr": "--matjac", + "output_file_template": "{input_image}_matjac", + } + ) + + with_affine_transform: bool = attrs.field( + metadata={ + "help_string": "include affine transform in field and jacobian images", + "argstr": "--withaff", + } + ) + + +class FNIRTFileUtils(pydra.engine.ShellCommandTask): + """Task definition for fnirtfileutils.""" + + executable = "fnirtfileutils" + + input_spec = pydra.specs.SpecInfo( + name="Input", bases=(FNIRTFileUtilsSpec, specs.VerboseSpec) + ) diff --git a/pydra/tasks/fsl/v6_0/fnirt/invwarp.py b/pydra/tasks/fsl/v6_0/fnirt/invwarp.py new file mode 100644 index 0000000..0ee4ca2 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fnirt/invwarp.py @@ -0,0 +1,105 @@ +""" +InvWarp +======= + +Examples +-------- + +>>> task = InvWarp( +... input_warpfield="warpvol.nii", +... reference_image= "refvol.nii", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'invwarp --warp warpvol.nii --ref refvol.nii --out ...warpvol_invwarp.nii' + +>>> task = InvWarp( +... input_warpfield="warpvol.nii", +... reference_image= "refvol.nii", +... output_warpfield="invwarpvol.nii", +... no_jacobian_constraints=True, +... ) +>>> task.cmdline +'invwarp --warp warpvol.nii --ref refvol.nii --out invwarpvol.nii --noconstraint' + +""" + +__all__ = ["InvWarp"] + +import os + +import attrs + +import pydra + +from . import specs + + +@attrs.define(slots=False, kw_only=True) +class InvWarpSpec(pydra.specs.ShellSpec): + """Specifications for invwarp.""" + + input_warpfield: os.PathLike = attrs.field( + metadata={ + "help_string": "input warp image", + "mandatory": True, + "argstr": "--warp", + } + ) + + reference_image: os.PathLike = attrs.field( + metadata={ + "help_string": "reference image", + "mandatory": True, + "argstr": "--ref", + } + ) + + output_warpfield: str = attrs.field( + metadata={ + "help_string": "output inverse warp image", + "argstr": "--out", + "output_file_template": "{input_warpfield}_invwarp", + } + ) + + warpfield_as: str = attrs.field( + metadata={ + "help_string": "treat deformation field as absolute (abs) or relative (rel)", + "argstr": "--{warpfield_as}", + "allowed_values": {"abs", "rel"}, + "requires": {"input_warpfield"}, + } + ) + + no_jacobian_constraints: bool = attrs.field( + metadata={ + "help_string": "do not constrain the Jacobian of the deformation field", + "argstr": "--noconstraint", + } + ) + + min_jacobian: float = attrs.field( + metadata={ + "help_string": "minimum Jacobian value", + "argstr": "--jmin", + "xor": {"no_jacobian_constraints"}, + } + ) + + max_jacobian: float = attrs.field( + metadata={ + "help_string": "maximum Jacobian value", + "argstr": "--jmax", + "xor": {"no_jacobian_constraints"}, + } + ) + + +class InvWarp(pydra.engine.ShellCommandTask): + """Task definition for invwarp.""" + + executable = "invwarp" + + input_spec = pydra.specs.SpecInfo( + name="Input", bases=(InvWarpSpec, specs.VerboseSpec) + ) diff --git a/pydra/tasks/fsl/v6_0/fnirt/specs.py b/pydra/tasks/fsl/v6_0/fnirt/specs.py new file mode 100644 index 0000000..7598831 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fnirt/specs.py @@ -0,0 +1,13 @@ +import attrs + +import pydra + + +@attrs.define(slots=False, kw_only=True) +class VerboseSpec(pydra.specs.ShellSpec): + verbose: bool = attrs.field( + metadata={ + "help_string": "enable verbose logging", + "argstr": "--verbose", + } + ) diff --git a/pydra/tasks/fsl/v6_0/fugue/__init__.py b/pydra/tasks/fsl/v6_0/fugue/__init__.py new file mode 100644 index 0000000..efa3700 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fugue/__init__.py @@ -0,0 +1,14 @@ +""" +FUGUE +===== + +.. automodule:: pydra.tasks.fsl.fugue.fugue +.. automodule:: pydra.tasks.fsl.fugue.prepare_fieldmap +.. automodule:: pydra.tasks.fsl.fugue.prelude +.. automodule:: pydra.tasks.fsl.fugue.sigloss +""" + +from .fugue import FUGUE +from .prelude import Prelude +from .prepare_fieldmap import PrepareFieldmap +from .sigloss import SigLoss diff --git a/pydra/tasks/fsl/v6_0/fugue/fugue.py b/pydra/tasks/fsl/v6_0/fugue/fugue.py new file mode 100644 index 0000000..014e158 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fugue/fugue.py @@ -0,0 +1,242 @@ +""" +FUGUE +===== + +>>> task = FUGUE( +... input_image="epi.nii", +... input_phasemap="phasemap.nii", +... dwell_to_asym_time_ratio=0.3, +... output_inverse_warpfield="unwarped.nii", +... ) +>>> task.cmdline +'fugue --in epi.nii --unwarp unwarped.nii --phasemap phasemap.nii --dwelltoasym 0.3' + +>>> task = FUGUE( +... input_image="unwarped.nii", +... input_phasemap="phasemap.nii", +... dwell_to_asym_time_ratio=0.3, +... output_warpfield="warped.nii", +... ) +>>> task.cmdline +'fugue --in unwarped.nii --warp warped.nii --phasemap phasemap.nii --dwelltoasym 0.3' + +>>> task = FUGUE( +... input_phasemap="phasemap.nii", +... output_shiftmap="shiftmap.nii", +... ) +>>> task.cmdline +'fugue --phasemap phasemap.nii --saveshift shiftmap.nii' +""" + +__all__ = ["FUGUE"] + +import os + +import attrs + +import pydra + + +@attrs.define(slots=False, kw_only=True) +class FUGUESpec(pydra.specs.ShellSpec): + """Specifications for fugue.""" + + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input image", + "argstr": "--in", + } + ) + + output_warpfield: os.PathLike = attrs.field( + metadata={ + "help_string": "output warpfield image", + "argstr": "--warp", + } + ) + + output_inverse_warpfield: os.PathLike = attrs.field( + metadata={ + "help_string": "output inverse warpfield image", + "argstr": "--unwarp", + } + ) + + input_phasemap: os.PathLike = attrs.field( + metadata={ + "help_string": "input phase image", + "argstr": "--phasemap", + } + ) + + dwell_to_asym_time_ratio: float = attrs.field( + metadata={ + "help_string": "dwell to asymmetric echo time ratio", + "argstr": "--dwelltoasym", + } + ) + + dwell_time: float = attrs.field( + metadata={ + "help_string": "EPI dwell time in seconds", + "argstr": "--dwell", + } + ) + + asym_time: float = attrs.field( + metadata={ + "help_string": "asymmetric spin echo time in seconds", + "argstr": "--asym", + } + ) + + input_fieldmap: os.PathLike = attrs.field( + metadata={ + "help_string": "load fieldmap image", + "argstr": "--loadfmap", + } + ) + + output_fieldmap: os.PathLike = attrs.field( + metadata={ + "help_string": "save fieldmap image", + "argstr": "--savefmap", + } + ) + + input_shiftmap: os.PathLike = attrs.field( + metadata={ + "help_string": "load pixel shift image", + "argstr": "--loadshift", + } + ) + + output_shiftmap: os.PathLike = attrs.field( + metadata={ + "help_string": "save pixel shift image", + "argstr": "--saveshift", + } + ) + + sigma2d: float = attrs.field( + metadata={ + "help_string": "apply 2D Gaussian smoothing of sigma in millimeter", + "argstr": "--smooth2", + } + ) + + sigma3d: float = attrs.field( + metadata={ + "help_string": "apply 3D Gaussian smoothing of sigma in millimeter", + "argstr": "--smooth3", + } + ) + + polynomial_order: int = attrs.field( + metadata={ + "help_string": "order of polynomial fitting", + "argstr": "--poly", + } + ) + + sinusoidal_order: int = attrs.field( + metadata={ + "help_string": "order of sinusoidal (Fourier) fitting", + "argstr": "--fourier", + } + ) + + direction: str = attrs.field( + metadata={ + "help_string": "unwarping direction", + "argstr": "--unwarpdir", + "allowed_values": {"x", "y", "z", "x-", "y-", "z-"}, + } + ) + + input_mask: os.PathLike = attrs.field( + metadata={ + "help_string": "mask for input image", + "argstr": "--mask", + } + ) + + output_unmasked_fieldmap: os.PathLike = attrs.field( + metadata={ + "help_string": "save unmasked fieldmap", + "argstr": "--unmaskfmap", + "requires": {"output_fieldmap"}, + } + ) + + output_unmasked_shiftmap: os.PathLike = attrs.field( + metadata={ + "help_string": "save unmasked shiftmap", + "argstr": "--unmaskshift", + "requires": {"output_shiftmap"}, + } + ) + + verbose: bool = attrs.field( + metadata={ + "help_string": "enable verbose logging", + "argstr": "--verbose", + } + ) + + +@attrs.define(slots=False, kw_only=True) +class FUGUEOutSpec(pydra.specs.ShellOutSpec): + """Output specifications for fugue.""" + + output_warpfield: str = attrs.field( + metadata={ + "help_string": "output warpfield image", + "output_file_template": "{output_warpfield}", + } + ) + + output_inverse_warpfield: str = attrs.field( + metadata={ + "help_string": "output inverse warpfield image", + "output_file_template": "{output_inverse_warpfield}", + } + ) + + output_fieldmap: str = attrs.field( + metadata={ + "help_string": "output fieldmap image", + "output_file_template": "{output_fieldmap}", + } + ) + + output_shiftmap: str = attrs.field( + metadata={ + "help_string": "output shiftmap image", + "output_file_template": "{output_shiftmap}", + } + ) + + output_unmasked_fieldmap: str = attrs.field( + metadata={ + "help_string": "output unmasked fieldmap", + "output_file_template": "{output_unmasked_fieldmap}", + } + ) + + output_unmasked_shiftmap: str = attrs.field( + metadata={ + "help_string": "output unmasked shiftmap", + "output_file_template": "{output_unmasked_shiftmap}", + } + ) + + +class FUGUE(pydra.engine.ShellCommandTask): + """Task definition for fugue.""" + + executable = "fugue" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(FUGUESpec,)) + + output_spec = pydra.specs.SpecInfo(name="Output", bases=(FUGUEOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/fugue/prelude.py b/pydra/tasks/fsl/v6_0/fugue/prelude.py new file mode 100644 index 0000000..6745f14 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fugue/prelude.py @@ -0,0 +1,173 @@ +""" +Prelude +======= + +Phase Region Expanding Labeller for Unwrapping Discrete Estimates. + +Examples +-------- + +>>> task = Prelude(complex_image="complex.nii") +>>> task.cmdline # doctest: +ELLIPSIS +'prelude --complex complex.nii --out complex_unwrapped_phase.nii --rawphase complex_raw_phase.nii \ +--labels complex_labels.nii --savemask complex_mask.nii ...' + +>>> task = Prelude( +... phase_image="phase.nii", +... magnitude_image="magnitude.nii", +... output_unwrapped_phase_image="unwrapped.nii", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'prelude --abs magnitude.nii --phase phase.nii --out unwrapped.nii ...' +""" + +__all__ = ["Prelude"] + +import os + +import attrs + +import pydra + + +def _output_filename_factory(complex_image, phase_image, suffix): + from pathlib import PurePath + + stem, ext = PurePath(complex_image or phase_image).name.split(".", maxsplit=1) + + return f"{stem}_{suffix}.{ext}" + + +@attrs.define(slots=False, kw_only=True) +class PreludeSpec(pydra.specs.ShellSpec): + """Specifications for prelude.""" + + complex_image: os.PathLike = attrs.field( + metadata={ + "help_string": "complex phase image", + "mandatory": True, + "argstr": "--complex", + "xor": {"phase_image"}, + } + ) + + magnitude_image: os.PathLike = attrs.field( + metadata={"help_string": "magnitude image", "argstr": "--abs"} + ) + + phase_image: os.PathLike = attrs.field( + metadata={ + "help_string": "raw phase image", + "mandatory": True, + "argstr": "--phase", + "requires": {"magnitude_image"}, + "xor": {"complex_image"}, + } + ) + + input_mask: os.PathLike = attrs.field( + metadata={"help_string": "input mask", "argstr": "--mask"} + ) + + output_unwrapped_phase_image: str = attrs.field( + metadata={ + "help_string": "output unwrapped phase image", + "formatter": lambda field, complex_image, phase_image: "--out {}".format( + field + or _output_filename_factory( + complex_image, phase_image, "unwrapped_phase" + ) + ), + } + ) + + output_raw_phase_image: str = attrs.field( + metadata={ + "help_string": "output raw phase image", + "formatter": lambda field, complex_image, phase_image: "--rawphase {}".format( + field + or _output_filename_factory(complex_image, phase_image, "raw_phase") + ), + } + ) + + output_labels: str = attrs.field( + metadata={ + "help_string": "output labels", + "formatter": lambda field, complex_image, phase_image: "--labels {}".format( + field or _output_filename_factory(complex_image, phase_image, "labels") + ), + } + ) + + output_mask: os.PathLike = attrs.field( + metadata={ + "help_string": "output mask", + "formatter": lambda field, complex_image, phase_image: "--savemask {}".format( + field or _output_filename_factory(complex_image, phase_image, "mask") + ), + } + ) + + num_partitions: int = attrs.field( + default=8, + metadata={ + "help_string": "number of phase partitions", + "argstr": "--numphasesplit", + }, + ) + + process_labels_in_2d: bool = attrs.field( + metadata={ + "help_string": "process labels in 2D", + "argstr": "--labelslices", + "xor": {"process_all_in_2d", "process_all_in_3d"}, + } + ) + + process_all_in_2d: bool = attrs.field( + metadata={ + "help_string": "process all in 2D", + "argstr": "--slices", + "xor": {"process_labels_in_2d", "process_all_in_3d"}, + } + ) + + process_all_in_3d: bool = attrs.field( + metadata={ + "help_string": "process all in 3D", + "argstr": "--force3D", + "xor": {"process_labels_in_2d", "process_all_in_2d"}, + } + ) + + threshold: float = attrs.field( + default=0.0, + metadata={ + "help_string": "intensity threshold for masking", + "argstr": "--thresh", + }, + ) + + first_image_index: int = attrs.field( + metadata={"help_string": "index of first image to process", "argstr": "--start"} + ) + + last_image_index: int = attrs.field( + metadata={"help_string": "index of last image to process", "argstr": "--end"} + ) + + remove_ramps: bool = attrs.field( + metadata={ + "help_string": "remove phase ramps during unwrapping", + "argstr": "--removeramps", + } + ) + + +class Prelude(pydra.engine.ShellCommandTask): + """Task definition for prelude.""" + + executable = "prelude" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(PreludeSpec,)) diff --git a/pydra/tasks/fsl/v6_0/fugue/prepare_fieldmap.py b/pydra/tasks/fsl/v6_0/fugue/prepare_fieldmap.py new file mode 100644 index 0000000..6e6bb67 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fugue/prepare_fieldmap.py @@ -0,0 +1,74 @@ +""" +PrepareFieldmap +=============== + +EPI fieldmap preprocessing. + +Examples +======== + +>>> task = PrepareFieldmap(phase_image="gre_phase.nii", magnitude_image="gre_mag.nii", output_image="fmap.nii") +>>> task.cmdline +'fsl_prepare_fieldmap SIEMENS gre_phase.nii gre_mag.nii fmap.nii 2.46' +""" + +__all__ = ["PrepareFieldmap"] + +from os import PathLike + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class PrepareFieldmapSpec(ShellSpec): + """Specifications for fsl_prepare_fieldmap.""" + + scanner: str = field( + default="SIEMENS", + metadata={"help_string": "scanner (usually SIEMENS)", "argstr": ""}, + ) + + phase_image: PathLike = field( + metadata={"help_string": "phase image", "mandatory": True, "argstr": ""} + ) + + magnitude_image: PathLike = field( + metadata={ + "help_string": "magnitude (brain extracted) image", + "mandatory": True, + "argstr": "", + } + ) + + output_image: str = field( + metadata={ + "help_string": "output fieldmap image in rad/s", + "argstr": "", + "output_file_template": "{phase_image}_fmap", + } + ) + + delta_te: float = field( + default=2.46, + metadata={ + "help_string": "echo time difference of the fieldmap sequence in milliseconds (usually 2.46 on SIEMENS)", + "argstr": "", + }, + ) + + no_check: bool = field( + metadata={ + "help_string": "disable sanity checks for images", + "argstr": "--nocheck", + } + ) + + +class PrepareFieldmap(ShellCommandTask): + """Task definition for fsl_prepare_fieldmap.""" + + executable = "fsl_prepare_fieldmap" + + input_spec = SpecInfo(name="Input", bases=(PrepareFieldmapSpec,)) diff --git a/pydra/tasks/fsl/v6_0/fugue/sigloss.py b/pydra/tasks/fsl/v6_0/fugue/sigloss.py new file mode 100644 index 0000000..45ba20e --- /dev/null +++ b/pydra/tasks/fsl/v6_0/fugue/sigloss.py @@ -0,0 +1,68 @@ +""" +SigLoss +======= + +Estimate signal loss from a B0 map. + +Examples +-------- + +>>> task = SigLoss(input_image="b0map.nii", input_mask="mask.nii", output_image="sigloss.nii") +>>> task.cmdline # doctest: +ELLIPSIS +'sigloss ... --in b0map.nii --mask mask.nii --sigloss sigloss.nii' +""" + +__all__ = ["SigLoss"] + +import os + +import attrs + +import pydra + + +@attrs.define(slots=False, kw_only=True) +class SigLossSpec(pydra.specs.ShellSpec): + """Specifications for sigloss.""" + + echo_time: float = attrs.field( + default=1.0, + metadata={"help_string": "echo time in seconds", "argstr": "--te"}, + ) + + slice_direction: str = attrs.field( + default="z", + metadata={ + "help_string": "slice direction", + "argstr": "--slicedir", + "allowed_values": {"x", "y", "z"}, + }, + ) + + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input B0-map image in rad/s", + "mandatory": True, + "argstr": "--in", + } + ) + + input_mask: os.PathLike = attrs.field( + metadata={"help_string": "input mask", "argstr": "--mask"} + ) + + output_image: str = attrs.field( + metadata={ + "help_string": "output signal-loss image", + "argstr": "--sigloss", + "output_file_template": "{input_image}_sigloss", + } + ) + + +class SigLoss(pydra.engine.ShellCommandTask): + """Task definition for sigloss.""" + + executable = "sigloss" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(SigLossSpec,)) diff --git a/pydra/tasks/fsl/v6_0/maths.py b/pydra/tasks/fsl/v6_0/maths.py new file mode 100644 index 0000000..1670cde --- /dev/null +++ b/pydra/tasks/fsl/v6_0/maths.py @@ -0,0 +1,128 @@ +""" +fslmaths +======== + +Mathematical manipulation of images. + +Examples +-------- + +Convert input image to float: + +>>> task = Maths(input_image="input.nii") +>>> task.cmdline # doctest: +ELLIPSIS +'fslmaths input.nii .../input_fslmaths.nii' + +Multiply input image with a binary mask: + +>>> task = Mul(input_image="input.nii", other_image="mask.nii", output_image="output.nii") +>>> task.cmdline +'fslmaths input.nii -mul mask.nii output.nii' + +>>> task = Threshold(input_image="input.nii", threshold=0.3, output_image="output.nii") +>>> task.cmdline +'fslmaths input.nii -thr 0.3 output.nii' +""" + +__all__ = ["Maths", "MathsSpec", "Mul", "Threshold"] + +from os import PathLike + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class MathsSpec(ShellSpec): + """Specifications for fslmaths.""" + + _datatypes = {"char", "short", "int", "float", "double", "input"} + + internal_datatype: str = field( + metadata={ + "help_string": "internal datatype", + "argstr": "-dt", + "position": 1, + "allowed_values": _datatypes, + } + ) + + input_image: PathLike = field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "", + "position": 2, + } + ) + + output_image: str = field( + metadata={ + "help_string": "output image", + "argstr": "", + "position": -2, + "output_file_template": "{input_image}_fslmaths", + } + ) + + output_datatype: str = field( + metadata={ + "help_string": "output datatype", + "argstr": "-odt", + "position": -1, + "allowed_values": _datatypes, + } + ) + + +class Maths(ShellCommandTask): + """Task definition for fslmaths.""" + + executable = "fslmaths" + + input_spec = SpecInfo(name="Input", bases=(MathsSpec,)) + + +@define(kw_only=True) +class MulSpec(MathsSpec): + """Specifications for fslmaths' mul.""" + + other_image: PathLike = field( + metadata={ + "help_string": "multiply input with other image", + "mandatory": True, + "argstr": "-mul", + } + ) + + +class Mul(Maths): + """Task definition for fslmaths' mul.""" + + input_spec = SpecInfo(name="Input", bases=(MulSpec,)) + + +@define(kw_only=True) +class ThresholdSpec(MathsSpec): + """Specifications for fslmaths' threshold.""" + + threshold: float = field( + metadata={ + "help_string": "value for thresholding the image", + "mandatory": True, + "argstr": "-thr", + } + ) + + +class Threshold(Maths): + """Task definition for fslmaths' threshold.""" + + input_spec = SpecInfo(name="Input", bases=(ThresholdSpec,)) + + +# TODO: Drop compatibility alias for 0.x +FSLMaths = Maths +FSLMathsSpec = MathsSpec +__all__ += ["FSLMaths", "FSLMathsSpec"] diff --git a/pydra/tasks/fsl/v6_0/susan.py b/pydra/tasks/fsl/v6_0/susan.py new file mode 100644 index 0000000..d6a06dd --- /dev/null +++ b/pydra/tasks/fsl/v6_0/susan.py @@ -0,0 +1,106 @@ +""" +SUSAN +===== + +Structure-preserving noise reduction. + +Examples +-------- + +>>> task = SUSAN(input_image="input.nii") +>>> task.cmdline # doctest: +ELLIPSIS +'susan input.nii 3.0 3 1 0 .../input_susan.nii' + +>>> task = SUSAN( +... input_image="input.nii", +... output_image="output.nii", +... use_median=False, +... usans=[("usan1.nii", 1.0), ("usan2.nii", -1.0)], +... ) +>>> task.cmdline +'susan input.nii 3.0 3 0 2 usan1.nii 1.0 usan2.nii -1.0 output.nii' +""" + +__all__ = ["SUSAN"] + +import os + +import attrs + +import pydra + + +@attrs.define(slots=False, kw_only=True) +class SUSANSpec(pydra.specs.ShellSpec): + """Specifications for SUSAN.""" + + input_image: os.PathLike = attrs.field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "", + } + ) + + output_image: str = attrs.field( + metadata={ + "help_string": "output image", + "argstr": "", + "position": -1, + "output_file_template": "{input_image}_susan", + } + ) + + brightness_threshold: float = attrs.field( + default=0.0, + metadata={ + "help_string": "brightness threshold", + "argstr": "", + }, + ) + + smoothing: float = attrs.field( + default=3.0, + metadata={ + "help_string": "spatial smoothing in millimeters", + "argstr": "", + }, + ) + + dimensionality: int = attrs.field( + default=3, + metadata={ + "help_string": "perform smoothing in 2D or 3D", + "argstr": "", + "allowed_values": {2, 3}, + }, + ) + + use_median: bool = attrs.field( + default=True, + metadata={ + "help_string": "use median when no neighborhood is found", + "formatter": lambda field: f"{int(field)}", + }, + ) + + # TODO: Replace with factory=list. + usans: list = attrs.field( + metadata={ + "help_string": "find smoothing area from secondary images (up to 2)", + "formatter": lambda field: ( + " ".join( + [f"{len(field or [])}"] + + [f"{usan} {bt}" for usan, bt in field or []] + ) + ), + }, + ) + + +class SUSAN(pydra.engine.ShellCommandTask): + """Task definition for SUSAN.""" + + executable = "susan" + + input_spec = pydra.specs.SpecInfo(name="Input", bases=(SUSANSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/__init__.py b/pydra/tasks/fsl/v6_0/utils/__init__.py new file mode 100644 index 0000000..4d94ca8 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/__init__.py @@ -0,0 +1,30 @@ +""" +Utils +===== + +.. automodule:: pydra.tasks.fsl.utils.chfiletype +.. automodule:: pydra.tasks.fsl.utils.fft +.. automodule:: pydra.tasks.fsl.utils.info +.. automodule:: pydra.tasks.fsl.utils.interleave +.. automodule:: pydra.tasks.fsl.utils.merge +.. automodule:: pydra.tasks.fsl.utils.orient +.. automodule:: pydra.tasks.fsl.utils.reorient2std +.. automodule:: pydra.tasks.fsl.utils.roi +.. automodule:: pydra.tasks.fsl.utils.selectvols +.. automodule:: pydra.tasks.fsl.utils.smoothfill +.. automodule:: pydra.tasks.fsl.utils.split +.. automodule:: pydra.tasks.fsl.utils.swapdim +""" + +from .chfiletype import ChFileType +from .fft import FFT +from .info import Info +from .interleave import Interleave +from .merge import Merge +from .orient import Orient +from .reorient2std import Reorient2Std +from .roi import ROI +from .selectvols import SelectVols +from .smoothfill import SmoothFill +from .split import Slice, Split +from .swapdim import SwapDim diff --git a/pydra/tasks/fsl/v6_0/utils/chfiletype.py b/pydra/tasks/fsl/v6_0/utils/chfiletype.py new file mode 100644 index 0000000..dce65e9 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/chfiletype.py @@ -0,0 +1,107 @@ +""" +ChFileType +========== + +Convert image to a different NIfTI file format. + +Examples +-------- + +>>> task = ChFileType(filetype="NIFTI2_GZ", input_image="input.nii", output_basename="output") +>>> task.cmdline +'fslchfiletype NIFTI2_GZ input.nii output' +""" + +__all__ = ["ChFileType"] + +from os import PathLike +from pathlib import Path + +from attrs import define, field +from pydra.engine.specs import File, ShellOutSpec, ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + +ALLOWED_FILETYPES = { + "ANALYZE", + "ANALYZE_GZ", + "NIFTI", + "NIFTI_GZ", + "NIFTI_STD::PAIR", + "NIFTI_STD::PAIR_GZ", + "NIFTI2", + "NIFTI2_GZ", + "NIFTI2_STD::PAIR", + "NIFTI2_STD::PAIR_GZ", +} + + +def _get_output_basename(output_basename, input_image): + return output_basename or Path(input_image).name.split(".", 1)[0] + + +def _get_output_image(output_basename, input_image, filetype): + output_basename = _get_output_basename(output_basename, input_image) + + extension = "img" if any(pat in filetype for pat in ["ANALYZE", "PAIR"]) else "nii" + if "GZ" in filetype: + extension += ".gz" + + return Path.cwd() / f"{output_basename}.{extension}" + + +def _get_output_header(output_basename, input_image, filetype): + output_basename = _get_output_basename(output_basename, input_image) + + if any(pat in filetype for pat in ["ANALYZE", "PAIR"]): + extension = "hdr.gz" if "GZ" in filetype else "hdr" + return Path.cwd() / f"{output_basename}.{extension}" + else: + return None + + +@define(kw_only=True) +class ChFileTypeSpec(ShellSpec): + """Specifications for fslchfiletype.""" + + filetype: str = field( + metadata={ + "help_string": "change to this file type", + "mandatory": True, + "argstr": "", + "allowed_values": ALLOWED_FILETYPES, + } + ) + + input_image: PathLike = field( + metadata={"help_string": "input image", "mandatory": True, "argstr": ""} + ) + + output_basename: str = field( + metadata={"help_string": "output basename", "formatter": _get_output_basename} + ) + + +@define(slots=False, kw_only=True) +class ChFileTypeOutSpec(ShellOutSpec): + """Output specifications for fslchfiletype.""" + + output_image: File = field( + metadata={"help_string": "output image", "callable": _get_output_image} + ) + + output_header: File = field( + metadata={ + "help_string": "output header for filetypes which support it", + "callable": _get_output_header, + } + ) + + +class ChFileType(ShellCommandTask): + """Task definition for fslchfiletype.""" + + executable = "fslchfiletype" + + input_spec = SpecInfo(name="Input", bases=(ChFileTypeSpec,)) + + output_spec = SpecInfo(name="Output", bases=(ChFileTypeOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/fft.py b/pydra/tasks/fsl/v6_0/utils/fft.py new file mode 100644 index 0000000..b51c86c --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/fft.py @@ -0,0 +1,58 @@ +""" +FFT (Fast Fourier Transform) +============================ + +Compute the forward or inverse Fast Fourier Transform of a NIfTI image. + +Examples +-------- + +Compute the forward FFT: + +>>> task = FFT(input_image="input.nii") +>>> task.cmdline # doctest: +ELLIPSIS +'fslfft input.nii .../input_fft.nii' + +Compute the inverse FFT: + +>>> task = FFT(input_image="input.nii", output_image="output.nii", inverse=True) +>>> task.cmdline +'fslfft input.nii output.nii -inv' +""" + +__all__ = ["FFT"] + +from os import PathLike + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class FFTSpec(ShellSpec): + """Specifications for fslfft.""" + + input_image: PathLike = field( + metadata={"help_string": "input image", "mandatory": True, "argstr": ""} + ) + + output_image: str = field( + metadata={ + "help_string": "output image", + "argstr": "", + "output_file_template": "{input_image}_fft", + } + ) + + inverse: bool = field( + metadata={"help_string": "compute the inverse FFT", "argstr": "-inv"} + ) + + +class FFT(ShellCommandTask): + """Task definition for fslfft.""" + + executable = "fslfft" + + input_spec = SpecInfo(name="Input", bases=(FFTSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/info.py b/pydra/tasks/fsl/v6_0/utils/info.py new file mode 100644 index 0000000..a142bb6 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/info.py @@ -0,0 +1,152 @@ +""" +Info +==== + +Read essential metadata from the header of a NIfTI image. +""" + +__all__ = ["Info"] + +import re +from os import PathLike + +from attrs import define, field +from pydra.engine.specs import ShellOutSpec, ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(slots=False, kw_only=True) +class InfoSpec(ShellSpec): + """Specifications for fslinfo.""" + + input_image: PathLike = field( + metadata={"help_string": "input image", "mandatory": True, "argstr": ""} + ) + + +@define(kw_only=True) +class InfoOutSpec(ShellOutSpec): + """Output specifications for fslinfo.""" + + data_type: str = field( + metadata={ + "help_string": "data type string", + "callable": lambda stdout: re.search(r"data_type\s*(.*)", stdout).group(1), + } + ) + + dim1: int = field( + metadata={ + "help_string": "array size in 1st dimension", + "callable": lambda stdout: int( + re.search(r"\sdim1\s*(.*)", stdout).group(1) + ), + } + ) + + dim2: int = field( + metadata={ + "help_string": "array size in 2nd dimension", + "callable": lambda stdout: int( + re.search(r"\sdim2\s*(.*)", stdout).group(1) + ), + } + ) + + dim3: int = field( + metadata={ + "help_string": "array size in 3rd dimension", + "callable": lambda stdout: int( + re.search(r"\sdim3\s*(.*)", stdout).group(1) + ), + } + ) + + dim4: int = field( + metadata={ + "help_string": "array size in 4th dimension", + "callable": lambda stdout: int( + re.search(r"\sdim4\s*(.*)", stdout).group(1) + ), + } + ) + + datatype: int = field( + metadata={ + "help_string": "data type code", + "callable": lambda stdout: int( + re.search(r"datatype\s*(.*)", stdout).group(1) + ), + } + ) + + pixdim1: float = field( + metadata={ + "help_string": "pixel spacing in 1st dimension", + "callable": lambda stdout: float( + re.search(r"pixdim1\s*(.*)", stdout).group(1) + ), + } + ) + + pixdim2: float = field( + metadata={ + "help_string": "pixel spacing in 2nd dimension", + "callable": lambda stdout: float( + re.search(r"pixdim2\s*(.*)", stdout).group(1) + ), + } + ) + + pixdim3: float = field( + metadata={ + "help_string": "pixel spacing in 3rd dimension", + "callable": lambda stdout: float( + re.search(r"pixdim3\s*(.*)", stdout).group(1) + ), + } + ) + + pixdim4: float = field( + metadata={ + "help_string": "pixel spacing in 4th dimension", + "callable": lambda stdout: float( + re.search(r"pixdim4\s*(.*)", stdout).group(1) + ), + } + ) + + cal_max: float = field( + metadata={ + "help_string": "maximum display intensity", + "callable": lambda stdout: float( + re.search(r"cal_max\s*(.*)", stdout).group(1) + ), + } + ) + + cal_min: float = field( + metadata={ + "help_string": "minimum display intensity", + "callable": lambda stdout: float( + re.search(r"cal_min\s*(.*)", stdout).group(1) + ), + } + ) + + file_type: str = field( + metadata={ + "help_string": "NIfTI file type", + "callable": lambda stdout: re.search(r"file_type\s*(.*)", stdout).group(1), + } + ) + + +class Info(ShellCommandTask): + """Task definition for fslinfo.""" + + executable = "fslinfo" + + input_spec = SpecInfo(name="Input", bases=(InfoSpec,)) + + output_spec = SpecInfo(name="Output", bases=(InfoOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/interleave.py b/pydra/tasks/fsl/v6_0/utils/interleave.py new file mode 100644 index 0000000..14260ce --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/interleave.py @@ -0,0 +1,65 @@ +""" +Interleave +========== + +Examples +-------- + +Interleave images: + +>>> task = Interleave(input_image="in1.nii", other_image="in2.nii") +>>> task.cmdline # doctest: +ELLIPSIS +'fslinterleave in1.nii in2.nii .../in1_interleave.nii' + +Interleave in reverse order: + +>>> task = Interleave( +... input_image="in1.nii", +... other_image="in2.nii", +... output_image="out.nii", +... reverse=True, +... ) +>>> task.cmdline +'fslinterleave in1.nii in2.nii out.nii -i' +""" + +__all__ = ["Interleave"] + +from os import PathLike + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class InterleaveSpec(ShellSpec): + """Specifications for fslinterleave.""" + + input_image: PathLike = field( + metadata={"help_string": "input image", "mandatory": True, "argstr": ""} + ) + + other_image: PathLike = field( + metadata={"help_string": "other image", "mandatory": True, "argstr": ""} + ) + + output_image: str = field( + metadata={ + "help_string": "output_image", + "argstr": "", + "output_file_template": "{input_image}_interleave", + } + ) + + reverse: bool = field( + metadata={"help_string": "reverse slice order", "argstr": "-i"} + ) + + +class Interleave(ShellCommandTask): + """Task definition for fslinterleave.""" + + executable = "fslinterleave" + + input_spec = SpecInfo(name="Input", bases=(InterleaveSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/merge.py b/pydra/tasks/fsl/v6_0/utils/merge.py new file mode 100644 index 0000000..13b4e28 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/merge.py @@ -0,0 +1,75 @@ +""" +Merge +===== + +Examples +-------- + +>>> task = Merge(dimension="t", input_images=["vol1.nii", "vol2.nii"]) +>>> task.cmdline # doctest: +ELLIPSIS +'fslmerge -t ...merged vol1.nii vol2.nii' +""" + +__all__ = ["Merge"] + +from os import PathLike +from typing import Iterable + +from attrs import define, field +from pydra.engine.specs import File, ShellOutSpec, ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class MergeSpec(ShellSpec): + """Specifications for fslmerge.""" + + dimension: str = field( + metadata={ + "help_string": "merge dimension", + "mandatory": True, + "argstr": "-{dimension}", + "allowed_values": {"t", "x", "y", "z", "a", "tr"}, + "xor": {"volume_index"}, + } + ) + + volume_index: int = field( + metadata={ + "help_string": "merge volume N from each input file", + "mandatory": True, + "argstr": "-n", + "xor": {"dimension"}, + } + ) + + output_image: str = field( + metadata={ + "help_string": "output image", + "argstr": "", + "output_file_template": "merged", + } + ) + + input_images: Iterable[PathLike] = field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "...", + } + ) + + repetition_time: float = field( + metadata={ + "help_string": "specify TR value in seconds (default is 1.0)", + "argstr": "", + } + ) + + +class Merge(ShellCommandTask): + """Task definition for fslmerge.""" + + executable = "fslmerge" + + input_spec = SpecInfo(name="Input", bases=(MergeSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/orient.py b/pydra/tasks/fsl/v6_0/utils/orient.py new file mode 100644 index 0000000..dc93a09 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/orient.py @@ -0,0 +1,118 @@ +""" +Orient +====== + +Change the orientation of an image. + +Examples +-------- + +>>> import tempfile +>>> input_file = tempfile.NamedTemporaryFile(suffix="input.nii") + +Change orientation to radiological: + +>>> task = Orient(input_image=input_file.name, force_radiological=True) +>>> task.cmdline # doctest: +ELLIPSIS +'fslorient -forceradiological ...input.nii' + +Change orientation to neurological: + +>>> task = Orient(input_image=input_file.name, force_neurological=True) +>>> task.cmdline # doctest: +ELLIPSIS +'fslorient -forceneurological ...input.nii' + +Swap between radiological and neurological: + +>>> task = Orient(input_image=input_file.name, swap_orientation=True) +>>> task.cmdline # doctest: +ELLIPSIS +'fslorient -swaporient ...input.nii' + +Delete orientation: + +>>> task = Orient(input_image=input_file.name, delete_orientation=True) +>>> task.cmdline # doctest: +ELLIPSIS +'fslorient -deleteorient ...input.nii' +""" + +__all__ = ["Orient"] + +from attrs import define, field +from pydra.engine.specs import File, ShellOutSpec, ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class OrientSpec(ShellSpec): + """Specifications for fslorient.""" + + _xor = { + "delete_orientation", + "force_radiological", + "force_neurological", + "swap_orientation", + } + + input_image: File = field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "", + "position": -1, + "copyfile": True, + } + ) + + delete_orientation: bool = field( + metadata={ + "help_string": "delete orientation", + "argstr": "-deleteorient", + "xor": _xor, + } + ) + + force_radiological: bool = field( + metadata={ + "help_string": "force orientation to radiological", + "argstr": "-forceradiological", + "xor": _xor, + } + ) + + force_neurological: bool = field( + metadata={ + "help_string": "force orientation to neurological", + "argstr": "-forceneurological", + "xor": _xor, + } + ) + + swap_orientation: bool = field( + metadata={ + "help_string": "swap between radiological and neurological", + "argstr": "-swaporient", + "xor": _xor, + } + ) + + +@define(kw_only=True) +class OrientOutSpec(ShellOutSpec): + """Output specifications for fslorient.""" + + output_image: File = field( + metadata={ + "help_string": "output image", + "output_file_template": "{input_image}", + } + ) + + +class Orient(ShellCommandTask): + """Task definition for fslorient.""" + + executable = "fslorient" + + input_spec = SpecInfo(name="Input", bases=(OrientSpec,)) + + output_spec = SpecInfo(name="Output", bases=(OrientOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/reorient2std.py b/pydra/tasks/fsl/v6_0/utils/reorient2std.py new file mode 100644 index 0000000..e563216 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/reorient2std.py @@ -0,0 +1,62 @@ +""" +Reorient2Std +============ + +Change orientation of the image to match the one used +for standard template images (MNI152). + +Examples +-------- + +>>> task = Reorient2Std(input_image="image.nii") +>>> task.cmdline # doctest: +ELLIPSIS +'fslreorient2std -m ...image_r2std.mat image.nii ...image_r2std.nii' +""" + +__all__ = ["Reorient2Std"] + +from os import PathLike + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class Reorient2StdSpec(ShellSpec): + """Specifications for fslreorient2std.""" + + input_image: PathLike = field( + metadata={ + "help_string": "input image", + "mandatory": True, + "argstr": "", + "position": -2, + } + ) + + output_image: str = field( + metadata={ + "help_string": "output reoriented image", + "argstr": "", + "position": -1, + "output_file_template": "{input_image}_r2std", + } + ) + + output_matrix: str = field( + metadata={ + "help_string": "output transformation matrix", + "argstr": "-m", + "output_file_template": "{input_image}_r2std.mat", + "keep_extension": False, + } + ) + + +class Reorient2Std(ShellCommandTask): + """Task definition for fslreorient2std.""" + + executable = "fslreorient2std" + + input_spec = SpecInfo(name="Input", bases=(Reorient2StdSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/roi.py b/pydra/tasks/fsl/v6_0/utils/roi.py new file mode 100644 index 0000000..72cd5f7 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/roi.py @@ -0,0 +1,122 @@ +""" +ROI (Region-Of-Interest) +======================== + +Manual cropping to a region-of-interest for structural brain images. + +Examples +-------- + +Extract a 16-voxel cube starting at position (10, 20, 30): + +>>> task = ROI( +... input_image="image.nii", +... x_min=10, +... x_size=16, +... y_min=20, +... y_size=16, +... z_min=30, +... z_size=16, +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'fslroi image.nii ...image_roi.nii 10 16 20 16 30 16 ...' + +Extract a temporal window starting at 5 onwards: + +>>> task = ROI(input_image="input.nii", output_image="output.nii", t_min=5) +>>> task.cmdline +'fslroi input.nii output.nii 5 -1' +""" + +__all__ = ["ROI"] + +from os import PathLike + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class ROISpec(ShellSpec): + """Specifications for fslroi.""" + + _requires = {"x_min", "y_min", "z_min"} + + input_image: PathLike = field( + metadata={"help_string": "input image", "mandatory": True, "argstr": ""} + ) + + output_image: str = field( + metadata={ + "help_string": "output image", + "argstr": "", + "output_file_template": "{input_image}_roi", + } + ) + + x_min: int = field( + metadata={ + "help_string": "start of ROI in x (0-based indexing)", + "argstr": "", + "requires": _requires, + } + ) + + x_size: int = field( + metadata={ + "help_string": "size of ROI in x (-1 for maximum)", + "argstr": "", + "requires": {"x_min"}, + } + ) + + y_min: int = field( + metadata={ + "help_string": "start of ROI in y (0-based indexing)", + "argstr": "", + "requires": _requires, + } + ) + + y_size: int = field( + metadata={ + "help_string": "size of ROI in y (-1 for maximum)", + "argstr": "", + "requires": {"y_min"}, + } + ) + + z_min: int = field( + metadata={ + "help_string": "start of ROI in z (0-based indexing)", + "argstr": "", + "requires": _requires, + } + ) + + z_size: int = field( + metadata={ + "help_string": "size of ROI in z (-1 for maximum)", + "argstr": "", + "requires": {"z_min"}, + } + ) + + t_min: int = field( + default=0, + metadata={"help_string": "start of ROI in t (0-based indexing)", "argstr": ""}, + ) + + t_size: int = field( + default=-1, + metadata={"help_string": "size of ROI in t (-1 for maximum)", "argstr": ""}, + ) + + +class ROI(ShellCommandTask): + """Task definition for fslroi.""" + + executable = "fslroi" + + input_spec = SpecInfo(name="Input", bases=(ROISpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/selectvols.py b/pydra/tasks/fsl/v6_0/utils/selectvols.py new file mode 100644 index 0000000..972d04a --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/selectvols.py @@ -0,0 +1,95 @@ +""" +SelectVols +========== + +Examples +-------- + +Select volumes from a list and concatenate them: + +>>> task = SelectVols(input_image="input.nii", volumes=[0, 1, 6, 7]) +>>> task.cmdline +'fslselectvols --in input.nii --out .../input_selectvols.nii --vols 0,1,6,7' + +Select volumes from a file and calculate their mean: + +>>> task = SelectVols( +... input_image="input.nii", +... output_image="mean.nii", +... volumes="volumes.txt", +... calculate_mean=True, +... ) +>>> task.cmdline +'fslselectvols --in input.nii --out mean.nii --vols volumes.txt -m' + +Select volumes from a file and calculate their variance: + +>>> task = SelectVols( +... input_image="input.nii", +... output_image="variance.nii", +... volumes="volumes.txt", +... calculate_variance=True, +... ) +>>> task.cmdline +'fslselectvols --in input.nii --out variance.nii --vols volumes.txt -v' +""" + +__all__ = ["SelectVols"] + +from os import PathLike +from typing import Iterable, Union + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class SelectVolsSpec(ShellSpec): + """Specifications for fslselectvols.""" + + input_image: PathLike = field( + metadata={"help_string": "input image", "mandatory": True, "argstr": "--in"} + ) + + output_image: str = field( + metadata={ + "help_string": "output image", + "argstr": "--out", + "output_file_template": "{input_image}_selectvols", + } + ) + + volumes: Union[PathLike, Iterable[int]] = field( + metadata={ + "help_string": "volumes to select (from a file or as a list)", + "mandatory": True, + "formatter": lambda volumes: ( + f"--vols {str(volumes) if isinstance(volumes, (PathLike, str)) else ','.join(map(str, volumes))}" + ), + } + ) + + calculate_mean: bool = field( + metadata={ + "help_string": "calculate mean", + "argstr": "-m", + "xor": {"calculate_variance"}, + } + ) + + calculate_variance: bool = field( + metadata={ + "help_string": "calculate variance", + "argstr": "-v", + "xor": {"calculate_mean"}, + } + ) + + +class SelectVols(ShellCommandTask): + """Task definition for fslselectvols.""" + + executable = "fslselectvols" + + input_spec = SpecInfo(name="Input", bases=(SelectVolsSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/smoothfill.py b/pydra/tasks/fsl/v6_0/utils/smoothfill.py new file mode 100644 index 0000000..3a0eb66 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/smoothfill.py @@ -0,0 +1,52 @@ +""" +SmoothFill +========== + +Examples +-------- + +>>> task = SmoothFill(input_image="input.nii", output_image="smoothed.nii", input_mask="mask.nii") +>>> task.cmdline +'fslsmoothfill --in input.nii --out smoothed.nii --mask mask.nii' +""" + +__all__ = ["SmoothFill"] + +from os import PathLike + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class SmoothFillSpec(ShellSpec): + """Specifications for fslsmoothfill.""" + + input_image: PathLike = field( + metadata={"help_string": "input image", "mandatory": True, "argstr": "--in"} + ) + + output_image: str = field( + metadata={ + "help_string": "output image", + "argstr": "--out", + "output_file_template": "{input_image}_smoothfill", + } + ) + + input_mask: PathLike = field( + metadata={"help_string": "input mask", "argstr": "--mask"} + ) + + num_iterations: int = field( + metadata={"help_string": "number of iterations", "argstr": "--niter"} + ) + + +class SmoothFill(ShellCommandTask): + """Task definition for fslsmoothfill.""" + + executable = "fslsmoothfill" + + input_spec = SpecInfo(name="Input", bases=(SmoothFillSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/split.py b/pydra/tasks/fsl/v6_0/utils/split.py new file mode 100644 index 0000000..01e0d23 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/split.py @@ -0,0 +1,100 @@ +""" +Split +===== + +Examples +-------- +>>> task = Split(input_image="input.nii.gz") +>>> task.cmdline +'fslsplit input.nii.gz input -t' + +>>> task = Slice(input_image="volume.nii", output_basename="slice") +>>> task.cmdline +'fslsplit volume.nii slice -z' +""" + +__all__ = ["Split", "Slice"] + +from os import PathLike +from pathlib import Path + +from attrs import define, field +from pydra.engine.specs import MultiOutputFile, ShellOutSpec, ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +def _get_output_basename(output_basename, input_image): + return output_basename or Path(input_image).name.split(".", 1)[0] + + +def _get_output_images(output_basename, input_image): + output_basename = _get_output_basename(output_basename, input_image) + + return sorted(Path.cwd().glob(f"{output_basename}*.*")) + + +@define(kw_only=True) +class SplitSpec(ShellSpec): + """Specifications for fslsplit.""" + + input_image: PathLike = field( + metadata={"help_string": "input image", "mandatory": True, "argstr": ""} + ) + + output_basename: str = field( + metadata={"help_string": "output basename", "formatter": _get_output_basename} + ) + + direction: str = field( + default="t", + metadata={ + "help_string": "split direction", + "argstr": "-{direction}", + "allowed_values": {"x", "y", "z", "t"}, + }, + ) + + +@define(slots=False, kw_only=True) +class SplitOutSpec(ShellOutSpec): + """Output specifications for fslsplit.""" + + output_images: MultiOutputFile = field( + metadata={"help_string": "output images", "callable": _get_output_images} + ) + + +class Split(ShellCommandTask): + """Task definition for fslsplit.""" + + executable = "fslsplit" + + input_spec = SpecInfo(name="Input", bases=(SplitSpec,)) + + output_spec = SpecInfo(name="Output", bases=(SplitOutSpec,)) + + +@define(kw_only=True) +class SliceSpec(SplitSpec): + """Specifications for fslslice.""" + + direction: str = field( + default="z", + metadata={ + "help_string": "split direction (z)", + "argstr": "-{direction}", + "allowed_values": {"z"}, + }, + ) + + +class SliceOutSpec(SplitOutSpec): + """Output specifications for fslslice.""" + + +class Slice(Split): + """Task definition for fslslice.""" + + input_spec = SpecInfo(name="Input", bases=(SliceSpec,)) + + output_spec = SpecInfo(name="Output", bases=(SliceOutSpec,)) diff --git a/pydra/tasks/fsl/v6_0/utils/swapdim.py b/pydra/tasks/fsl/v6_0/utils/swapdim.py new file mode 100644 index 0000000..4aa0607 --- /dev/null +++ b/pydra/tasks/fsl/v6_0/utils/swapdim.py @@ -0,0 +1,88 @@ +""" +SwapDim +======= + +Examples +-------- + +>>> task = SwapDim( +... input_image="input.nii", +... new_x="y", +... new_y="x", +... new_z="-z", +... ) +>>> task.cmdline # doctest: +ELLIPSIS +'fslswapdim input.nii y x -z ...input_swapdim.nii' + +>>> task = SwapDim( +... input_image="input.nii", +... output_image="output.nii", +... new_x="RL", +... new_y="PA", +... new_z="IS", +... ) +>>> task.cmdline +'fslswapdim input.nii RL PA IS output.nii' +""" + +__all__ = ["SwapDim"] + +from os import PathLike + +from attrs import define, field +from pydra.engine.specs import ShellSpec, SpecInfo +from pydra.engine.task import ShellCommandTask + + +@define(kw_only=True) +class SwapDimSpec(ShellSpec): + """Specifications for fslswapdim.""" + + ALLOWED_AXES = {"x", "-x", "y", "-y", "z", "-z", "LR", "RL", "AP", "PA", "SI", "IS"} + + input_image: PathLike = field( + metadata={"help_string": "input image", "mandatory": True, "argstr": ""} + ) + + new_x: str = field( + metadata={ + "help_string": "new x-axis", + "mandatory": True, + "argstr": "", + "allowed_values": ALLOWED_AXES, + } + ) + + new_y: str = field( + metadata={ + "help_string": "new y-axis", + "mandatory": True, + "argstr": "", + "allowed_values": ALLOWED_AXES, + } + ) + + new_z: str = field( + metadata={ + "help_string": "new z-axis", + "mandatory": True, + "argstr": "", + "allowed_values": ALLOWED_AXES, + } + ) + + output_image: str = field( + metadata={ + "help_string": "output image", + "argstr": "", + "output_file_template": "{input_image}_swapdim", + } + ) + + +class SwapDim(ShellCommandTask): + """Task definition for fslswapdim.""" + + executable = "fslswapdim" + + input_spec = SpecInfo(name="Input", bases=(SwapDimSpec,)) diff --git a/pyproject.toml b/pyproject.toml index 3a0ead8..85c326b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,75 +1,108 @@ [build-system] -requires = ["flit_scm"] -build-backend = "flit_scm:buildapi" +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" [project] name = "pydra-fsl" -description = "FSL tasks for the Pydra dataflow engine" -readme = "README.md" -requires-python = ">=3.7" -dependencies = ["pydra >=0.14.1"] -license = {file = "LICENSE"} -authors = [{name = "Nipype developers", email = "neuroimaging@python.org"}] -keywords = ["pydra", "fsl"] +description = "Pydra tasks package for fsl" +readme = "README.rst" +requires-python = ">=3.8" +dependencies = [ + "pydra >=0.22", + "fileformats >=0.8.3", + "fileformats-datascience >=0.1", + "fileformats-medimage >=0.4.1", + "fileformats-medimage-fsl", +] +license = { file = "LICENSE" } +keywords = ["pydra", "neuroimaging", "fsl"] +authors = [ + { name = "Nipype developers", email = "neuroimaging@python.org" }, + { name = "Ghislain Vaillant", email = "ghislain.vaillant@icm-institute.org" }, +] +maintainers = [ + { name = "Nipype developers", email = "neuroimaging@python.org" }, + { name = "Ghislain Vaillant", email = "ghislain.vaillant@icm-institute.org" }, +] classifiers = [ - "Development Status :: 3 - Alpha", - "Environment :: Console", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: Apache Software License", - "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Topic :: Scientific/Engineering", + "Development Status :: 3 - Alpha", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Scientific/Engineering", + "Topic :: Software Development :: Libraries", ] dynamic = ["version"] [project.optional-dependencies] -all = [ - "pydra-fsl[dev]", - "pydra-fsl[doc]", -] -dev = [ - "pydra-fsl[test]", - "nipype", - "pyyaml", - "black", - "pre-commit", -] +dev = ["black", "pre-commit"] doc = [ - "packaging", - "sphinx >=2.1.2", - "sphinx_rtd_theme", - "sphinxcontrib-apidoc ~=0.3.0", - "sphinxcontrib-napoleon", - "sphinxcontrib-versioning", -] -docs = [ - "pydra-fsl[doc]", + "packaging", + "sphinx >=2.1.2", + "sphinx_rtd_theme", + "sphinxcontrib-apidoc ~=0.3.0", + "sphinxcontrib-napoleon", + "sphinxcontrib-versioning", ] test = [ - "pytest >=4.4.0", - "pytest-cov", - "pytest-env", - "pytest-xdist", - "pytest-rerunfailures", - "codecov", -] -tests = [ - "pydra-fsl[test]", + "nipype2pydra", + "pytest >= 4.4.0", + "pytest-cov", + "pytest-env", + "pytest-xdist", + "pytest-rerunfailures", + "codecov", + "fileformats-extras", + "fileformats-datascience-extras", + "fileformats-medimage-extras", + "fileformats-medimage-fsl-extras", ] -[project.urls] -repository = "https://github.com/nipype/pydra-fsl" +[tool.hatch.version] +source = "vcs" -[tool.flit.module] -name = "pydra.tasks.fsl" +[tool.hatch.build.hooks.vcs] +version-file = "pydra/tasks/fsl/_version.py" -[tool.setuptools_scm] -write_to = "pydra/tasks/fsl/_version.py" +[tool.hatch.build.targets.wheel] +packages = ["pydra"] +include-only = ["pydra/tasks/fsl"] [tool.black] -line-length = 99 -target-version = ['py37'] -skip-string-normalization = true -extend-exclude = '_version.py|versioneer.py' +target-version = ["py38"] +exclude = "_version.py" + +[tool.codespell] +ignore-words = ".codespell-ignorewords" + +[tool.flake8] +doctests = true +per-file-ignores = ["__init__.py:F401,F403"] +max-line-length = 88 +select = "C,E,F,W,B,B950" +extend-ignore = ['E203', 'E501', 'E129', 'W503'] + +[project.urls] +Documentation = "https://github.com/nipype/pydra-tasks-fsl#readme" +Issues = "https://github.com/nipype/pydra-tasks-fsl/issues" +Source = "https://github.com/nipype/pydra-tasks-fsl" + +[tool.coverage.run] +branch = true +parallel = true + +[tool.coverage.report] + +[tool.isort] +profile = "black" + +[tool.pytest.ini_options] +minversion = "6.0" +# addopts = ["--doctest-modules", "--doctest-continue-on-failure"] +testpaths = ["pydra"] diff --git a/related-packages/conftest.py b/related-packages/conftest.py new file mode 100644 index 0000000..2a703c0 --- /dev/null +++ b/related-packages/conftest.py @@ -0,0 +1,37 @@ +import os +import logging +from pathlib import Path +import tempfile +import pytest + +# Set DEBUG logging for unittests + +log_level = logging.WARNING + +logger = logging.getLogger("fileformats") +logger.setLevel(log_level) + +sch = logging.StreamHandler() +sch.setLevel(log_level) +formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") +sch.setFormatter(formatter) +logger.addHandler(sch) + + +# For debugging in IDE's don't catch raised exceptions and let the IDE +# break at it +if os.getenv("_PYTEST_RAISE", "0") != "0": + + @pytest.hookimpl(tryfirst=True) + def pytest_exception_interact(call): + raise call.excinfo.value + + @pytest.hookimpl(tryfirst=True) + def pytest_internalerror(excinfo): + raise excinfo.value + + +@pytest.fixture +def work_dir(): + work_dir = tempfile.mkdtemp() + return Path(work_dir) diff --git a/related-packages/fileformats-extras/LICENSE b/related-packages/fileformats-extras/LICENSE new file mode 100644 index 0000000..e00bcb3 --- /dev/null +++ b/related-packages/fileformats-extras/LICENSE @@ -0,0 +1,13 @@ + Copyright 2021 Nipype 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. diff --git a/related-packages/fileformats-extras/README.rst b/related-packages/fileformats-extras/README.rst new file mode 100644 index 0000000..385482c --- /dev/null +++ b/related-packages/fileformats-extras/README.rst @@ -0,0 +1,32 @@ +FileFormats-medimage-fsl Extras +=============================== + +.. image:: https://github.com/nipype/pydra-freesurfer/actions/workflows/ci-cd.yaml/badge.svg + :target: https://github.com/nipype/pydra-freesurfer/actions/workflows/ci-cd.yaml + + +This is a extras module for the `fileformats-medimage-fsl `__ +fileformats extension package, which provides additional functionality to format classes (i.e. aside +from basic identification and validation), such as conversion tools, metadata parsers, +sample data generators, etc... + + +Quick Installation +------------------ + +This extension can be installed for Python 3 using *pip*:: + + $ pip3 install fileformats-medimage-fsl-extras + +This will install the package, base packages, and any other dependencies required to +implement the extra functionality. + +License +------- + +This work is licensed under a +`Creative Commons Attribution 4.0 International License `_ + +.. image:: https://i.creativecommons.org/l/by/4.0/88x31.png + :target: http://creativecommons.org/licenses/by/4.0/ + :alt: Creative Commons Attribution 4.0 International License diff --git a/related-packages/fileformats-extras/fileformats/extras/medimage_fsl/__init__.py b/related-packages/fileformats-extras/fileformats/extras/medimage_fsl/__init__.py new file mode 100644 index 0000000..9a674a9 --- /dev/null +++ b/related-packages/fileformats-extras/fileformats/extras/medimage_fsl/__init__.py @@ -0,0 +1,13 @@ +from ._version import __version__ # noqa: F401 +from pathlib import Path +import typing as ty +from random import Random +from fileformats.core import FileSet, SampleFileGenerator +from fileformats.medimage_fsl import ( + Con, +) + + +@FileSet.generate_sample_data.register +def gen_sample_con_data(con: Con, generator: SampleFileGenerator) -> ty.Iterable[Path]: + raise NotImplementedError diff --git a/related-packages/fileformats-extras/fileformats/extras/medimage_fsl/tests/test_generate_sample_data.py b/related-packages/fileformats-extras/fileformats/extras/medimage_fsl/tests/test_generate_sample_data.py new file mode 100644 index 0000000..a213223 --- /dev/null +++ b/related-packages/fileformats-extras/fileformats/extras/medimage_fsl/tests/test_generate_sample_data.py @@ -0,0 +1,9 @@ +import pytest +from fileformats.medimage_fsl import ( + Con, +) + + +@pytest.mark.xfail(reason="generate_sample_data not implemented") +def test_generate_sample_con_data(): + assert isinstance(Con.sample(), Con) diff --git a/related-packages/fileformats-extras/pyproject.toml b/related-packages/fileformats-extras/pyproject.toml new file mode 100644 index 0000000..c6304d3 --- /dev/null +++ b/related-packages/fileformats-extras/pyproject.toml @@ -0,0 +1,87 @@ +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +[project] +name = "fileformats-medimage-fsl-extras" +description = "Extensions to add functionality to tool-specific *fileformats* classes" +readme = "README.rst" +requires-python = ">=3.8" +dependencies = [ + "fileformats", + "fileformats-medimage-fsl", + "pydra >= 0.23.0a" +] +license = {file = "LICENSE"} +authors = [ + {name = "Thomas G. Close", email = "tom.g.close@gmail.com"}, +] +maintainers = [ + {name = "Thomas G. Close", email = "tom.g.close@gmail.com"}, +] +keywords = [ + "file formats", + "data", +] +classifiers = [ + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Scientific/Engineering", +] +dynamic = ["version"] + +[project.optional-dependencies] +dev = [ + "black", + "pre-commit", + "codespell", + "flake8", + "flake8-pyproject", +] +test = [ + "pytest >=6.2.5", + "pytest-env>=0.6.2", + "pytest-cov>=2.12.1", + "codecov", +] + +converters = [ +] + +[project.urls] +repository = "https://github.com/nipype/pydra-fsl" + +[tool.hatch.version] +source = "vcs" +raw-options = { root = "../.." } + +[tool.hatch.build.hooks.vcs] +version-file = "fileformats/extras/medimage_fsl/_version.py" + +[tool.hatch.build.targets.wheel] +packages = ["fileformats"] + +[tool.black] +target-version = ['py38'] +exclude = "fileformats/extras/medimage_fsl/_version.py" + +[tool.codespell] +ignore-words = ".codespell-ignorewords" + +[tool.flake8] +doctests = true +per-file-ignores = [ + "__init__.py:F401" +] +max-line-length = 88 +select = "C,E,F,W,B,B950" +extend-ignore = ['E203', 'E501', 'E129'] diff --git a/related-packages/fileformats/LICENSE b/related-packages/fileformats/LICENSE new file mode 100644 index 0000000..e00bcb3 --- /dev/null +++ b/related-packages/fileformats/LICENSE @@ -0,0 +1,13 @@ + Copyright 2021 Nipype 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. diff --git a/related-packages/fileformats/README.rst b/related-packages/fileformats/README.rst new file mode 100644 index 0000000..36df02a --- /dev/null +++ b/related-packages/fileformats/README.rst @@ -0,0 +1,28 @@ +FileFormats-medimage-fsl +======================== + +.. image:: https://github.com/nipype/pydra-fsl/actions/workflows/ci-cd.yml/badge.svg + :target: https://github.com/nipype/pydra-fsl/actions/workflows/ci-cd.yml + +This is an extension module of the `fileformats `__ +package for defining file formats that are specific to the CHANGME software toolkit. + + +Quick Installation +------------------ + +This extension can be installed for Python 3 using *pip*:: + + $ pip3 install fileformats-medimage-fsl + +This will install the format extensions and dependent base packages. + +License +------- + +This work is licensed under a +`Creative Commons Attribution 4.0 International License `_ + +.. image:: https://i.creativecommons.org/l/by/4.0/88x31.png + :target: http://creativecommons.org/licenses/by/4.0/ + :alt: Creative Commons Attribution 4.0 International License diff --git a/related-packages/fileformats/fileformats/medimage_fsl/__init__.py b/related-packages/fileformats/fileformats/medimage_fsl/__init__.py new file mode 100644 index 0000000..8ec8dec --- /dev/null +++ b/related-packages/fileformats/fileformats/medimage_fsl/__init__.py @@ -0,0 +1,11 @@ +from ._version import __version__ # noqa: F401 +from fileformats.generic import File, Directory + + +class Con(File): + ext = ".con" + binary = True + + +class MelodicIca(Directory): + """Directory containing output from Melodic ICA""" diff --git a/related-packages/fileformats/pyproject.toml b/related-packages/fileformats/pyproject.toml new file mode 100644 index 0000000..f0b3af0 --- /dev/null +++ b/related-packages/fileformats/pyproject.toml @@ -0,0 +1,84 @@ +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +[project] +name = "fileformats-medimage-fsl" +description = "Classes for representing different file formats in Python classes for use in type hinting in data workflows" +readme = "README.rst" +requires-python = ">=3.8" +dependencies = [ + "fileformats", + "fileformats-medimage" +] +license = {file = "LICENSE"} +authors = [ + {name = "Thomas G. Close", email = "tom.g.close@gmail.com"}, +] +maintainers = [ + {name = "Thomas G. Close", email = "tom.g.close@gmail.com"}, +] +keywords = [ + "file formats", + "data", +] +classifiers = [ + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Scientific/Engineering", +] +dynamic = ["version"] + +[project.optional-dependencies] +dev = [ + "black", + "pre-commit", + "codespell", + "flake8", + "flake8-pyproject", +] +test = [ + "pytest >=6.2.5", + "pytest-env>=0.6.2", + "pytest-cov>=2.12.1", + "codecov", + "fileformats-medimage-CHANGME-extras", +] + +[project.urls] +repository = "https://github.com/nipype/pydra-fsl" + +[tool.hatch.version] +source = "vcs" +raw-options = { root = "../.." } + +[tool.hatch.build.hooks.vcs] +version-file = "fileformats/medimage_fsl/_version.py" + +[tool.hatch.build.targets.wheel] +packages = ["fileformats"] + +[tool.black] +target-version = ['py38'] +exclude = "fileformats/medimage_fsl/_version.py" + +[tool.codespell] +ignore-words = ".codespell-ignorewords" + +[tool.flake8] +doctests = true +per-file-ignores = [ + "__init__.py:F401" +] +max-line-length = 88 +select = "C,E,F,W,B,B950" +extend-ignore = ['E203', 'E501', 'E129'] diff --git a/report_progress.py b/report_progress.py new file mode 100644 index 0000000..1fc0767 --- /dev/null +++ b/report_progress.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +from pathlib import Path +import json +import yaml +import click + + +@click.command +@click.argument( + "out_json_path", + type=click.Path(path_type=Path), + help="The output path to save the report", +) +def report_progress(out_json_path: Path): + + out_json_path.parent.mkdir(exist_ok=True, parents=True) + + SPECS_DIR = Path(__file__).parent / "nipype-auto-conv" / "specs" + + report = {} + + for spec_path in SPECS_DIR.glob("*.yaml"): + with open(spec_path) as f: + spec = yaml.load(f, Loader=yaml.SafeLoader) + + report[spec["task_name"]] = { + n: not s["xfail"] for n, s in spec["tests"].items() + } + + with open(out_json_path, "w") as f: + json.dump(report, f) diff --git a/specs/callables.py b/specs/callables.py deleted file mode 100644 index 44240cf..0000000 --- a/specs/callables.py +++ /dev/null @@ -1,411 +0,0 @@ -def Cluster_output(field, inputs): - import os, attr - from pydra.engine.helpers_file import split_filename - - in_file = inputs.in_file - name = field.name - pth, fname, ext = split_filename(in_file) - - if name == "index_file": - return os.path.join(pth, f"{fname}_index{ext}") - elif name == "localmax_txt_file": - return os.path.join(pth, f"{fname}_localmax.txt") - elif name == "localmax_vol_file": - return os.path.join(pth, f"{fname}_localmax{ext}") - elif name == "max_file": - return os.path.join(pth, f"{fname}_max{ext}") - elif name == "mean_file": - return os.path.join(pth, f"{fname}_mean{ext}") - elif name == "pval_file": - return os.path.join(pth, f"{fname}_pval{ext}") - elif name == "size_file": - return os.path.join(pth, f"{fname}_size{ext}") - elif name == "threshold_file": - return os.path.join(pth, f"{fname}_threshold{ext}") - - else: - raise Exception( - f"this function should be run only for index_file, localmax_txt_file, localmax_vol_file, max_file, mean_file, pval_file, size_file, or threshold_file not {name}" - ) - - -def Complex_output(inputs): - import attr - - if inputs.complex_cartesian: - in_file = inputs.real_in_file - elif inputs.complex_polar: - in_file = inputs.magnitude_in_file - elif inputs.complex_split or inputs.complex_merge: - in_file = inputs.complex_in_file - else: - return None - return f"{in_file}_cplx" - - -def ConvertXFM_output(inputs): - import attr - - in_file = inputs.in_file - if inputs.invert_xfm: - return f"{in_file}_inv" - elif inputs.concat_xfm: - if inputs.in_file2.exists(): - in_file2 = inputs.in_file2 - return f"{in_file}_{in_file2}" - else: - raise Exception("in_file2 is needed to use concat_xfm") - - elif inputs.fix_scale_skew: - return f"{in_file}_fix" - else: - raise Exception("this function requires invert_xfm, or concat_xfm," "or fix_scale_skew") - - -def FAST_output(field, in_files, out_basename): - import attr - - if out_basename in [None, attr.NOTHING]: - out_basename = in_files[-1] - name = field.name - if name == "tissue_class_map": - return f"{out_basename}_seg" - elif name == "mixeltype": - return f"{out_basename}_mixeltype" - elif name == "partial_volume_map": - return f"{out_basename}_pveseg" - else: - raise Exception( - f"this function should be run only for issue_class_map, " - f"or mixeltype, not for {name}" - ) - - outputs = [] - if len(in_files) > 1: - # for multi-image segmentation there is one corrected image - # per input - for val, f in enumerate(in_files): - # image numbering is 1-based - outputs.append(f"{out_basename}_restore_{val+1}") - else: - # single image segmentation has unnumbered output image - outputs.append(f"{out_basename}_restore") - return outputs - - -def FAST_output_nclass(field, in_files, nclasses, out_basename): - import attr - - if out_basename in [None, attr.NOTHING]: - out_basename = in_files[-1] - name = field.name - - if name == "tissue_class_files": - suffix = "seg" - elif name == "partial_volume_files": - suffix = "pve" - elif name == "probability_maps": - suffix = "prob" - else: - raise Exception( - f"this function should be run only for tissue_class_files, " - f"partial_volume_files or probability_maps, not for {name}" - ) - - outputs = [] - for ii in range(nclasses): - outputs.append(f"{out_basename}_{suffix}_{ii}") - return outputs - - -def FAST_output_infile(field, in_files, out_basename): - import attr - - if out_basename in [None, attr.NOTHING]: - out_basename = in_files[-1] - name = field.name - if name == "restored_image": - suffix = "restore" - elif name == "bias_field": - suffix = "bias" - else: - raise Exception( - f"this function should be run only for restored_image, " - f"or bias_field, not for {name}" - ) - - outputs = [] - if len(in_files) > 1: - # for multi-image segmentation there is one corrected image - # per input - for val, f in enumerate(in_files): - # image numbering is 1-based - outputs.append(f"{out_basename}_{suffix}_{val+1}") - else: - # single image segmentation has unnumbered output image - outputs.append(f"{out_basename}_{suffix}") - return outputs - - -def FEAT_output(fsf_file): - is_ica = False - with open(fsf_file, "rt") as fp: - text = fp.read() - if "set fmri(inmelodic) 1" in text: - is_ica = True - for line in text.split("\n"): - if line.find("set fmri(outputdir)") > -1: - try: - outputdir_spec = line.split('"')[-2] - if os.path.exists(outputdir_spec): - outputs = outputdir_spec - except: - pass - - if not outputs: - if is_ica: - outputs = glob(os.path.join(os.getcwd(), "*ica"))[0] - else: - outputs = glob(os.path.join(os.getcwd(), "*feat"))[0] - print("Outputs from FEATmodel:", outputs) - return outputs - - -def FEATModel_output(field, fsf_file): - import os - - # TODO: figure out file names and get rid off the globs - outputs = {} - _, fname = os.path.split(fsf_file) - root = fname.split(".")[0] - name = field.name - if name == "design_file": - design_file = glob(os.path.join(os.getcwd(), "%s*.mat" % root)) - assert len(design_file) == 1, "No mat file generated by FEAT Model" - outputs = design_file[0] - elif name == "design_image": - design_image = glob(os.path.join(os.getcwd(), "%s.png" % root)) - assert len(design_image) == 1, "No design image generated by FEAT Model" - outputs = design_image[0] - elif name == "design_cov": - design_cov = glob(os.path.join(os.getcwd(), "%s_cov.png" % root)) - assert len(design_cov) == 1, "No covariance image generated by FEAT Model" - outputs = design_cov[0] - elif name == "con_file": - con_file = glob(os.path.join(os.getcwd(), "%s*.con" % root)) - assert len(con_file) == 1, "No con file generated by FEAT Model" - outputs = con_file[0] - elif name == "fcon_file": - fcon_file = glob(os.path.join(os.getcwd(), "%s*.fts" % root)) - if fcon_file: - assert len(fcon_file) == 1, "No fts file generated by FEAT Model" - outputs = fcon_file[0] - else: - raise Exception( - f"this function should be run only for design_file, design_image" - f"design_cov, con_file, or fcon_file, not for {name}" - ) - return outputs - - -def FILMGLS_output(field, inputs): - import os, attr - - def _get_pe_files(design_file, pth): - files = None - if design_file not in [None, attr.NOTHING]: - fp = open(design_file, "rt") - for line in fp.readlines(): - if line.startswith("/NumWaves"): - numpes = int(line.split()[-1]) - files = [] - for i in range(numpes): - files.append(os.path.join(pth, ("pe%d.nii.gz" % (i + 1)))) - break - fp.close() - return files - - def _get_numcons(inputs): - numtcons = 0 - numfcons = 0 - if inputs.tcon_file not in [None, attr.NOTHING]: - fp = open(inputs.tcon_file, "rt") - for line in fp.readlines(): - if line.startswith("/NumContrasts"): - numtcons = int(line.split()[-1]) - break - fp.close() - if inputs.fcon_file not in [None, attr.NOTHING]: - fp = open(inputs.fcon_file, "rt") - for line in fp.readlines(): - if line.startswith("/NumContrasts"): - numfcons = int(line.split()[-1]) - break - fp.close() - return numtcons, numfcons - - name = field.name - pth = inputs.results_dir - if name == "results_dir": - return pth - elif name == "param_estimates": - design_file = inputs.design_file - pe_files = _get_pe_files(design_file, pth) - if pe_files: - return pe_files - elif name == "residual4d": - return os.path.join(pth, "res4d.nii.gz") - elif name == "dof_file": - return os.path.join(pth, "dof") - elif name == "sigmasquareds": - return os.path.join(pth, "sigmasquareds.nii.gz") - elif name == "thresholdac": - return os.path.join(pth, "threshac1.nii.gz") - elif name == "logfile": - return os.path.join(pth, "logfile") - - numtcons, numfcons = _get_numcons(inputs) - base_contrast = 1 - copes = [] - varcopes = [] - zstats = [] - tstats = [] - for i in range(numtcons): - copes.append(os.path.join(pth, ("cope%d.nii.gz" % (base_contrast + i)))) - varcopes.append(os.path.join(pth, ("varcope%d.nii.gz" % (base_contrast + i)))) - zstats.append(os.path.join(pth, ("zstat%d.nii.gz" % (base_contrast + i)))) - tstats.append(os.path.join(pth, ("tstat%d.nii.gz" % (base_contrast + i)))) - if copes: - if name == "copes": - return copes - elif name == "varcopes": - return varcopes - elif name == "zstats": - return zstats - elif name == "tstats": - return tstats - fstats = [] - zfstats = [] - for i in range(numfcons): - fstats.append(os.path.join(pth, ("fstat%d.nii.gz" % (base_contrast + i)))) - zfstats.append(os.path.join(pth, ("zfstat%d.nii.gz" % (base_contrast + i)))) - if fstats: - if name == "fstats": - return fstats - elif name == "zfstats": - return - - -def FLAMEO_output(field, inputs): - import os, glob, attr - - def human_order_sorted(l): - """ - Sorts string in human order (i.e. 'stat10' will go after 'stat2') - """ - - def atoi(text): - return int(text) if text.isdigit() else text - - def natural_keys(text): - import re - - if isinstance(text, tuple): - text = text[0] - return [atoi(c) for c in re.split(r"(\d+)", text)] - - return sorted(l, key=natural_keys) - - pth = inputs.log_dir - name = field.name - - if name == "pes": - pes = human_order_sorted(glob.glob(os.path.join(pth, "pe[0-9]*.*"))) - if len(pes) >= 1: - return pes - elif name == "res4d": - res4d = human_order_sorted(glob.glob(os.path.join(pth, "res4d.*"))) - if len(res4d) == 1: - return res4d[0] - elif name == "copes": - copes = human_order_sorted(glob.glob(os.path.join(pth, "cope[0-9]*.*"))) - if len(copes) >= 1: - return copes - elif name == "var_copes": - var_copes = human_order_sorted(glob.glob(os.path.join(pth, "varcope[0-9]*.*"))) - if len(var_copes) >= 1: - return var_copes - elif name == "zstats": - zstats = human_order_sorted(glob.glob(os.path.join(pth, "zstat[0-9]*.*"))) - if len(zstats) >= 1: - return zstats - elif name == "tstats": - tstats = human_order_sorted(glob.glob(os.path.join(pth, "tstat[0-9]*.*"))) - if len(tstats) >= 1: - return tstats - elif name == "mrefvars": - mrefs = human_order_sorted(glob.glob(os.path.join(pth, "mean_random_effects_var[0-9]*.*"))) - if len(mrefs) >= 1: - return mrefs - elif name == "tdof": - tdof = human_order_sorted(glob.glob(os.path.join(pth, "tdof_t[0-9]*.*"))) - if len(tdof) >= 1: - return tdof - elif name == "weights": - weights = human_order_sorted(glob.glob(os.path.join(pth, "weights[0-9]*.*"))) - if len(weights) >= 1: - return weights - elif name == "stats_dir": - return pth - elif inputs.f_con_file not in [None, attr.NOTHING]: - if name == "zfstats": - zfstats = human_order_sorted(glob.glob(os.path.join(pth, "zfstat[0-9]*.*"))) - if len(zfstats) >= 1: - return zfstats - elif name == "fstats": - fstats = human_order_sorted(glob.glob(os.path.join(pth, "fstat[0-9]*.*"))) - if len(fstats) >= 1: - return fstats - else: - raise Exception( - f"this function should be run only for pes, res4d, copes, var_copes, zfstats," - f"fstats, zstats, tstats, mrefs, tdof, weights, or stats_dir, not for {name}" - ) - - -def MELODIC_output(field, inputs): - import os, attr - - name = field.name - if name == "out_dir": - if inputs.out_dir not in [None, attr.NOTHING]: - outputs = inputs.out_dir - else: - outputs = os.getcwd() - elif name == "report_dir": - if inputs.report not in [None, attr.NOTHING]: - if inputs.out_dir not in [None, attr.NOTHING]: - out_dir = inputs.out_dir - else: - out_dir = os.getcwd() - outputs = os.path.join(out_dir, "report") - return outputs - - -# def SLICE_output(inputs): -# import glob - -# suffix = "slice_*" -# if inputs.out_base_name: -# fname_template = f"{inputs.out_base_name}_{suffix}" -# else: -# fname_template = f"{inputs.in_file}_{suffix}" - -# return sorted(glob(fname_template)) - - -def Split_output(inputs): - import os, glob - - output_dir = os.getcwd() - return sorted(glob.glob(os.path.join(output_dir, f"{inputs.output_basename}*.*"))) diff --git a/specs/fsl_aroma_param.yml b/specs/fsl_aroma_param.yml deleted file mode 100644 index e62318c..0000000 --- a/specs/fsl_aroma_param.yml +++ /dev/null @@ -1,8 +0,0 @@ -# ICA_AROMA: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: diff --git a/specs/fsl_dti_param.yml b/specs/fsl_dti_param.yml deleted file mode 100644 index 112fd97..0000000 --- a/specs/fsl_dti_param.yml +++ /dev/null @@ -1,125 +0,0 @@ -# BEDPOSTX: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# BEDPOSTX5: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# DTIFit: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# DistanceMap: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# FSLXCommand: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# FindTheBiggest: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# MakeDyadicVectors: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# ProbTrackX: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# ProbTrackX2: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# ProjThresh: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# TrackSckeleton: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# VecReg: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# XFibres: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# XFibres5: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: diff --git a/specs/fsl_epi_param.yml b/specs/fsl_epi_param.yml deleted file mode 100644 index 451c55e..0000000 --- a/specs/fsl_epi_param.yml +++ /dev/null @@ -1,80 +0,0 @@ -# ApplyTOPUP: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# EPIDeWarp: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# Eddy: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# EddyCorrect: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# EddyQuad: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# EpiReg: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# PrepareFieldmap: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# SigLoss: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# TOPUP: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: diff --git a/specs/fsl_fix_param.yml b/specs/fsl_fix_param.yml deleted file mode 100644 index 177ef20..0000000 --- a/specs/fsl_fix_param.yml +++ /dev/null @@ -1,44 +0,0 @@ -# Classifier: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# Cleaner: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# FeatureExtractor: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# Training: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# TrainingSetCreator: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: diff --git a/specs/fsl_maths_param.yml b/specs/fsl_maths_param.yml deleted file mode 100644 index 87128ad..0000000 --- a/specs/fsl_maths_param.yml +++ /dev/null @@ -1,170 +0,0 @@ -# AR1Image: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# ApplyMask: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# BinaryMaths: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# ChangeDataType: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# DilateImage: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# ErodeImage: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# IsotropicSmooth: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# MathsCommand: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# MaxImage: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# MeanImage: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# MedianImage: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# MinImage: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# MultiImageMaths: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# PercentileImage: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# SpatialFilter: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# StdImage: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# TemporalFilter: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# Threshold: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# UnaryMaths: -# output_requirements: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: diff --git a/specs/fsl_model_param.yml b/specs/fsl_model_param.yml deleted file mode 100644 index de66663..0000000 --- a/specs/fsl_model_param.yml +++ /dev/null @@ -1,349 +0,0 @@ -Cluster: - output_requirements: - index_file: [in_file, out_index_file] - localmax_txt_file: [in_file, out_localmax_txt_file] - localmax_vol_file: [in_file, out_localmax_vol_file] - max_file: [in_file, out_max_file] - mean_file: [in_file, out_mean_file] - pval_file: [in_file, out_pval_file] - size_file: [in_file, out_size_file] - threshold_file: [in_file, out_threshold_file] - output_callables: - index_file: Cluster_output - localmax_txt_file: Cluster_output - localmax_vol_file: Cluster_output - max_file: Cluster_output - mean_file: Cluster_output - pval_file: Cluster_output - size_file: Cluster_output - threshold_file: Cluster_output - output_templates: - - inputs_drop: - doctest: - in_file: zstat1.nii.gz - threshold: 2.3 - use_mm: True - out_index_file: zstat1_index.nii.gz - out_threshold_file: zstat1_threshold.nii.gz - out_localmax_txt_file: zstat1_localmax.txt - out_localmax_vol_file: zstat1_localmax.nii.gz - out_size_file: zstat1_size.nii.gz - out_max_file: zstat1_max.nii.gz - out_mean_file: zstat1_mean.nii.gz - out_pval_file: zstat1_pval.nii.gz - cmdline: cluster --in=zstat1.nii.gz --thresh=2.3000000000 --mm - tests_inputs: - - in_file: zstat1.nii.gz - threshold: 2.3 - use_mm: True - out_index_file: 'zstat1_index.nii.gz' - out_threshold_file: 'zstat1_threshold.nii.gz' - out_localmax_txt_file: 'zstat1_localmax.txt' - out_localmax_vol_file: 'zstat1_localmax.nii.gz' - out_size_file: 'zstat1_size.nii.gz' - out_max_file: 'zstat1_max.nii.gz' - out_mean_file: 'zstat1_mean.nii.gz' - out_pval_file: 'zstat1_pval.nii.gz' - tests_outputs: - - [out_index_file,out_localmax_txt_file,out_localmax_vol_file,out_threshold_file,out_max_file,out_mean_file,out_pval_file,out_size_file,out_threshold_file] - - -# ContrastMgr: -# output_requirements: -# copes: -# fstats: -# neffs: -# tstats: -# varcopes: -# zfstats: -# zstats: - -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# DualRegression: -# output_requirements: -# out_dir: [group_IC_maps_4D, in_files, n_perm] -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# in_files: [functional.nii, functional2.nii, functional3.nii] -# group_IC_maps_4D: allFA.nii -# des_norm: False -# one_sample_group_mean: True -# n_perm: 10 -# out_dir: my_output_directory -# cmdline: dual_regression allFA.nii 0 -1 10 my_output_directory functional.nii functional2.nii functional3.nii -# tests_inputs: -# - -# tests_outputs: -# - - -FEAT: # need a simpler test.fsf - output_requirements: - feat_dir: [fsf_file] - output_callables: - feat_dir: FEAT_output - output_templates: - inputs_drop: - doctest: - fsf_file: test.fsf - cmdline: feat test.fsf - tests_inputs: - - - tests_outputs: - - AttributeError - -FEATModel: - output_requirements: - con_file: - design_cov: - design_file: - design_image: - fcon_file: - - output_callables: - con_file: FEATModel_output - design_cov: FEATModel_output - design_file: FEATModel_output - design_image: FEATModel_output - fcon_file: FEATModel_output - output_templates: - inputs_drop: - doctest: # feat_model [confound matrix text file] - tests_inputs: - - - tests_outputs: - - AttributeError - -# FEATRegister: -# output_requirements: -# fsf_file: [feat_dirs, reg_image] -# output_callables: -# output_templates: -# fsf_file: register.fsf -# inputs_drop: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -FILMGLS: - output_requirements: - corrections: - dof_file: - logfile: - param_estimates: - residual4d: - results_dir: - sigmasquareds: - thresholdac: - output_callables: - corrections: FILMGLS_output - dof_file: FILMGLS_output - logfile: FILMGLS_output - param_estimates: FILMGLS_output - residual4d: FILMGLS_output - results_dir: FILMGLS_output - sigmasquareds: FILMGLS_output - thresholdac: FILMGLS_output - output_templates: - inputs_drop: - doctest: - in_file: test_film_gls.nii.gz - design_file: design_film_gls.mat - threshold: 10 - results_dir: stats - cmdline: film_gls --rn=stats --in=test_film_gls.nii.gz --pd=design_film_gls.mat --thr=10 - tests_inputs: - - in_file: test_film_gls.nii.gz - design_file: design_film_gls.mat - threshold: 10 - results_dir: stats - tests_outputs: - - [dof_file,logfile,param_estimates,residual4d,results_dir,sigmasquareds,thresholdac] - -FLAMEO: - output_requirements: - copes: - var_copes: - mrefvars: - weights: - pes: - res4d: - tdof: - tstats: [t_con_file] - zstats: [t_con_file] - zfstats: [f_con_file] - fstats: [f_con_file] - stats_dir: - - output_callables: - copes: FLAMEO_output - fstats: FLAMEO_output - mrefvars: FLAMEO_output - pes: FLAMEO_output - res4d: FLAMEO_output - tdof: FLAMEO_output - tstats: FLAMEO_output - var_copes: FLAMEO_output - weights: FLAMEO_output - zfstats: FLAMEO_output - zstats: FLAMEO_output - stats_dir: FLAMEO_output - - output_templates: - - inputs_drop: - - doctest: - cope_file: cope_merged.nii.gz - var_cope_file: varcope_merged.nii.gz - cov_split_file: design.grp - design_file: design.mat - t_con_file: design.con - mask_file: mask.nii.gz - run_mode: fe - cmdline: flameo --copefile=cope_merged.nii.gz --varcopefile=varcope_merged.nii.gz --maskfile=mask.nii.gz --designfile=design.mat --tcontrastsfile=design.con --covsplitfile=design.grp --runmode=fe --ld=stats - - tests_inputs: - - cope_file: cope_merged.nii.gz - var_cope_file: varcope_merged.nii.gz - cov_split_file: design.grp - design_file: design.mat - t_con_file: design.con - mask_file: mask.nii.gz - run_mode: fe - log_dir: stats - tests_outputs: - - [copes, var_copes, mrefvars, pes, res4d, tdof, weights, tstats, zstats, stats_dir] - -GLM: - output_requirements: - out_file: [in_file] - output_callables: - output_templates: - out_file: "{in_file}_glm" - inputs_drop: - doctest: - in_file: test.nii.gz - design: confounds_regressors.tsv - cmdline: fsl_glm -i test.nii.gz -d confounds_regressors.tsv # doctest: +ELLIPSIS - tests_inputs: - - in_file: test.nii.gz - design: confounds_regressors.tsv - tests_outputs: - - out_file - -# L2Model: -# output_requirements: -# design_con: -# design_grp: -# design_mat: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# Level1Design: -# output_requirements: -# ev_files: -# fsf_files: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -MELODIC: - output_requirements: - out_dir: - report_dir: - output_callables: - out_dir: MELODIC_output - report_dir: MELODIC_output - output_templates: - inputs_drop: - doctest: - approach: tica - in_files: [test2.nii,test3.nii] - no_bet: True - bg_threshold: 10 - tr_sec: 1.5 - out_stats: True - t_des: timeDesign.mat - t_con: timeDesign.con - s_des: subjectDesign.mat - s_con: subjectDesign.con - out_dir: groupICA.out - cmdline: melodic -i test2.nii,test3.nii -o groupICA.out --nobet --bgthreshold=10 -a tica --tr=1.5 --Tdes=timeDesign.mat --Tcon=timeDesign.con --Sdes=subjectDesign.mat --Scon=subjectDesign.con --Ostats - tests_inputs: - - - tests_outputs: - - AttributeError - -# MultipleRegressDesign: -# output_requirements: -# design_con: -# design_fts: -# design_grp: -# design_mat: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# Randomise: -# output_requirements: -# f_corrected_p_files: -# f_p_files: -# fstat_files: -# t_corrected_p_files: -# t_p_files: -# tstat_files: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# cmdline: randomise -i allFA.nii -o "randomise" -d design.mat -t design.con -m mask.nii -# tests_inputs: -# tests_outputs: - -# SMM: -# output_requirements: -# activation_p_map: -# deactivation_p_map: -# null_p_map: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# tests_inputs: -# tests_outputs: - -# SmoothEstimate: # need new test data -# output_requirements: -# dlh: -# resels: -# volume: -# output_callables: -# output_templates: -# inputs_drop: -# doctest: -# zstat_file: zstat1.nii.gz -# mask_file: mask.nii -# cmdline: smoothest --mask=mask.nii --zstat=zstat1.nii.gz -# tests_inputs: -# tests_outputs: diff --git a/specs/fsl_possum_param.yml b/specs/fsl_possum_param.yml deleted file mode 100644 index f589896..0000000 --- a/specs/fsl_possum_param.yml +++ /dev/null @@ -1,11 +0,0 @@ -# B0Calc: -# output_requirements: -# out_file : [in_file] -# output_templates: -# out_file: "{in_file}_b0field" -# tests_inputs: -# - - -# tests_outputs: -# - AttributeError -# Exception: format from --b0x=%0.2f --b0y=%0.2f --b0=%0.2f is not supported TODO diff --git a/specs/fsl_preprocess_param.yml b/specs/fsl_preprocess_param.yml deleted file mode 100644 index 458fc42..0000000 --- a/specs/fsl_preprocess_param.yml +++ /dev/null @@ -1,231 +0,0 @@ -BET: - output_requirements: - out_file: [in_file] - mask_file: - - [mask: True] - - [reduce_bias: True] - outline_file: [outline: True] - meshfile: - - [mesh: True] - - [surfaces: True] - inskull_mask_file: [surfaces: True] - inskull_mesh_file: [surfaces: True] - outskull_mask_file: [surfaces: True] - outskull_mesh_file: [surfaces: True] - outskin_mask_file: [surfaces: True] - outskin_mesh_file: [surfaces: True] - skull_mask_file: [surfaces: True] - skull_file: [skull: True] - - output_templates: - out_file: "{in_file}_brain" - mask_file: "{out_file}_mask" - outline_file: "{out_file}_overlay" - meshfile: "{out_file}_mesh.vtk" - inskull_mask_file: "{out_file}_inskull_mask" - inskull_mesh_file: "{out_file}_inskull_mesh" - outskull_mask_file: "{out_file}_outskull_mask" - outskull_mesh_file: "{out_file}_outskull_mesh" - outskin_mask_file: "{out_file}_outskin_mask" - outskin_mesh_file: "{out_file}_outskin_mesh" - skull_mask_file: "{out_file}_skull_mask" - skull_file: "{out_file}_skull" - - - doctest: - in_file: "test.nii.gz" - out_file: test_brain.nii.gz - frac: 0.7 - cmdline: 'bet test.nii.gz test_brain.nii.gz -f 0.70' - - tests_inputs: - - - - mask: True - - surfaces: True - - tests_outputs: - - out_file - - [out_file, mask_file] - - [out_file, meshfile, inskull_mask_file, inskull_mesh_file, outskull_mask_file, - outskull_mesh_file, outskin_mask_file, outskin_mesh_file, skull_mask_file] - - -FAST: - inputs_metadata: - number_classes: - default: 3 - - output_requirements: - tissue_class_files: [segments: True] - partial_volume_map: [no_pve: False] # possibly [False, None, attr.NOTHING] - partial_volume_files: [no_pve: False] # possibly [False, None, attr.NOTHING] - bias_field: [output_biasfield: True] - probability_maps: [probability_maps: True] - - output_callables: - tissue_class_map: FAST_output - tissue_class_files: FAST_output_nclass - restored_image: FAST_output_infile - mixeltype: FAST_output - partial_volume_map: FAST_output - partial_volume_files: FAST_output_nclass - bias_field: FAST_output_infile - probability_maps: FAST_output_nclass - - doctest: - in_files: "test.nii.gz" - out_basename: "fast_" - cmdline: 'fast -o fast_ -n 3 test.nii.gz' - - tests_inputs: - - - - tests_outputs: - - AttributeError - - -MCFLIRT: - output_requirements: - out_file: [in_file] - variance_img: [in_file, stats_imgs: True] - std_img: [in_file, stats_imgs: True] - mean_img: [in_file, mean_vol: True] - par_file: [save_plots] -# mat_file: -# rms_files: [save_rms] - - - output_templates: - out_file: "{in_file}_mcf" - variance_img: "{out_file}_variance.ext" - std_img: "{out_file}_sigma.ext" - mean_img: "{out_file}_mean_reg.ext" - par_file: "{out_file}.par" -# mat_file: -# rms_files: - - tests_inputs: - - - - tests_outputs: - - out_file - - -FLIRT: - output_requirements: - - output_templates: - - tests_inputs: - - - - tests_outputs: - - AttributeError - - -FNIRT: - output_requirements: - warped_file: [in_file] - field_file: [in_file] - jacobian_file: [in_file] - modulatedref_file: [in_file] - #out_intensitymap_file: [in_file] - log_file: [in_file] - fieldcoeff_file: [in_file] - - - output_templates: - warped_file: "{in_file}_warped" - field_file: "{in_file}_field" - jacobian_file: "{in_file}_field_jacobian" - modulatedref_file: "{in_file}_modulated" - #out_intensitymap_file: "{in_file}_intmap" - log_file: "{in_file}_log.txt" - fieldcoeff_file: "{in_file}_fieldwarp" - - tests_inputs: - - - - ref_file: f"{in_file}" - - tests_outputs: - - AttributeError - - [warped_file, field_file, jacobian_file, modulatedref_file, log_file, fieldcoeff_file] - - -ApplyWarp: - output_templates: - out_file: "{in_file}_warp" - - tests_inputs: - - ref_file: f"{in_file}" - - tests_outputs: - - out_file - - -SliceTimer: - output_requirements: - slice_time_corrected_file: [out_file] - - output_templates: - out_file: "{in_file}_st" - slice_time_corrected_file: "{out_file}" - - tests_inputs: - - ref_file: f"{in_file}" - - tests_outputs: - - [out_file, slice_time_corrected_file] - - -SUSAN: - output_requirements: - smoothed_file: [out_file] - - output_templates: - out_file: "{in_file}_smooth" - smoothed_file: "{out_file}" - - tests_inputs: - - - - - brightness_threshold: 0.01 - fwhm: 2 - - tests_outputs: - - AttributeError - - [out_file, smoothed_file] - - -PRELUDE: - output_requirements: - unwrapped_phase_file: [phase_file] - - output_templates: - unwrapped_phase_file: "{phase_file}_unwrapped" - - tests_inputs: - - - - tests_outputs: - - AttributeError - - -FIRST: - output_requirements: - original_segmentations: [in_file] - segmentation_file: [in_file] - vtk_surfaces: [in_file] - bvars: [in_file] - - output_templates: - original_segmentations: "{in_file}_original_segmentations" - segmentation_file: "{in_file}_segmentation_file" - vtk_surfaces: "{in_file}_vtk_surfaces" - bvars: "{in_file}_bvars" - - tests_inputs: - - - - tests_outputs: - - AttributeError diff --git a/specs/fsl_utils_param.yml b/specs/fsl_utils_param.yml deleted file mode 100644 index f62cc9f..0000000 --- a/specs/fsl_utils_param.yml +++ /dev/null @@ -1,401 +0,0 @@ -# AvScale: # complex output -# output_requirements: -# average_scaling: -# backward_half_transform: -# determinant: -# forward_half_transform: -# left_right_orientation_preserved: -# rot_angles: -# rotation_translation_matrix: -# scales: -# skews: -# translations: -# output_templates: -# doctest: -# mat_file: "flirt.mat" -# cmdline: "avscale flirt.mat" -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -Complex: # this one needs to rethink, the callable is not shown up - output_requirements: - - output_callables: - complex_out_file: Complex_output - output_templates: - imaginary_out_file: "{in_file}_imag" - magnitude_out_file: "{in_file}_mag" - phase_out_file: "{in_file}_phase" - real_out_file: "{in_file}_real" - doctest: - tests_inputs: - - - tests_outputs: - - AttributeError - - -ConvertWarp: # needs more test data - output_requirements: - out_file: [reference] - output_templates: - out_file: "{reference}_concatwarp" - doctest: - warp1: warpfield.nii - reference: test.nii.gz - relwarp: True - out_file: test_concatwarp.nii.gz - cmdline: convertwarp --ref=test.nii.gz --warp1=warpfield.nii --rel --out=test_concatwarp.nii.gz - tests_inputs: - - - tests_outputs: - - AttributeError - -ConvertXFM: - output_requirements: - out_file: [in_file] - - output_templates: - out_file: [ConvertXFM_output] - - doctest: - in_file: flirt.mat - invert_xfm: True - out_file: flirt_inv.mat - cmdline: convert_xfm -omat flirt_inv.mat -inverse flirt.mat - tests_inputs: - - in_file: flirt.mat - invert_xfm: True - tests_outputs: - - out_file - -CopyGeom: - output_requirements: - out_file: [in_file, dest_file] - output_templates: - dest_file: "original" - out_file: "{dest_file}" - doctest: - in_file: test.nii.gz - dest_file: dest.nii.gz - cmdline: fslcpgeom test.nii.gz dest.nii.gz - tests_inputs: - - - - tests_outputs: - - AttributeError - -ExtractROI: - output_requirements: - roi_file: [in_file] - output_templates: - roi_file: "{in_file}_trim" - inputs_drop: - - crop_list - doctest: - in_file: test.nii.gz - t_min: 0 - t_size: 3 - roi_file: test_trim.nii.gz - cmdline: fslroi test.nii.gz test_trim.nii.gz 0 3 - tests_inputs: - - in_file: test.nii.gz - t_min: 0 - t_size: 1 - tests_outputs: - - roi_file - -FilterRegressor: - output_requirements: - out_file: [in_file, design_file] - inputs_drop: - - filter_all - output_templates: - out_file: "{in_file}_filtered" - doctest: - in_file: test.nii.gz - design_file: design - filter_columns: 1,2,3 - out_file: test_filtered.nii.gz - cmdline: fsl_regfilt -i test.nii.gz -o test_filtered.nii.gz -d design -f 1,2,3 - tests_inputs: - - - tests_outputs: - - AttributeError - -ImageMaths: - output_requirements: - out_file: [in_file] - output_templates: - out_file: "{in_file}_maths" - inputs_drop: # input from nipype interface that's not required by fsl - - suffix - - doctest: - in_file: test.nii.gz - op_string: -add 5 - out_file: test_maths.nii.gz - cmdline: fslmaths test.nii.gz -add 5 test_maths.nii.gz - tests_inputs: - - - tests_outputs: - - out_file - -ImageMeants: - output_requirements: - out_file: [in_file] - output_templates: - out_file: "{in_file}_meants.txt" - doctest: - in_file: test.nii.gz - mask: mask.nii.gz - out_file: test_meants.txt - cmdline: fslmeants -i test.nii.gz -o test_meants.txt -m mask.nii.gz --order=1 - tests_inputs: - - - tests_outputs: - - out_file - -ImageStats: - output_requirements: - out_stat: [in_file, op_string] - output_templates: - doctest: - in_file: test.nii.gz - op_string: -M - cmdline: fslstats test.nii.gz -M - tests_inputs: - - - tests_outputs: - - AttributeError - -InvWarp: - output_requirements: - inverse_warp: [reference, warp] - output_templates: - inverse_warp: "{warp}_inverse" - doctest: - reference: anatomical.nii - warp: struct2mni.nii - inverse_warp: struct2mni_inverse.nii.gz - cmdline: invwarp --warp=struct2mni.nii --ref=anatomical.nii --out=struct2mni_inverse.nii.gz - tests_inputs: - - - tests_outputs: - - AttributeError - -# Merge: #need to fix -# output_requirements: -# merged_file: [in_files] -# output_templates: -# merged_file: "{in_files[0]}_merged" -# doctest: -# in_files: [test.nii, test2.nii] -# dimension: t -# tr: 2.25 -# cmdline: fslmerge -tr test_merged.nii.gz test.nii test2.nii 2.25 -# tests_inputs: -# - in_files: [test.nii, test2.nii] -# dimension: t -# tr: 2.25 -# tests_outputs: -# - merged_file - -# MotionOutliers: -# output_requirements: -# out_file: [in_file] -# out_metric_plot: [in_file] -# out_metric_values: [in_file] -# output_templates: -# out_file: "{infile}_outlier" -# out_metric_plot: "{infile}_metrics" -# out_metric_values: "{infile}_metrics" -# doctest: -# in_file: "epi.nii" -# cmdline: "fsl_motion_outliers -i epi.nii -o epi_outliers.txt -p epi_metrics.png -s epi_metrics.txt" -# tests_inputs: -# - -# tests_outputs: -# - [out_file, out_metric_plot, out_metric_values] - -# Overlay: -# output_requirements: -# out_file: ["auto_thresh_bg", "background_image", "stat_image", "stat_thresh"] -# output_templates: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -# PlotMotionParams: -# output_requirements: -# output_templates: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -# PlotTimeSeries: -# output_requirements: -# output_templates: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -# PowerSpectrum: -# output_requirements: -# output_templates: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -# Reorient2Std: -# output_requirements: -# output_templates: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -# RobustFOV: -# output_requirements: -# output_templates: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -# SigLoss: -# output_requirements: -# output_templates: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -# Slice: #needs to fix -# output_requirements: -# out_files: [in_file] -# output_templates: -# out_files: [SLICE_output] -# doctest: -# in_file: test.nii.gz -# out_base_name: sl -# cmdline: fslslice test.nii.gz sl -# tests_inputs: -# - in_file: test.nii.gz -# out_base_name: sl -# tests_outputs: -# - out_files - -# Slicer: -# output_requirements: -# out_file: [in_file] -# output_templates: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -Smooth: - output_requirements: - smoothed_file: [in_file, sigma] - - output_templates: - smoothed_file: "{in_file}_smooth" - - inputs_drop: - - fwhm - - doctest: - in_file: test.nii.gz - sigma: 3.397 - smoothed_file: test_smooth.nii.gz - cmdline: fslmaths test.nii.gz -kernel gauss 3.397 -fmean test_smooth.nii.gz - - tests_inputs: - - in_file: test.nii.gz - sigma: 3.397 - tests_outputs: - - smoothed_file - -Split: - output_requirements: - out_files: [in_file, output_basename, dimension] - output_callables: - out_files: Split_output - doctest: - in_file: test.nii.gz - output_basename: test_split - dimension: t - cmdline: fslsplit test.nii.gz test_split -t - - tests_inputs: - - in_file: test.nii.gz - output_basename: test_split - dimension: t - tests_outputs: - - out_files - -SwapDimensions: - output_requirements: - out_file: [in_file, new_dims] - output_templates: - out_file: "{in_file}_newdims" - doctest: - tests_inputs: - - - tests_outputs: - - AttributeError - -# WarpPoints: -# output_requirements: -# out_file: [dest_file, in_coords, src_file] -# output_templates: -# out_file: "{in_coords}_warped" -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -# WarpPointsFromStd: -# output_requirements: -# output_templates: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -# WarpPointsToStd: -# output_requirements: -# output_templates: -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError - -# WarpUtils: -# output_requirements: -# out_file: [in_file, reference, write_jacobian] -# out_jacobian: [in_file, reference, write_jacobian: True] -# output_templates: -# out_file: "{in_file}_coeffs" -# doctest: -# tests_inputs: -# - -# tests_outputs: -# - AttributeError diff --git a/tools/__init__.py b/tools/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tools/converter.py b/tools/converter.py deleted file mode 100644 index eca5cc1..0000000 --- a/tools/converter.py +++ /dev/null @@ -1,607 +0,0 @@ -from attr import has -from ast import literal_eval -from nipype.interfaces import fsl -from nipype.interfaces.base import traits_extension -from pydra.engine import specs -from pydra.engine.helpers import ensure_list - -import os, sys, yaml, black, imp -import traits -from pathlib import Path -import typing as ty -import inspect -import click -import warnings -import functools - -sys.path.append(str(Path(__file__).resolve().parent.parent / 'specs')) -import callables - - -class FSLConverter: - INPUT_KEYS = [ - "allowed_values", - "argstr", - "container_path", - "copyfile", - "desc", - "mandatory", - "position", - "requires", - "sep", - "xor", - ] - OUTPUT_KEYS = ["desc"] - NAME_MAPPING = {"desc": "help_string"} - - TRAITS_IRREL = [ - 'output_type', - 'args', - 'environ', - 'environ_items', - '__all__', - 'trait_added', - 'trait_modified', - ] - - TYPE_REPLACE = [ - ("\'File\'", "specs.File"), - ("\'bool\'", "bool"), - ("\'str\'", "str"), - ("\'Any\'", "ty.Any"), - ("\'int\'", "int"), - ("\'float\'", "float"), - ("\'list\'", "list"), - ("\'dict\'", "dict"), - ("\'MultiInputObj\'", "specs.MultiInputObj"), - ("\'MultiOutputObj\'", "specs.MultiOutputObj"), - ("\'MultiInputFile\'", "specs.MultiInputFile"), - ("\'MultiOutputFile\'", "specs.MultiOutputFile"), - ] - - def __init__(self, interface_name, interface_spec_file): - self.interface_name = interface_name - with interface_spec_file.open() as f: - self.interface_spec = yaml.safe_load(f)[self.interface_name] - if self.interface_spec.get("output_requirements") is None: - self.interface_spec["output_requirements"] = [] - if self.interface_spec.get("inputs_metadata") is None: - self.interface_spec["inputs_metadata"] = {} - if self.interface_spec.get("inputs_drop") is None: - self.interface_spec["inputs_drop"] = [] - if self.interface_spec.get("output_templates") is None: - self.interface_spec["output_templates"] = {} - if self.interface_spec.get("output_callables") is None: - self.interface_spec["output_callables"] = {} - if ( - not self.interface_spec["output_callables"] - .keys() - .isdisjoint(self.interface_spec["output_templates"].keys()) - ): - raise Exception("output_callables and output_templates have the same keys") - if self.interface_spec.get("doctest") is None: - self.interface_spec["doctest"] = {} - - # getting input/output spec from nipype - nipype_interface = getattr(fsl, self.interface_name) - self.cmd = nipype_interface._cmd - self.nipype_input_spec = nipype_interface.input_spec() - self.nipype_output_spec = nipype_interface.output_spec() - - def pydra_specs(self, write=False, dirname=None): - """creating pydra input/output spec from nipype specs - if write is True, a pydra Task class will be written to the file together with tests - """ - input_fields_pdr, inp_templates = self.convert_input_fields() - output_fields_pdr = self.convert_output_spec(fields_from_template=inp_templates) - - input_spec_pydra = specs.SpecInfo( - name="Input", fields=input_fields_pdr, bases=(specs.ShellSpec,) - ) - output_spec_pydra = specs.SpecInfo( - name="Output", fields=output_fields_pdr, bases=(specs.ShellOutSpec,) - ) - - if write: - if dirname is None: - raise Exception("dirname has to be provided if write is True") - self.write_pydra_files( - dirname=dirname, - pydra_input_spec=input_fields_pdr, - pydra_output_spec=output_fields_pdr, - ) - return input_spec_pydra, output_spec_pydra - - def write_pydra_files(self, dirname, pydra_input_spec, pydra_output_spec): - """writing pydra task and tests to the files""" - testdir = dirname / "tests" - testdir.mkdir(parents=True, exist_ok=True) - Path.touch(dirname / "__init__.py") - Path.touch(testdir / "__init__.py") - filename = dirname / f"{self.interface_name.lower()}.py" - filename_test = testdir / f"test_spec_{filename.name}" - filename_test_run = testdir / f"test_run_{filename.name}" - - print("\n FILENAME", filename) - self.write_task(filename, pydra_input_spec, pydra_output_spec) - - self.write_test(filename_test=filename_test) - self.write_test(filename_test=filename_test_run, run=True) - - def write_task(self, filename, input_fields, output_fields): - """writing pydra task to the dile based on the input and output spec""" - - def types_to_names(spec_fields): - spec_fields_str = [] - for el in spec_fields: - el = list(el) - try: - el[1] = el[1].__name__ - except AttributeError: - el[1] = el[1]._name - spec_fields_str.append(tuple(el)) - return spec_fields_str - - input_fields_str = types_to_names(spec_fields=input_fields) - output_fields_str = types_to_names(spec_fields=output_fields) - functions_str = self.function_callables() - spec_str = "from pydra.engine import specs \nfrom pydra import ShellCommandTask \n" - spec_str += f"import typing as ty\n" - spec_str += functions_str - spec_str += f"input_fields = {input_fields_str}\n" - spec_str += f"{self.interface_name}_input_spec = specs.SpecInfo(name='Input', fields=input_fields, bases=(specs.ShellSpec,))\n\n" - spec_str += f"output_fields = {output_fields_str}\n" - spec_str += f"{self.interface_name}_output_spec = specs.SpecInfo(name='Output', fields=output_fields, bases=(specs.ShellOutSpec,))\n\n" - - spec_str += f"class {self.interface_name}(ShellCommandTask):\n" - if self.interface_spec["doctest"]: - spec_str += self.create_doctest() - spec_str += f" input_spec = {self.interface_name}_input_spec\n" - spec_str += f" output_spec = {self.interface_name}_output_spec\n" - spec_str += f" executable='{self.cmd}'\n" - - for tp_repl in self.TYPE_REPLACE: - spec_str = spec_str.replace(*tp_repl) - - spec_str_black = black.format_file_contents(spec_str, fast=False, mode=black.FileMode()) - - with open(filename, "w") as f: - f.write(spec_str_black) - - def write_test(self, filename_test, run=False): - """writing tests for the specific interface based on the test spec (from interface_spec) - if run is True the test contains task run, - if run is False only the spec is check by the test - """ - tests_inputs = self.interface_spec["tests_inputs"] - tests_outputs = self.interface_spec["tests_outputs"] - if len(tests_inputs) != len(tests_outputs): - raise Exception("tests and tests_outputs should have the same length") - - tests_inp_outp = [] - tests_inp_error = [] - for i, out in enumerate(tests_outputs): - if isinstance(out, list): - tests_inp_outp.append((tests_inputs[i], out)) - elif out is None: - tests_inp_outp.append((tests_inputs[i], [])) - # allowing for incomplete or incorrect inputs that should raise an exception - elif out not in ["AttributeError", "Exception"]: - tests_inp_outp.append((tests_inputs[i], [out])) - else: - tests_inp_error.append((tests_inputs[i], out)) - - spec_str = f"import re, os, shutil, pytest \nfrom pathlib import Path\n" - spec_str += f"from ..{self.interface_name.lower()} import {self.interface_name} \n\n" - if run: - spec_str += ( - "@pytest.mark.xfail('FSLDIR' not in os.environ, reason='no FSL found', " - "raises=FileNotFoundError)\n" - ) - spec_str += f"@pytest.mark.parametrize('inputs, outputs', {tests_inp_outp})\n" - spec_str += f"def test_{self.interface_name}(test_data, inputs, outputs):\n" - spec_str += f" if inputs is None:\n" - spec_str += f" in_file = Path(test_data) / 'test.nii.gz'\n" - spec_str += f" task = {self.interface_name}(in_file=in_file)\n" - spec_str += f" else:\n" - spec_str += f" for key, val in inputs.items():\n" - spec_str += f" try: \n" - spec_str += f" pattern = r'\.[a-zA-Z]*'\n" - spec_str += f" if isinstance(val, str):\n" - spec_str += f" if re.findall(pattern, val) != []:\n" - spec_str += f" inputs[key] = Path(test_data) / val\n" - spec_str += f" elif '_dir' in key:\n" - spec_str += f" dirpath = Path(test_data) / val\n" - spec_str += f" if dirpath.exists() and dirpath.is_dir():\n" - spec_str += f" shutil.rmtree(dirpath)\n" - spec_str += f" inputs[key] = Path(test_data) / val\n" - spec_str += f" else: inputs[key] = eval(val)\n" - spec_str += f" elif isinstance(val, list):\n" - spec_str += f" if all (re.findall(pattern, _) != [] for _ in val):\n" - spec_str += f" inputs[key] = [Path(test_data)/_ for _ in val] \n" - spec_str += f" else: inputs[key] = eval(val)\n" - spec_str += f" except: pass\n" - spec_str += f" task = {self.interface_name}(**inputs)\n" - spec_str += ( - f" assert set(task.generated_output_names) == " - f"set(['return_code', 'stdout', 'stderr'] + outputs)\n" - ) - - if run: - spec_str += f" res = task()\n" - spec_str += f" print('RESULT: ', res)\n" - spec_str += f" for out_nm in outputs:\n" - spec_str += f" if isinstance(getattr(res.output, out_nm), list): assert [os.path.exists(x) for x in getattr(res.output, out_nm)]\n" - spec_str += f" else: assert os.path.exists(getattr(res.output, out_nm))\n" - - # if test_inp_error is not empty, than additional test function will be created - if tests_inp_error: - spec_str += self.write_test_error(input_error=tests_inp_error) - - spec_str_black = black.format_file_contents(spec_str, fast=False, mode=black.FileMode()) - - with open(filename_test, "w") as f: - f.write(spec_str_black) - - def write_test_error(self, input_error): - """creating a tests for incorrect or incomplete inputs - checking if the exceptions are raised - """ - spec_str = "\n\n" - spec_str += f"@pytest.mark.parametrize('inputs, error', {input_error})\n" - spec_str += f"def test_{self.interface_name}_exception(test_data, inputs, error):\n" - spec_str += f" if inputs is None:\n" - spec_str += f" in_file = Path(test_data) / 'test.nii.gz'\n" - spec_str += f" task = {self.interface_name}(in_file=in_file)\n" - spec_str += f" else:\n" - spec_str += f" for key, val in inputs.items():\n" - spec_str += f" try: \n" - spec_str += f" pattern = r'\.[a-zA-Z]*'\n" - spec_str += f" if isinstance(val, str):\n" - spec_str += f" if re.findall(pattern, val) != []:\n" - spec_str += f" inputs[key] = Path(test_data) / val\n" - spec_str += f" elif '_dir' in key:\n" - spec_str += f" dirpath = Path(test_data) / val\n" - spec_str += f" if dirpath.exists() and dirpath.is_dir():\n" - spec_str += f" shutil.rmtree(dirpath)\n" - spec_str += f" inputs[key] = Path(test_data) / val\n" - spec_str += f" else: inputs[key] = eval(val)\n" - spec_str += f" elif isinstance(val, list):\n" - spec_str += f" if all (re.findall(pattern, _) != [] for _ in val):\n" - spec_str += f" inputs[key] = [Path(test_data)/_ for _ in val] \n" - spec_str += f" else: inputs[key] = eval(val)\n" - spec_str += f" except: pass\n" - spec_str += f" task = {self.interface_name}(**inputs)\n" - spec_str += f" with pytest.raises(eval(error)):\n" - spec_str += f" task.generated_output_names\n" - - return spec_str - - def create_doctest(self): - """adding doctests to the interfaces""" - cmdline = self.interface_spec["doctest"].pop("cmdline") - doctest = ' """\n Example\n -------\n' - doctest += f' >>> task = {self.interface_name}()\n' - for key, val in self.interface_spec["doctest"].items(): - if type(val) is str: - doctest += f' >>> task.inputs.{key} = "{val}"\n' - else: - doctest += f' >>> task.inputs.{key} = {val}\n' - doctest += ' >>> task.cmdline\n' - doctest += f" '{cmdline}'" - doctest += '\n """\n' - return doctest - - def convert_input_fields(self): - """creating fields list for pydra input spec""" - fields_pdr_dict = {} - position_dict = {} - has_template = [] - for name, fld in self.nipype_input_spec.traits().items(): - if name in self.TRAITS_IRREL: - continue - if name in self.interface_spec["inputs_drop"]: - continue - fld_pdr, pos = self.pydra_fld_input(fld, name) - meta_pdr = fld_pdr[-1] - if "output_file_template" in meta_pdr: - has_template.append(name) - fields_pdr_dict[name] = (name,) + fld_pdr - if pos is not None: - position_dict[name] = pos - - fields_pdr_l = list(fields_pdr_dict.values()) - return fields_pdr_l, has_template - - def pydra_fld_input(self, field, nm): - """converting a single nipype field to one element of fields for pydra input_spec""" - tp_pdr = self.pydra_type_converter(field, spec_type="input", name=nm) - if nm in self.interface_spec["inputs_metadata"]: - metadata_extra_spec = self.interface_spec["inputs_metadata"][nm] - else: - metadata_extra_spec = {} - - if "default" in metadata_extra_spec: - default_pdr = metadata_extra_spec.pop("default") - elif getattr(field, "usedefault") and field.default is not traits.ctrait.Undefined: - default_pdr = field.default - else: - default_pdr = None - - metadata_pdr = {"help_string": ""} - for key in self.INPUT_KEYS: - key_nm_pdr = self.NAME_MAPPING.get(key, key) - val = getattr(field, key) - if val is not None: - if key == "argstr" and "%" in val: - val = self.string_formats(argstr=val, name=nm) - metadata_pdr[key_nm_pdr] = val - - if getattr(field, "name_template"): - template = getattr(field, "name_template") - name_source = ensure_list(getattr(field, "name_source")) - - metadata_pdr["output_file_template"] = self.string_formats( - argstr=template, name=name_source[0] - ) - if tp_pdr in [specs.File, specs.Directory]: - tp_pdr = str - elif getattr(field, "genfile"): - if nm in self.interface_spec["output_templates"]: - if isinstance(self.interface_spec["output_templates"][nm], list): - metadata_pdr["output_file_template"] = self.interface_spec["output_templates"][ - nm - ][0] - else: - metadata_pdr["output_file_template"] = self.interface_spec["output_templates"][ - nm - ] - if tp_pdr in [ - specs.File, - specs.Directory, - ]: # since this is a template, the file doesn't exist - tp_pdr = str - elif nm not in self.interface_spec["output_callables"]: - raise Exception( - f"the filed {nm} has genfile=True, but no output template or callables provided" - ) - - metadata_pdr.update(metadata_extra_spec) - - pos = metadata_pdr.get("position", None) - - if default_pdr is not None and not metadata_pdr.get("mandatory", None): - return (tp_pdr, default_pdr, metadata_pdr), pos - else: - return (tp_pdr, metadata_pdr), pos - - def convert_output_spec(self, fields_from_template): - """creating fields list for pydra output spec""" - fields_pdr_l = [] - for name, fld in self.nipype_output_spec.traits().items(): - if ( - name in self.interface_spec["output_requirements"] - and name not in fields_from_template - ): - fld_pdr = self.pydra_fld_output(fld, name) - fields_pdr_l.append((name,) + fld_pdr) - return fields_pdr_l - - def pydra_fld_output(self, field, nm): - """converting a single nipype field to one element of fields for pydra output_spec""" - tp_pdr = self.pydra_type_converter(field, spec_type="output", name=nm) - - metadata_pdr = {} - for key in self.OUTPUT_KEYS: - key_nm_pdr = self.NAME_MAPPING.get(key, key) - val = getattr(field, key) - if val: - metadata_pdr[key_nm_pdr] = val - - if self.interface_spec["output_requirements"][nm]: - if all( - [isinstance(el, list) for el in self.interface_spec["output_requirements"][nm]] - ): - requires_l = self.interface_spec["output_requirements"][nm] - nested_flag = True - elif all( - [ - isinstance(el, (str, dict)) - for el in self.interface_spec["output_requirements"][nm] - ] - ): - requires_l = [self.interface_spec["output_requirements"][nm]] - nested_flag = False - else: - Exception("has to be either list of list or list of str/dict") - - metadata_pdr["requires"] = [] - for requires in requires_l: - requires_mod = [] - for el in requires: - if isinstance(el, str): - requires_mod.append(el) - elif isinstance(el, dict): - requires_mod += list(el.items()) - metadata_pdr["requires"].append(requires_mod) - if nested_flag is False: - metadata_pdr["requires"] = metadata_pdr["requires"][0] - - if nm in self.interface_spec["output_templates"]: - if isinstance(self.interface_spec["output_templates"][nm], list): - metadata_pdr["output_file_template"] = self.interface_spec["output_templates"][nm][ - 0 - ] - else: - metadata_pdr["output_file_template"] = self.interface_spec["output_templates"][nm] - elif nm in self.interface_spec["output_callables"]: - metadata_pdr["callable"] = self.interface_spec["output_callables"][nm] - return (tp_pdr, metadata_pdr) - - def function_callables(self): - fun_names = [] - if not self.interface_spec["output_callables"]: - if self.interface_spec["output_templates"]: - tmpls = list(self.interface_spec["output_templates"].values()) - for tmpl in tmpls: - if isinstance(tmpl, list): - fun_names.append(tmpl[0]) - if len(fun_names) < 1: - pass - python_functions_spec = Path(os.path.dirname(__file__)) / "../specs/callables.py" - if not python_functions_spec.exists(): - raise Exception( - "specs/callables.py file is needed if functions are used in the spec files" - ) - - fun_names.extend(list(set(self.interface_spec["output_callables"].values()))) - fun_names.sort() - fun_str = "" - for fun_nm in fun_names: - fun = getattr(callables, fun_nm) - fun_str += inspect.getsource(fun) + "\n" - return fun_str - - def pydra_type_converter(self, field, spec_type, name): - """converting types to types used in pydra""" - if spec_type not in ["input", "output"]: - raise Exception(f"spec_type has to be input or output, but {spec_type} provided") - tp = field.trait_type - if isinstance(tp, traits.trait_types.Int): - tp_pdr = int - elif isinstance(tp, traits.trait_types.Float): - tp_pdr = float - elif isinstance(tp, traits.trait_types.Str): - tp_pdr = str - elif isinstance(tp, traits.trait_types.Bool): - tp_pdr = bool - elif isinstance(tp, traits.trait_types.Dict): - tp_pdr = dict - elif isinstance(tp, traits_extension.InputMultiObject): - if isinstance(field.inner_traits[0].trait_type, traits_extension.File): - tp_pdr = specs.MultiInputFile - else: - tp_pdr = specs.MultiInputObj - elif isinstance(tp, traits_extension.OutputMultiObject): - if isinstance(field.inner_traits[0].trait_type, traits_extension.File): - tp_pdr = specs.MultiOutputFile - else: - tp_pdr = specs.MultiOutputObj - elif isinstance(tp, traits_extension.InputMultiPath): - if isinstance(field.inner_traits[0].trait_type, traits_extension.File): - tp_pdr = specs.MultiInputFile - else: - tp_pdr = specs.MultiInputObj - elif isinstance(tp, traits_extension.OutputMultiPath): - if isinstance(field.inner_traits[0].trait_type, traits_extension.File): - tp_pdr = specs.MultiOutputFile - else: - tp_pdr = specs.MultiOutputObj - elif isinstance(tp, traits.trait_types.List): - if isinstance(field.inner_traits[0].trait_type, traits_extension.File): - if spec_type == "input": - tp_pdr = specs.MultiInputFile - else: - tp_pdr = specs.MultiOutputFile - else: - tp_pdr = list - elif isinstance(tp, traits_extension.File): - if ( - spec_type == "output" or tp.exists is True - ): # TODO check the hash_file metadata in nipype - tp_pdr = specs.File - else: - tp_pdr = str - else: - tp_pdr = ty.Any - return tp_pdr - - def string_formats(self, argstr, name): - import re - - if "%s" in argstr: - argstr_new = argstr.replace("%s", f"{{{name}}}") - elif "%d" in argstr: - argstr_new = argstr.replace("%d", f"{{{name}}}") - elif "%f" in argstr: - argstr_new = argstr.replace("%f", f"{{{name}}}") - elif "%g" in argstr: - argstr_new = argstr.replace("%g", f"{{{name}}}") - elif len(re.findall("%[0-9.]+f", argstr)) == 1: - old_format = re.findall("%[0-9.]+f", argstr)[0] - argstr_new = argstr.replace(old_format, f"{{{name}:{old_format[1:]}}}") - else: - raise Exception(f"format from {argstr} is not supported TODO") - return argstr_new - - -FSL_MODULES = ['aroma', 'dti', 'epi', 'fix', 'maths', 'model', 'possum', 'preprocess', 'utils'] - - -@click.command() -@click.option( - "-i", - "--interface_name", - required=True, - default="all", - help="name of the interface (name used in Nipype, e.g. BET) or all (default)" - "if all is used all interfaces from the spec file will be created", -) -@click.option( - "-m", "--module_name", required=True, help=f"name of the module from the list {FSL_MODULES}" -) -def create_pydra_spec(interface_name, module_name): - if module_name not in FSL_MODULES: - raise Exception( - f"module name {module_name} not available;" f"should be from the list {FSL_MODULES}" - ) - - spec_file = Path(os.path.dirname(__file__)) / f"../specs/fsl_{module_name}_param.yml" - if not spec_file.exists(): - raise Exception( - f"the specification file doesn't exist for the module {module_name}," - f"create the specification file in {spec_file.parent}" - ) - - @functools.lru_cache() - def all_interfaces(module): - nipype_module = getattr(fsl, module) - all_specs = [el for el in dir(nipype_module) if "InputSpec" in el] - all_interf = [el.replace("InputSpec", "") for el in all_specs] - - # interfaces in the spec file - with open(spec_file) as f: - spec_interf = yaml.safe_load(f).keys() - - if set(all_interf) - set(spec_interf): - warnings.warn( - f"some interfaces are not in the spec file: " - f"{set(all_interf) - set(spec_interf)}, " - f"and pydra interfaces will not be created for them" - ) - return spec_interf - - if interface_name == "all": - interface_list = all_interfaces(module_name) - elif interface_name in all_interfaces(module_name): - interface_list = [interface_name] - else: - raise Exception( - f"interface_name has to be 'all' " - f"or a name from the list {all_interfaces(module_name)}" - ) - - dirname_interf = Path(__file__).parent.parent / f"pydra/tasks/fsl/{module_name}" - dirname_interf.mkdir(exist_ok=True) - - for interface_el in interface_list: - converter = FSLConverter( - interface_name=interface_el, - interface_spec_file=Path(__file__).parent.parent - / f"specs/fsl_{module_name}_param.yml", - ) - converter.pydra_specs(write=True, dirname=dirname_interf) - - -if __name__ == '__main__': - create_pydra_spec() diff --git a/tools/data_tests/test.nii.gz b/tools/data_tests/test.nii.gz deleted file mode 100644 index 3424c44..0000000 --- a/tools/data_tests/test.nii.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ffd0a1a4abf91c63edb64a7add1978e1d990a8bf2fbc057fd93d2367f335c9d4 -size 10379696 diff --git a/tools/increment_tool_version.py b/tools/increment_tool_version.py new file mode 100755 index 0000000..e6d56ed --- /dev/null +++ b/tools/increment_tool_version.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +from pathlib import Path +import inspect +from importlib import import_module +import click +from looseversion import LooseVersion +from pydra.engine.core import TaskBase + + +PKG_DIR = Path(__file__).parent.parent +TASKS_DIR = PKG_DIR / "pydra" / "tasks" / "ants" +VERSION_GRANULARITY = ( + 2 # Number of version parts to include: 1 - major, 2 - minor, 3 - micro +) + + +@click.command( + help="""Increment the latest version or create a new sub-package for interfaces for +a new release of AFNI depending on whether one already exists or not. + +NEW_VERSION the version of AFNI to create a new sub-package for +""" +) +@click.argument("new_version", type=LooseVersion) +def increment_tool_version(new_version: LooseVersion): + + # Get the name of the sub-package, e.g. "v2_5" + new_subpkg_name = "_".join(str(p) for p in new_version.version[:VERSION_GRANULARITY]) # type: ignore + if not new_subpkg_name.startswith("v"): + new_subpkg_name = "v" + new_subpkg_name + sub_pkg_dir = TASKS_DIR / new_subpkg_name + if not sub_pkg_dir.exists(): + + prev_version = sorted( + ( + p.name + for p in TASKS_DIR.iterdir() + if p.is_dir() and p.name.startswith("v") + ), + key=lambda x: LooseVersion(".".join(x.split("_"))).version, + )[-1] + prev_ver_mod = import_module(f"pydra.tasks.ants.{prev_version}") + + mod_attrs = [getattr(prev_ver_mod, a) for a in dir(prev_ver_mod)] + task_classes = [ + a for a in mod_attrs if inspect.isclass(a) and issubclass(a, TaskBase) + ] + + code_str = ( + f"from pydra.tasks.ants import {prev_version}\n" + "from . import _tool_version\n" + ) + + for task_cls in task_classes: + code_str += ( + f"\n\nclass {task_cls.__name__}({prev_version}.{task_cls.__name__}):\n" + " TOOL_VERSION = _tool_version.TOOL_VERSION\n" + ) + + sub_pkg_dir.mkdir(exist_ok=True) + with open(sub_pkg_dir / "__init__.py", "w") as f: + f.write(code_str) + + with open(sub_pkg_dir / "_tool_version.py", "w") as f: + f.write(f'TOOL_VERSION = "{new_version}"\n') + + +if __name__ == "__main__": + increment_tool_version() diff --git a/tools/rename_template.py b/tools/rename_template.py new file mode 100755 index 0000000..2c75953 --- /dev/null +++ b/tools/rename_template.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +import sys +import os +import re +import fnmatch +import functools +from pathlib import Path + +PACKAGE_ROOT = Path(__file__).absolute().parent.parent + + +@functools.lru_cache() +def load_gitignore(repo): + gitignore = repo / ".gitignore" + ignore = [fnmatch.translate(".git/"), fnmatch.translate(Path(__file__).name)] + if gitignore.exists(): + ignore.extend( + fnmatch.translate(line.strip()) + for line in gitignore.read_text().splitlines() + if line.strip() and not line[0] == "#" + ) + return re.compile("|".join(ignore)) + + +cmd, new_name, *_ = sys.argv + +for root_, dirs, files in os.walk(PACKAGE_ROOT): + ignore = load_gitignore(PACKAGE_ROOT).search + for d in [d for d in dirs if ignore(f"{d}/")]: + dirs.remove(d) + for f in [f for f in files if ignore(f)]: + files.remove(f) + + root = Path(root_) + for src in list(dirs): + if "fsl" in src: + dst = src.replace("fsl", new_name) + print(f"Renaming: {root / src} -> {root / dst}") + os.rename(root / src, root / dst) + dirs.remove(src) + dirs.append(dst) + for fname in files: + text = Path.read_text(root / fname) + if "fsl" in text: + print(f"Rewriting: {root / fname}") + Path.write_text(root / fname, text.replace("fsl", new_name)) diff --git a/tools/report_progress.py b/tools/report_progress.py new file mode 100755 index 0000000..10935f0 --- /dev/null +++ b/tools/report_progress.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +from pathlib import Path +import json +import yaml +import click + +TOOLKIT_NAME = "FSL" + + +@click.command +@click.argument( + "out_json_path", + type=click.Path(path_type=Path), + help="The output path to save the report", +) +def report_progress(out_json_path: Path): + + out_json_path.parent.mkdir(exist_ok=True, parents=True) + + SPECS_DIR = Path(__file__).parent / "nipype-auto-conv" / "specs" + + report = {"name": TOOLKIT_NAME, "tasks": {}} + + for spec_path in SPECS_DIR.glob("*.yaml"): + with open(spec_path) as f: + spec = yaml.load(f, Loader=yaml.SafeLoader) + + report["tasks"][spec["task_name"]] = { + n: not s["xfail"] for n, s in spec["tests"].items() + } + + with open(out_json_path, "w") as f: + json.dump(report, f) diff --git a/tools/requirements.txt b/tools/requirements.txt new file mode 100644 index 0000000..bdc0666 --- /dev/null +++ b/tools/requirements.txt @@ -0,0 +1,3 @@ +click >= 8.1.3 +looseversion >= 1.1 +pydra >= 0.23 diff --git a/tools/tests/test_converter.py b/tools/tests/test_converter.py deleted file mode 100644 index 0444726..0000000 --- a/tools/tests/test_converter.py +++ /dev/null @@ -1,92 +0,0 @@ -import pytest -import pydra -import os, imp -from pathlib import Path - -from ..converter import FSLConverter - -# TODO: rethink teh tests - - -@pytest.mark.skip() -def test_spec(tmpdir): - interface_name = "BET" - converter = FSLConverter(interface_name=interface_name) - input_spec_pydra, output_spec_pydra = converter.pydra_specs() - - in_file = Path(os.path.dirname(__file__)) / "data_tests/test.nii.gz" - out_file = Path(os.path.dirname(__file__)) / "data_tests/test_brain.nii.gz" - cmd = "bet" - - shelly = pydra.ShellCommandTask( - name="bet_task", executable=cmd, input_spec=input_spec_pydra, output_spec=output_spec_pydra - ) - shelly.inputs.in_file = in_file - assert shelly.inputs.executable == "bet" - assert shelly.cmdline == f"bet {in_file} {str(shelly.output_dir / 'test_brain.nii.gz')}" - res = shelly() - assert res.output.out_file.exists() - print("\n Result: ", res) - - shelly_mask = pydra.ShellCommandTask( - name="bet_task", executable=cmd, input_spec=input_spec_pydra, output_spec=output_spec_pydra - ) - shelly_mask.inputs.in_file = in_file - shelly_mask.inputs.mask = True - assert ( - shelly_mask.cmdline - == f"bet {in_file} {str(shelly_mask.output_dir / 'test_brain.nii.gz')} -m" - ) - res = shelly_mask() - assert res.output.out_file.exists() - assert res.output.mask_file.exists() - print("\n Result: ", res) - - -@pytest.mark.skip() -def test_spec_from_file(tmpdir): - interface_name = "BET" - converter = FSLConverter(interface_name=interface_name) - - dirname_spec = Path(tmpdir) - (dirname_spec / "tests").mkdir() - - _, _ = converter.pydra_specs(write=True, dirname=dirname_spec) - - imp.load_source("bet_module", str(dirname_spec / "bet.py")) - import bet_module as bm - - in_file = Path(os.path.dirname(__file__)) / "data_tests/test.nii.gz" - - shelly = bm.BET(name="my_bet") - shelly.inputs.in_file = in_file - assert shelly.inputs.executable == "bet" - assert shelly.cmdline == f"bet {in_file} {str(shelly.output_dir / 'test_brain.nii.gz')}" - res = shelly() - assert res.output.out_file.exists() - print("\n Result: ", res) - - shelly_mask = bm.BET(name="my_bet") - shelly_mask.inputs.in_file = in_file - shelly_mask.inputs.mask = True - assert ( - shelly_mask.cmdline - == f"bet {in_file} {str(shelly_mask.output_dir / 'test_brain.nii.gz')} -m" - ) - res = shelly_mask() - assert res.output.out_file.exists() - assert res.output.mask_file.exists() - print("\n Result: ", res) - - shelly_surf = bm.BET(name="my_bet") - shelly_surf.inputs.in_file = in_file - shelly_surf.inputs.surfaces = True - assert ( - shelly_surf.cmdline - == f"bet {in_file} {str(shelly_surf.output_dir / 'test_brain.nii.gz')} -A" - ) - res = shelly_surf() - assert res.output.out_file.exists() - assert res.output.inskull_mask_file.exists() - assert res.output.skull_mask_file.exists() - print("\n Result: ", res)