Skip to content

Commit 2de8786

Browse files
committed
Merge pull request #6 from nipy/master
Re-basing code with nipype master branch
2 parents 5dac574 + 038223f commit 2de8786

29 files changed

+1221
-383
lines changed

.noserc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[nosetests]
2+
verbosity=3
3+
4+
with-coverage=1
5+
cover-branches=1
6+
cover-xml=1
7+
cover-xml-file=./coverage.xml
8+
cover-min-percentage=50
9+
10+
11+
with-xunit=1

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ before_install:
2323
- if $INSTALL_DEB_DEPENDECIES; then travis_retry sudo apt-get install -qq fsl-atlases;
2424
fi
2525
- if $INSTALL_DEB_DEPENDECIES; then source /etc/fsl/fsl.sh; fi
26+
- if $INSTALL_DEB_DEPENDECIES; then source /etc/afni/afni.sh; fi
27+
- export FSLOUTPUTTYPE=NIFTI_GZ
2628
install:
2729
- conda update --yes conda
2830
- conda create -n testenv --yes pip python=$TRAVIS_PYTHON_VERSION

CHANGES

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
Next release
22
============
33

4+
* ENH: Added support for PETPVC (https://github.com/nipy/nipype/pull/1335)
5+
* ENH: Merge S3DataSink into DataSink, added AWS documentation (https://github.com/nipy/nipype/pull/1316)
6+
* TST: Cache APT in CircleCI (https://github.com/nipy/nipype/pull/1333)
7+
* ENH: Add new flags to the BRAINSABC for new features (https://github.com/nipy/nipype/pull/1322)
48
* ENH: Provides a Nipype wrapper for ANTs DenoiseImage (https://github.com/nipy/nipype/pull/1291)
59
* FIX: Minor bugfix logging hash differences (https://github.com/nipy/nipype/pull/1298)
610
* FIX: Use released Prov python library (https://github.com/nipy/nipype/pull/1279)

circle.yml

Lines changed: 29 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,71 @@
11
dependencies:
22
cache_directories:
3+
- "~/.apt-cache"
34
- "~/examples/data"
45
- "~/examples/fsdata"
5-
- "~/examples/feeds"
66
- "~/mcr"
77
- "~/spm12"
8-
- "~/fsl"
98
- "~/examples/fsl_course_data"
9+
pre:
10+
# Let CircleCI cache the apt archive
11+
- sudo rm -rf /var/cache/apt/archives && sudo ln -s ~/.apt-cache /var/cache/apt/archives && mkdir -p ~/.apt-cache/partial
12+
- wget -O- http://neuro.debian.net/lists/precise.us-ca.full | sudo tee /etc/apt/sources.list.d/neurodebian.sources.list
13+
- sudo apt-key adv --recv-keys --keyserver hkp://pgp.mit.edu:80 0xA5D32F012649A5A9
14+
- sudo apt-get update
1015
override:
16+
# Install apt packages
17+
- sudo apt-get install -y fsl-core fsl-atlases fsl-mni152-templates fsl-feeds afni
18+
- echo "source /etc/fsl/fsl.sh" >> $HOME/.profile
19+
- echo "source /etc/afni/afni.sh" >> $HOME/.profile
20+
- mkdir -p ~/examples/ && ln -sf /usr/share/fsl-feeds/ ~/examples/feeds
21+
# Set up python environment
1122
- pip install --upgrade pip
1223
- pip install -e .
13-
- pip install matplotlib sphinx ipython boto
24+
- pip install matplotlib sphinx ipython boto coverage
1425
- gem install fakes3
15-
- if [[ ! -d ~/fsl ]]; then wget "http://fsl.fmrib.ox.ac.uk/fsldownloads/fsl-5.0.9-centos6_64.tar.gz"; tar zxvf fsl-5.0.9-centos6_64.tar.gz; mv fsl ~/fsl; fi
16-
- if [[ ! -d ~/examples/data ]]; then wget "http://tcpdiag.dl.sourceforge.net/project/nipy/nipype/nipype-0.2/nipype-tutorial.tar.bz2"; tar jxvf nipype-tutorial.tar.bz2; mkdir ~/examples; mv nipype-tutorial/* ~/examples/; fi
17-
# we download this manually because CircleCI does not cache apt
18-
- if [[ ! -d ~/examples/feeds ]]; then wget "http://fsl.fmrib.ox.ac.uk/fsldownloads/fsl-5.0.9-feeds.tar.gz"; tar zxvf fsl-5.0.9-feeds.tar.gz; mv feeds ~/examples/; fi
19-
- if [[ ! -d ~/examples/fsl_course_data ]]; then wget -c "http://fsl.fmrib.ox.ac.uk/fslcourse/fdt1.tar.gz" ; wget -c "http://fsl.fmrib.ox.ac.uk/fslcourse/fdt2.tar.gz"; wget -c "http://fsl.fmrib.ox.ac.uk/fslcourse/tbss.tar.gz"; mkdir ~/examples/fsl_course_data; tar zxvf fdt1.tar.gz -C ~/examples/fsl_course_data; tar zxvf fdt2.tar.gz -C ~/examples/fsl_course_data; tar zxvf tbss.tar.gz -C ~/examples/fsl_course_data; fi
26+
- if [[ ! -d ~/examples/data ]]; then wget "http://tcpdiag.dl.sourceforge.net/project/nipy/nipype/nipype-0.2/nipype-tutorial.tar.bz2" && tar jxvf nipype-tutorial.tar.bz2 && mv nipype-tutorial/* ~/examples/; fi
27+
- if [[ ! -d ~/examples/fsl_course_data ]]; then wget -c "http://fsl.fmrib.ox.ac.uk/fslcourse/fdt1.tar.gz" && wget -c "http://fsl.fmrib.ox.ac.uk/fslcourse/fdt2.tar.gz" && wget -c "http://fsl.fmrib.ox.ac.uk/fslcourse/tbss.tar.gz" && mkdir ~/examples/fsl_course_data && tar zxvf fdt1.tar.gz -C ~/examples/fsl_course_data && tar zxvf fdt2.tar.gz -C ~/examples/fsl_course_data && tar zxvf tbss.tar.gz -C ~/examples/fsl_course_data; fi
2028
- bash ~/nipype/tools/install_spm_mcr.sh
21-
- mkdir -p ~/.nipype && echo "[logging]" > ~/.nipype/nipype.cfg && echo "workflow_level = DEBUG" >> ~/.nipype/nipype.cfg && echo "interface_level = DEBUG" >> ~/.nipype/nipype.cfg && echo "filemanip_level = DEBUG" >> ~/.nipype/nipype.cfg
29+
- mkdir -p ~/.nipype && echo '[logging]' > ~/.nipype/nipype.cfg && echo 'workflow_level = DEBUG' >> ~/.nipype/nipype.cfg && echo 'interface_level = DEBUG' >> ~/.nipype/nipype.cfg && echo 'filemanip_level = DEBUG' >> ~/.nipype/nipype.cfg
30+
machine:
31+
environment:
32+
FSLOUTPUTTYPE: NIFTI_GZ
2233
test:
2334
override:
24-
- nosetests --with-doctest --logging-level=DEBUG --verbosity=3:
35+
- mkdir -p ${CIRCLE_TEST_REPORTS}/nose
36+
- source $HOME/.profile; nosetests --with-doctest --xunit-file="${CIRCLE_TEST_REPORTS}/nose/${CIRCLE_PROJECT_REPONAME}.xml" -c ./.noserc --logging-level=DEBUG --verbosity=3:
2537
environment:
2638
SPMMCRCMD: "$HOME/spm12/run_spm12.sh $HOME/mcr/v85/ script"
2739
FORCE_SPMMCR: 1
2840
FSL_COURSE_DATA: "$HOME/examples/fsl_course_data"
29-
FSLDIR: "$HOME/fsl/"
30-
PATH: "$HOME/fsl/bin:$PATH"
31-
LD_LIBRARY_PATH: "$HOME/fsl/lib"
32-
FSLOUTPUTTYPE: "NIFTI_GZ"
3341
timeout: 2600
3442
- set -o pipefail && cd doc && make html 2>&1 | tee ~/log.txt
3543
- cat ~/log.txt && if grep -q "ERROR" ~/log.txt; then false; else true; fi
36-
- python ~/nipype/tools/run_examples.py test_spm Linear workflow3d workflow4d:
44+
- source $HOME/.profile; python ~/nipype/tools/run_examples.py test_spm Linear workflow3d workflow4d:
3745
pwd: ../examples
3846
environment:
3947
SPMMCRCMD: "$HOME/spm12/run_spm12.sh $HOME/mcr/v85/ script"
4048
FORCE_SPMMCR: 1
41-
FSLDIR: "$HOME/fsl/"
42-
PATH: "$HOME/fsl/bin:$PATH"
43-
LD_LIBRARY_PATH: "$HOME/fsl/lib"
44-
FSLOUTPUTTYPE: "NIFTI_GZ"
4549
timeout: 1600
46-
- python ~/nipype/tools/run_examples.py fmri_fsl_feeds Linear l1pipeline:
50+
- source $HOME/.profile; python ~/nipype/tools/run_examples.py fmri_fsl_feeds Linear l1pipeline:
4751
pwd: ../examples
48-
environment:
49-
FSLDIR: "$HOME/fsl/"
50-
PATH: "$HOME/fsl/bin:$PATH"
51-
LD_LIBRARY_PATH: "$HOME/fsl/lib"
52-
FSLOUTPUTTYPE: "NIFTI_GZ"
53-
- python ~/nipype/tools/run_examples.py fmri_spm_dartel Linear level1 l2pipeline:
52+
- source $HOME/.profile; python ~/nipype/tools/run_examples.py fmri_spm_dartel Linear level1 l2pipeline:
5453
pwd: ../examples
5554
environment:
5655
SPMMCRCMD: "$HOME/spm12/run_spm12.sh $HOME/mcr/v85/ script"
5756
FORCE_SPMMCR: 1
58-
FSLDIR: "$HOME/fsl/"
59-
PATH: "$HOME/fsl/bin:$PATH"
60-
LD_LIBRARY_PATH: "$HOME/fsl/lib"
61-
FSLOUTPUTTYPE: "NIFTI_GZ"
6257
timeout: 1600
63-
- python ~/nipype/tools/run_examples.py fmri_fsl_reuse Linear level1_workflow:
58+
- source $HOME/.profile; python ~/nipype/tools/run_examples.py fmri_fsl_reuse Linear level1_workflow:
6459
pwd: ../examples
65-
environment:
66-
FSLDIR: "$HOME/fsl/"
67-
PATH: "$HOME/fsl/bin:$PATH"
68-
LD_LIBRARY_PATH: "$HOME/fsl/lib"
69-
FSLOUTPUTTYPE: "NIFTI_GZ"
70-
- python ~/nipype/tools/run_examples.py fmri_spm_nested Linear level1 l2pipeline:
60+
- source $HOME/.profile; python ~/nipype/tools/run_examples.py fmri_spm_nested Linear level1 l2pipeline:
7161
pwd: ../examples
7262
environment:
7363
SPMMCRCMD: "$HOME/spm12/run_spm12.sh $HOME/mcr/v85/ script"
7464
FORCE_SPMMCR: 1
75-
FSLDIR: "$HOME/fsl/"
76-
PATH: "$HOME/fsl/bin:$PATH"
77-
LD_LIBRARY_PATH: "$HOME/fsl/lib"
78-
FSLOUTPUTTYPE: "NIFTI_GZ"
7965

8066
general:
8167
artifacts:
8268
- "doc/_build/html"
8369
- "~/log.txt"
70+
- "nosetests.xml"
71+
- "coverage.xml"

doc/users/aws.rst

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
.. _aws:
2+
3+
============================================
4+
Using Nipype with Amazon Web Services (AWS)
5+
============================================
6+
Several groups have been successfully using Nipype on AWS. This procedure
7+
involves setting a temporary cluster using StarCluster and potentially
8+
transferring files to/from S3. The latter is supported by Nipype through
9+
DataSink and S3DataGrabber.
10+
11+
12+
Using DataSink with S3
13+
======================
14+
The DataSink class now supports sending output data directly to an AWS S3
15+
bucket. It does this through the introduction of several input attributes to the
16+
DataSink interface and by parsing the `base_directory` attribute. This class
17+
uses the `boto3 <https://boto3.readthedocs.org/en/latest/>`_ and
18+
`botocore <https://botocore.readthedocs.org/en/latest/>`_ Python packages to
19+
interact with AWS. To configure the DataSink to write data to S3, the user must
20+
set the ``base_directory`` property to an S3-style filepath. For example:
21+
22+
::
23+
24+
import nipype.interfaces.io as nio
25+
ds = nio.DataSink()
26+
ds.inputs.base_directory = 's3://mybucket/path/to/output/dir'
27+
28+
With the "s3://" prefix in the path, the DataSink knows that the output
29+
directory to send files is on S3 in the bucket "mybucket". "path/to/output/dir"
30+
is the relative directory path within the bucket "mybucket" where output data
31+
will be uploaded to (NOTE: if the relative path specified contains folders that
32+
don’t exist in the bucket, the DataSink will create them). The DataSink treats
33+
the S3 base directory exactly as it would a local directory, maintaining support
34+
for containers, substitutions, subfolders, "." notation, etc to route output
35+
data appropriately.
36+
37+
There are four new attributes introduced with S3-compatibility: ``creds_path``,
38+
``encrypt_bucket_keys``, ``local_copy``, and ``bucket``.
39+
40+
::
41+
42+
ds.inputs.creds_path = '/home/user/aws_creds/credentials.csv'
43+
ds.inputs.encrypt_bucket_keys = True
44+
ds.local_copy = '/home/user/workflow_outputs/local_backup'
45+
46+
``creds_path`` is a file path where the user's AWS credentials file (typically
47+
a csv) is stored. This credentials file should contain the AWS access key id and
48+
secret access key and should be formatted as one of the following (these formats
49+
are how Amazon provides the credentials file by default when first downloaded).
50+
51+
Root-account user:
52+
53+
::
54+
55+
AWSAccessKeyID=ABCDEFGHIJKLMNOP
56+
AWSSecretKey=zyx123wvu456/ABC890+gHiJk
57+
58+
IAM-user:
59+
60+
::
61+
62+
User Name,Access Key Id,Secret Access Key
63+
"username",ABCDEFGHIJKLMNOP,zyx123wvu456/ABC890+gHiJk
64+
65+
The ``creds_path`` is necessary when writing files to a bucket that has
66+
restricted access (almost no buckets are publicly writable). If ``creds_path``
67+
is not specified, the DataSink will check the ``AWS_ACCESS_KEY_ID`` and
68+
``AWS_SECRET_ACCESS_KEY`` environment variables and use those values for bucket
69+
access.
70+
71+
``encrypt_bucket_keys`` is a boolean flag that indicates whether to encrypt the
72+
output data on S3, using server-side AES-256 encryption. This is useful if the
73+
data being output is sensitive and one desires an extra layer of security on the
74+
data. By default, this is turned off.
75+
76+
``local_copy`` is a string of the filepath where local copies of the output data
77+
are stored in addition to those sent to S3. This is useful if one wants to keep
78+
a backup version of the data stored on their local computer. By default, this is
79+
turned off.
80+
81+
``bucket`` is a boto3 Bucket object that the user can use to overwrite the
82+
bucket specified in their ``base_directory``. This can be useful if one has to
83+
manually create a bucket instance on their own using special credentials (or
84+
using a mock server like `fakes3 <https://github.com/jubos/fake-s3>`_). This is
85+
typically used for developers unit-testing the DataSink class. Most users do not
86+
need to use this attribute for actual workflows. This is an optional argument.
87+
88+
Finally, the user needs only to specify the input attributes for any incoming
89+
data to the node, and the outputs will be written to their S3 bucket.
90+
91+
::
92+
93+
workflow.connect(inputnode, 'subject_id', ds, 'container')
94+
workflow.connect(realigner, 'realigned_files', ds, 'motion')
95+
96+
So, for example, outputs for sub001’s realigned_file1.nii.gz will be in:
97+
s3://mybucket/path/to/output/dir/sub001/motion/realigned_file1.nii.gz
98+
99+
100+
Using S3DataGrabber
101+
======================
102+
Coming soon...

doc/users/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
spmmcr
3939
mipav
4040
nipypecmd
41+
aws
4142

4243

4344

nipype/algorithms/misc.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,14 @@ class TSNRInputSpec(BaseInterfaceInputSpec):
263263
in_file = InputMultiPath(File(exists=True), mandatory=True,
264264
desc='realigned 4D file or a list of 3D files')
265265
regress_poly = traits.Range(low=1, desc='Remove polynomials')
266+
tsnr_file = File('tsnr.nii.gz', usedefault=True, hash_files=False,
267+
desc='output tSNR file')
268+
mean_file = File('mean.nii.gz', usedefault=True, hash_files=False,
269+
desc='output mean file')
270+
stddev_file = File('stdev.nii.gz', usedefault=True, hash_files=False,
271+
desc='output tSNR file')
272+
detrended_file = File('detrend.nii.gz', usedefault=True, hash_files=False,
273+
desc='input file after detrending')
266274

267275

268276
class TSNROutputSpec(TraitedSpec):
@@ -288,24 +296,18 @@ class TSNR(BaseInterface):
288296
input_spec = TSNRInputSpec
289297
output_spec = TSNROutputSpec
290298

291-
def _gen_output_file_name(self, suffix=None):
292-
_, base, ext = split_filename(self.inputs.in_file[0])
293-
if suffix in ['mean', 'stddev']:
294-
return os.path.abspath(base + "_tsnr_" + suffix + ext)
295-
elif suffix in ['detrended']:
296-
return os.path.abspath(base + "_" + suffix + ext)
297-
else:
298-
return os.path.abspath(base + "_tsnr" + ext)
299-
300299
def _run_interface(self, runtime):
301300
img = nb.load(self.inputs.in_file[0])
302301
header = img.header.copy()
303302
vollist = [nb.load(filename) for filename in self.inputs.in_file]
304303
data = np.concatenate([vol.get_data().reshape(
305-
vol.shape[:3] + (-1,)) for vol in vollist], axis=3)
304+
vol.get_shape()[:3] + (-1,)) for vol in vollist], axis=3)
305+
data = data.nan_to_num()
306+
306307
if data.dtype.kind == 'i':
307308
header.set_data_dtype(np.float32)
308309
data = data.astype(np.float32)
310+
309311
if isdefined(self.inputs.regress_poly):
310312
timepoints = img.shape[-1]
311313
X = np.ones((timepoints, 1))
@@ -318,26 +320,28 @@ def _run_interface(self, runtime):
318320
betas[1:, :, :, :], 0, 3)),
319321
0, 4)
320322
data = data - datahat
321-
img = nb.Nifti1Image(data, img.affine, header)
322-
nb.save(img, self._gen_output_file_name('detrended'))
323+
img = nb.Nifti1Image(data, img.get_affine(), header)
324+
nb.save(img, op.abspath(self.inputs.detrended_file))
325+
323326
meanimg = np.mean(data, axis=3)
324327
stddevimg = np.std(data, axis=3)
325-
tsnr = meanimg / stddevimg
326-
img = nb.Nifti1Image(tsnr, img.affine, header)
327-
nb.save(img, self._gen_output_file_name())
328-
img = nb.Nifti1Image(meanimg, img.affine, header)
329-
nb.save(img, self._gen_output_file_name('mean'))
330-
img = nb.Nifti1Image(stddevimg, img.affine, header)
331-
nb.save(img, self._gen_output_file_name('stddev'))
328+
tsnr = np.zeros_like(meanimg)
329+
tsnr[stddevimg > 1.e-3] = meanimg[stddevimg > 1.e-3] / stddevimg[stddevimg > 1.e-3]
330+
img = nb.Nifti1Image(tsnr, img.get_affine(), header)
331+
nb.save(img, op.abspath(self.inputs.tsnr_file))
332+
img = nb.Nifti1Image(meanimg, img.get_affine(), header)
333+
nb.save(img, op.abspath(self.inputs.mean_file))
334+
img = nb.Nifti1Image(stddevimg, img.get_affine(), header)
335+
nb.save(img, op.abspath(self.inputs.stddev_file))
332336
return runtime
333337

334338
def _list_outputs(self):
335339
outputs = self._outputs().get()
336-
outputs['tsnr_file'] = self._gen_output_file_name()
337-
outputs['mean_file'] = self._gen_output_file_name('mean')
338-
outputs['stddev_file'] = self._gen_output_file_name('stddev')
340+
for k in ['tsnr_file', 'mean_file', 'stddev_file']:
341+
outputs[k] = op.abspath(getattr(self.inputs, k))
342+
339343
if isdefined(self.inputs.regress_poly):
340-
outputs['detrended_file'] = self._gen_output_file_name('detrended')
344+
outputs['detrended_file'] = op.abspath(self.inputs.detrended_file)
341345
return outputs
342346

343347

nipype/algorithms/tests/test_auto_TSNR.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,24 @@
44

55

66
def test_TSNR_inputs():
7-
input_map = dict(ignore_exception=dict(nohash=True,
7+
input_map = dict(detrended_file=dict(hash_files=False,
8+
usedefault=True,
9+
),
10+
ignore_exception=dict(nohash=True,
811
usedefault=True,
912
),
1013
in_file=dict(mandatory=True,
1114
),
15+
mean_file=dict(hash_files=False,
16+
usedefault=True,
17+
),
1218
regress_poly=dict(),
19+
stddev_file=dict(hash_files=False,
20+
usedefault=True,
21+
),
22+
tsnr_file=dict(hash_files=False,
23+
usedefault=True,
24+
),
1325
)
1426
inputs = TSNR.input_spec()
1527

0 commit comments

Comments
 (0)