Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: SDC integration #55

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8d49995
ci: add reusable anchors
eilidhmacnicol May 11, 2023
6e056ca
ci: restore cache paths for build and smoke test
eilidhmacnicol May 11, 2023
1cb001c
ci: pull latest image from local registry for smoke test
eilidhmacnicol May 11, 2023
c078d0c
ci: pull from docker registry in smoke test
eilidhmacnicol May 11, 2023
42cc759
wip: add sdc wf into base wf
eilidhmacnicol May 23, 2022
4249176
wip: update bold wf with fieldmap info
eilidhmacnicol May 23, 2022
0b668ce
fix: change registration to ants from fsl
eilidhmacnicol May 23, 2022
681118d
fix: update init_anat_template_wf after smriprep bump
eilidhmacnicol Apr 18, 2023
359ea17
fix: duplicate node error
eilidhmacnicol Apr 19, 2023
be4bb48
fix: task selection
eilidhmacnicol Apr 19, 2023
17a8b3a
WIP: base and functional wf overhaul
eilidhmacnicol May 11, 2023
31cbf14
fix: sdcflow out_path_base to fmriprep dir
eilidhmacnicol Apr 25, 2023
0ef6a25
fix: surgery on sdcflows to scale images for topup and descale outputs
eilidhmacnicol Apr 27, 2023
16c89e9
fix: add distorted ref to unwarp_wf
eilidhmacnicol Apr 27, 2023
e05a3d7
fix: improve coregistration parameters
eilidhmacnicol May 2, 2023
eadbbfe
wip: fixing sdcflows orientations
eilidhmacnicol May 2, 2023
e3d5519
maint: update fmriplot compatibility to niworkflows 1.7.x
eilidhmacnicol May 2, 2023
d8ee462
enh: scale min zooms to 1mm for topup
eilidhmacnicol May 9, 2023
e4df1c3
fix: bold native ref workflow connections
eilidhmacnicol May 9, 2023
e802f83
fix: generate final bold reference after resampling
eilidhmacnicol May 9, 2023
c001021
pin: add sdcflows as dependency
eilidhmacnicol May 11, 2023
398b929
pin: bump niworkflows to 1.8.x
eilidhmacnicol May 23, 2023
1bd4448
pin: bump nirodents
eilidhmacnicol Jun 6, 2023
913da47
fix: keep bold native resolution, not template
eilidhmacnicol Jun 6, 2023
d66fe9d
pin: bump smriprep
eilidhmacnicol Jun 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 60 additions & 37 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,49 @@
# reusable anchors
_machine_defaults: &machine_defaults
environment:
TZ: "/usr/share/zoneinfo/America/Los_Angeles"
machine:
image: ubuntu-2204:current
docker_layer_caching: true

_docker_auth: &docker_auth
name: Docker authentication
command: |
if [[ -n $DOCKER_PAT ]]; then
echo "$DOCKER_PAT" | docker login -u $DOCKER_USER --password-stdin
fi

_setup_docker_registry: &setup_docker_registry
name: Set up Docker registry
command: |
if [[ -f /tmp/images/registry.tar.gz ]]; then
echo "Loading saved registry image"
docker load < /tmp/images/registry.tar.gz
else
echo "Pulling registry image from DockerHub"
docker pull registry:2
fi
docker run -d -p 5000:5000 --restart=always --name=registry \
-v /tmp/docker:/var/lib/registry registry:2

_pull_from_registry: &pull_from_registry
name: Pull and tag image from local registry
command: |
docker pull localhost:5000/fmriprep-rodents
docker tag localhost:5000/fmriprep-rodents nipreps/fmriprep-rodents:latest


version: 2.1
orbs:
docker: circleci/docker@2.1.4

