Skip to content

Commit 0803c27

Browse files
committed
Updated tests for newly added tools
1 parent 1996381 commit 0803c27

17 files changed

+244
-116
lines changed

public/cwl/amico/amico_noddi.cwl

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
11
#!/usr/bin/env cwl-runner
22

3-
# https://github.com/daducci/AMICO
3+
# https://github.com/cookpa/amico-noddi
44
# AMICO NODDI (Neurite Orientation Dispersion and Density Imaging) fitting
55
# Uses convex optimization for fast and robust estimation of NODDI parameters
66

77
cwlVersion: v1.2
88
class: CommandLineTool
9-
baseCommand: ['python3', '-c']
109

1110
hints:
1211
DockerRequirement:
13-
dockerPull: cookpa/amico-noddi:latest
12+
dockerPull: cookpa/amico-noddi:0.1.2
1413

1514
requirements:
1615
InitialWorkDirRequirement:
1716
listing:
1817
- entry: $(inputs.dwi)
1918
entryname: dwi.nii.gz
2019
- entry: $(inputs.bvals)
21-
entryname: bvals
20+
entryname: dwi.bval
2221
- entry: $(inputs.bvecs)
23-
entryname: bvecs
22+
entryname: dwi.bvec
2423
- entry: $(inputs.mask)
2524
entryname: mask.nii.gz
2625
InlineJavascriptRequirement: {}
@@ -29,18 +28,14 @@ stdout: amico_noddi.log
2928
stderr: amico_noddi.err.log
3029

3130
arguments:
32-
- position: 1
33-
valueFrom: |
34-
import amico
35-
import os
36-
amico.core.setup()
37-
ae = amico.Evaluation('.', '.')
38-
ae.load_data('dwi.nii.gz', 'bvals', 'bvecs', mask_filename='mask.nii.gz')
39-
ae.set_model('NODDI')
40-
ae.generate_kernels()
41-
ae.load_kernels()
42-
ae.fit()
43-
ae.save_results()
31+
- prefix: --dwi-root
32+
valueFrom: dwi
33+
- prefix: --brain-mask
34+
valueFrom: mask.nii.gz
35+
- prefix: --output-root
36+
valueFrom: output/NODDI
37+
- prefix: --work-dir
38+
valueFrom: /tmp/amico_work
4439

4540
inputs:
4641
dwi:
@@ -55,28 +50,51 @@ inputs:
5550
mask:
5651
type: File
5752
label: Brain mask image
53+
num_threads:
54+
type: ['null', int]
55+
label: Maximum number of CPU threads (default 1)
56+
inputBinding:
57+
prefix: --num-threads
58+
b0_threshold:
59+
type: ['null', int]
60+
label: Threshold for considering measurements b=0 (default 10)
61+
inputBinding:
62+
prefix: --b0-threshold
63+
csf_diffusivity:
64+
type: ['null', double]
65+
label: CSF diffusivity in mm^2/s (default 0.003)
66+
inputBinding:
67+
prefix: --csf-diffusivity
68+
parallel_diffusivity:
69+
type: ['null', double]
70+
label: Intracellular diffusivity parallel to neurites in mm^2/s (default 0.0017)
71+
inputBinding:
72+
prefix: --parallel-diffusivity
73+
ex_vivo:
74+
type: ['null', boolean]
75+
label: Use ex-vivo AMICO model
76+
inputBinding:
77+
prefix: --ex-vivo
78+
valueFrom: '$(self ? "1" : "0")'
5879

5980
outputs:
6081
ndi_map:
6182
type: File
6283
outputBinding:
6384
glob:
64-
- AMICO/NODDI/FIT_ICVF.nii.gz
65-
- FIT_ICVF.nii.gz
85+
- output/NODDI*ICVF.nii.gz
6686
label: Neurite Density Index (NDI/ICVF) map
6787
odi_map:
6888
type: File
6989
outputBinding:
7090
glob:
71-
- AMICO/NODDI/FIT_OD.nii.gz
72-
- FIT_OD.nii.gz
91+
- output/NODDI*OD.nii.gz
7392
label: Orientation Dispersion Index (ODI) map
7493
fiso_map:
7594
type: File
7695
outputBinding:
7796
glob:
78-
- AMICO/NODDI/FIT_ISOVF.nii.gz
79-
- FIT_ISOVF.nii.gz
97+
- output/NODDI*ISOVF.nii.gz
8098
label: Isotropic Volume Fraction (fISO) map
8199
log:
82100
type: File

