Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
37fc070
:truck: Split longitudinal into anat and func \& :rotating_light: Lin…
shnizzedy Nov 13, 2024
9d09358
:wrench: Update config to allow choosing `mri_robust_template` for lo…
shnizzedy Nov 13, 2024
dc4c2df
:necktie: Use `max_iter` parameter for longitudinal template generation.
shnizzedy Nov 13, 2024
ae5be2c
:twisted_rightwards_arrows: Merge branch 'mri_robust_template' into f…
shnizzedy Nov 14, 2024
253ca80
:twisted_rightwards_arrows: Merge changes from #2160
shnizzedy Nov 15, 2024
c11c88f
:bug: Debug changes for longitudinal pipeline
shnizzedy Nov 15, 2024
af27165
:construction: WIP :sparkles: Drop in `mri_robust_template`
shnizzedy Nov 19, 2024
a5d2c60
:recycle: SSOT `check_creds_path`
shnizzedy Nov 20, 2024
1a90cc0
:necktie: Make cross-graph and cross-pool connections
shnizzedy Nov 21, 2024
322d660
:necktie: Convert xfms from `lta` to `mat`
shnizzedy Nov 21, 2024
342dae2
:necktie: Clarify longitudinal `xfm`s vs longitudinal `warp`s
shnizzedy Nov 23, 2024
7ce9361
:recycle: Differentiate longitudinal template images from session ima…
shnizzedy Nov 25, 2024
6ad7d55
:construction: :necktie: Enable subworkflow cross-graph connections
shnizzedy Dec 4, 2024
5b527a5
:necktie: Finalize longitudinal (FSL) connections
shnizzedy Dec 5, 2024
6e3da0d
:fire: Remove duplicate output rows
shnizzedy Dec 5, 2024
6339798
:necktie: Output longitudinal template images
shnizzedy Dec 5, 2024
1604b4f
:recycle: :art: SSOT `orientation_node`
shnizzedy Feb 3, 2025
1eacbe9
:necktie: Reorient `mri_robust_template` outputs
shnizzedy Feb 3, 2025
e7276e7
:art: Combine `get_cpac_provenance` + `check_prov_for_regtool` → `reg…
shnizzedy Feb 5, 2025
1a48bf3
:recycle: Refactor `ANTs_registration_connector` to make DRYer
shnizzedy Feb 5, 2025
78b2aa1
:recycle: Connect ANTs methods for longitudinal registration
shnizzedy Feb 7, 2025
087f1e3
:truck: Move `transform_derivative` into `registration.utils`
shnizzedy Feb 8, 2025
6162f2b
:necktie: Rewire ANTs registration + `mri_robust_template`
shnizzedy Feb 10, 2025
62451d2
:necktie: Update ANTs symmetric registration for longitudinal preproc…
shnizzedy Feb 13, 2025
870f43d
:truck: Longutudinal ↔ symtemplate to subject-level anat directory
shnizzedy Feb 14, 2025
0719a3e
:white_check_mark: Update test and signature re: docstring updates
shnizzedy Feb 17, 2025
5b1745a
:construction: WIP :recycle: :necktie: Refactor FSL registration for …
shnizzedy Feb 17, 2025
87e7bb9
:goal_net: Restore raising duplicate Node errors
shnizzedy Mar 26, 2025
4ba04c5
:recycle: Add an identity interface for "reorient" to avoid duplicate…
shnizzedy Mar 26, 2025
5f16386
:recycle: Just use `longitudinal-template_space-longitudinal_desc-hea…
shnizzedy Mar 26, 2025
610c191
:necktie: Create expected outputs log in longitudinal template flow
shnizzedy Apr 7, 2025
8dddb7a
:truck: Give logitudinal its own log
shnizzedy Apr 8, 2025
247d50d
:twisted_rightwards_arrows: Merge branch 'develop' into 'mri_robust_t…
shnizzedy Apr 9, 2025
220ef47
:bug: Ensure subject_id in logger
shnizzedy Apr 9, 2025
72dc0f2
:twisted_rightwards_arrows: Merge branch 'prep_for/mri_robust_templat…
shnizzedy Apr 9, 2025
c8410cc
:bug: Fix `Configuration.__contains__`
shnizzedy Apr 10, 2025
7495dc5
:recycle: Move nested methods to a Mixin
shnizzedy Apr 11, 2025
b46fc43
:bug: Ensure log dir exists when initializing logger
shnizzedy Apr 11, 2025
4981141
:bug: Reseparate longitudinal `expectedOutputs` from sessions specific
shnizzedy Apr 12, 2025
ae04b8d
:art: Clean up Configuration syntax
shnizzedy Apr 14, 2025
aff2971
:white_check_mark: Update exception expectation for pytest
shnizzedy Apr 16, 2025
e175b6e
:pencil2: Correct method call name
shnizzedy Jul 14, 2025
a3648ea
adding to changelog
birajstha May 27, 2025
f29fb35
adding a unit-test for ideal_bandpass
birajstha May 27, 2025
d8e0f0a
pre-commit run
birajstha May 27, 2025
ac22805
Update CPAC/nuisance/tests/test_bandpass.py
birajstha Jun 13, 2025
bed558a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 13, 2025
46bc62a
fixing the tests
birajstha Jun 13, 2025
63f44d0
check none before other
birajstha Jun 13, 2025
4fd5998
:white_check_mark: Adjust test parameters
shnizzedy Jul 21, 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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- New switch `mask_sbref` under `func_input_prep` in functional registration and set to default `on`.
- New resource `desc-head_bold` as non skull-stripped bold from nodeblock `bold_masking`.
- `censor_file_path` from `offending_timepoints_connector` in the `build_nuisance_regressor` node.
- `mri_robust_template` for longitudinal template generation.
- `max_iter` parameter for longitudinal template generation.

