Skip to content

Commit

Permalink
Merge pull request #787 from oesteban/enh/NewFreeSurfer
Browse files Browse the repository at this point in the history
[ENH] New FreeSurfer's license mechanism
  • Loading branch information
chrisgorgo committed Nov 8, 2017
2 parents 556b10e + 9f9d9ad commit 68efe57
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 9 deletions.
8 changes: 8 additions & 0 deletions .circle/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,15 @@ case ${CIRCLE_NODE_INDEX} in
rm -r $HOME/ds054/out/fmriprep/sub-100185/log
;;
1)
# Do not use --fs-license-file to exercise using the env variable
fmriprep-docker -i poldracklab/fmriprep:latest --config $HOME/nipype.cfg -w $HOME/ds005/scratch $HOME/data/ds005 $HOME/ds005/out participant --debug --write-graph --use-syn-sdc --use-aroma --ignore-aroma-denoising-errors
find ~/ds005/scratch -not -name "*.svg" -not -name "*.html" -not -name "*.rst" -not -name "*.mat" -not -name "*.lta" -type f -delete
# Check for --fs-license-file not defined
set +e
unset FS_LICENSE
fmriprep-docker -i poldracklab/fmriprep:latest --config $HOME/nipype.cfg -w $HOME/ds005/scratch $HOME/data/ds005 $HOME/ds005/out participant --debug --write-graph --use-syn-sdc --use-aroma --ignore-aroma-denoising-errors
RET=$?
set -e
[[ "$RET" -eq "1" ]]
;;
esac
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Next release
============

