diff --git a/subworkflows/nf-neuro/preproc_dwi/main.nf b/subworkflows/nf-neuro/preproc_dwi/main.nf index 959434e1..f16e2a36 100644 --- a/subworkflows/nf-neuro/preproc_dwi/main.nf +++ b/subworkflows/nf-neuro/preproc_dwi/main.nf @@ -14,41 +14,55 @@ include { TOPUP_EDDY } from '../topup_eddy/main' workflow PREPROC_DWI { take: - ch_dwi // channel: [ val(meta), [ dwi, bval, bvec ] ] - ch_rev_dwi // channel: [ val(meta), [ rev_dwi, bval, bvec ] ], optional - ch_b0 // Channel: [ val(meta), [ b0 ] ], optional - ch_rev_b0 // channel: [ val(meta), [ reverse b0 ] ], optional - ch_config_topup // channel: [ 'config_topup' ], optional + ch_dwi // channel: [ val(meta), dwi, bval, bvec ] + ch_rev_dwi // channel: [ val(meta), rev-dwi, bval, bvec ], optional + ch_b0 // Channel: [ val(meta), b0 ], optional + ch_rev_b0 // channel: [ val(meta), rev-b0 ], optional + ch_config_topup // channel: [ 'topup.cnf' ], optional main: ch_versions = Channel.empty() - ch_denoise_dwi = ch_dwi + ch_dwi_bvalbvec = ch_dwi .multiMap { meta, dwi, bval, bvec -> dwi: [ meta, dwi ] bvs_files: [ meta, bval, bvec ] } - // ** Denoised DWI ** // - DENOISE_DWI ( ch_denoise_dwi.dwi.map{ it + [[]] } ) - ch_versions = ch_versions.mix(DENOISE_DWI.out.versions.first()) - - ch_denoise_rev_dwi = ch_rev_dwi + ch_rev_dwi_bvalbvec = ch_rev_dwi .multiMap { meta, dwi, bval, bvec -> - rev_dwi: [ [id: "${meta.id}_rev", cache: meta], dwi ] + rev_dwi: [ meta, dwi ] rev_bvs_files: [ meta, bval, bvec ] } - DENOISE_REVDWI ( ch_denoise_rev_dwi.rev_dwi.map{ it + [[]] } ) + // ** Denoise DWI ** // + ch_denoise_dwi = ch_dwi_bvalbvec.dwi + .map{ it + [[]] } + + DENOISE_DWI ( ch_denoise_dwi ) + ch_versions = ch_versions.mix(DENOISE_DWI.out.versions.first()) + + // ** Denoise REV-DWI ** // + // Need to append "rev" to the ID, to ensure output filenames + // are different from the DWI and prevent file collisions + // - "cache: meta" is used to save the "real" metadata with valid ID for + // join operations, so it can be recovered after execution + ch_denoise_rev_dwi = ch_rev_dwi_bvalbvec.rev_dwi + .map{ meta, dwi -> [ [id: "${meta.id}_rev", cache: meta], dwi, [] ] } + + DENOISE_REVDWI ( ch_denoise_rev_dwi ) ch_versions = ch_versions.mix(DENOISE_REVDWI.out.versions.first()) + // ** Eddy Topup ** // + ch_topup_eddy_dwi = DENOISE_DWI.out.image + .join(ch_dwi_bvalbvec.bvs_files) + + // Recover the "real" ID from "meta[cache]" (see above), to join with the bval/bvec ch_topup_eddy_rev_dwi = DENOISE_REVDWI.out.image .map{ meta, dwi -> [ meta.cache, dwi ] } - .join(ch_denoise_rev_dwi.rev_bvs_files) + .join(ch_rev_dwi_bvalbvec.rev_bvs_files) - // ** Eddy Topup ** // - ch_topup_eddy_dwi = DENOISE_DWI.out.image.join(ch_denoise_dwi.bvs_files) TOPUP_EDDY ( ch_topup_eddy_dwi, ch_b0, ch_topup_eddy_rev_dwi, ch_rev_b0, ch_config_topup ) ch_versions = ch_versions.mix(TOPUP_EDDY.out.versions.first()) @@ -56,12 +70,14 @@ workflow PREPROC_DWI { ch_betcrop_dwi = TOPUP_EDDY.out.dwi .join(TOPUP_EDDY.out.bval) .join(TOPUP_EDDY.out.bvec) + BETCROP_FSLBETCROP ( ch_betcrop_dwi ) ch_versions = ch_versions.mix(BETCROP_FSLBETCROP.out.versions.first()) // ** Crop b0 ** // ch_crop_b0 = TOPUP_EDDY.out.b0 .join(BETCROP_FSLBETCROP.out.bbox) + BETCROP_CROPVOLUME ( ch_crop_b0 ) ch_versions = ch_versions.mix(BETCROP_CROPVOLUME.out.versions.first()) @@ -69,6 +85,7 @@ workflow PREPROC_DWI { ch_N4 = BETCROP_FSLBETCROP.out.image .join(BETCROP_CROPVOLUME.out.image) .join(BETCROP_FSLBETCROP.out.mask) + N4_DWI ( ch_N4 ) ch_versions = ch_versions.mix(N4_DWI.out.versions.first()) @@ -77,11 +94,14 @@ workflow PREPROC_DWI { .join(TOPUP_EDDY.out.bval) .join(TOPUP_EDDY.out.bvec) .join(BETCROP_FSLBETCROP.out.mask) + NORMALIZE_DWI ( ch_normalize ) ch_versions = ch_versions.mix(NORMALIZE_DWI.out.versions.first()) // ** Resample DWI ** // - ch_resample_dwi = NORMALIZE_DWI.out.dwi.map{ it + [[]] } + ch_resample_dwi = NORMALIZE_DWI.out.dwi + .map{ it + [[]] } + RESAMPLE_DWI ( ch_resample_dwi ) ch_versions = ch_versions.mix(RESAMPLE_DWI.out.versions.first()) @@ -94,18 +114,20 @@ workflow PREPROC_DWI { ch_versions = ch_versions.mix(EXTRACTB0_RESAMPLE.out.versions.first()) // ** Resample mask ** // - ch_resample_mask = BETCROP_FSLBETCROP.out.mask.map{ it + [[]] } + ch_resample_mask = BETCROP_FSLBETCROP.out.mask + .map{ it + [[]] } + RESAMPLE_MASK ( ch_resample_mask ) ch_versions = ch_versions.mix(RESAMPLE_MASK.out.versions.first()) emit: - dwi_resample = RESAMPLE_DWI.out.image // channel: [ val(meta), [ dwi_resample ] ] - bval = TOPUP_EDDY.out.bval // channel: [ val(meta), [ bval_corrected ] ] - bvec = TOPUP_EDDY.out.bvec // channel: [ val(meta), [ bvec_corrected ] ] - b0 = EXTRACTB0_RESAMPLE.out.b0 // channel: [ val(meta), [ b0 ] ] - b0_mask = RESAMPLE_MASK.out.image // channel: [ val(meta), [ b0_mask ] ] - dwi_bounding_box = BETCROP_FSLBETCROP.out.bbox // channel: [ val(meta), [ dwi_bounding_box ] ] - dwi_topup_eddy = TOPUP_EDDY.out.dwi // channel: [ val(meta), [ dwi_topup_eddy ] ] - dwi_n4 = N4_DWI.out.image // channel: [ val(meta), [ dwi_n4 ] ] - versions = ch_versions // channel: [ versions.yml ] + dwi_resample = RESAMPLE_DWI.out.image // channel: [ val(meta), dwi-resampled ] + bval = TOPUP_EDDY.out.bval // channel: [ val(meta), bval-corrected ] + bvec = TOPUP_EDDY.out.bvec // channel: [ val(meta), bvec-corrected ] + b0 = EXTRACTB0_RESAMPLE.out.b0 // channel: [ val(meta), b0-resampled ] + b0_mask = RESAMPLE_MASK.out.image // channel: [ val(meta), b0-mask ] + dwi_bounding_box = BETCROP_FSLBETCROP.out.bbox // channel: [ val(meta), dwi-bounding-box ] + dwi_topup_eddy = TOPUP_EDDY.out.dwi // channel: [ val(meta), dwi-after-topup-eddy ] + dwi_n4 = N4_DWI.out.image // channel: [ val(meta), dwi-after-n4 ] + versions = ch_versions // channel: [ versions.yml ] } diff --git a/subworkflows/nf-neuro/topup_eddy/main.nf b/subworkflows/nf-neuro/topup_eddy/main.nf index 57248a9d..8c3a9588 100644 --- a/subworkflows/nf-neuro/topup_eddy/main.nf +++ b/subworkflows/nf-neuro/topup_eddy/main.nf @@ -9,25 +9,26 @@ workflow TOPUP_EDDY { // ** In both cases, it will perform EDDY and also extract a b0 from the corrected DWI image. ** // take: - ch_dwi // channel: [ val(meta), [ dwi, bval, bvec ] - ch_b0 // channel: [ val(meta), b0 ] - ch_rev_dwi // channel: [ val(meta), [ rev_dwi, rev_bval, rev_bvec ] - ch_rev_b0 // channel: [ val(meta), rev_b0 ] - ch_config_topup // channel + ch_dwi // channel: [ val(meta), dwi, bval, bvec ] + ch_b0 // channel: [ val(meta), b0 ], optional + ch_rev_dwi // channel: [ val(meta), rev-dwi, rev-bval, rev-bvec ], optional + ch_rev_b0 // channel: [ val(meta), rev-b0 ], optional + ch_config_topup // channel: [ 'topup.cnf' ], optional main: ch_versions = Channel.empty() // ** Create channel for TOPUP ** // - // Input : [ meta, dwi, bval, bvec, b0 | [], rev-dwi | [], rev-bval | [], rev-bvec | [], rev-b0 | [] ] - // - join [ meta, dwi, bval, bvec, b0 | null ] - // - map [ meta, dwi, bval, bvec, b0 | [] ] - // - join [ meta, dwi, bval, bvec, b0 | [] ] + [ rev-dwi, rev-bval, rev-bvec ] | [ null ] - // - map [ meta, dwi, bval, bvec, b0 | [], rev-dwi | [], rev-bval | [], rev-bvec | [] ] - // - join [ meta, dwi, bval, bvec, b0 | [], rev-dwi | [], rev-bval | [], rev-bvec | [], rev-b0 | null ] - // - map [ meta, dwi, bval, bvec, b0 | [], rev-dwi | [], rev-bval | [], rev-bvec | [], rev-b0 | [] ] + // Result : [ meta, dwi, bval, bvec, b0 | [], rev-dwi | [], rev-bval | [], rev-bvec | [], rev-b0 | [] ] + // Steps : + // - join [ meta, dwi, bval, bvec, b0 | null ] + // - map [ meta, dwi, bval, bvec, b0 | [] ] + // - join [ meta, dwi, bval, bvec, b0 | [] ] + [ rev-dwi, rev-bval, rev-bvec ] | [ null ] + // - map [ meta, dwi, bval, bvec, b0 | [], rev-dwi | [], rev-bval | [], rev-bvec | [] ] + // - join [ meta, dwi, bval, bvec, b0 | [], rev-dwi | [], rev-bval | [], rev-bvec | [], rev-b0 | null ] + // - map [ meta, dwi, bval, bvec, b0 | [], rev-dwi | [], rev-bval | [], rev-bvec | [], rev-b0 | [] ] // - // Final filter ensures DWI comes with either a rev-dwi (index 5) or a rev-b0 (index 8) + // Finally, to create ch_topup, filter ensures DWI comes with either a rev-dwi (index 5) or a rev-b0 (index 8) ch_topup = ch_dwi .join(ch_b0, remainder: true) .map{ it[0..3] + [it[4] ?: []] } @@ -42,15 +43,16 @@ workflow TOPUP_EDDY { ch_versions = ch_versions.mix(PREPROC_TOPUP.out.versions.first()) // ** Create channel for EDDY ** // - // Input : [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [], coeffs | [], movpar | [] ] - // - join [ meta, dwi, bval, bvec ] + [ rev-dwi, rev-bval, rev-bvec ] | [ null ] - // - map [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [] ] - // - join [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | null ] - // - map [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [] ] - // - join [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [], coeffs | null ] - // - map [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [], coeffs | [] ] - // - join [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [], coeffs | [], movpar | null ] - // - map [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [], coeffs | [], movpar | [] ] + // Result : [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [], coeffs | [], movpar | [] ] + // Steps : + // - join [ meta, dwi, bval, bvec ] + [ rev-dwi, rev-bval, rev-bvec ] | [ null ] + // - map [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [] ] + // - join [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | null ] + // - map [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [] ] + // - join [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [], coeffs | null ] + // - map [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [], coeffs | [] ] + // - join [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [], coeffs | [], movpar | null ] + // - map [ meta, dwi, bval, bvec, rev-dwi | [], rev-bval | [], rev-bvec | [], b0 | [], coeffs | [], movpar | [] ] ch_eddy_input = ch_dwi .join(ch_rev_dwi, remainder: true) .map{ it[0..3] + [it[4] ? it[4..-1] : [], [], []] }