Skip to content
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
924ecef
Make command line option for fs ingress
e-kenneally Mar 26, 2024
d433513
Make filename parsing more generalizable
e-kenneally Apr 1, 2024
20572de
Change reg workflow to produce consistent outputs
e-kenneally Apr 16, 2024
4d26732
Merge pull request #2095 from FCP-INDI/feature/fs-ingress-cmdline
e-kenneally Apr 16, 2024
9f81479
Remove restore-brain option from pipeline config
e-kenneally Apr 17, 2024
68e3c41
Modified warp_timeseries_to_T1template_abcd to create space-template_…
Apr 17, 2024
03a503c
Remove coregistration -> reference option
e-kenneally Apr 17, 2024
fa8d481
added bold_mask to the list of nodeblock outputs
Apr 17, 2024
d68a733
Revert "added bold_mask to the list of nodeblock outputs"
birajstha Apr 18, 2024
4239a5f
Revert "Modified warp_timeseries_to_T1template_abcd to create space-t…
birajstha Apr 18, 2024
72f24bc
:bug: Fix bug in fs ingress commandline
e-kenneally Apr 18, 2024
4818a20
appending the nodeblock bold_mask_anatomical_resampled inside transfo…
birajstha Apr 18, 2024
c493e80
Abstracted anat_brain_to_bold_res and anat_brain_mask_to_bold_res fro…
birajstha Apr 23, 2024
436d8fa
Merge pull request #2096 from FCP-INDI/fix_flo_issues
birajstha May 2, 2024
a2f8d23
added template space warped mask as an output in the ANTs Registratio…
birajstha May 10, 2024
5ca3a1b
Edited ANTs registration to output the template mask file as well
birajstha May 10, 2024
cc285fd
Revert "added template space warped mask as an output in the ANTs Reg…
birajstha May 10, 2024
66894a4
changed bold_mask_anatomical_resampled to take in brain_mask instead …
birajstha May 10, 2024
dc41bf4
input bold data to node swapped with reorient-bold to resolve RAI/RPI…
birajstha May 13, 2024
5d6a9ca
:rotating_light: Lint in preparation for merge from
shnizzedy Nov 5, 2024
eef3569
🚚 Move entrypoint scripts into CPAC/_entrypoints in preparation for b…
shnizzedy Nov 5, 2024
d28aa5f
:twisted_rightwards_arrows: Merge unrelated changes from branch 'feat…
shnizzedy Nov 5, 2024
dc5663c
:twisted_rightwards_arrows: Merge changes from branch 'feature/check_…
shnizzedy Nov 5, 2024
590b437
adding f to f-string fixing typo
birajstha Nov 5, 2024
043a004
changing bold to desc-reorient_bold
birajstha Nov 7, 2024
c725a9d
:bug: :alien: Patch `NetCorr._list_outputs`
shnizzedy Nov 11, 2024
f1dac0c
:pencil2: Fix "perged" typo in comment
shnizzedy Nov 18, 2024
12bc033
Merge pull request #2163 from FCP-INDI/ts_Z_corr
sgiavasis Nov 21, 2024
5f20500
➕ Reorient resources to set orientation in config (#2161)
shnizzedy Dec 11, 2024
be61d7f
:sparkles: Add inventory utility
shnizzedy Jan 6, 2025
5758eed
:bug: Fix resource name: `unet_model` → `unet-model`
shnizzedy Jan 6, 2025
236e0fe
:children_crossing: Add CLI for resource inventory
shnizzedy Jan 6, 2025
36528bd
:children_crossing: Rename `resource_inventory` CLI command
shnizzedy Jan 6, 2025
20ce428
:children_crossing: Specify default in helpstring
shnizzedy Jan 7, 2025
780600a
:zap: Don't install torch just to look for NodeBlockFunctions
shnizzedy Jan 9, 2025
0f02aee
:memo: Add `resource_inventory` to CHANGELOG
shnizzedy Jan 9, 2025
38cdabe
:sparkles: Pick up more hard-coded resources
shnizzedy Jan 15, 2025
74a715b
:necktie: Match keys and values for assignment loops
shnizzedy Jan 16, 2025
9730dad
:necktie: Include func def args in context
shnizzedy Jan 16, 2025
252098b
:children_crossing: Exclude dummy node from inventory
shnizzedy Jan 16, 2025
b3521fc
:necktie: Handle some special cases
shnizzedy Jan 17, 2025
352516d
:children_crossing: Include resource soure information in resource-no…
shnizzedy Jan 9, 2025
77caa2a
:recycle: Move bids_examples into a reusable pyest fixture
shnizzedy Jan 10, 2025
5d11125
:white_check_mark: Add test for resource inventory error message
shnizzedy Jan 10, 2025
8b369f3
:construction_worker: Install `openssh-client` for bids-examples fixture
shnizzedy Jan 13, 2025
c6b3a18
:children_crossing: Increase indent before missing resource sources
shnizzedy Jan 20, 2025
11948a6
Checking if overwrite transform method is same as the anatomical regi…
birajstha Feb 11, 2025
7b3603a
with precommit changes
birajstha Feb 11, 2025
8dcef78
:twisted_rightwards_arrows: Merge remote-tracking branch 'origin/deve…
shnizzedy Mar 6, 2025
a8adeb4
Update CPAC/pipeline/schema.py
birajstha Mar 6, 2025
8cf804f
Update CPAC/pipeline/test/test_schema_validation.py
birajstha Mar 6, 2025
8c4a7af
Update CPAC/registration/registration.py
birajstha Mar 6, 2025
76bd2ae
Update CPAC/registration/registration.py
birajstha Mar 6, 2025
ba2cff4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 6, 2025
82e5b93
revert back adding error handler dir
birajstha Mar 6, 2025
22f3a86
adding to changelog
birajstha Mar 6, 2025
a91c854
fixing test for overwrite trasnsform
birajstha Mar 7, 2025
01cc822
fixing test for overwrite trasnsform
birajstha Mar 7, 2025
2388a1b
Update CPAC/pipeline/schema.py
birajstha Mar 11, 2025
9396a0c
Update CPAC/pipeline/test/test_schema_validation.py
birajstha Mar 11, 2025
74da7d9
Merge branch 'many_pipes' into inventory_error_message
sgiavasis Mar 12, 2025
0877614
Merge pull request #2171 from FCP-INDI/resource_inventory
sgiavasis Mar 12, 2025
75e3d5c
Merge branch 'many_pipes' into inventory_error_message
sgiavasis Mar 12, 2025
996a7be
Merge branch 'many_pipes' into overwrite_transform
sgiavasis Mar 14, 2025
77f4769
:construction_worker: :loud_sound: Log `git config --global url`
shnizzedy Mar 14, 2025
740ad1d
:construction_worker: :whale: :wrench: :octocat: :lock: Don't force S…
shnizzedy Mar 15, 2025
df2a841
:twisted_rightwards_arrows: Merge branch 'CVE-2023-51664' into invent…
shnizzedy Mar 15, 2025
30dfc6f
:truck: Move global fixtures to own file
shnizzedy Mar 15, 2025
766bfd4
:white_check_mark: Adjust paths for updated test
shnizzedy Mar 15, 2025
0e954fd
Merge pull request #2190 from FCP-INDI/overwrite_transform
birajstha Mar 17, 2025
36678a7
Merge branch 'develop' into many_pipes
birajstha Mar 17, 2025
7438a7c
Merge pull request #2172 from FCP-INDI/inventory_error_message
sgiavasis Mar 18, 2025
c203faf
Merge branch 'develop' into many_pipes
sgiavasis Mar 19, 2025
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Required positional parameter "wf" in input and output of `ingress_pipeconfig_paths` function, where a node to reorient templates is added to the `wf`.
- Required positional parameter "orientation" to `resolve_resolution`.
- Optional positional argument "cfg" to `create_lesion_preproc`.
- Allow enabling `overwrite_transform` only when the registration method is `ANTS`.
- `resource_inventory` utility to inventory NodeBlock function inputs and outputs.

### Changed

Expand Down
12 changes: 11 additions & 1 deletion CPAC/_entrypoints/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,14 @@ def run_main():
action="store_true",
)

parser.add_argument(
"--freesurfer_dir",
"--freesurfer-dir",
help="Specify path to pre-computed FreeSurfer outputs "
"to pull into C-PAC run",
default=False,
)

# get the command line arguments
args = parser.parse_args(
sys.argv[1 : (sys.argv.index("--") if "--" in sys.argv else len(sys.argv))]
Expand Down Expand Up @@ -743,6 +751,9 @@ def run_main():
c["pipeline_setup", "system_config", "num_participants_at_once"],
)

if args.freesurfer_dir:
c["pipeline_setup"]["freesurfer_dir"] = args.freesurfer_dir

if not args.data_config_file:
WFLOGGER.info("Input directory: %s", bids_dir)

Expand Down Expand Up @@ -783,7 +794,6 @@ def run_main():
sub_list = load_cpac_data_config(
args.data_config_file, args.participant_label, args.aws_input_creds
)
list(sub_list)
sub_list = sub_list_filter_by_labels(
sub_list, {"T1w": args.T1w_label, "bold": args.bold_label}
)
Expand Down
6 changes: 3 additions & 3 deletions CPAC/anat_preproc/anat_preproc.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2012-2023 C-PAC Developers
# Copyright (C) 2012-2025 C-PAC Developers

# This file is part of C-PAC.

Expand Down Expand Up @@ -2572,7 +2572,7 @@ def brain_mask_acpc_niworkflows_ants_T2(wf, cfg, strat_pool, pipe_num, opt=None)
config=["anatomical_preproc", "brain_extraction"],
option_key="using",
option_val="UNet",
inputs=["desc-preproc_T2w", "T1w-brain-template", "T1w-template", "unet_model"],
inputs=["desc-preproc_T2w", "T1w-brain-template", "T1w-template", "unet-model"],
outputs=["space-T2w_desc-brain_mask"],
)
def brain_mask_unet_T2(wf, cfg, strat_pool, pipe_num, opt=None):
Expand All @@ -2586,7 +2586,7 @@ def brain_mask_unet_T2(wf, cfg, strat_pool, pipe_num, opt=None):
config=["anatomical_preproc", "brain_extraction"],
option_key="using",
option_val="UNet",
inputs=["desc-preproc_T2w", "T1w-brain-template", "T1w-template", "unet_model"],
inputs=["desc-preproc_T2w", "T1w-brain-template", "T1w-template", "unet-model"],
outputs=["space-T2w_desc-acpcbrain_mask"],
)
def brain_mask_acpc_unet_T2(wf, cfg, strat_pool, pipe_num, opt=None):
Expand Down
138 changes: 114 additions & 24 deletions CPAC/func_preproc/func_preproc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1503,6 +1503,91 @@ def bold_mask_anatomical_based(wf, cfg, strat_pool, pipe_num, opt=None):
return (wf, outputs)


def anat_brain_to_bold_res(wf_name, cfg, pipe_num):
wf = pe.Workflow(name=f"{wf_name}_{pipe_num}")

inputNode = pe.Node(
util.IdentityInterface(
fields=["T1w-template-funcreg", "space-template_desc-preproc_T1w"]
),
name="inputspec",
)
outputNode = pe.Node(
util.IdentityInterface(fields=["space-template_res-bold_desc-brain_T1w"]),
name="outputspec",
)

# applywarp --rel --interp=spline -i ${T1wImage} -r ${ResampRefIm} --premat=$FSLDIR/etc/flirtsch/ident.mat -o ${WD}/${T1wImageFile}.${FinalfMRIResolution}
anat_brain_to_func_res = pe.Node(
interface=fsl.ApplyWarp(), name=f"resample_anat_brain_in_standard_{pipe_num}"
)

anat_brain_to_func_res.inputs.interp = "spline"
anat_brain_to_func_res.inputs.premat = cfg.registration_workflows[
"anatomical_registration"
]["registration"]["FSL-FNIRT"]["identity_matrix"]

wf.connect(
inputNode, "space-template_desc-preproc_T1w", anat_brain_to_func_res, "in_file"
)
wf.connect(inputNode, "T1w-template-funcreg", anat_brain_to_func_res, "ref_file")

wf.connect(
anat_brain_to_func_res,
"out_file",
outputNode,
"space-template_res-bold_desc-brain_T1w",
)
return wf


def anat_brain_mask_to_bold_res(wf_name, cfg, pipe_num):
# Create brain masks in this space from the FreeSurfer output (changing resolution)
# applywarp --rel --interp=nn -i ${FreeSurferBrainMask}.nii.gz -r ${WD}/${T1wImageFile}.${FinalfMRIResolution} --premat=$FSLDIR/etc/flirtsch/ident.mat -o ${WD}/${FreeSurferBrainMaskFile}.${FinalfMRIResolution}.nii.gz
wf = pe.Workflow(name=f"{wf_name}_{pipe_num}")
inputNode = pe.Node(
util.IdentityInterface(
fields=["space-template_desc-brain_mask", "space-template_desc-preproc_T1w"]
),
name="inputspec",
)
outputNode = pe.Node(
util.IdentityInterface(fields=["space-template_desc-bold_mask"]),
name="outputspec",
)

anat_brain_mask_to_func_res = pe.Node(
interface=fsl.ApplyWarp(),
name=f"resample_anat_brain_mask_in_standard_{pipe_num}",
)

anat_brain_mask_to_func_res.inputs.interp = "nn"
anat_brain_mask_to_func_res.inputs.premat = cfg.registration_workflows[
"anatomical_registration"
]["registration"]["FSL-FNIRT"]["identity_matrix"]

wf.connect(
inputNode,
"space-template_desc-brain_mask",
anat_brain_mask_to_func_res,
"in_file",
)
wf.connect(
inputNode,
"space-template_desc-preproc_T1w",
anat_brain_mask_to_func_res,
"ref_file",
)
wf.connect(
anat_brain_mask_to_func_res,
"out_file",
outputNode,
"space-template_desc-bold_mask",
)

return wf


@nodeblock(
name="bold_mask_anatomical_resampled",
switch=[
Expand All @@ -1528,39 +1613,35 @@ def bold_mask_anatomical_resampled(wf, cfg, strat_pool, pipe_num, opt=None):

Adapted from `DCAN Lab's BOLD mask method from the ABCD pipeline <https://github.com/DCAN-Labs/DCAN-HCP/blob/1d90814/fMRIVolume/scripts/OneStepResampling.sh#L121-L132>`_.
"""
# applywarp --rel --interp=spline -i ${T1wImage} -r ${ResampRefIm} --premat=$FSLDIR/etc/flirtsch/ident.mat -o ${WD}/${T1wImageFile}.${FinalfMRIResolution}
anat_brain_to_func_res = pe.Node(
interface=fsl.ApplyWarp(), name=f"resample_anat_brain_in_standard_{pipe_num}"
)

anat_brain_to_func_res.inputs.interp = "spline"
anat_brain_to_func_res.inputs.premat = cfg.registration_workflows[
"anatomical_registration"
]["registration"]["FSL-FNIRT"]["identity_matrix"]
anat_brain_to_func_res = anat_brain_to_bold_res(wf, cfg, pipe_num)

node, out = strat_pool.get_data("space-template_desc-preproc_T1w")
wf.connect(node, out, anat_brain_to_func_res, "in_file")
wf.connect(
node, out, anat_brain_to_func_res, "inputspec.space-template_desc-preproc_T1w"
)

node, out = strat_pool.get_data("T1w-template-funcreg")
wf.connect(node, out, anat_brain_to_func_res, "ref_file")
wf.connect(node, out, anat_brain_to_func_res, "inputspec.T1w-template-funcreg")

# Create brain masks in this space from the FreeSurfer output (changing resolution)
# applywarp --rel --interp=nn -i ${FreeSurferBrainMask}.nii.gz -r ${WD}/${T1wImageFile}.${FinalfMRIResolution} --premat=$FSLDIR/etc/flirtsch/ident.mat -o ${WD}/${FreeSurferBrainMaskFile}.${FinalfMRIResolution}.nii.gz
anat_brain_mask_to_func_res = pe.Node(
interface=fsl.ApplyWarp(),
name=f"resample_anat_brain_mask_in_standard_{pipe_num}",
anat_brain_mask_to_func_res = anat_brain_mask_to_bold_res(
wf_name="anat_brain_mask_to_bold_res", cfg=cfg, pipe_num=pipe_num
)

anat_brain_mask_to_func_res.inputs.interp = "nn"
anat_brain_mask_to_func_res.inputs.premat = cfg.registration_workflows[
"anatomical_registration"
]["registration"]["FSL-FNIRT"]["identity_matrix"]

node, out = strat_pool.get_data("space-template_desc-brain_mask")
wf.connect(node, out, anat_brain_mask_to_func_res, "in_file")
wf.connect(
node,
out,
anat_brain_mask_to_func_res,
"inputspec.pace-template_desc-brain_mask",
)

wf.connect(
anat_brain_to_func_res, "out_file", anat_brain_mask_to_func_res, "ref_file"
anat_brain_to_func_res,
"outputspec.space-template_res-bold_desc-brain_T1w",
anat_brain_mask_to_func_res,
"inputspec.space-template_desc-preproc_T1w",
)

# Resample func mask in template space back to native space
Expand All @@ -1574,15 +1655,24 @@ def bold_mask_anatomical_resampled(wf, cfg, strat_pool, pipe_num, opt=None):
func_mask_template_to_native.inputs.outputtype = "NIFTI_GZ"

wf.connect(
anat_brain_mask_to_func_res, "out_file", func_mask_template_to_native, "in_file"
anat_brain_mask_to_func_res,
"outputspec.space-template_desc-bold_mask",
func_mask_template_to_native,
"in_file",
)

node, out = strat_pool.get_data("desc-preproc_bold")
wf.connect(node, out, func_mask_template_to_native, "master")

outputs = {
"space-template_res-bold_desc-brain_T1w": (anat_brain_to_func_res, "out_file"),
"space-template_desc-bold_mask": (anat_brain_mask_to_func_res, "out_file"),
"space-template_res-bold_desc-brain_T1w": (
anat_brain_to_func_res,
"outputspec.space-template_res-bold_desc-brain_T1w",
),
"space-template_desc-bold_mask": (
anat_brain_mask_to_func_res,
"outputspec.space-template_desc-bold_mask",
),
"space-bold_desc-brain_mask": (func_mask_template_to_native, "out_file"),
}

Expand Down
4 changes: 2 additions & 2 deletions CPAC/nuisance/nuisance.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ def choose_nuisance_blocks(cfg, rpool, generate_only=False):
]
apply_transform_using = to_template_cfg["apply_transform"]["using"]
input_interface = {
"default": ("desc-preproc_bold", ["desc-preproc_bold", "bold"]),
"abcd": ("desc-preproc_bold", "bold"),
"default": ("desc-preproc_bold", ["desc-preproc_bold", "desc-reorient_bold"]),
"abcd": ("desc-preproc_bold", "desc-reorient_bold"),
"single_step_resampling_from_stc": ("desc-preproc_bold", "desc-stc_bold"),
}.get(apply_transform_using)
if input_interface is not None:
Expand Down
45 changes: 24 additions & 21 deletions CPAC/pipeline/engine.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2021-2024 C-PAC Developers
# Copyright (C) 2021-2025 C-PAC Developers

# This file is part of C-PAC.

Expand All @@ -17,13 +17,15 @@
import ast
import copy
import hashlib
from importlib.resources import files
from itertools import chain
import json
import os
import re
from typing import Optional
import warnings

import pandas as pd
from nipype import config, logging
from nipype.interfaces import afni
from nipype.interfaces.utility import Rename
Expand Down Expand Up @@ -1007,6 +1009,19 @@ def post_process(self, wf, label, connection, json_info, pipe_idx, pipe_x, outs)
for label_con_tpl in post_labels:
label = label_con_tpl[0]
connection = (label_con_tpl[1], label_con_tpl[2])
if "desc-" not in label:
if "space-template" in label:
new_label = label.replace(
"space-template", "space-template_desc-zstd"
)
else:
new_label = f"desc-zstd_{label}"
else:
for tag in label.split("_"):
if "desc-" in tag:
newtag = f"{tag}-zstd"
new_label = label.replace(tag, newtag)
break
if label in Outputs.to_zstd:
zstd = z_score_standardize(f"{label}_zstd_{pipe_x}", input_type)

Expand All @@ -1015,20 +1030,6 @@ def post_process(self, wf, label, connection, json_info, pipe_idx, pipe_x, outs)
node, out = self.get_data(mask, pipe_idx=mask_idx)
wf.connect(node, out, zstd, "inputspec.mask")

if "desc-" not in label:
if "space-template" in label:
new_label = label.replace(
"space-template", "space-template_desc-zstd"
)
else:
new_label = f"desc-zstd_{label}"
else:
for tag in label.split("_"):
if "desc-" in tag:
newtag = f"{tag}-zstd"
new_label = label.replace(tag, newtag)
break

post_labels.append((new_label, zstd, "outputspec.out_file"))

self.set_data(
Expand Down Expand Up @@ -1188,7 +1189,7 @@ def gather_pipes(self, wf, cfg, all=False, add_incl=None, add_excl=None):
key
for json_info in all_jsons
for key in json_info.get("CpacVariant", {}).keys()
if key not in (*MOVEMENT_FILTER_KEYS, "regressors")
if key not in (*MOVEMENT_FILTER_KEYS, "timeseries")
}
if "bold" in unlabelled:
all_bolds = list(
Expand Down Expand Up @@ -2411,15 +2412,17 @@ def strip_template(data_label, dir_path, filename):
return data_label, json


def template_dataframe() -> pd.DataFrame:
"""Return the template dataframe."""
template_csv = files("CPAC").joinpath("resources/cpac_templates.csv")
return pd.read_csv(str(template_csv), keep_default_na=False)


def ingress_pipeconfig_paths(wf, cfg, rpool, unique_id, creds_path=None):
# ingress config file paths
# TODO: may want to change the resource keys for each to include one level up in the YAML as well

import pandas as pd
import pkg_resources as p

template_csv = p.resource_filename("CPAC", "resources/cpac_templates.csv")
template_df = pd.read_csv(template_csv, keep_default_na=False)
template_df = template_dataframe()
desired_orientation = cfg.pipeline_setup["desired_orientation"]

for row in template_df.itertuples():
Expand Down
Loading