* [FIX] Adopt new FreeSurfer license mechanism (#787)


1.0.0-rc9 (2nd of November 2017)
================================
Expand Down
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ RUN apt-get update && \
apt-get update

# Installing freesurfer
RUN curl -sSL https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/6.0.0/freesurfer-Linux-centos6_x86_64-stable-pub-v6.0.0.tar.gz | tar zxv -C /opt \
RUN curl -sSL https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/6.0.1/freesurfer-Linux-centos6_x86_64-stable-pub-v6.0.1.tar.gz | tar zxv --no-same-owner -C /opt \
--exclude='freesurfer/trctrain' \
--exclude='freesurfer/subjects/fsaverage_sym' \
--exclude='freesurfer/subjects/fsaverage3' \
Expand Down Expand Up @@ -53,7 +53,6 @@ ENV SUBJECTS_DIR=$FREESURFER_HOME/subjects \
ENV PERL5LIB=$MINC_LIB_DIR/perl5/5.8.5 \
MNI_PERL5LIB=$MINC_LIB_DIR/perl5/5.8.5 \
PATH=$FREESURFER_HOME/bin:$FSFAST_HOME/bin:$FREESURFER_HOME/tktools:$MINC_BIN_DIR:$PATH
RUN echo "cHJpbnRmICJrcnp5c3p0b2YuZ29yZ29sZXdza2lAZ21haWwuY29tXG41MTcyXG4gKkN2dW12RVYzelRmZ1xuRlM1Si8yYzFhZ2c0RVxuIiA+IC9vcHQvZnJlZXN1cmZlci9saWNlbnNlLnR4dAo=" | base64 -d | sh

# Installing Neurodebian packages (FSL, AFNI, git)
RUN apt-get update && \
Expand Down
2 changes: 2 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ machine:
DS005_URL: "${OSF_PROJECT}/57f32a429ad5a101f977eb75"
DS005_FS_URL: "${OSF_PROJECT}/58fe59eb594d900250960180"
DS054_URL: "${OSF_PROJECT}/57f32c22594d9001ef91bf9e"
FS_LICENSE: /tmp/fslicense/license.txt
services:
- docker

Expand All @@ -20,6 +21,7 @@ dependencies:
- mkdir -p $HOME/ds005/out && sudo setfacl -R -d -m group:ubuntu:rwx $HOME/ds005 && sudo setfacl -R -m group:ubuntu:rwx $HOME/ds005
- mkdir -p $HOME/ds054 && sudo setfacl -d -m group:ubuntu:rwx $HOME/ds054 && sudo setfacl -m group:ubuntu:rwx $HOME/ds054
- mkdir -p $HOME/docs && sudo setfacl -d -m group:ubuntu:rwx $HOME/docs && sudo setfacl -m group:ubuntu:rwx $HOME/docs
- mkdir -p /tmp/fslicense && cd /tmp/fslicense && echo "cHJpbnRmICJrcnp5c3p0b2YuZ29yZ29sZXdza2lAZ21haWwuY29tXG41MTcyXG4gKkN2dW12RVYzelRmZ1xuRlM1Si8yYzFhZ2c0RVxuIiA+IGxpY2Vuc2UudHh0Cg==" | base64 -d | sh
# Download test data
- if [[ ! -d $HOME/data/ds005 ]]; then wget --retry-connrefused --waitretry=5 --read-timeout=20 --timeout=15 -t 0 -q -O ds005_downsampled.tar.gz "${DS005_URL}" && tar xzf ds005_downsampled.tar.gz -C $HOME/data/; fi
- if [[ ! -d $HOME/data/ds054 ]]; then wget --retry-connrefused --waitretry=5 --read-timeout=20 --timeout=15 -t 0 -q -O ds054_downsampled.tar.gz "${DS054_URL}" && tar xzf ds054_downsampled.tar.gz -C $HOME/data/; fi
Expand Down
45 changes: 42 additions & 3 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ print it out for reporting purposes, and then run the command, e.g.::
$ fmriprep-docker /path/to/data/dir /path/to/output/dir participant
RUNNING: docker run --rm -it -v /path/to/data/dir:/data:ro \
-v /path/to_output/dir:/out poldracklab/fmriprep:1.0.0 \
/data /out participant
/data /out participant --no-freesurfer
...

You may also invoke ``docker`` directly::
Expand All @@ -47,7 +47,7 @@ You may also invoke ``docker`` directly::
-v filepath/to/output/dir:/out \
poldracklab/fmriprep:latest \
/data /out/out \
participant
participant --no-freesurfer

For example: ::

Expand All @@ -57,11 +57,50 @@ For example: ::
poldracklab/fmriprep:latest \
/data /out/out \
participant \
--ignore fieldmaps
--ignore fieldmaps --no-freesurfer

See `External Dependencies`_ for more information (e.g., specific versions) on
what is included in the latest Docker images.

If the flag ``--no-freesurfer`` is not set, then FreeSurfer will require a proper
license file.
It is possible to run the docker container pointing the image to a local path
where a valid license file is stored.
For example, if the license is stored in the ``$HOME/.licenses/freesurfer/license.txt``
file on the host system: ::

$ docker run -ti --rm \
-v $HOME/fullds005:/data:ro \
-v $HOME/dockerout:/out \
-v $HOME/.licenses/freesurfer/license.txt:/opt/freesurfer/license.txt \
poldracklab/fmriprep:latest \
/data /out/out \
participant \
--ignore fieldmaps

It is also possible to run ``fmriprep-docker`` with FreeSurfer processing: ::

$ fmriprep-docker --fs-license-file $HOME/.licenses/freesurfer/license.txt \
/path/to/data/dir /path/to/output/dir participant
RUNNING: docker run --rm -it -v /path/to/data/dir:/data:ro \
-v /home/user/.licenses/freesurfer/license.txt:/opt/freesurfer/license.txt \
-v /path/to_output/dir:/out poldracklab/fmriprep:1.0.0 \
/data /out participant
...

If the environment variable ``$FS_LICENSE`` is set in the host system, then
it will automatically used by ``fmriprep-docker``. For instance, the following
would be equivalent to the latest example: ::

$ export FS_LICENSE=$HOME/.licenses/freesurfer/license.txt
$ fmriprep-docker /path/to/data/dir /path/to/output/dir participant
RUNNING: docker run --rm -it -v /path/to/data/dir:/data:ro \
-v /home/user/.licenses/freesurfer/license.txt:/opt/freesurfer/license.txt \
-v /path/to_output/dir:/out poldracklab/fmriprep:1.0.0 \
/data /out participant
...


Singularity Container
=====================

Expand Down
14 changes: 14 additions & 0 deletions fmriprep/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ def get_parser():
help='disable FreeSurfer preprocessing')
g_fs.add_argument('--no-submm-recon', action='store_false', dest='hires',
help='disable sub-millimeter (hires) reconstruction')
g_fs.add_argument(
'--fs-license-file', metavar='PATH', type=os.path.abspath,
help='Path to FreeSurfer license key file. Get it (for free) by registering'
' at https://surfer.nmr.mgh.harvard.edu/registration.html')

