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

[WIP] add module decompose connectivity #86

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions modules/nf-neuro/connectivity/decompose/environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
channels: []
dependencies: []
name: connectivity_decompose
63 changes: 63 additions & 0 deletions modules/nf-neuro/connectivity/decompose/main.nf
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
process CONNECTIVITY_DECOMPOSE {
tag "$meta.id"
label 'process_high'

container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ?
'scil.usherbrooke.ca/containers/scilus_2.0.2.sif':
'scilus/scilus:2.0.2' }"

input:
tuple val(meta), path(trk), path(labels)

output:
tuple val(meta), path("*__decomposed.h5") , emit: hdf5
tuple val(meta), path("*__labels_list.txt") , emit: labels_list
path "versions.yml" , emit: versions

when:
task.ext.when == null || task.ext.when

script:
def prefix = task.ext.prefix ?: "${meta.id}"
def no_pruning = task.ext.no_pruning ? "--no_pruning" : ""
def no_remove_loops = task.ext.no_remove_loops ? "--no_remove_loops" : ""
def no_remove_outliers = task.ext.no_remove_outliers ? "--no_remove_outliers" : ""
def no_remove_curv = task.ext.no_remove_curv ? "--no_remove_curv" : ""

def min_len = task.ext.min_len ? "--min_len " + task.ext.min_len : ""
def max_len = task.ext.max_len ? "--max_len " + task.ext.max_len : ""
def outlier_threshold = task.ext.outlier_threshold ? "--outlier_threshold " + task.ext.outlier_threshold : ""
def max_angle = task.ext.max_angle ? "--loop_max_angle " + task.ext.max_angle : ""
def max_curv = task.ext.max_curv ? "--curv_qb_distance " + task.ext.max_curv : ""

"""

scil_decompose_connectivity.py $trk $labels \
"${prefix}__decomposed.h5" --processes $task.cpus \
--out_labels_list "${prefix}__labels_list.txt" \
$no_pruning $no_remove_loops $no_remove_outliers \
$no_remove_curv $min_len $max_len $outlier_threshold \
$max_angle $max_curv


cat <<-END_VERSIONS > versions.yml
"${task.process}":
scilpy: \$(pip list | grep scilpy | tr -s ' ' | cut -d' ' -f2)
END_VERSIONS
"""

stub:
def prefix = task.ext.prefix ?: "${meta.id}"

"""
touch ${prefix}__decomposed.h5
touch ${prefix}__labels_list.txt

scil_decompose_connectivity.py -h

cat <<-END_VERSIONS > versions.yml
"${task.process}":
scilpy: \$(pip list | grep scilpy | tr -s ' ' | cut -d' ' -f2)
END_VERSIONS
"""
}
61 changes: 61 additions & 0 deletions modules/nf-neuro/connectivity/decompose/meta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
name: "connectivity_decompose"
description: Divide a tractogram into its various connections using a brain parcellation(labels).
The hdf5 output format allows to store other information required for connectivity, such as the associated labels.
keywords:
- nifti
- connectivity
- decompose
- scilpy
tools:
- "scilpy":
description: "The Sherbrooke Connectivity Imaging Lab (SCIL) Python dMRI processing toolbox."
homepage: "https://github.com/scilus/scilpy.git"

input:
- meta:
type: map
description: |
Groovy Map containing sample information
e.g. `[ id:'sample1', single_end:false ]`

- trk:
type: file
description: Tractogram to decompose.
pattern: "*.{trk, tck, vtk, fib, dpy}"

- labels:
type: file
description: brain parcellation. Labels must have 0 as background. Volumes must have isotropic voxels.
pattern: "*.nii.gz"

output:
- meta:
type: map
description: |
Groovy Map containing sample information
e.g. `[ id:'sample1', single_end:false ]`

- hdf5:
type: file
description: |
Output hdf5 file where each bundles is a group with key'LABEL1_LABEL2'.
The array_sequence format cannot be stored directly in a hdf5, so each
group is composed of 'data', 'offsets' and 'lengths' from the array
sequence. The 'data' is stored in VOX/CORNER for simplicity and efficiency.
pattern: "*__decomposed.h5"

- labels_list:
type: file
description: Save the labels list as text file.
pattern: "*__labels_list.txt"

- versions:
type: file
description: File containing software versions
pattern: "versions.yml"