jobs:
build:
environment:
TZ: "/usr/share/zoneinfo/America/Los_Angeles"
docker:
- image: cimg/python:3.9
<<: *machine_defaults
resource_class: large
working_directory: /tmp/src/fmriprep-rodents
environment:
DOCKER_BUILDKIT: 1
steps:
- checkout
- run:
Expand All @@ -21,39 +56,26 @@ jobs:
echo "Only docs build"
circleci step halt
fi

- restore_cache:
keys:
- build-v0-{{ .Branch }}-{{ .Revision }}
- build-v0--{{ .Revision }}
- build-v0-{{ .Branch }}-
- build-v0-master-
- build-v0-
paths:
- /tmp/docker
- /tmp/images
- docker/install-docker-credential-helper
- run:
name: Docker authentication
command: |
if [[ -n $DOCKER_PAT ]]; then
echo "$DOCKER_PAT" | docker login -u $DOCKER_USER --password-stdin
fi

- setup_remote_docker:
docker_layer_caching: true

- run:
name: Set up Docker registry
command: |
if [[ -f /tmp/images/registry.tar.gz ]]; then
echo "Loading saved registry image"
docker load < /tmp/images/registry.tar.gz
else
echo "Pulling registry image from DockerHub"
docker pull registry:2
fi
docker run -d -p 5000:5000 --restart=always --name=registry \
-v /tmp/docker:/var/lib/registry registry:2

- run: *docker_auth
- run: *setup_docker_registry
- run:
name: Save docker registry
command: |
if [[ ! -f /tmp/images/registry.tar.gz ]]; then
mkdir -p /tmp/images
docker save registry:2 | gzip > /tmp/images/registry.tar.gz
fi

- run:
name: Pull Ubuntu/jammy image
command: |
Expand All @@ -77,7 +99,6 @@ jobs:
docker tag ubuntu:jammy localhost:5000/ubuntu
docker push localhost:5000/ubuntu
fi

- run:
name: Pull a base image if not cached
no_output_timeout: 60m
Expand All @@ -94,7 +115,6 @@ jobs:
echo "Pulling from Docker Hub"
docker pull nipreps/fmriprep-rodents:latest
fi

- run:
name: Build Docker image
no_output_timeout: 60m
Expand All @@ -116,7 +136,6 @@ jobs:

# Build docker image
make docker-build version="${CIRCLE_TAG:-$THISVERSION}"

- run:
name: Check Docker image
command: |
Expand Down Expand Up @@ -218,7 +237,6 @@ jobs:
key: data-se-v0-{{ .Branch }}-{{ .Revision }}-{{ epoch }}
paths:
- /tmp/data/nirodents-bold-se

- run:
name: Store FreeSurfer license file
command: |
Expand All @@ -240,10 +258,8 @@ jobs:
- config/nipype.cfg

