Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ These are the most common things requested on pull requests (PRs).

Remember that PRs should be made against the dev branch, unless you're preparing a pipeline release.

Learn more about contributing: [CONTRIBUTING.md](https://github.com/scilus/sf-pediatric/tree/master/.github/CONTRIBUTING.md)
Learn more about contributing: [CONTRIBUTING.md](https://github.com/scilus/sf-pediatric/blob/master/docs/CONTRIBUTING.md)

-->

## PR checklist

- [ ] This comment contains a description of changes (with reason).
- [ ] If you've fixed a bug or added code that should be tested, add tests!
- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/scilus/sf-pediatric/tree/master/.github/CONTRIBUTING.md)
- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/scilus/sf-pediatric/blob/master/docs/CONTRIBUTING.md)
- [ ] Make sure your code lints (`nf-core pipelines lint`).
- [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir <OUTDIR>`).
- [ ] Ensure the test suite passes (`nf-test test tests/<profile>.nf.test --profile=+docker`).
- [ ] Check for unexpected warnings in debug mode (`nextflow run . -profile debug,test,docker --outdir <OUTDIR>`).
- [ ] [Documentation](https://github.com/scilus/sf-pediatric-documentation) has been updated according to your changes
- [ ] `CHANGELOG.md` is updated.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.1] - [Unreleased]
## [0.3.1] - [2026-11-06]

### `Added`

- Support for subject-level `*_sessions.tsv` files ([#131](https://github.com/scilus/sf-pediatric/pull/133))

### `Fixed`

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Visit our documentation at https://scilus.github.io/sf-pediatric/ for detailed i

## Contributions and Support

Contributions welcome! See our [contributing guidelines](.github/CONTRIBUTING.md).
Contributions welcome! See our [contributing guidelines](docs/CONTRIBUTING.md).

**sf-pediatric** was originally written by Anthony Gagnon.

Expand Down
2 changes: 1 addition & 1 deletion assets/multiqc_config.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
report_comment: >
This report has been generated by the <a href="https://github.com/scilus/sf-pediatric/releases/tag/0.3.0" target="_blank">scilus/sf-pediatric</a> analysis pipeline.
This report has been generated by the <a href="https://github.com/scilus/sf-pediatric/releases/tag/0.3.1" target="_blank">scilus/sf-pediatric</a> analysis pipeline.

report_section_order:
"sf-pediatric-methods-description":
Expand Down
2 changes: 1 addition & 1 deletion assets/multiqc_config_global.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
report_comment: >
This report has been generated by the <a href="https://github.com/scilus/sf-pediatric/releases/tag/0.3.0" target="_blank">scilus/sf-pediatric</a> analysis pipeline.
This report has been generated by the <a href="https://github.com/scilus/sf-pediatric/releases/tag/0.3.1" target="_blank">scilus/sf-pediatric</a> analysis pipeline.

report_section_order:
"sf-pediatric-methods-description":
Expand Down
165 changes: 58 additions & 107 deletions docs/CONTRIBUTING.md

Large diffs are not rendered by default.

85 changes: 42 additions & 43 deletions ro-crate-metadata.json

Large diffs are not rendered by default.

57 changes: 50 additions & 7 deletions subworkflows/local/utils_nfcore_sf_pediatric_pipeline/main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,17 @@ workflow PIPELINE_INITIALISATION {
// Create channel from input file provided through params.input using nf-bids plugin
//
if ( input_bids ) {
// Copy to preserve the value of input_bids for the sessions.tsv file.
def bids_path = input_bids

// ** To support comma separated participant labels and list ** //
def participant_ids = params.participant_label ?
params.participant_label instanceof String ?
params.participant_label.tokenize(",") :
params.participant_label : []

ch_inputs = channel.fromBIDS(
input_bids,
bids_path,
"$projectDir/assets/nf-bids_config.yml",
[flatten_output: true,
unpack_json_sidecar: true]
Expand All @@ -131,20 +134,60 @@ workflow PIPELINE_INITIALISATION {
def id = item.meta.subject
def ses = item.meta.session == "NA" ? null : item.meta.session

// ** Instantiate a variable that will collect prints related to BIDS file matching ** //
// ** to be printed in a log file later ** //
def logs = []

// Look for a *sessions.tsv file to get the age per session if available.
def sessions_files = files("${bids_path}/${id}/*sessions.tsv")
def age = null

if ( sessions_files && ses ) {
def log = null
def lines = sessions_files[0].readLines().findAll { line -> line.trim() }
def header = lines[0].split("\t") as List
def ses_idx = header.indexOf("session_id")
def age_idx = header.indexOf("age")

// Find the age for the current session.
if ( ses_idx < 0 || age_idx < 0 ) {
log = "[${id}${ses ? "/" + ses : ""}] Missing 'session_id' or 'age' column in sessions.tsv file. Please validate."
} else {
def row = lines.drop(1)
.collect { line -> line.split("\t", -1) }
.find { cols -> cols[ses_idx] == ses.toString() || cols[ses_idx] == ses.toString().replaceAll("ses-", "") }
def value = row ? row[age_idx]?.trim() : null

if ( !row ) {
log = "[${id}${ses ? "/" + ses : ""}] No row found for session ${ses} in sessions.tsv file. Please validate."
} else if ( value && value.isNumber() ) {
age = value.toFloat()
} else {
log = "[${id}${ses ? "/" + ses : ""}] Invalid age value '${value}' for session ${ses} in sessions.tsv file. Please validate."
}

if ( log ) {
logs << log
}
}

// Copy the sessions.tsv file to the output directory.
sessions_files[0].copyTo(file("$outdir/${id}/${id}_sessions.tsv"))
}

// Age is already fetched from the participants.tsv file, flag subjects with missing age and exit.
def age = item.meta.age ? item.meta.age.toFloat() : 0.0
if ( age == 0.0 ) {
if ( age == null ) {
age = item.meta.age ? item.meta.age.toFloat() : null
}
if ( age == null ) {
error "ERROR: Age not found for participant ${id}${ses ? " and session " + ses : ""} in participants.tsv file. Please validate."
}

// Temp age in years for priors prediction (only if data is over 25, as we assume it is gestational age).
// ** Setting to a minimum of 0.04 (~ 2 weeks) to avoid negative values for the priors prediction ** //
age = age.toFloat() > 25 ? Math.max(Math.abs((age.toFloat() - 40) / 52), 0.04) : age.toFloat()
def priors = fetchPriors(age)

// ** Instantiate a variable that will collect prints related to BIDS file matching ** //
// ** to be printed in a log file later ** //
def logs = []

// DWI and associated files
def dwi = item.dwi?.nii ?: []
def dwi_json = item.dwi?.json ?: []
Expand Down
4 changes: 4 additions & 0 deletions tests/chained.nf.test.snap
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,7 @@
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-MNIInfant_mode-image_desc-warp_xfm.nii.gz",
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-T1w_mode-image_desc-affine_xfm.mat",
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-T1w_mode-image_desc-warp_xfm.nii.gz",
"sub-test1/sub-test1_sessions.tsv",
"sub-test2",
"sub-test2/anat",
"sub-test2/anat/sub-test2_run-01_seg-BrainnetomeChild_desc-labels_dseg.tsv",
Expand Down Expand Up @@ -1666,6 +1667,7 @@
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-T2w_to-T1w_mode-image_desc-affine_xfm.mat",
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-T1w_mode-image_desc-affine_xfm.mat",
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-T1w_mode-image_desc-warp_xfm.nii.gz",
"sub-test1/sub-test1_sessions.tsv",
"sub-test2",
"sub-test2/anat",
"sub-test2/anat/sub-test2_run-01_space-DWI_desc-preproc_T2w.json",
Expand Down Expand Up @@ -2313,6 +2315,7 @@
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-T2w_to-T1w_mode-image_desc-affine_xfm.mat",
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-T1w_mode-image_desc-affine_xfm.mat",
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-T1w_mode-image_desc-warp_xfm.nii.gz",
"sub-test1/sub-test1_sessions.tsv",
"sub-test2",
"sub-test2/anat",
"sub-test2/anat/sub-test2_run-01_space-DWI_desc-preproc_T2w.json",
Expand Down Expand Up @@ -2681,6 +2684,7 @@
"sub-test1/ses-time1/multiqc/sub-test1_multiqc_data",
"sub-test1/ses-time1/multiqc/sub-test1_multiqc_plots",
"sub-test1/ses-time1/multiqc/sub-test1_multiqc_report.html",
"sub-test1/sub-test1_sessions.tsv",
"sub-test3",
"sub-test3/anat",
"sub-test3/anat/sub-test3_seg-BrainnetomeChild_desc-labels_dseg.tsv",
Expand Down
2 changes: 0 additions & 2 deletions tests/data/bids/participants.tsv
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
participant_id session_id age
sub-test1 ses-baseline 43
sub-test1 ses-time1 4
sub-test2 1
sub-test3 2
sub-test4 8
3 changes: 3 additions & 0 deletions tests/data/bids/sub-test1/sub-test1_sessions.tsv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
session_id age
ses-baseline 43
ses-time1 4
1 change: 1 addition & 0 deletions tests/segmentation.nf.test.snap
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"sub-test1/ses-time1/multiqc/sub-test1_multiqc_data",
"sub-test1/ses-time1/multiqc/sub-test1_multiqc_plots",
"sub-test1/ses-time1/multiqc/sub-test1_multiqc_report.html",
"sub-test1/sub-test1_sessions.tsv",
"sub-test3",
"sub-test3/anat",
"sub-test3/anat/sub-test3_seg-BrainnetomeChild_desc-labels_dseg.tsv",
Expand Down
10 changes: 6 additions & 4 deletions tests/tracking.nf.test.snap
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-T2w_to-T1w_mode-image_desc-affine_xfm.mat",
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-T1w_mode-image_desc-affine_xfm.mat",
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-T1w_mode-image_desc-warp_xfm.nii.gz",
"sub-test1/sub-test1_sessions.tsv",
"sub-test2",
"sub-test2/anat",
"sub-test2/anat/sub-test2_run-01_space-DWI_desc-preproc_T2w.json",
Expand Down Expand Up @@ -833,10 +834,10 @@
"sub-test4/xfm/sub-test4_from-dwi_to-T1w_mode-image_desc-warp_xfm.nii.gz"
]
],
"timestamp": "2026-07-13T16:17:52.707781",
"timestamp": "2026-11-06T09:32:37.994202",
"meta": {
"nf-test": "0.9.5",
"nextflow": "26.04.4"
"nextflow": "26.04.6"
}
},
"Tracking profile no dwi preprocessing - should run successfully": {
Expand Down Expand Up @@ -1135,6 +1136,7 @@
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-T2w_to-T1w_mode-image_desc-affine_xfm.mat",
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-T1w_mode-image_desc-affine_xfm.mat",
"sub-test1/ses-time1/xfm/sub-test1_ses-time1_from-dwi_to-T1w_mode-image_desc-warp_xfm.nii.gz",
"sub-test1/sub-test1_sessions.tsv",
"sub-test2",
"sub-test2/anat",
"sub-test2/anat/sub-test2_run-01_space-DWI_desc-preproc_T2w.json",
Expand Down Expand Up @@ -1480,10 +1482,10 @@
"sub-test4/xfm/sub-test4_from-dwi_to-T1w_mode-image_desc-warp_xfm.nii.gz"
]
],
"timestamp": "2026-07-13T16:28:24.606351",
"timestamp": "2026-11-06T09:47:05.660257",
"meta": {
"nf-test": "0.9.5",
"nextflow": "26.04.4"
"nextflow": "26.04.6"
}
}
}
Loading