public/cwl/fsl/applytopup.cwl

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ hints:
1111
DockerRequirement:
1212
dockerPull: brainlife/fsl:latest
1313

14+
requirements:
15+
InlineJavascriptRequirement: {}
16+
InitialWorkDirRequirement:
17+
listing:
18+
- entryname: $(inputs.topup_fieldcoef.basename)
19+
entry: $(inputs.topup_fieldcoef)
20+
- entryname: $(inputs.topup_movpar.basename)
21+
entry: $(inputs.topup_movpar)
22+
1423
stdout: applytopup.log
1524
stderr: applytopup.err.log
1625

@@ -21,12 +30,12 @@ inputs:
2130
inputBinding:
2231
prefix: --imain=
2332
separate: false
24-
topup_prefix:
25-
type: string
26-
label: Basename of the topup output (field coefficients)
27-
inputBinding:
28-
prefix: --topup=
29-
separate: false
33+
topup_fieldcoef:
34+
type: File
35+
label: Topup field coefficients file (_fieldcoef.nii.gz from topup)
36+
topup_movpar:
37+
type: File
38+
label: Topup movement parameters file (_movpar.txt from topup)
3039
encoding_file:
3140
type: File
3241
label: Acquisition parameters file (same as used for topup)
@@ -79,6 +88,11 @@ inputs:
7988
inputBinding:
8089
prefix: -v
8190

91+
arguments:
92+
- prefix: --topup=
93+
separate: false
94+
valueFrom: $(inputs.topup_fieldcoef.basename.replace(/_fieldcoef\.nii\.gz$|_fieldcoef\.nii$/, ''))
95+
8296
outputs:
8397
corrected_images:
8498
type: File

public/cwl/fsl/bianca.cwl

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@ baseCommand: 'bianca'
99

1010
hints:
1111
DockerRequirement:
12-
dockerPull: brainlife/fsl:latest
12+
dockerPull: brainlife/fsl:6.0.4-patched2
13+
14+
requirements:
15+
InlineJavascriptRequirement: {}
16+
InitialWorkDirRequirement:
17+
listing:
18+
- entry: $(inputs.training_data)
19+
writable: false
1320

1421
stdout: bianca.log
1522
stderr: bianca.err.log
@@ -21,6 +28,9 @@ inputs:
2128
inputBinding:
2229
prefix: --singlefile=
2330
separate: false
31+
training_data:
32+
type: Directory
33+
label: Directory containing all subject data files referenced in master file
2434
querysubjectnum:
2535
type: int
2636
label: Row number in master file for the subject to segment

public/cwl/fsl/fsl_prepare_fieldmap.cwl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ inputs:
4545
label: Suppress sanity checking of image size/range/dimensions
4646
inputBinding:
4747
prefix: --nocheck
48+
position: 6
4849

4950
outputs:
5051
fieldmap:

public/cwl/fsl/tbss_non_FA.cwl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ requirements:
2020
- entry: $(inputs.stats_directory)
2121
entryname: stats
2222
writable: true
23+
- entry: $(inputs.measure_directory)
24+
entryname: $(inputs.measure)
25+
writable: true
2326

2427
stdout: tbss_non_FA.log
2528
stderr: tbss_non_FA.err.log
@@ -32,10 +35,13 @@ inputs:
3235
position: 1
3336
fa_directory:
3437
type: Directory
35-
label: FA directory from TBSS pipeline
38+
label: FA directory from TBSS pipeline (contains per-subject FA images and warps)
3639
stats_directory:
3740
type: Directory
38-
label: stats directory containing all_<measure>.nii.gz
41+
label: stats directory (mean_FA_skeleton, skeleton_mask, all_FA, all_FA_skeletonised)
42+
measure_directory:
43+
type: Directory
44+
label: Directory containing per-subject non-FA images (filenames must match FA subjects without _FA suffix)
3945