### Changed

Expand All @@ -45,6 +47,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Input `desc-brain_bold` to `desc-preproc_bold` for `sbref` generation nodeblock `coregistration_prep_vol`.
- Turned `generate_xcpqc_files` on for all preconfigurations except `blank`.
- Introduced specific switch `restore_t1w_intensity` for `correct_restore_brain_intensity_abcd` nodeblock, enabling it by default only in `abcd-options` pre-config.
- Updated GitHub Actions to run automated integration and regression tests on HPC.
- Made `mri_robust_template` default implementation for longitudinal template generation.

### Fixed

Expand All @@ -54,6 +58,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- A bug in which bandpass filters always assumed 1D regressor files have exactly 5 header rows.
- Removed an erroneous connection to AFNI 3dTProject in nuisance denoising that would unnecessarily send a spike regressor as a censor. This would sometimes cause TRs to unnecessarily be dropped from the timeseries as if scrubbing were being performed.
- Supplied missing `subject_id` for longitudinal workflow logger and make that field optional for the logger.
- Lingering calls to `cpac_outputs.csv` (was changed to `cpac_outputs.tsv` in v1.8.1).
- A bug in the `freesurfer_abcd_preproc` nodeblock where the `Template` image was incorrectly used as `reference` during the `inverse_warp` step. Replacing it with the subject-specific `T1w` image resolved the issue of the `desc-restoreBrain_T1w` being chipped off.
- A bug in `ideal_bandpass` where the frequency mask was incorrectly applied, which caused filter to fail in certain cases.

### Removed

Expand Down
10 changes: 3 additions & 7 deletions CPAC/alff/alff.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2012-2024 C-PAC Developers
# Copyright (C) 2012-2025 C-PAC Developers

# This file is part of C-PAC.

Expand All @@ -23,9 +23,8 @@
from CPAC.alff.utils import get_opt_string
from CPAC.pipeline import nipype_pipeline_engine as pe
from CPAC.pipeline.nodeblock import nodeblock
from CPAC.registration.registration import apply_transform
from CPAC.registration.utils import apply_transform
from CPAC.utils.interfaces import Function
from CPAC.utils.utils import check_prov_for_regtool


def create_alff(wf_name="alff_workflow"):
Expand Down Expand Up @@ -320,10 +319,7 @@ def alff_falff(wf, cfg, strat_pool, pipe_num, opt=None):
def alff_falff_space_template(wf, cfg, strat_pool, pipe_num, opt=None):
outputs = {}
if strat_pool.check_rpool("desc-denoisedNofilt_bold"):
xfm_prov = strat_pool.get_cpac_provenance(
"from-bold_to-template_mode-image_xfm"
)
reg_tool = check_prov_for_regtool(xfm_prov)
reg_tool = strat_pool.reg_tool("from-bold_to-template_mode-image_xfm")

num_cpus = cfg.pipeline_setup["system_config"]["max_cores_per_participant"]

Expand Down
44 changes: 6 additions & 38 deletions CPAC/anat_preproc/anat_preproc.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
wb_command,
)
from CPAC.pipeline import nipype_pipeline_engine as pe
from CPAC.pipeline.nodeblock import nodeblock
from CPAC.pipeline.nodeblock import nodeblock, NODEBLOCK_RETURN
from CPAC.utils.interfaces import Function
from CPAC.utils.interfaces.fsl import Merge as fslMerge

Expand Down Expand Up @@ -1227,15 +1227,7 @@ def freesurfer_fsl_brain_connector(wf, cfg, strat_pool, pipe_num, opt):
wf.connect(node, out, convert_fs_T1_to_nifti, "in_file")

# 3dresample -orient RPI -inset brainmask.nii.gz -prefix brain_fs.nii.gz
reorient_fs_brainmask = pe.Node(
interface=afni.Resample(),
name=f"reorient_fs_brainmask_{node_id}",
mem_gb=0,
mem_x=(0.0115, "in_file", "t"),
)
reorient_fs_brainmask.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
reorient_fs_brainmask.inputs.outputtype = "NIFTI_GZ"

reorient_fs_brainmask = cfg.orientation_node(f"reorient_fs_brainmask_{node_id}")
wf.connect(
convert_fs_brainmask_to_nifti, "out_file", reorient_fs_brainmask, "in_file"
)
Expand All @@ -1249,15 +1241,7 @@ def freesurfer_fsl_brain_connector(wf, cfg, strat_pool, pipe_num, opt):
wf.connect(reorient_fs_brainmask, "out_file", binarize_fs_brain, "in_file")

# 3dresample -orient RPI -inset T1.nii.gz -prefix head_fs.nii.gz
reorient_fs_T1 = pe.Node(
interface=afni.Resample(),
name=f"reorient_fs_T1_{node_id}",
mem_gb=0,
mem_x=(0.0115, "in_file", "t"),
)
reorient_fs_T1.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
reorient_fs_T1.inputs.outputtype = "NIFTI_GZ"

reorient_fs_T1 = cfg.orientation_node(f"reorient_fs_T1_{node_id}")
wf.connect(convert_fs_T1_to_nifti, "out_file", reorient_fs_T1, "in_file")

# flirt -in head_fs.nii.gz -ref ${FSLDIR}/data/standard/MNI152_T1_1mm.nii.gz \
Expand Down Expand Up @@ -1447,22 +1431,14 @@ def mask_T2(wf_name="mask_T2"):
inputs=["T1w"],
outputs=["desc-preproc_T1w", "desc-reorient_T1w", "desc-head_T1w"],
)
def anatomical_init(wf, cfg, strat_pool, pipe_num, opt=None):
def anatomical_init(wf, cfg, strat_pool, pipe_num, opt=None) -> NODEBLOCK_RETURN:
anat_deoblique = pe.Node(interface=afni.Refit(), name=f"anat_deoblique_{pipe_num}")
anat_deoblique.inputs.deoblique = True

node, out = strat_pool.get_data("T1w")
wf.connect(node, out, anat_deoblique, "in_file")

anat_reorient = pe.Node(
interface=afni.Resample(),
name=f"anat_reorient_{pipe_num}",
mem_gb=0,
mem_x=(0.0115, "in_file", "t"),
)
anat_reorient.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
anat_reorient.inputs.outputtype = "NIFTI_GZ"

anat_reorient = cfg.orientation_node(f"anat_reorient_{pipe_num}")
wf.connect(anat_deoblique, "out_file", anat_reorient, "in_file")

outputs = {
Expand Down Expand Up @@ -2262,15 +2238,7 @@ def anatomical_init_T2(wf, cfg, strat_pool, pipe_num, opt=None):
node, out = strat_pool.get_data("T2w")
wf.connect(node, out, T2_deoblique, "in_file")

T2_reorient = pe.Node(
interface=afni.Resample(),
name=f"T2_reorient_{pipe_num}",
mem_gb=0,
mem_x=(0.0115, "in_file", "t"),
)
T2_reorient.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
T2_reorient.inputs.outputtype = "NIFTI_GZ"

T2_reorient = cfg.orientation_node(f"T2_reorient_{pipe_num}")
wf.connect(T2_deoblique, "out_file", T2_reorient, "in_file")

outputs = {
Expand Down
17 changes: 5 additions & 12 deletions CPAC/anat_preproc/lesion_preproc.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2019-2023 C-PAC Developers
# Copyright (C) 2019-2025 C-PAC Developers

# This file is part of C-PAC.

Expand All @@ -20,6 +20,7 @@

from CPAC.pipeline import nipype_pipeline_engine as pe
from CPAC.utils.interfaces import Function
from CPAC.utils.nifti_utils import orientation_node


def inverse_lesion(lesion_path):
Expand Down Expand Up @@ -126,18 +127,10 @@ def create_lesion_preproc(cfg=None, wf_name="lesion_preproc"):
preproc.connect(lesion_deoblique, "out_file", outputnode, "refit")

# Anatomical reorientation
lesion_reorient = pe.Node(
interface=afni.Resample(),
name="lesion_reorient",
mem_gb=0,
mem_x=(0.0115, "in_file", "t"),
node_name = "lesion_reorient"
lesion_reorient = (
cfg.orientation_node(node_name) if cfg else orientation_node(node_name, "RPI")
)

lesion_reorient.inputs.orientation = (
cfg.pipeline_setup["desired_orientation"] if cfg else "RPI"
)
lesion_reorient.inputs.outputtype = "NIFTI_GZ"

preproc.connect(lesion_deoblique, "out_file", lesion_reorient, "in_file")
preproc.connect(lesion_reorient, "out_file", outputnode, "reorient")

Expand Down
6 changes: 2 additions & 4 deletions CPAC/func_preproc/func_motion.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2012-2024 C-PAC Developers
# Copyright (C) 2012-2025 C-PAC Developers

# This file is part of C-PAC.

Expand Down Expand Up @@ -34,7 +34,6 @@
from CPAC.pipeline.nodeblock import nodeblock
from CPAC.pipeline.schema import valid_options
from CPAC.utils.interfaces.function import Function
from CPAC.utils.utils import check_prov_for_motion_tool


@nodeblock(
Expand Down Expand Up @@ -68,8 +67,7 @@
)
def calc_motion_stats(wf, cfg, strat_pool, pipe_num, opt=None):
"""Calculate motion statistics for motion parameters."""
motion_prov = strat_pool.get_cpac_provenance("desc-movementParameters_motion")
motion_correct_tool = check_prov_for_motion_tool(motion_prov)
motion_correct_tool = strat_pool.motion_tool("desc-movementParameters_motion")
coordinate_transformation = [
"filtered-coordinate-transformation",
"coordinate-transformation",
Expand Down
24 changes: 3 additions & 21 deletions CPAC/func_preproc/func_preproc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 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 @@ -718,16 +718,7 @@ def func_reorient(wf, cfg, strat_pool, pipe_num, opt=None):
node, out = strat_pool.get_data("bold")
wf.connect(node, out, func_deoblique, "in_file")

func_reorient = pe.Node(
interface=afni_utils.Resample(),
name=f"func_reorient_{pipe_num}",
mem_gb=0,
mem_x=(0.0115, "in_file", "t"),
)

func_reorient.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
func_reorient.inputs.outputtype = "NIFTI_GZ"

func_reorient = cfg.orientation_node(f"func_reorient_{pipe_num}")
wf.connect(func_deoblique, "out_file", func_reorient, "in_file")

outputs = {
Expand Down Expand Up @@ -1320,16 +1311,7 @@ def bold_mask_anatomical_refined(wf, cfg, strat_pool, pipe_num, opt=None):
node, out = strat_pool.get_data("bold")
wf.connect(node, out, func_deoblique, "in_file")

func_reorient = pe.Node(
interface=afni_utils.Resample(),
name=f"raw_func_reorient_{pipe_num}",
mem_gb=0,
mem_x=(0.0115, "in_file", "t"),
)

func_reorient.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
func_reorient.inputs.outputtype = "NIFTI_GZ"

func_reorient = cfg.orientation_node(f"raw_func_reorient_{pipe_num}")
wf.connect(func_deoblique, "out_file", func_reorient, "in_file")

wf.connect(func_reorient, "out_file", init_bold_mask, "inputspec.func")
Expand Down
1 change: 1 addition & 0 deletions CPAC/longitudinal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from CPAC.utils.docs import DOCS_URL_PREFIX

assert isinstance(__doc__, str)
__doc__ += f"""

See {DOCS_URL_PREFIX}/user/longitudinal
Expand Down
Loading