Skip to content

feat(nextflow): integrate virtual-stain into mantis-v2 pipeline#271

Merged
ieivanov merged 7 commits into
mainfrom
nextflow-virtual-stain
Jun 23, 2026
Merged

feat(nextflow): integrate virtual-stain into mantis-v2 pipeline#271
ieivanov merged 7 commits into
mainfrom
nextflow-virtual-stain

Conversation

@ieivanov

@ieivanov ieivanov commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Recreates the Nextflow virtual-staining integration against the current biahub virtual-stain CLI (post-#267, which rewrote prediction to run in-process via cytoland). Replaces #259, which was built on the old viscy predict → temp-zarr → biahub virtual-stain --copy flow that no longer exists.

The new CLI makes this much simpler than #259: per-position work is a single in-process biahub virtual-stain --cluster debug call — identical in shape to run_deskew / run_apply_inv_tf. No temp per-position zarr, no --copy merge.

Changes

  • New nextflow/modules/virtual_stain.nf — three-phase subworkflow mirroring reconstruct.nf:
    1. init_virtual_stain (cpu_local): biahub virtual-stain --init creates the output plate, emits RESOURCES:
    2. run_virtual_stain_preprocess (cpu): viscy preprocess over the whole input plate — computes the normalization statistics virtual_stain_position reads via viscy_data.read_norm_meta (errors if missing). Note: mutates the input store by adding norm metadata.
    3. run_virtual_stain (gpu, --gres=gpu:1): per-position biahub virtual-stain --cluster debug
  • Both biahub virtual-stain and viscy run via a stain_cmd() helper that adds --extra stain (cytoland → viscy-utils provides the viscy console script).
  • nextflow.config: add a gpu process label (queue = 'gpu' in the slurm profile).
  • mantis-v2.nf: add params.virtual_stain_config, include + wire virtual_stain_wf after reconstruct, uncomment 3-virtual-stain in DIRECTORY_LAYOUT.

Test plan

  • biahub virtual-stain --help → shows --init / --cluster
  • uv run --extra stain viscy preprocess --help → resolves; flags (--data_path / --channel_names / --num_workers / --block_size) match the module exactly
  • Tier 3 (GPU node, real acceptance): run mantis-v2.nf -profile slurm against a small reconstruct output (--max_positions 2), passing --virtual_stain_config settings/example_virtual_stain_settings.yml and --biahub_project <path>. Expect init_virtual_stain (1/1) → run_virtual_stain_preprocess (1/1) → run_virtual_stain (2/2) and an output plate at 3-virtual-stain/<ds>.zarr with the predicted channels and input geometry.

Closes #259.

🤖 Generated with Claude Code

Recreate the Nextflow virtual-stain integration against the current
in-process cytoland CLI (post-#267), replacing the #259 approach which
was built on the old `viscy predict` + `--copy` temp-zarr flow.

- New `nextflow/modules/virtual_stain.nf`: init → preprocess → fan-out
  per-position GPU prediction. Per-position work is a single
  `biahub virtual-stain --cluster debug` call (no temp zarr, no --copy).
- `viscy preprocess` runs over the whole input plate to compute the
  normalization statistics the model reads via read_norm_meta.
- Both `biahub virtual-stain` and `viscy` run under biahub's `stain`
  extra (cytoland → viscy-utils provides the `viscy` console script).
- Add a `gpu` process label (queue=gpu) to nextflow.config.
- Wire virtual_stain_wf after reconstruct in mantis-v2.nf.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ieivanov and others added 6 commits June 16, 2026 16:35
Every step CLI (deskew, flat-field, apply-inv-tf, virtual-stain) now emits
its per-position resource request through a single shared helper,
biahub.cli.utils.echo_resources, as a JSON payload:

    RESOURCES:{"cpus": 16, "mem_gb": 64, "time_min": 480}

The same (cpus, total mem_gb, time_min) values feed both the CLI's own
slurm_* submission args and, via parse_resources in nextflow, the Nextflow
per-position task directives — so the SLURM fan-out and the Nextflow fan-out
can no longer request different resources.

- Add echo_resources() and parse the JSON in common.nf::parse_resources,
  which now returns time_min alongside cpus/mem_gb.
- Emit memory as a TOTAL (mem_gb) and request it via slurm_mem rather than
  slurm_mem_per_cpu, fixing virtual-stain's per-cpu over-request.
- Wire each CLI's slurm_time from time_min; drop the hardcoded `time`
  literals in the run_* processes for `meta.time_min * task.attempt`.
- virtual-stain computes time_min before the init_only return so --init
  emits it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Avoids confusion with "minimum time"; renames the resource payload key
and Nextflow meta field consistently across both languages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ieivanov
ieivanov merged commit 12fdb93 into main Jun 23, 2026
5 checks passed
aofei-liu added a commit that referenced this pull request Jul 9, 2026
Adopt merged-PR decisions: JSON echo_resources protocol (cpus/mem_gb/
time_minutes) migrated across stabilize/track/concatenate/estimate-crop/
nf init-resources; take main's deskew/flat-field/reconstruct/virtual-stain
(#255/#257/#258/#267/#271); nextflow.config preempted-partition hardening
(#275); iohub>=0.3.8 (#272). Remove obsolete virtual-stain CLI test; move
example_pipeline_steps.yml to nextflow/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tayllatheodoro added a commit that referenced this pull request Jul 9, 2026
Bring PR #260 (track --init/--cluster + rename-channels + cellpose) up to date
with main. main had already merged the deskew/flat-field/reconstruct (#255/#257/
#258), cytoland virtual-stain (#267/#271), and stitch-vendor (#238) refactors,
which the refactor-* stack implemented in parallel; those subsystems are
resolved in favour of main.

Conflict resolution:
- Took main's versions of deskew.py, flat_field_correction.py,
  apply_inverse_transfer_function.py, virtual_stain.py (cytoland rewrite,
  supersedes the stack's VisCy --init/--copy), cli/utils.py, and the
  deskew/flat_field/reconstruct/virtual_stain Nextflow modules + tests.
- Took main's nextflow.config (adds the gpu label/queue that tracking.nf's
  run_track needs) and common.nf (JSON resources contract), and mantis-v2.nf.
- pyproject.toml/uv.lock resolved to main (identical after taking iohub>=0.3.8).
- Adopted main's JSON resources contract in track.py: --init now calls
  echo_resources(num_cpus, mem_gb, time_minutes) instead of the old
  space-separated 'RESOURCES:' line, so parse_resources (common.nf) works.
- Preserved PR #260's unique work (tracking.nf, rename_channels.nf, the
  refactored/cellpose track.py, example_track_settings.yml).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant