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
2 changes: 2 additions & 0 deletions assets/catalog/catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
- [tiberius/merge](../../modules/nextflow/tiberius/merge/main.nf) — Merge chunk GTFs with merge_annotations.py, restore FASTA order, emit GTF/GFF3 and optional protein/CDS FASTAs.
- [subworkflows/tiberius](../../subworkflows/tiberius/main.nf) — Scatter (none / chromosome / weighted), predict, and merge.
- [workflows/tiberius](../../workflows/tiberius/main.nf) — Standalone Tiberius pipeline.
- [oriongeno/predict](../../modules/nextflow/oriongeno/predict/main.nf) — OrionGeno ab initio gene annotation on one GPU (`process_gpu`). No CPU fallback. Default checkpoint: mammals. GTF by default, GFF3 via `meta.oriongeno_format`. Bundled OrionGeno is non-commercial.
- [oriongeno/multi](../../modules/nextflow/oriongeno/multi/main.nf) — OrionGeno annotation across the GPUs assigned to the task (`oriongeno multi`). Writes GTF. `process_gpu` requests one GPU; raise `accelerator` on `ORIONGENO_MULTI` to use more.

---

Expand Down
114 changes: 114 additions & 0 deletions modules/nextflow/oriongeno/multi/main.nf
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
Copyright (c) 2026 The Hiller Lab at the Senckenberg Gessellschaft für Naturforschung
Distributed under the terms of the Apache License, Version 2.0.
*/

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ORIONGENO_MULTI — Ab initio OrionGeno annotation across one or more GPUs.

Thin wrapper around `oriongeno multi`. `--devices` is the GPU list
Nextflow assigned in CUDA_VISIBLE_DEVICES, or 0 when that variable is
unset. `label 'process_gpu'` requests one GPU under `-profile gpu`.
To use several GPUs, set accelerator for this process in the config;
that selector overrides the label:

process {
withName: 'ORIONGENO_MULTI' {
accelerator = 4
}
}

`oriongeno multi` writes GTF. meta.oriongeno_format other than gtf is
an error. Lineage, species, repeat output, and extra args match
ORIONGENO_PREDICT. Inference requires an NVIDIA GPU; there is no CPU
fallback. Bundled OrionGeno is non-commercial.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

process ORIONGENO_MULTI {
tag "$meta.id"
label 'process_high'
label 'process_gpu'

container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ?
'' :
'ghcr.io/hillerlab/oriongeno:latest' }"

input:
tuple val(meta), path(genome)
val lineage

output:
tuple val(meta), path("annotation/*"), emit: annotation
tuple val(meta), path("repeats/*"), emit: repeats, optional: true
path "versions.yml", emit: versions

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

script:
def args = [task.ext.args ?: '', meta.oriongeno_args ?: ''].findAll { it }.join(' ')
def prefix = task.ext.prefix ?: "${meta.id}"
def known = ['mammals', 'birds', 'fish', 'other_vertebrates', 'arthropods', 'other_invertebrates', 'plants', 'fungi']
def lineage_name = lineage.toString()
def checkpoint = (task.ext.checkpoint ?: meta.checkpoint ?: '').toString()
if (!checkpoint) {
if (!known.contains(lineage_name)) {
error "Unknown OrionGeno lineage '${lineage_name}'. Expected one of: ${known.join(', ')}. Or set task.ext.checkpoint / meta.checkpoint to a checkpoint directory."
}
checkpoint = "/opt/oriongeno/checkpoints/oriongeno_${lineage_name}"
}
def format = (meta.oriongeno_format ?: 'gtf').toString().toLowerCase()
if (format != 'gtf') {
error "ORIONGENO_MULTI writes GTF. oriongeno multi does not emit GFF."
}
def species = (task.ext.species_name ?: meta.species_name ?: meta.species ?: '').toString()
def species_arg = species ? "--species-name \"${species}\"" : ''
def emit_repeat = meta.oriongeno_output_repeat == true || meta.oriongeno_output_repeat == 'true'
"""
set -euo pipefail
mkdir -p annotation

devices="\${CUDA_VISIBLE_DEVICES:-0}"
if [ -z "\$devices" ]; then
devices=0
fi

oriongeno multi \\
--genome "${genome}" \\
--output "annotation/${prefix}.gtf" \\
--checkpoint "${checkpoint}" \\
--devices "\$devices" \\
--work-dir oriongeno-work \\
--output-gene true \\
--output-repeat ${emit_repeat ? 'true' : 'false'} \\
${species_arg} \\
${args}

if [ -f "annotation/${prefix}.repeat.gtf" ]; then
mkdir -p repeats
mv "annotation/${prefix}.repeat.gtf" "repeats/${prefix}.repeat.gtf"
fi

cat <<-END_VERSIONS > versions.yml
"${task.process}":
oriongeno: \$( oriongeno --version 2>/dev/null | sed 's/^oriongeno //' || echo "2026.7.10" )
END_VERSIONS
"""