smoke_test:
machine:
image: ubuntu-2204:current
docker_layer_caching: true
resource_class: xlarge
<<: *machine_defaults
resource_class: xlarge
working_directory: /tmp/rodent-se
environment:
- FS_LICENSE: /tmp/fslicense/license.txt
Expand All @@ -269,6 +285,9 @@ jobs:
- restore_cache:
keys:
- build-v0-{{ .Branch }}-{{ .Revision }}
paths:
- /tmp/docker
- /tmp/images
- restore_cache:
keys:
- data-se-v0-{{ .Branch }}-{{ .Revision }}-{{ epoch }}
Expand All @@ -281,6 +300,10 @@ jobs:
- nirodents-bold-se-anat-v01-{{ .Branch }}
- nirodents-bold-se-anat-v01-master
- nirodents-bold-se-anat-v01-
- docker/install-docker-credential-helper
- run: *docker_auth
- run: *setup_docker_registry
- run: *pull_from_registry
- run:
name: Run anatomical workflow on rodents
no_output_timeout: 2h
Expand Down
30 changes: 14 additions & 16 deletions fprodents/data/translation_rigid.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@
"dimension": 3,
"float": true,
"winsorize_lower_quantile": 0.005,
"winsorize_upper_quantile": 0.998,
"winsorize_upper_quantile": 0.995,
"collapse_output_transforms": true,
"write_composite_transform": true,
"use_histogram_matching": [ true, true ],
"use_estimate_learning_rate_once": [ true, true ],
"transforms": [ "Translation", "Rigid" ],
"number_of_iterations": [ [ 500 ], [ 200 ] ],
"transform_parameters": [ [ 0.05 ], [ 0.01 ] ],
"convergence_threshold": [ 1e-07, 1e-08 ],
"convergence_window_size": [ 200, 100 ],
"metric": [ "Mattes", "Mattes" ],
"sampling_percentage": [ 0.5, 0.5 ],
"sampling_strategy": [ "Random", "Random" ],
"smoothing_sigmas": [ [ 8.0 ], [ 2.0 ] ],
"sigma_units": [ "mm", "mm" ],
"metric_weight": [ 1.0, 1.0 ],
"shrink_factors": [ [ 2 ], [ 1 ] ],
"radius_or_number_of_bins": [ 64, 64 ],
"use_histogram_matching": [ true ],
"use_estimate_learning_rate_once": [ true ],
"transforms": [ "Rigid" ],
"number_of_iterations": [ [ 500, 250, 100 ] ],
"transform_parameters": [ [ 0.1 ] ],
"metric": [ "Mattes" ],
"sampling_percentage": [ 0.3 ],
"sampling_strategy": [ "Regular" ],
"smoothing_sigmas": [ [ 2.0, 1.0, 0.0 ] ],
"sigma_units": [ "vox" ],
"metric_weight": [ 1.0 ],
"shrink_factors": [ [ 4, 2, 1 ] ],
"radius_or_number_of_bins": [ 32 ],
"interpolation": "LanczosWindowedSinc"
}
57 changes: 26 additions & 31 deletions fprodents/interfaces/confounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import os
import re
import shutil
import nibabel as nb
import numpy as np
import pandas as pd
from nipype import logging
Expand All @@ -25,6 +26,8 @@
isdefined,
SimpleInterface,
)
from niworkflows.utils.timeseries import _nifti_timeseries
from niworkflows.viz.plots import fMRIPlot

LOGGER = logging.getLogger("nipype.interface")

Expand Down Expand Up @@ -315,28 +318,20 @@ def _get_ica_confounds(ica_out_dir, skip_vols, newpath=None):


class FMRISummaryInputSpec(BaseInterfaceInputSpec):
in_func = File(
exists=True,
mandatory=True,
desc="input BOLD time-series (4D file) or dense timeseries CIFTI",
)
in_mask = File(exists=True, desc="3D brain mask")
in_segm = File(exists=True, desc="resampled segmentation")
in_nifti = File(exists=True, mandatory=True, desc="input BOLD (4D NIfTI file)")
in_segm = File(exists=True, desc="volumetric segmentation corresponding to in_nifti")
confounds_file = File(exists=True, desc="BIDS' _confounds.tsv file")

str_or_tuple = traits.Either(
traits.Str,
traits.Tuple(traits.Str, traits.Either(None, traits.Str)),
traits.Tuple(
traits.Str, traits.Either(None, traits.Str), traits.Either(None, traits.Str)
),
traits.Tuple(traits.Str, traits.Either(None, traits.Str), traits.Either(None, traits.Str)),
)
confounds_list = traits.List(
str_or_tuple,
minlen=1,
desc="list of headers to extract from the confounds_file",
str_or_tuple, minlen=1, desc='list of headers to extract from the confounds_file'
)
tr = traits.Either(None, traits.Float, usedefault=True, desc="the repetition time")
drop_trs = traits.Int(0, usedefault=True, desc="dummy scans")


class FMRISummaryOutputSpec(TraitedSpec):
Expand All @@ -352,22 +347,26 @@ class FMRISummary(SimpleInterface):
output_spec = FMRISummaryOutputSpec