4046
outputs:
4147
skeletonised_data:

public/cwl/toolMap.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4377,7 +4377,8 @@ export const TOOL_MAP = {
43774377
requiredInputs: {
43784378
measure: { type: 'string', label: 'Non-FA measure name (e.g., MD, AD, RD)' },
43794379
fa_directory: { type: 'Directory', passthrough: true, label: 'FA directory from TBSS pipeline' },
4380-
stats_directory: { type: 'Directory', label: 'Stats directory containing all_<measure>.nii.gz' }
4380+
stats_directory: { type: 'Directory', label: 'Stats directory (mean_FA_skeleton, skeleton_mask, all_FA, all_FA_skeletonised)' },
4381+
measure_directory: { type: 'Directory', label: 'Directory with per-subject non-FA images (names matching FA subjects without _FA suffix)' }
43814382
},
43824383

43834384
optionalInputs: {},
@@ -4399,7 +4400,8 @@ export const TOOL_MAP = {
43994400

44004401
requiredInputs: {
44014402
input: { type: 'File', passthrough: true, label: 'Input image(s) to correct', acceptedExtensions: ['.nii', '.nii.gz'] },
4402-
topup_prefix: { type: 'string', label: 'Basename of topup output (field coefficients)' },
4403+
topup_fieldcoef: { type: 'File', label: 'Topup field coefficients file (_fieldcoef.nii.gz)', acceptedExtensions: ['.nii', '.nii.gz'] },
4404+
topup_movpar: { type: 'File', label: 'Topup movement parameters file (_movpar.txt)', acceptedExtensions: ['.txt'] },
44034405
encoding_file: { type: 'File', label: 'Acquisition parameters file' },
44044406
inindex: { type: 'string', label: 'Comma-separated indices into encoding file' },
44054407
output: { type: 'string', label: 'Output basename for corrected images' }
@@ -4486,14 +4488,15 @@ export const TOOL_MAP = {
44864488

44874489
requiredInputs: {
44884490
singlefile: { type: 'File', passthrough: true, label: 'Master file listing subjects, images, masks, and transformations' },
4491+
training_data: { type: 'Directory', label: 'Directory containing all subject data files referenced in master file' },
44894492
querysubjectnum: { type: 'int', label: 'Row number for subject to segment' },
44904493
brainmaskfeaturenum: { type: 'int', label: 'Column number containing brain mask' },
44914494
labelfeaturenum: { type: 'int', label: 'Column number containing manual lesion mask' },
4492-
trainingnums: { type: 'string', label: 'Training subject row numbers (comma-separated or "all")' },
4493-
output_name: { type: 'string', label: 'Output file basename' }
4495+
trainingnums: { type: 'string', label: 'Training subject row numbers (comma-separated or "all")' }
44944496
},
44954497

44964498
optionalInputs: {
4499+
output_name: { type: 'string', label: 'Output file basename (default: bianca_output)' },
44974500
featuresubset: { type: 'string', label: 'Column numbers for intensity features (comma-separated)', flag: '--featuresubset' },
44984501
matfeaturenum: { type: 'int', label: 'Column number containing MNI transformation matrices', flag: '--matfeaturenum' },
44994502
spatialweight: { type: 'double', label: 'Weighting for MNI spatial coordinates (default 1)', flag: '--spatialweight' },
@@ -4732,12 +4735,18 @@ export const TOOL_MAP = {
47324735
mask: { type: 'File', label: 'Brain mask image', acceptedExtensions: ['.nii', '.nii.gz'] }
47334736
},
47344737

4735-
optionalInputs: {},
4738+
optionalInputs: {
4739+
num_threads: { type: 'int', label: 'Maximum number of CPU threads (default 1)' },
4740+
b0_threshold: { type: 'int', label: 'Threshold for considering measurements b=0 (default 10)' },
4741+
csf_diffusivity: { type: 'double', label: 'CSF diffusivity in mm^2/s (default 0.003)' },
4742+
parallel_diffusivity: { type: 'double', label: 'Intracellular diffusivity parallel to neurites in mm^2/s (default 0.0017)' },
4743+
ex_vivo: { type: 'boolean', label: 'Use ex-vivo AMICO model' }
4744+
},
47364745

47374746
outputs: {
4738-
ndi_map: { type: 'File', label: 'Neurite Density Index (NDI/ICVF) map', glob: ['AMICO/NODDI/FIT_ICVF.nii.gz', 'FIT_ICVF.nii.gz'] },
4739-
odi_map: { type: 'File', label: 'Orientation Dispersion Index (ODI) map', glob: ['AMICO/NODDI/FIT_OD.nii.gz', 'FIT_OD.nii.gz'] },
4740-
fiso_map: { type: 'File', label: 'Isotropic Volume Fraction (fISO) map', glob: ['AMICO/NODDI/FIT_ISOVF.nii.gz', 'FIT_ISOVF.nii.gz'] },
4747+
ndi_map: { type: 'File', label: 'Neurite Density Index (NDI/ICVF) map', glob: ['output/NODDI*ICVF.nii.gz'] },
4748+
odi_map: { type: 'File', label: 'Orientation Dispersion Index (ODI) map', glob: ['output/NODDI*OD.nii.gz'] },
4749+
fiso_map: { type: 'File', label: 'Isotropic Volume Fraction (fISO) map', glob: ['output/NODDI*ISOVF.nii.gz'] },
47414750
log: { type: 'File', label: 'Log file', glob: ['amico_noddi.log'] },
47424751
err_log: { type: 'File', label: 'Error log file', glob: ['amico_noddi.err.log'] }
47434752
}

utils/amico_tests/_common.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
# Source this file at the top of every test_*.sh script.
44

55
# Chain to the structural MRI common infrastructure
6-
source "$(cd "$(dirname "${BASH_SOURCE[1]:-${BASH_SOURCE[0]}"}")/../structural_mri_tests" && pwd)/_common.sh"
6+
source "$(cd "$(dirname "${BASH_SOURCE[1]:-${BASH_SOURCE[0]}}")"/../structural_mri_tests && pwd)/_common.sh"
77

88
# Docker image
9-
AMICO_IMAGE="${AMICO_DOCKER_IMAGE:-cookpa/amico-noddi:latest}"
9+
AMICO_IMAGE="${AMICO_DOCKER_IMAGE:-cookpa/amico-noddi:0.1.2}"
1010

1111
docker_amico() {
1212
_docker_run "$AMICO_IMAGE" "$@"

utils/amico_tests/test_amico_noddi.sh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ EOF
3131
run_tool "$TOOL" "${JOB_DIR}/${TOOL}.yml" "$CWL"
3232

3333
# ── Verify outputs ─────────────────────────────────────────────
34+
# AMICO output naming uses 'x' separator: NODDIFITxICVF.nii.gz
3435
dir="${OUT_DIR}/${TOOL}"
35-
expected_outputs=("FIT_ICVF.nii.gz" "FIT_OD.nii.gz" "FIT_ISOVF.nii.gz")
36+
expected_patterns=("NODDI*ICVF.nii.gz" "NODDI*OD.nii.gz" "NODDI*ISOVF.nii.gz")
3637

37-
for expected in "${expected_outputs[@]}"; do
38-
# Check in both AMICO/NODDI/ subdirectory and top-level
38+
for pattern in "${expected_patterns[@]}"; do
3939
found_file=""
40-
for candidate in "${dir}/AMICO/NODDI/${expected}" "${dir}/${expected}"; do
40+
for candidate in "${dir}"/${pattern} "${dir}"/output/${pattern}; do
4141
if [[ -f "$candidate" ]]; then
4242
found_file="$candidate"
4343
break
@@ -48,8 +48,8 @@ for expected in "${expected_outputs[@]}"; do
4848
if [[ ! -s "$found_file" ]]; then
4949
echo " FAIL: zero-byte output: $found_file"; exit 1
5050
fi
51-
echo " OK: ${expected} ($(wc -c < "$found_file") bytes)"
51+
echo " OK: $(basename "$found_file") ($(wc -c < "$found_file") bytes)"
5252
else
53-
echo " WARN: ${expected} not found"
53+
echo " WARN: ${pattern} not found"
5454
fi
5555
done

0 commit comments

Comments
 (0)