authors:
- "@ThoumyreStanislas"
maintainers:
- "@ThoumyreStanislas"
93 changes: 93 additions & 0 deletions modules/nf-neuro/connectivity/decompose/tests/main.nf.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
nextflow_process {

name "Test Process CONNECTIVITY_DECOMPOSE"
script "../main.nf"
process "CONNECTIVITY_DECOMPOSE"

tag "modules"
tag "modules_nfcore"
tag "connectivity"
tag "connectivity/decompose"

tag "subworkflows/load_test_data"

setup {
run("LOAD_TEST_DATA", alias: "LOAD_DATA") {
script "../../../../../subworkflows/nf-neuro/load_test_data/main.nf"
process {
"""
input[0] = Channel.from( [ "connectivity.zip" ] )
input[1] = "test.load-test-data"
"""
}
}
}

test("connectivity - decompose - without option") {
when {
process {
"""
input[0] = LOAD_DATA.out.test_data_directory.map{
test_data_directory -> [
[ id:'test', single_end:false ], // meta map
file("\${test_data_directory}/bundle_all_1mm.trk", checkIfExists: true),
file("\${test_data_directory}/endpoints_atlas.nii.gz", checkIfExists: true)
]
}
"""
}
}
then {
assertAll(
{ assert process.success },
{ assert snapshot(process.out).match() }
)
}
}

test("connectivity - decompose - with all option") {
config "./nextflow.config"
when {
process {
"""
input[0] = LOAD_DATA.out.test_data_directory.map{
test_data_directory -> [
[ id:'test', single_end:false ], // meta map
file("\${test_data_directory}/bundle_all_1mm.trk", checkIfExists: true),
file("\${test_data_directory}/endpoints_atlas.nii.gz", checkIfExists: true)
]
}
"""
}
}
then {
assertAll(
{ assert process.success },
{ assert snapshot(process.out).match() }
)
}
}
ThoumyreStanislas marked this conversation as resolved.
Show resolved Hide resolved

test("connectivity - visualisation - stub-run") {
options "-stub-run"
when {
process {
"""
input[0] = LOAD_DATA.out.test_data_directory.map{
test_data_directory -> [
[ id:'test', single_end:false ], // meta map
file("\${test_data_directory}/bundle_all_1mm.trk", checkIfExists: true),
file("\${test_data_directory}/endpoints_atlas.nii.gz", checkIfExists: true)
]
}
"""
}
}
then {
assertAll(
{ assert process.success },
{ assert snapshot(process.out.versions).match() }
)
}
}
}
120 changes: 120 additions & 0 deletions modules/nf-neuro/connectivity/decompose/tests/main.nf.test.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{
"connectivity - decompose - without option": {
"content": [
{
"0": [
[
{
"id": "test",
"single_end": false
},
"test__decomposed.h5:md5,90ff9ae7ceb1371349231f85b616874e"
]
],
"1": [
[
{
"id": "test",
"single_end": false
},
"test__labels_list.txt:md5,3b0332e02daabf31651a5a0d81ba830a"
]
],
"2": [
"versions.yml:md5,ca6d20bf86c1e32c1bccea5813810f02"
],
"hdf5": [
[
{
"id": "test",
"single_end": false
},
"test__decomposed.h5:md5,90ff9ae7ceb1371349231f85b616874e"
]
],
"labels_list": [
[
{
"id": "test",
"single_end": false
},
"test__labels_list.txt:md5,3b0332e02daabf31651a5a0d81ba830a"
]
],
"versions": [
"versions.yml:md5,ca6d20bf86c1e32c1bccea5813810f02"
]
}
],
"meta": {
"nf-test": "0.9.0",
"nextflow": "24.10.3"
},
"timestamp": "2025-01-16T12:03:16.31875384"
},
"connectivity - visualisation - stub-run": {
"content": [
[
"versions.yml:md5,ca6d20bf86c1e32c1bccea5813810f02"
]
],
"meta": {
"nf-test": "0.9.0",
"nextflow": "24.10.3"
},
"timestamp": "2025-01-16T12:03:27.09566413"
},
"connectivity - decompose - with all option": {
"content": [
{
"0": [
[
{
"id": "test",
"single_end": false
},
"test__decomposed.h5:md5,5660bb84f333b6586ed247c6b95f6a98"
]
],
"1": [
[
{
"id": "test",
"single_end": false
},
"test__labels_list.txt:md5,3b0332e02daabf31651a5a0d81ba830a"
]
],
"2": [
"versions.yml:md5,ca6d20bf86c1e32c1bccea5813810f02"
],
"hdf5": [
[
{
"id": "test",
"single_end": false
},
"test__decomposed.h5:md5,5660bb84f333b6586ed247c6b95f6a98"
]
],
"labels_list": [
[
{
"id": "test",
"single_end": false
},
"test__labels_list.txt:md5,3b0332e02daabf31651a5a0d81ba830a"
]
],
"versions": [
"versions.yml:md5,ca6d20bf86c1e32c1bccea5813810f02"
]
}
],
"meta": {
"nf-test": "0.9.0",
"nextflow": "24.10.3"
},
"timestamp": "2025-01-16T12:03:21.738887954"
}
}
13 changes: 13 additions & 0 deletions modules/nf-neuro/connectivity/decompose/tests/nextflow.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
process {
withName: "CONNECTIVITY_DECOMPOSE" {
ext.no_pruning = true
ext.no_remove_loops = true
ext.no_remove_outliers = true
ext.no_remove_curv = true
ext.min_len = 20.0
ext.max_len = 200.0
ext.outlier_threshold = 0.6
ext.max_angle = 330.0
ext.max_curv = 10.0
}
}
2 changes: 2 additions & 0 deletions modules/nf-neuro/connectivity/decompose/tests/tags.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
connectivity/decompose:
- "modules/nf-neuro/connectivity/decompose/**"
Loading