def _run_interface(self, runtime):
from niworkflows.viz.plots import fMRIPlot
self._results['out_file'] = fname_presuffix(
self.inputs.in_nifti, suffix='_fmriplot.svg', use_ext=False, newpath=runtime.cwd
)

self._results["out_file"] = fname_presuffix(
self.inputs.in_func,
suffix="_fmriplot.svg",
use_ext=False,
newpath=runtime.cwd,
# Read input object and create timeseries + segments object
seg_file = self.inputs.in_segm if isdefined(self.inputs.in_segm) else None
dataset, segments = _nifti_timeseries(
nb.load(self.inputs.in_nifti),
nb.load(seg_file),
remap_rois=False,
labels=(("GM", "WM", "CSF", "other")),
)

dataframe = pd.read_csv(
self.inputs.confounds_file,
sep="\t",
index_col=None,
dtype="float32",
dtype='float32',
na_filter=True,
na_values="n/a",
na_values='n/a',
)

headers = []
Expand All @@ -391,20 +390,16 @@ def _run_interface(self, runtime):
else:
data = dataframe[headers]

colnames = data.columns.ravel().tolist()

for name, newname in list(names.items()):
colnames[colnames.index(name)] = newname

data.columns = colnames
data = data.rename(columns=names)

fig = fMRIPlot(
self.inputs.in_func,
mask_file=self.inputs.in_mask if isdefined(self.inputs.in_mask) else None,
seg_file=(self.inputs.in_segm if isdefined(self.inputs.in_segm) else None),
dataset,
segments=segments,
tr=self.inputs.tr,
data=data,
confounds=data,
units=units,
nskip=self.inputs.drop_trs,
paired_carpet=False,
).plot()
fig.savefig(self._results["out_file"], bbox_inches="tight")
return runtime
13 changes: 8 additions & 5 deletions fprodents/patch/workflows/anatomical.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,10 @@ def init_anat_preproc_wf(

# 1. Anatomical reference generation - average input T1w images.
anat_template_wf = init_anat_template_wf(
longitudinal=longitudinal, omp_nthreads=omp_nthreads, num_t1w=num_t2w
longitudinal=longitudinal,
omp_nthreads=omp_nthreads,
num_files=num_t2w,
contrast="T2w"
)

anat_validate = pe.Node(
Expand Down Expand Up @@ -338,15 +341,15 @@ def _check_img(img):
# fmt:off
workflow.connect([
# Step 1.
(inputnode, anat_template_wf, [('t2w', 'inputnode.t1w')]),
(inputnode, anat_template_wf, [('t2w', 'inputnode.anat_files')]),
(anat_template_wf, anat_validate, [
('outputnode.t1w_ref', 'in_file')]),
('outputnode.anat_ref', 'in_file')]),
(anat_validate, brain_extraction_wf, [
('out_file', 'inputnode.in_files')]),
(brain_extraction_wf, outputnode, [
(('outputnode.out_corrected', _pop), 't2w_preproc')]),
(anat_template_wf, outputnode, [
('outputnode.t1w_realign_xfm', 't2w_ref_xfms')]),
('outputnode.anat_realign_xfm', 't2w_ref_xfms')]),
(buffernode, outputnode, [('t2w_brain', 't2w_brain'),
('t2w_mask', 't2w_mask')]),
# Steps 2 and 3
Expand Down Expand Up @@ -389,7 +392,7 @@ def _check_img(img):
workflow.connect([
# Connect derivatives
(anat_template_wf, anat_derivatives_wf, [
('outputnode.t1w_valid_list', 'inputnode.source_files')]),
('outputnode.anat_valid_list', 'inputnode.source_files')]),
(anat_norm_wf, anat_derivatives_wf, [
('outputnode.template', 'inputnode.template'),
('outputnode.anat2std_xfm', 'inputnode.anat2std_xfm'),
Expand Down
Loading