Skip to content

Commit f785fac

Browse files
committed
Merge remote-tracking branch 'nipy/master'
2 parents 9ffdc91 + a81d993 commit f785fac

40 files changed

+393
-279
lines changed

.circle/codecov.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash
2+
#
3+
# This script pull all coverage files into the $CIRCLE_TEST_REPORTS folder
4+
# and sends data to codecov.
5+
#
6+
7+
# Setting # $ help set
8+
set -e # Exit immediately if a command exits with a non-zero status.
9+
set -u # Treat unset variables as an error when substituting.
10+
set -x # Print command traces before executing command.
11+
12+
mkdir -p ${CIRCLE_TEST_REPORTS}/
13+
for report in $( ls ~/scratch/*.xml ); do
14+
rname=$( basename $report )
15+
cp ${report} ${CIRCLE_TEST_REPORTS}/${rname:: -4}_${CIRCLE_NODE_INDEX}.xml
16+
done
17+
18+
# Send coverage data to codecov.io
19+
curl -so codecov.io https://codecov.io/bash
20+
chmod 755 codecov.io
21+
22+
find "${CIRCLE_TEST_REPORTS}/" -name 'coverage*.xml' -print0 | \
23+
xargs -0 -I file ./codecov.io -f file -t "${CODECOV_TOKEN}" -F unittests
24+
find "${CIRCLE_TEST_REPORTS}/" -name 'smoketests*.xml' -print0 | \
25+
xargs -0 -I file ./codecov.io -f file -t "${CODECOV_TOKEN}" -F smoketests
Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
#!/bin/bash
2+
#
3+
# Balance nipype testing workflows across CircleCI build nodes
4+
#
25

3-
set -o nounset
4-
set -o xtrace
5-
6-
export CODECOV_TOKEN=ac172a50-8e66-42e5-8822-5373fcf54686
6+
# Setting # $ help set
7+
set -e # Exit immediately if a command exits with a non-zero status.
8+
set -u # Treat unset variables as an error when substituting.
9+
set -x # Print command traces before executing command.
710

811
if [ "${CIRCLE_NODE_TOTAL:-}" != "4" ]; then
912
echo "These tests were designed to be run at 4x parallelism."
@@ -14,15 +17,15 @@ fi
1417
# They may need to be rebalanced in the future.
1518
case ${CIRCLE_NODE_INDEX} in
1619
0)
17-
docker run --rm -it -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /scratch nipype/nipype_test:py35 /usr/bin/run_examples.sh fmri_spm_dartel Linear /root/examples/ level1 && \
18-
docker run --rm -it -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /scratch nipype/nipype_test:py35 /usr/bin/run_examples.sh fmri_spm_dartel Linear /root/examples/ l2pipeline
19-
;;
20-
1)
21-
docker run --rm -it -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /scratch nipype/nipype_test:py35 /usr/bin/run_examples.sh test_spm Linear /root/examples/ workflow3d && \
22-
docker run --rm -it -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /scratch nipype/nipype_test:py35 /usr/bin/run_examples.sh test_spm Linear /root/examples/ workflow4d && \
2320
docker run --rm -it -e FSL_COURSE_DATA="/root/examples/nipype-fsl_course_data" -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /root/src/nipype nipype/nipype_test:py27 /usr/bin/run_pytests.sh py27 && \
2421
docker run --rm -it -e FSL_COURSE_DATA="/root/examples/nipype-fsl_course_data" -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /root/src/nipype nipype/nipype_test:py35 /usr/bin/run_pytests.sh py35 && \
25-
docker run --rm -it -v $SCRATCH:/scratch -w /root/src/nipype/doc nipype/nipype_test:py35 /usr/bin/run_builddocs.sh
22+
docker run --rm -it -v $SCRATCH:/scratch -w /root/src/nipype/doc nipype/nipype_test:py35 /usr/bin/run_builddocs.sh && \
23+
docker run --rm -it -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /scratch nipype/nipype_test:py35 /usr/bin/run_examples.sh test_spm Linear /root/examples/ workflow3d && \
24+
docker run --rm -it -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /scratch nipype/nipype_test:py35 /usr/bin/run_examples.sh test_spm Linear /root/examples/ workflow4d
25+
;;
26+
1)
27+
docker run --rm -it -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /scratch nipype/nipype_test:py35 /usr/bin/run_examples.sh fmri_spm_dartel Linear /root/examples/ level1 && \
28+
docker run --rm -it -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /scratch nipype/nipype_test:py35 /usr/bin/run_examples.sh fmri_spm_dartel Linear /root/examples/ l2pipeline
2629
;;
2730
2)
2831
docker run --rm -it -e NIPYPE_NUMBER_OF_CPUS=4 -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /scratch nipype/nipype_test:py27 /usr/bin/run_examples.sh fmri_spm_nested MultiProc /root/examples/ level1 && \
@@ -34,14 +37,3 @@ case ${CIRCLE_NODE_INDEX} in
3437
docker run --rm -it -v $HOME/examples:/root/examples:ro -v $SCRATCH:/scratch -w /scratch nipype/nipype_test:py35 /usr/bin/run_examples.sh fmri_fsl_reuse Linear /root/examples/ level1_workflow
3538
;;
3639
esac
37-
38-
# Put the artifacts in place
39-
bash docker/files/teardown.sh
40-
41-
# Send coverage data to codecov.io
42-
curl -so codecov.io https://codecov.io/bash
43-
chmod 755 codecov.io
44-
find "${CIRCLE_TEST_REPORTS}/pytest" -name 'coverage*.xml' -print0 | \
45-
xargs -0 -I file ./codecov.io -f file -t "${CODECOV_TOKEN}" -F unittests
46-
find "${CIRCLE_TEST_REPORTS}/pytest" -name 'smoketests*.xml' -print0 | \
47-
xargs -0 -I file ./codecov.io -f file -t "${CODECOV_TOKEN}" -F smoketests

.dockerignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ src/
2323
# other
2424
docs/**/*
2525
docs/
26+
.circle/**/*
27+
.circle/
28+
circle.yml
2629
.coverage
2730
.coveragerc
2831
codecov.yml
2932
rtd_requirements.txt
30-
circle.yml
3133
Vagrantfile
3234
.travis.yml
3335
.noserc

CHANGES

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
1-
Upcoming release 0.13
1+
Upcoming Release
22
=====================
33

4+
* ENH: Added non-steady state detector for EPI data (https://github.com/nipy/nipype/pull/1839)
5+
* ENH: Enable new BBRegister init options for FSv6+ (https://github.com/nipy/nipype/pull/1811)
6+
* REF: Splits nipype.interfaces.utility into base, csv, and wrappers (https://github.com/nipy/nipype/pull/1828)
7+
* FIX: Makespec now runs with nipype in current directory (https://github.com/nipy/nipype/pull/1813)
8+
* FIX: Flexible nifti opening with mmap if Numpy < 1.12.0 (https://github.com/nipy/nipype/pull/1796 + https://github.com/nipy/nipype/pull/1831)
49
* ENH: DVARS includes intensity normalization feature - turned on by default (https://github.com/nipy/nipype/pull/1827)
510
* FIX: DVARS is correctly using sum of squares instead of standard deviation (https://github.com/nipy/nipype/pull/1827)
611
* ENH: Refactoring of nipype.interfaces.utility (https://github.com/nipy/nipype/pull/1828)
712
* FIX: CircleCI were failing silently. Some fixes to tests (https://github.com/nipy/nipype/pull/1833)
813
* FIX: Issues in Docker image permissions, and docker documentation (https://github.com/nipy/nipype/pull/1825)
914
* ENH: Revised all Dockerfiles and automated deployment to Docker Hub
1015
from CircleCI (https://github.com/nipy/nipype/pull/1815)
16+
* ENH: Update ReconAll interface for FreeSurfer v6.0.0 (https://github.com/nipy/nipype/pull/1790)
17+
* FIX: Cast DVARS float outputs to avoid memmap error (https://github.com/nipy/nipype/pull/1777)
18+
* FIX: FSL FNIRT intensity mapping files (https://github.com/nipy/nipype/pull/1799)
19+
* ENH: Additional outputs generated by FSL EDDY (https://github.com/nipy/nipype/pull/1793)
20+
* TST: Parallelize CircleCI build across 4 containers (https://github.com/nipy/nipype/pull/1769)
21+
22+
23+
0.13.0-rc1 (January 4, 2017)
24+
===============================
25+
26+
* FIX: Compatibility with traits 4.6 (https://github.com/nipy/nipype/pull/1770)
27+
* FIX: Multiproc deadlock (https://github.com/nipy/nipype/pull/1756)
28+
* TST: Replace nose and unittest with pytest (https://github.com/nipy/nipype/pull/1722, https://github.com/nipy/nipype/pull/1751)
1129
* FIX: Semaphore capture using MultiProc plugin (https://github.com/nipy/nipype/pull/1689)
1230
* REF: Refactor AFNI interfaces (https://github.com/nipy/nipype/pull/1678, https://github.com/nipy/nipype/pull/1680)
1331
* ENH: Move nipype commands to group command using click (https://github.com/nipy/nipype/pull/1608)
@@ -36,7 +54,6 @@ Upcoming release 0.13
3654
* ENH: Added support for custom job submission check in SLURM (https://github.com/nipy/nipype/pull/1582)
3755
* ENH: Added ANTs interface CreateJacobianDeterminantImage; replaces deprecated JacobianDeterminant
3856
(https://github.com/nipy/nipype/pull/1654)
39-
* ENH: Update ReconAll interface for FreeSurfer v6.0.0 (https://github.com/nipy/nipype/pull/1790)
4057

4158
Release 0.12.1 (August 3, 2016)
4259
===============================

README.rst

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ Support and Communication
7878
-------------------------
7979

8080
If you have a problem or would like to ask a question about how to do something in Nipype please open an issue to
81-
`NeuroStars.org <http://neurostars.org>`_ with a *nipype* tag. `NeuroStars.org <http://neurostars.org>`_ is a
82-
platform similar to StackOverflow but dedicated to neuroinformatics.
81+
`NeuroStars.org <http://neurostars.org>`_ with a *nipype* tag. `NeuroStars.org <http://neurostars.org>`_ is a
82+
platform similar to StackOverflow but dedicated to neuroinformatics.
8383

8484
To participate in the Nipype development related discussions please use the following mailing list::
8585

@@ -117,16 +117,3 @@ Currently Nipype consists of the following files and directories:
117117
setup.py
118118
Script for building and installing NIPYPE.
119119

120-
License information
121-
-------------------
122-
123-
We use the 3-clause BSD license; the full license is in the file ``LICENSE`` in
124-
the nipype distribution.
125-
126-
There are interfaces to some GNU code but these are entirely optional.
127-
128-
All trademarks referenced herein are property of their respective
129-
holders.
130-
131-
Copyright (c) 2009-2015, NIPY Developers
132-
All rights reserved.

circle.yml

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ machine:
88
DATA_NIPYPE_FSL_COURSE: "${OSF_NIPYPE_URL}/57f472cf9ad5a101f977ecfe"
99
DATA_NIPYPE_FSL_FEEDS: "${OSF_NIPYPE_URL}/57f473066c613b01f113e7af"
1010
SCRATCH: "$HOME/scratch"
11+
CODECOV_TOKEN: "ac172a50-8e66-42e5-8822-5373fcf54686"
1112
services:
1213
- docker
1314

@@ -25,40 +26,46 @@ dependencies:
2526
- mkdir -p $SCRATCH && sudo setfacl -d -m group:ubuntu:rwx $SCRATCH && sudo setfacl -m group:ubuntu:rwx $SCRATCH
2627
- mkdir -p $HOME/docker $HOME/examples $SCRATCH/pytest $SCRATCH/logs
2728
override:
29+
- if [[ -e $HOME/docker/cache.tar ]]; then docker load --input $HOME/docker/cache.tar; else echo 'No docker image found in cache'; fi :
30+
timeout: 6000
2831
- if [[ ! -d ~/examples/nipype-tutorial ]]; then wget --retry-connrefused --waitretry=5 --read-timeout=20 --timeout=15 -t 0 -q -O nipype-tutorial.tar.bz2 "${DATA_NIPYPE_TUTORIAL_URL}" && tar xjf nipype-tutorial.tar.bz2 -C ~/examples/; fi
2932
- if [[ ! -d ~/examples/nipype-fsl_course_data ]]; then wget --retry-connrefused --waitretry=5 --read-timeout=20 --timeout=15 -t 0 -q -O nipype-fsl_course_data.tar.gz "${DATA_NIPYPE_FSL_COURSE}" && tar xzf nipype-fsl_course_data.tar.gz -C ~/examples/; fi
3033
- if [[ ! -d ~/examples/feeds ]]; then wget --retry-connrefused --waitretry=5 --read-timeout=20 --timeout=15 -t 0 -q -O fsl-5.0.9-feeds.tar.gz "${DATA_NIPYPE_FSL_FEEDS}" && tar xzf fsl-5.0.9-feeds.tar.gz -C ~/examples/; fi
31-
- if [[ -e $HOME/docker/image.tar ]]; then docker load --input $HOME/docker/image.tar; else echo 'No docker image found in cache'; fi
3234
- docker images
3335
- sed -i -E "s/(__version__ = )'[A-Za-z0-9.-]+'/\1'$CIRCLE_TAG'/" nipype/info.py
34-
- e=1 && for i in {1..5}; do docker build -t nipype/nipype:latest --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` --build-arg VCS_REF=`git rev-parse --short HEAD` --build-arg VERSION=$CIRCLE_TAG . && e=0 && break || sleep 15; done && [ "$e" -eq "0" ] :
36+
- e=1 && for i in {1..5}; do docker build --rm=false -t nipype/nipype:latest --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` --build-arg VCS_REF=`git rev-parse --short HEAD` --build-arg VERSION=$CIRCLE_TAG . && e=0 && break || sleep 15; done && [ "$e" -eq "0" ] :
3537
timeout: 21600
36-
- e=1 && for i in {1..5}; do docker build -f docker/Dockerfile_py27 -t nipype/nipype_test:py27 . && e=0 && break || sleep 15; done && [ "$e" -eq "0" ] :
38+
- e=1 && for i in {1..5}; do docker build --rm=false -f docker/Dockerfile_py27 -t nipype/nipype_test:py27 . && e=0 && break || sleep 15; done && [ "$e" -eq "0" ] :
3739
timeout: 1600
38-
- e=1 && for i in {1..5}; do docker build -f docker/Dockerfile_py35 -t nipype/nipype_test:py35 . && e=0 && break || sleep 15; done && [ "$e" -eq "0" ] :
39-
timeout: 1600
40-
- docker save -o $HOME/docker/image.tar nipype/nipype:latest nipype/nipype_test:py27 nipype/nipype_test:py35 :
40+
- e=1 && for i in {1..5}; do docker build --rm=false -f docker/Dockerfile_py35 -t nipype/nipype_test:py35 . && e=0 && break || sleep 15; done && [ "$e" -eq "0" ] :
4141
timeout: 1600
42+
- docker save -o $HOME/docker/cache.tar nipype/nipype:latest nipype/nipype_test:py27 nipype/nipype_test:py35 :
43+
timeout: 6000
4244

4345
test:
4446
override:
45-
- bash docker/files/tests.sh :
47+
- bash .circle/tests.sh :
4648
timeout: 7200
4749
parallel: true
50+
post:
51+
# Send coverage data to codecov.io
52+
- bash .circle/codecov.sh
4853

4954
general:
5055
artifacts:
51-
- "~/docs"
52-
- "~/logs"
56+
- "~/scratch/docs"
57+
- "~/scratch/logs"
5358

5459
deployment:
5560
production:
5661
tag: /.*/
5762
commands:
63+
# Deploy to docker hub
5864
- if [[ -n "$DOCKER_PASS" ]]; then docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS && docker push nipype/nipype:latest; fi :
5965
timeout: 21600
6066
- if [[ -n "$DOCKER_PASS" ]]; then docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS && docker tag nipype/nipype nipype/nipype:$CIRCLE_TAG && docker push nipype/nipype:$CIRCLE_TAG; fi :
6167
timeout: 21600
68+
6269
# Automatic deployment to Pypi:
6370
# - printf "[distutils]\nindex-servers =\n pypi\n\n[pypi]\nusername:$PYPI_USER\npassword:$PYPI_PASS\n" > ~/.pypirc
6471
# - python setup.py sdist upload -r pypi

docker/files/teardown.sh

Lines changed: 0 additions & 15 deletions
This file was deleted.

nipype/algorithms/confounds.py

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
from ..interfaces.base import (traits, TraitedSpec, BaseInterface,
2828
BaseInterfaceInputSpec, File, isdefined,
2929
InputMultiPath)
30-
from nipype.utils import NUMPY_MMAP
30+
from ..utils import NUMPY_MMAP
31+
from ..utils.misc import normalize_mc_params
3132

3233
IFLOG = logging.getLogger('interface')
3334

@@ -206,7 +207,10 @@ def _list_outputs(self):
206207

207208

208209
class FramewiseDisplacementInputSpec(BaseInterfaceInputSpec):
209-
in_plots = File(exists=True, mandatory=True, desc='motion parameters as written by FSL MCFLIRT')
210+
in_file = File(exists=True, mandatory=True, desc='motion parameters')
211+
parameter_source = traits.Enum("FSL", "AFNI", "SPM", "FSFAST",
212+
desc="Source of movement parameters",
213+
mandatory=True)
210214
radius = traits.Float(50, usedefault=True,
211215
desc='radius in mm to calculate angular FDs, 50mm is the '
212216
'default since it is used in Power et al. 2012')
@@ -260,9 +264,12 @@ class FramewiseDisplacement(BaseInterface):
260264
}]
261265

262266
def _run_interface(self, runtime):
263-
mpars = np.loadtxt(self.inputs.in_plots) # mpars is N_t x 6
264-
diff = mpars[:-1, :] - mpars[1:, :]
265-
diff[:, :3] *= self.inputs.radius
267+
mpars = np.loadtxt(self.inputs.in_file) # mpars is N_t x 6
268+
mpars = np.apply_along_axis(func1d=normalize_mc_params,
269+
axis=1, arr=mpars,
270+
source=self.inputs.parameter_source)
271+
diff = mpars[:-1, :6] - mpars[1:, :6]
272+
diff[:, 3:6] *= self.inputs.radius
266273
fd_res = np.abs(diff).sum(axis=1)
267274

268275
self._results = {
@@ -572,6 +579,79 @@ def _list_outputs(self):
572579
outputs['detrended_file'] = op.abspath(self.inputs.detrended_file)
573580
return outputs
574581

582+
583+
class NonSteadyStateDetectorInputSpec(BaseInterfaceInputSpec):
584+
in_file = File(exists=True, mandatory=True, desc='4D NIFTI EPI file')
585+
586+
587+
class NonSteadyStateDetectorOutputSpec(TraitedSpec):
588+
n_volumes_to_discard = traits.Int(desc='Number of non-steady state volumes'
589+
'detected in the beginning of the scan.')
590+
591+
592+
class NonSteadyStateDetector(BaseInterface):
593+
"""
594+
Returns the number of non-steady state volumes detected at the beginning
595+
of the scan.
596+
"""
597+
598+
input_spec = NonSteadyStateDetectorInputSpec
599+
output_spec = NonSteadyStateDetectorOutputSpec
600+
601+
def _run_interface(self, runtime):
602+
in_nii = nb.load(self.inputs.in_plots)
603+
global_signal = in_nii.get_data()[:,:,:,:50].mean(axis=0).mean(axis=0).mean(axis=0)
604+
605+
self._results = {
606+
'out_file': _is_outlier(global_signal)
607+
}
608+
609+
return runtime
610+
611+
def _list_outputs(self):
612+
return self._results
613+
614+
def _is_outlier(points, thresh=3.5):
615+
"""
616+
Returns a boolean array with True if points are outliers and False
617+
otherwise.
618+
619+
Parameters:
620+
-----------
621+
points : An numobservations by numdimensions array of observations
622+
thresh : The modified z-score to use as a threshold. Observations with
623+
a modified z-score (based on the median absolute deviation) greater
624+
than this value will be classified as outliers.
625+
626+
Returns:
627+
--------
628+
mask : A numobservations-length boolean array.
629+
630+
References:
631+
----------
632+
Boris Iglewicz and David Hoaglin (1993), "Volume 16: How to Detect and
633+
Handle Outliers", The ASQC Basic References in Quality Control:
634+
Statistical Techniques, Edward F. Mykytka, Ph.D., Editor.
635+
"""
636+
if len(points.shape) == 1:
637+
points = points[:, None]
638+
median = np.median(points, axis=0)
639+
diff = np.sum((points - median) ** 2, axis=-1)
640+
diff = np.sqrt(diff)
641+
med_abs_deviation = np.median(diff)
642+
643+
modified_z_score = 0.6745 * diff / med_abs_deviation
644+
645+
timepoints_to_discard = 0
646+
for i in range(len(modified_z_score)):
647+
if modified_z_score[i] <= thresh:
648+
break
649+
else:
650+
timepoints_to_discard += 1
651+
652+
return timepoints_to_discard
653+
654+
575655
def regress_poly(degree, data, remove_mean=True, axis=-1):
576656
''' returns data with degree polynomial regressed out.
577657
Be default it is calculated along the last axis (usu. time).

nipype/algorithms/rapidart.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
OutputMultiPath, TraitedSpec, File,
3535
BaseInterfaceInputSpec, isdefined)
3636
from ..utils.filemanip import filename_to_list, save_json, split_filename
37-
from ..utils.misc import find_indices
37+
from ..utils.misc import find_indices, normalize_mc_params
3838
from .. import logging, config
3939
iflogger = logging.getLogger('interface')
4040

@@ -46,15 +46,12 @@ def _get_affine_matrix(params, source):
4646
source : the package that generated the parameters
4747
supports SPM, AFNI, FSFAST, FSL, NIPY
4848
"""
49-
if source == 'FSL':
50-
params = params[[3, 4, 5, 0, 1, 2]]
51-
elif source in ('AFNI', 'FSFAST'):
52-
params = params[np.asarray([4, 5, 3, 1, 2, 0]) + (len(params) > 6)]
53-
params[3:] = params[3:] * np.pi / 180.
5449
if source == 'NIPY':
5550
# nipy does not store typical euler angles, use nipy to convert
5651
from nipy.algorithms.registration import to_matrix44
5752
return to_matrix44(params)
53+
54+
params = normalize_mc_params(params, source)
5855
# process for FSL, SPM, AFNI and FSFAST
5956
rotfunc = lambda x: np.array([[np.cos(x), np.sin(x)],
6057
[-np.sin(x), np.cos(x)]])

0 commit comments

Comments
 (0)