diff --git a/modules.json b/modules.json index a8ab9350..3cc453a3 100644 --- a/modules.json +++ b/modules.json @@ -5,6 +5,11 @@ "https://github.com/nf-core/modules.git": { "modules": { "nf-core": { + "cellpose": { + "branch": "master", + "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", + "installed_by": ["modules"] + }, "custom/dumpsoftwareversions": { "branch": "master", "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", diff --git a/modules/nf-core/cellpose/main.nf b/modules/nf-core/cellpose/main.nf new file mode 100644 index 00000000..f100904f --- /dev/null +++ b/modules/nf-core/cellpose/main.nf @@ -0,0 +1,58 @@ +process CELLPOSE { + tag "$meta.id" + label 'process_medium' + + container "docker.io/biocontainers/cellpose:3.0.1_cv1" + + input: + tuple val(meta), path(image) + path(model) + + output: + tuple val(meta), path("*masks.tif") , emit: mask + tuple val(meta), path("*flows.tif") , emit: flows, optional: true + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "I did not manage to create a cellpose module in Conda that works in all OSes. Please use Docker / Singularity / Podman instead." + } + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def model_command = model ? "--pretrained_model $model" : "" + def VERSION = '3.0.1' + """ + cellpose \\ + --image_path $image \\ + --save_tif \\ + $model_command \\ + $args + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + cellpose: $VERSION + END_VERSIONS + """ + stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "I did not manage to create a cellpose module in Conda that works in all OSes. Please use Docker / Singularity / Podman instead." + } + def prefix = task.ext.prefix ?: "${meta.id}" + def VERSION = "3.0.1" // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + def name = image.name + def base = name.lastIndexOf('.') != -1 ? name[0..name.lastIndexOf('.') - 1] : name + """ + touch ${base}_cp_masks.tif + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + cellpose: $VERSION + END_VERSIONS + """ + +} diff --git a/modules/nf-core/cellpose/meta.yml b/modules/nf-core/cellpose/meta.yml new file mode 100644 index 00000000..5397944b --- /dev/null +++ b/modules/nf-core/cellpose/meta.yml @@ -0,0 +1,63 @@ +name: "cellpose" +description: cellpose segments cells in images +keywords: + - segmentation + - image + - cellpose +tools: + - "cellpose": + description: "cellpose is an anatomical segmentation algorithm written in Python + 3 by Carsen Stringer and Marius Pachitariu" + homepage: "https://github.com/MouseLand/cellpose" + documentation: "https://cellpose.readthedocs.io/en/latest/command.html" + tool_dev_url: "https://github.com/MouseLand/cellpose" + doi: 10.1038/s41592-022-01663-4 + licence: ["BSD 3-Clause"] + identifier: biotools:cellpose +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + (sample id) + - image: + type: file + description: tif file for ready for segmentation + pattern: "*.{tif,tiff}" + - - model: + type: file + description: Optional input file. Cellpose 2 model trained by user using human-in-the-loop + approach. +output: + - mask: + - meta: + type: map + description: | + Groovy Map containing sample information + [sample id] + - "*masks.tif": + type: file + description: labelled mask output from cellpose in tif format + pattern: "*.{tif, tiff}" + - flows: + - meta: + type: map + description: | + Groovy Map containing sample information + [sample id] + - "*flows.tif": + type: file + description: cell flow output from cellpose + pattern: "*.{tif}" + - versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@josenimo" + - "@FloWuenne" +maintainers: + - "@josenimo" + - "@FloWuenne" + - "@kbestak" diff --git a/modules/nf-core/cellpose/tests/main.nf.test b/modules/nf-core/cellpose/tests/main.nf.test new file mode 100644 index 00000000..6a7688ba --- /dev/null +++ b/modules/nf-core/cellpose/tests/main.nf.test @@ -0,0 +1,63 @@ +nextflow_process { + + name "Test Process CELLPOSE" + script "../main.nf" + process "CELLPOSE" + + tag "modules" + tag "modules_nfcore" + tag "cellpose" + + test("cellpose - with flows, no model") { + + when { + config "./nextflow_wflows.config" + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'imaging/segmentation/cycif_tonsil_registered.ome.tif', checkIfExists: true) + ] + input[1] = [] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out.mask).match("mask") }, + { assert snapshot(process.out.flows).match("flows") }, + { assert snapshot(process.out.versions).match("versions") } + ) + } + + } + + + test("cellpose - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'imaging/segmentation/cycif_tonsil_registered.ome.tif', checkIfExists: true) + ] + input[1] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/cellpose/tests/main.nf.test.snap b/modules/nf-core/cellpose/tests/main.nf.test.snap new file mode 100644 index 00000000..03b4dbfc --- /dev/null +++ b/modules/nf-core/cellpose/tests/main.nf.test.snap @@ -0,0 +1,87 @@ +{ + "flows": { + "content": [ + [ + [ + { + "id": "test" + }, + "cycif_tonsil_registered.ome_flows.tif:md5,de79a792d4bebd2f9753ceb47a0de5f7" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-18T14:22:16.855256249" + }, + "versions": { + "content": [ + [ + "versions.yml:md5,ce42208b574084f390cf58b4c19b5717" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-18T14:22:16.875087557" + }, + "cellpose - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "cycif_tonsil_registered.ome_cp_masks.tif:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + + ], + "2": [ + "versions.yml:md5,ce42208b574084f390cf58b4c19b5717" + ], + "flows": [ + + ], + "mask": [ + [ + { + "id": "test" + }, + "cycif_tonsil_registered.ome_cp_masks.tif:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,ce42208b574084f390cf58b4c19b5717" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-18T14:22:39.339792992" + }, + "mask": { + "content": [ + [ + [ + { + "id": "test" + }, + "cycif_tonsil_registered.ome_cp_masks.tif:md5,001ad312413f18bc2615741bd3ad12cf" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-18T14:22:16.8369758" + } +} \ No newline at end of file diff --git a/modules/nf-core/cellpose/tests/nextflow_wflows.config b/modules/nf-core/cellpose/tests/nextflow_wflows.config new file mode 100644 index 00000000..773c97bd --- /dev/null +++ b/modules/nf-core/cellpose/tests/nextflow_wflows.config @@ -0,0 +1,5 @@ +process { + withName: "CELLPOSE" { + ext.args = '--pretrained_model nuclei --diameter 9 --channel_axis 0 --no_npy --save_flows' + } +} diff --git a/modules/nf-core/cellpose/tests/tags.yml b/modules/nf-core/cellpose/tests/tags.yml new file mode 100644 index 00000000..1280d1f9 --- /dev/null +++ b/modules/nf-core/cellpose/tests/tags.yml @@ -0,0 +1,2 @@ +cellpose: + - "modules/nf-core/cellpose/**"