stub:
def prefix = task.ext.prefix ?: "${meta.id}"
def emit_repeat = meta.oriongeno_output_repeat == true || meta.oriongeno_output_repeat == 'true'
"""
set -euo pipefail
mkdir -p annotation
touch "annotation/${prefix}.gtf"
${emit_repeat ? "mkdir -p repeats && touch \"repeats/${prefix}.repeat.gtf\"" : ''}

cat <<-END_VERSIONS > versions.yml
"${task.process}":
oriongeno: \$( oriongeno --version 2>/dev/null | sed 's/^oriongeno //' || echo "2026.7.10" )
END_VERSIONS
"""
}
105 changes: 105 additions & 0 deletions modules/nextflow/oriongeno/predict/main.nf
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
Copyright (c) 2026 The Hiller Lab at the Senckenberg Gessellschaft für Naturforschung
Distributed under the terms of the Apache License, Version 2.0.
*/

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ORIONGENO_PREDICT — Ab initio OrionGeno annotation on one GPU.

Thin wrapper around `oriongeno`. Inference requires an NVIDIA GPU
(compute capability >= 7.0, driver >= 525.60.13). There is no CPU fallback.
`lineage` selects a checkpoint baked into the image. It does not select
the species. The published image contains mammals unless it was built
with ORIONGENO_MODELS. A directory in task.ext.checkpoint or
meta.checkpoint overrides the lineage. Species conditioning is
meta.species_name (or meta.species, or task.ext.species_name).
meta.oriongeno_format is gtf (default) or gff3. meta.oriongeno_output_repeat
also writes the repeat annotation. Extra flags go in task.ext.args or
meta.oriongeno_args and are not given biological defaults here.
Bundled OrionGeno is non-commercial.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

process ORIONGENO_PREDICT {
tag "$meta.id"
label 'process_high'
label 'process_gpu'

container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ?
'' :
'ghcr.io/hillerlab/oriongeno:latest' }"

input:
tuple val(meta), path(genome)
val lineage

output:
tuple val(meta), path("annotation/*"), emit: annotation
tuple val(meta), path("repeats/*"), emit: repeats, optional: true
path "versions.yml", emit: versions

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

script:
def args = [task.ext.args ?: '', meta.oriongeno_args ?: ''].findAll { it }.join(' ')
def prefix = task.ext.prefix ?: "${meta.id}"
def known = ['mammals', 'birds', 'fish', 'other_vertebrates', 'arthropods', 'other_invertebrates', 'plants', 'fungi']
def lineage_name = lineage.toString()
def checkpoint = (task.ext.checkpoint ?: meta.checkpoint ?: '').toString()
if (!checkpoint) {
if (!known.contains(lineage_name)) {
error "Unknown OrionGeno lineage '${lineage_name}'. Expected one of: ${known.join(', ')}. Or set task.ext.checkpoint / meta.checkpoint to a checkpoint directory."
}
checkpoint = "/opt/oriongeno/checkpoints/oriongeno_${lineage_name}"
}
def format = (meta.oriongeno_format ?: 'gtf').toString().toLowerCase()
if (!(format in ['gtf', 'gff', 'gff3'])) {
error "Unknown OrionGeno format '${format}'. Use gtf or gff3."
}
def ext = (format == 'gff' || format == 'gff3') ? 'gff3' : 'gtf'
def species = (task.ext.species_name ?: meta.species_name ?: meta.species ?: '').toString()
def species_arg = species ? "--species-name \"${species}\"" : ''
def emit_repeat = meta.oriongeno_output_repeat == true || meta.oriongeno_output_repeat == 'true'
"""
set -euo pipefail
mkdir -p annotation

oriongeno \\
--genome "${genome}" \\
--output "annotation/${prefix}.${ext}" \\
--checkpoint "${checkpoint}" \\
--output-gene true \\
--output-repeat ${emit_repeat ? 'true' : 'false'} \\
${species_arg} \\
${args}

if [ -f "annotation/${prefix}.repeat.${ext}" ]; then
mkdir -p repeats
mv "annotation/${prefix}.repeat.${ext}" "repeats/${prefix}.repeat.${ext}"
fi

cat <<-END_VERSIONS > versions.yml
"${task.process}":
oriongeno: \$( oriongeno --version 2>/dev/null | sed 's/^oriongeno //' || echo "2026.7.10" )
END_VERSIONS
"""

stub:
def prefix = task.ext.prefix ?: "${meta.id}"
def format = (meta.oriongeno_format ?: 'gtf').toString().toLowerCase()
def ext = (format == 'gff' || format == 'gff3') ? 'gff3' : 'gtf'
def emit_repeat = meta.oriongeno_output_repeat == true || meta.oriongeno_output_repeat == 'true'
"""
set -euo pipefail
mkdir -p annotation
touch "annotation/${prefix}.${ext}"
${emit_repeat ? "mkdir -p repeats && touch \"repeats/${prefix}.repeat.${ext}\"" : ''}

cat <<-END_VERSIONS > versions.yml
"${task.process}":
oriongeno: \$( oriongeno --version 2>/dev/null | sed 's/^oriongeno //' || echo "2026.7.10" )
END_VERSIONS
"""
}
119 changes: 119 additions & 0 deletions modules/wdl/oriongeno/multi/main.wdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Copyright (c) 2026 The Hiller Lab at the Senckenberg Gessellschaft für Naturforschung
# Distributed under the terms of the Apache License, Version 2.0.

# ORIONGENO_MULTI — Ab initio OrionGeno annotation across one or more GPUs.
# Thin wrapper around `oriongeno multi`. devices is a comma-separated list of
# GPU ids ("0,1,2,3"). The caller schedules those devices; this task writes GTF.
# lineage, species_name, output_repeat, checkpoint, and extra_args match predict.
# Inference requires an NVIDIA GPU. There is no CPU fallback.
# Bundled OrionGeno is non-commercial.

version 1.3

task multi {
input {
File genome
String devices
String lineage = "mammals"
String species_name = ""
Boolean output_repeat = false
String checkpoint = ""
String extra_args = ""
String prefix = ""
}

String stem = sub(sub(basename(genome), "\\.gz$", ""), "\\.(fa|fasta|fna|fas)$", "")
String sample = if prefix != "" then prefix else stem
String annotation_path = "annotation/" + sample + ".gtf"
String repeat_path = "repeats/" + sample + ".repeat.gtf"

command <<<
set -euo pipefail

lineage="~{lineage}"
devices="~{devices}"
checkpoint="~{checkpoint}"
species="~{species_name}"

if [ -z "$devices" ]; then
echo "ORIONGENO_MULTI requires at least one GPU id in devices." >&2
exit 1
fi

if [ -n "$checkpoint" ]; then
ckpt="$checkpoint"
else
case "$lineage" in
mammals|birds|fish|other_vertebrates|arthropods|other_invertebrates|plants|fungi) ;;
*)
echo "Unknown OrionGeno lineage '$lineage'." >&2
exit 1
;;
esac
ckpt="/opt/oriongeno/checkpoints/oriongeno_${lineage}"
fi

mkdir -p annotation
species_args=()
if [ -n "$species" ]; then
species_args+=(--species-name "$species")
fi

oriongeno multi \
--genome "~{genome}" \
--output "~{annotation_path}" \
--checkpoint "$ckpt" \
--devices "$devices" \
--work-dir oriongeno-work \
--output-gene true \
--output-repeat ~{if output_repeat then "true" else "false"} \
"${species_args[@]}" \
~{extra_args}

gene="~{annotation_path}"
repeat_src="${gene%.*}.repeat.${gene##*.}"
if [ -f "$repeat_src" ]; then
mkdir -p repeats
mv "$repeat_src" "~{repeat_path}"
fi
>>>

output {
File annotation = annotation_path
File? repeats = repeat_path
}

requirements {
container: "ghcr.io/hillerlab/oriongeno:latest"
}
}

workflow run {
input {
File genome
String devices
String lineage = "mammals"
String species_name = ""
Boolean output_repeat = false
String checkpoint = ""
String extra_args = ""
String prefix = ""
}

call multi {
input:
genome = genome,
devices = devices,
lineage = lineage,
species_name = species_name,
output_repeat = output_repeat,
checkpoint = checkpoint,
extra_args = extra_args,
prefix = prefix
}

output {
File annotation = multi.annotation
File? repeats = multi.repeats
}
}
Loading
Loading