g_other = parser.add_argument_group('Other options')
g_other.add_argument('-w', '--work-dir', action='store', default='work',
Expand All @@ -194,6 +198,16 @@ def main():
if opts.debug:
logger.setLevel(logging.DEBUG)

default_license = op.join(os.getenv('FREESURFER_HOME', ''), 'license.txt')
# Precedence: --fs-license-file, $FS_LICENSE, default_license
license_file = opts.fs_license_file or os.getenv('FS_LICENSE', default_license)
if opts.freesurfer:
if not os.path.exists(license_file):
raise RuntimeError('ERROR: when --no-freesurfer is not set, a valid '
'license file is required for FreeSurfer to run.')
else:
os.environ['FS_LICENSE'] = license_file

# Validity of some inputs - OE should be done in parse_args?
# ERROR check if use_aroma was specified, but the correct template was not
if opts.use_aroma and (opts.template != 'MNI152NLin2009cAsym' or
Expand Down
27 changes: 23 additions & 4 deletions wrapper/fmriprep_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import sys
import os
import re
import argparse
import subprocess

standard_library.install_aliases()
Expand Down Expand Up @@ -154,7 +153,8 @@ def merge_help(wrapper_help, target_help):

# Make sure we're not clobbering options we don't mean to
overlap = set(w_flags).intersection(t_flags)
expected_overlap = set(['h', 'v', 'w', 'output-grid-reference'])
expected_overlap = set(['h', 'v', 'w', 'output-grid-reference',
'fs-license-file'])
assert overlap == expected_overlap, "Clobbering options: {}".format(
', '.join(overlap - expected_overlap))

Expand Down Expand Up @@ -194,11 +194,13 @@ def merge_help(wrapper_help, target_help):
sections.append(w_groups[2])

# All remaining sections, show target then wrapper (skipping duplicates)
sections.extend(t_groups[3:] + w_groups[5:])
sections.extend(t_groups[3:] + w_groups[6:])
return '\n\n'.join(sections)


def main():
def get_parser():
"""Defines the command line interface of the wrapper"""
import argparse
parser = argparse.ArgumentParser(
description='fMRI Preprocessing workflow',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
Expand Down Expand Up @@ -231,6 +233,11 @@ def main():
type=os.path.abspath,
help='Grid reference image for resampling BOLD files to volume template '
'space.')
g_wrap.add_argument(
'--fs-license-file', metavar='PATH', type=os.path.abspath,
default=os.getenv('FS_LICENSE', None),
help='Path to FreeSurfer license key file. Get it (for free) by registering'
' at https://surfer.nmr.mgh.harvard.edu/registration.html')

# Developer patch/shell options
g_dev = parser.add_argument_group(
Expand All @@ -250,6 +257,13 @@ def main():
g_dev.add_argument('--config', metavar='PATH', action='store',
type=os.path.abspath, help='Use custom nipype.cfg file')

return parser


def main():
"""Entry point"""

parser = get_parser()
# Capture additional arguments to pass inside container
opts, unknown_args = parser.parse_known_args()

Expand Down Expand Up @@ -315,6 +329,11 @@ def main():
if repo_path is not None:
command.extend(['-v', '{}:{}:ro'.format(repo_path, pkg_path)])

if opts.fs_license_file:
command.extend([
'-v', '{}:/opt/freesurfer/license.txt:ro'.format(
opts.fs_license_file)])

main_args = []
if opts.bids_dir:
command.extend(['-v', ':'.join((opts.bids_dir, '/data', 'ro'))])
Expand Down

0 comments on commit 68efe57

Please sign in to comment.