Skip to content

Implementation of antsRegistration_affine_SyN.sh for registration - #282

Draft
gdevenyi wants to merge 7 commits into
nf-neuro:mainfrom
gdevenyi:antsRegistration_affine_SyN
Draft

Implementation of antsRegistration_affine_SyN.sh for registration#282
gdevenyi wants to merge 7 commits into
nf-neuro:mainfrom
gdevenyi:antsRegistration_affine_SyN

Conversation

@gdevenyi

@gdevenyi gdevenyi commented Jan 8, 2026

Copy link
Copy Markdown
Contributor

Describe your changes

Implement the CoBrALab variant of antsRegistrationSyN.sh with optimized pyramids.

List test packages used by your module

Checklist before requesting a review

  • Create the tool:
    • Edit ./modules/nf-neuro/<category>/<tool>/main.nf
    • Edit ./modules/nf-neuro/<category>/<tool>/meta.yml
    • Edit ./modules/nf-neuro/<category>/<tool>/environment.yml
  • Generate the tests:
    • Edit ./modules/nf-neuro/<category>/<tool>/tests/main.nf.test
    • Run the tests to generate the main.nf.test.snap snapshots
  • Ensure the syntax is correct :
    • Run prettier and editorconfig-checker to fix common syntax issues
    • Run nf-core modules lint and fix all errors
    • Ensure your variables have good, clear names

@gdevenyi
gdevenyi force-pushed the antsRegistration_affine_SyN branch from 390c9c1 to a90da89 Compare January 8, 2026 16:19
@AlexVCaron

Copy link
Copy Markdown
Contributor

Minimal work is required so the module fits with the nf-core framework. Modules names can only be composed of capital alphanumerical characters and must follow the category/module filenaming convention. So here, it would be (with category) REGISTRATION/COBRALABANTS, using the current file hierarchy.

Once done, most linting and testing should work out the box. But nf-test expects some naming/formatting, that sadly isn't targetted when nf-core conventions are not abided to.

@gdevenyi
gdevenyi force-pushed the antsRegistration_affine_SyN branch 2 times, most recently from 2878c25 to ae312c2 Compare January 15, 2026 18:45
@gdevenyi

Copy link
Copy Markdown
Contributor Author

@AlexVCaron I can't sort out how to run the test properly inside the devcontainer, what's the appropriate command?

@gdevenyi
gdevenyi force-pushed the antsRegistration_affine_SyN branch from ae312c2 to b91bb4a Compare January 22, 2026 15:52
@AlexVCaron

AlexVCaron commented Jan 22, 2026

Copy link
Copy Markdown
Contributor

I run the test suite for any component from the root of the repo via : nf-test test <path-to-component-base-directory> --update-snapshot --clean-snapshot

In this case, the path is modules/nf-neuro/registration/cobralab_ants

For the lint, it is done via the nf-core command, from the root of the repo again, but without the full path, just the component name : nf-core modules lint registration/cobralab_ants

Tell me of any problems, I can pull your PR and help debug !

@gdevenyi

Copy link
Copy Markdown
Contributor Author

Right. OK. It seems like the devcontainer doesn't have the antsRegistration_affine_SyN.sh that I got merged into the main repo...

@AlexVCaron

Copy link
Copy Markdown
Contributor

I'll get into that this w-e. It should've been included in the build, I'll investigate

@AlexVCaron

Copy link
Copy Markdown
Contributor

As stated on scilus/containers-scilus#42, scilus/scilus:dev is the container including the dependency for now.

@gdevenyi
gdevenyi force-pushed the antsRegistration_affine_SyN branch 2 times, most recently from 0932c5d to a7e2ecb Compare February 5, 2026 04:43
@gdevenyi
gdevenyi force-pushed the antsRegistration_affine_SyN branch 2 times, most recently from 4db49ca to b09a2af Compare May 29, 2026 19:26
@arnaudbore

Copy link
Copy Markdown
Contributor

@gdevenyi container is updated, we still have some issues with our servers I'll let you know asap when ready.

@gdevenyi

gdevenyi commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

@gdevenyi container is updated, we still have some issues with our servers I'll let you know asap when ready.

No problem my local testbed works.

@gdevenyi
gdevenyi force-pushed the antsRegistration_affine_SyN branch 2 times, most recently from e9318a2 to 191152d Compare June 4, 2026 15:23
@gdevenyi

gdevenyi commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

Depends on scilus/containers-scilus#45, also need to update the container reference once its released

@arnaudbore

Copy link
Copy Markdown
Contributor

Depends on scilus/containers-scilus#45, also need to update the container reference once its released

Merged and scilus/scilus:dev is updated

@gdevenyi

gdevenyi commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

This all works, I guess the only thing now is this should be pinned to an official scilus container version instead of dev

@gagnonanthony

Copy link
Copy Markdown
Member

I'm not sure there will be a release with a new version soon, right @arnaudbore ? In the meantime, you could pin it to the image SHA.

@gdevenyi

gdevenyi commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

In the meantime, you could pin it to the image SHA.

Sure.

@gdevenyi
gdevenyi force-pushed the antsRegistration_affine_SyN branch 2 times, most recently from 3ec0077 to cb0a599 Compare June 11, 2026 17:03
@gdevenyi
gdevenyi marked this pull request as ready for review June 11, 2026 17:04
@gdevenyi
gdevenyi requested review from a team and Copilot June 11, 2026 17:04
@gdevenyi

Copy link
Copy Markdown
Contributor Author

The masking implementation here depends on #369, if that's changed this should be as well

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a new registration/cobralab_ants Nextflow module to nf-neuro, including module metadata and an nf-test suite covering default, “quick”, “no warp”, and stub modes.

Changes:

  • Introduces the REGISTRATION_COBRALABANTS process implementation and module metadata.
  • Adds nf-test coverage and snapshots for multiple registration configurations.
  • Adds test tagging and per-test Nextflow config overrides.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
modules/nf-neuro/registration/cobralab_ants/main.nf Adds the REGISTRATION_COBRALABANTS process implementation, including optional QC generation and stub behavior.
modules/nf-neuro/registration/cobralab_ants/meta.yml Documents module inputs/outputs/tools and parameters used by the process.
modules/nf-neuro/registration/cobralab_ants/environment.yml Adds module conda environment placeholder for linting/metadata consistency.
modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test Adds nf-test cases for default, quick, no-warp, and stub runs.
modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test.snap Adds snapshots asserting expected emitted outputs/hashes for each test.
modules/nf-neuro/registration/cobralab_ants/tests/nextflow.config Test config enabling reproducibility + single-thread mode.
modules/nf-neuro/registration/cobralab_ants/tests/nextflow_quick.config Test config enabling fast mode + QC + single-thread mode.
modules/nf-neuro/registration/cobralab_ants/tests/nextflow_no_warp.config Test config enabling fast + linear-only (no nonlinear warp) + single-thread mode.
modules/nf-neuro/registration/cobralab_ants/tests/tags.yml Adds tags mapping to allow selective test execution by module path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread modules/nf-neuro/registration/cobralab_ants/main.nf
Comment thread modules/nf-neuro/registration/cobralab_ants/main.nf
Comment thread modules/nf-neuro/registration/cobralab_ants/main.nf Outdated
Comment thread modules/nf-neuro/registration/cobralab_ants/main.nf
Comment thread modules/nf-neuro/registration/cobralab_ants/main.nf Outdated
Comment thread modules/nf-neuro/registration/cobralab_ants/tests/nextflow.config
Comment thread modules/nf-neuro/registration/cobralab_ants/meta.yml
Comment thread modules/nf-neuro/registration/cobralab_ants/meta.yml
@gdevenyi gdevenyi changed the title Initial implementation of antsRegistration_affine_SyN.sh Implementation of antsRegistration_affine_SyN.sh for registration Jun 11, 2026
@arnaudbore

Copy link
Copy Markdown
Contributor

@gdevenyi scilus/scilus:2.3.0 is ready 👍

@gdevenyi

Copy link
Copy Markdown
Contributor Author

Cool. Still pending confirmation of the masking implementation in #369

@gdevenyi
gdevenyi force-pushed the antsRegistration_affine_SyN branch from cb0a599 to 235e030 Compare June 25, 2026 15:24
@gdevenyi
gdevenyi marked this pull request as draft June 25, 2026 15:24
@gdevenyi
gdevenyi requested a review from Copilot July 14, 2026 17:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread modules/nf-neuro/registration/cobralab_ants/main.nf Outdated
Comment thread modules/nf-neuro/registration/cobralab_ants/main.nf Outdated
Comment thread modules/nf-neuro/registration/cobralab_ants/main.nf Outdated
@gdevenyi

gdevenyi commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Re: "Still pending confirmation of the masking implementation in #369" — I have just reviewed and tested #369 in depth (review), so here is the confirmation, plus what it means for this module.

Scope note: I looked at this PR for its integration surface with #369, not as a full standalone review.

The good news for this module

Your --fixed-mask / --moving-mask implementation is the cleanest of the four registration backends, and it is the only one that cannot hit the bug I found. #369's anattodwi builds -x "${fixed_mask},${moving_mask}" and hands it to raw antsRegistration, which wants --masks [fixed,moving]. ANTs reads mask.nii.gz,NULL as one filename, cannot open it, and — as you noted — treats an unreadable name as no mask:

 file T1w_mask.nii.gz,NULL does not exist .
      No fixed mask

Non-fatal, rc=0, so CI stays green while nothing is masked. Confirmed against ANTs 2.6.5, and confirmed by #369's own snapshot: its anattodwi - fixed mask test is byte-identical to the no-mask test on every output md5.

Separate flags sidestep that entirely. Two related findings worth having:

  • A single --masks is broadcast to all stages (itkantsRegistrationHelper.hxx:867, if (m_FixedImageMasks.size() == 1) fixedMaskIndex = 0;), so no per-stage repetition is needed anywhere.
  • Bare brackets in a Nextflow script are a live pathname-glob hazard, as you warned. With a one-character file in the work dir, -t [x_affine.mat,1] expands: I measured -x [T1w_mask.nii.gz,NULL] collapsing to -x T. This module's antsApplyTransforms -d 3 -t [${prefix}_forward1_affine.mat,1] and -o Linear[...] have the same shape. It is a repo-wide pre-existing pattern (registration/ants does it too), not a defect introduced here, and it needs an implausible filename to bite — but quoting the bracketed argument is free.

What is still unsettled, and why it blocks you

The masking_strategy gate you copied is broken in #369 in ways you would inherit:

  1. apriori / both abort the pipeline. All three IMAGE_APPLYMASK aliases in the registration subworkflow emit ${prefix}_masked.nii.gz, so two masked inputs to one process trigger input file name collision. Reproduced. This hits cobralab_ants the moment it is wired into the subworkflow, and is fixed centrally by a modules.config with per-alias ext.first_suffix.
  2. The subworkflow-level option is untested — none of [ENH] Fix registration + use mask apply in tractoflow #369's tests set masking_strategy on the subworkflow, and the two new ones are wired to the wrong take: slots, so they run REGISTRATION_ANATTODWI instead of REGISTRATION_ANTS.

My recommendation, and what it would mean here

I have suggested #369 keep the none/apriori/internal/both policy in the subworkflow and let each module keep plain masks given ⇒ masks used. This PR is the best argument for it: four backends express masks four different ways (-x "f,m", -x "[f,m]", --fixed-mask/--moving-mask, and no support at all), while the policy is identical everywhere and is now duplicated a third time.

If that lands, the change here is a deletion — drop the masking_strategy condition and keep:

if ( fixed_mask ) args += " --fixed-mask $fixed_mask"
if ( moving_mask ) args += " --moving-mask $moving_mask"

If instead the module-level enum stays, this module is already correct in shape; it just needs choices: [none, apriori, internal, both] added to the masking_strategy entry in meta.yml to match ants and anattodwi.

Either way it is worth settling before both merge, because mask_extract's description here already documents behaviour in terms of the enum ("Requires masks to be forwarded to the tool (masking_strategy = 'internal' or 'both')").

Two other integration items

  • Suffix contract. [ENH] Fix registration + use mask apply in tractoflow #369 declares suffix as an "Obligatory" arg on registration/ants (default warped) and its description says registration modules need to define one. This module has no suffix arg and hardcodes ${prefix}_${moving_id}_warped.nii.gz. I have asked over there for the contract to be written into the subworkflow meta.yml; either way this will need it.
  • mqc filename. This emits *_registration_ants_mqc.gif, the same name registration/ants uses. Once both are selectable backends behind one subworkflow, the QC images should be distinguishable in the MultiQC report — *_registration_cobralabants_mqc.gif or similar.

Otherwise this is a drop-in for the ANTs branch: every channel the subworkflow consumes is present with matching globs, and computing *_warped_reference.nii.gz via an explicit antsApplyTransforms is more robust than #369's approach in registration/ants, which relies on antsRegistrationSyN*.sh always emitting outputInverseWarped.nii.gz.

gdevenyi and others added 7 commits August 3, 2026 15:27
Split single mask input into separate fixed_mask and moving_mask inputs,
matching the pattern from PR nf-neuro#367 for the ants registration module.
antsRegistration_affine_SyN.sh supports --fixed-mask and --moving-mask
as independent flags.
…hread support

- Forward --reproducibility and --random-seed CLI flags to
  antsRegistration_affine_SyN.sh (CoBrALab PR nf-neuro#7)
- Export ANTS_RANDOM_SEED env var (default 1234) for ancillary ANTs tools
- Replace hardcoded thread counts with task.ext.single_thread-aware
  expressions for ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS and OMP_NUM_THREADS
- Remove OPENBLAS_NUM_THREADS (set globally in test config)
- Add reproducibility, ants_rng_seed, single_thread args to meta.yml

Mirrors the pattern already applied to registration/ants (nf-neuro PR nf-neuro#342).
Align cobralab_ants with the registration subworkflow masking rework
(PR nf-neuro#369): gate fixed/moving mask forwarding behind masking_strategy
(none/apriori/internal/both), add fixed_warped output (reference warped
to moving space via antsApplyTransforms), and update tests accordingly.
…ames

Address Copilot review: parse moving/fixed IDs extension-agnostically
(.nii and .nii.gz) and strip by ${prefix} instead of ${meta.id}; use a
concrete viz output filename instead of a glob. Matches the registration/ants
reference module.
Conformance fixes found while reviewing this module against the canonical
registration/ants module and the registration subworkflow contract:

- Add ext.suffix support (declared "obligatory" by registration/ants) instead
  of hardcoding _warped, in both script and stub.
- Rename QC output to *_registration_cobralabants_mqc.gif. It previously used
  registration/ants' exact filename, which would make the two indistinguishable
  in a MultiQC report once both are selectable registration backends.
- Declare choices: on masking_strategy, matching registration/ants and
  registration/anattodwi.
- Quote bracketed antsApplyTransforms arguments. Nextflow emits the script as
  bash source, so an unquoted [file,1] is a valid pathname glob and expands if
  any single-character filename is present in the work directory.
- Derive moving_id in the stub instead of hardcoding "t1", matching the script
  and registration/ants.
- Drop a stray indent on the output0GenericAffine.mat rename.

Snapshots re-recorded: the only content change is the QC filename; every md5
is unchanged, including across two independent runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KaGdNMxpjiMAicdMN5ewtY
@gdevenyi
gdevenyi force-pushed the antsRegistration_affine_SyN branch from 587282e to b28dc8f Compare August 3, 2026 20:33
@gdevenyi

gdevenyi commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main (was 34 commits behind; clean, no conflicts) and pushed the conformance fixes from my review above, plus a pass over the Copilot threads.

Fixes (b28dc8f)

  • ext.suffix support. registration/ants declares suffix as an "Obligatory suffix to add to the output file name"; this module had no such arg and hardcoded _warped. Now def suffix = task.ext.suffix ? "${task.ext.suffix}_warped" : "warped" in both script: and stub:, matching the reference module. Default behaviour is unchanged.
  • QC filename. *_registration_ants_mqc.gif*_registration_cobralabants_mqc.gif. It previously used registration/ants' exact output name, which would make the two indistinguishable in a MultiQC report once both are selectable registration backends. The repo convention is _registration_<module>_mqc.gif (anattodwi, antsapplytransforms).
  • choices: on masking_strategy, matching registration/ants and registration/anattodwi.
  • Quoted the bracketed antsApplyTransforms arguments. Nextflow emits the script as bash source, so an unquoted [file,1] is a valid pathname glob. With a one-character file in the work dir it silently collapses — I measured -x [T1w_mask.nii.gz,NULL] becoming -x T. Needs an implausible filename to bite, but quoting is free.
  • Stub derives moving_id instead of hardcoding t1, so it produces the same name as the real path for any input.
  • Dropped a stray indent on the output0GenericAffine.mat rename.

Verification

Full suite re-run locally in .dev/dev devops (nf-test 0.9.3, apptainer, scilus/scilus:2.3.0) — 6/6 passing, ~25 min:

'registration - cobralab_ants - SyN'                PASSED (412.1s)
'registration - cobralab_ants - SyN quick'          PASSED (113.7s)
'registration - cobralab_ants - no warps'           PASSED (34.3s)
'registration - cobralab_ants - both - moving mask' PASSED (766.1s)
'registration - cobralab_ants - both - fixed mask'  PASSED (145.6s)
'registration - cobralab_ants - stub'               PASSED (11.9s)

I ran once without --update-snapshot first, so the changes are attributable rather than absorbed. The entire snapshot diff is the QC rename plus timestamps — every md5 is unchanged, including image_warped, which confirms the suffix refactor is a true no-op at its default:

- "test_..._registration_ants_mqc.gif:md5,38c677f86df720fee58c2d55535e0bed"
+ "test_..._registration_cobralabants_mqc.gif:md5,38c677f86df720fee58c2d55535e0bed"

Identical md5s across two independent runs also confirms ext.reproducibility = true is doing its job. prettier --check passes; the editorconfig rules (final newline, no trailing whitespace, no tabs) check out manually — editorconfig-checker can't self-install in the container.

Copilot threads — all 11 resolved

Nine were already answered; I verified those claims against the current code rather than taking them at face value, and corrected one that over-claimed. The .nii / .nii.gz threads were only half addressed: ID parsing is genuinely extension-agnostic now, but the QC block still does mv $fixed_image fixed_image.nii.gz, which would break mrinfo on an uncompressed .nii input since mrtrix selects its reader by extension. I left it and said so explicitly — the line is identical in registration/ants and anattodwi, so a cobralab-only change would diverge from the reference on a QC-only path. Same rationale as the meta.yml transform-description threads, where I confirmed the wording is word-for-word identical to the canonical module.

So there are two repo-wide follow-ups banked here, neither belonging to this PR: the mv-to-.gz assumption, and the forward_image_transform descriptions that reference REGISTRATION_TRANSFORMTRACTOGRAM.

Still blocked on #369

The masking_strategy block is untouched, since that is the open question. If #369 moves the policy into the subworkflow as I suggested, the change here is a deletion — drop the condition and keep the two --fixed-mask / --moving-mask lines. If the module-level enum stays, this module is now already conformant.

One thing worth noting for whoever merges second: this module is on scilus/scilus:2.3.0 (needed for antsRegistration_affine_SyN.sh) while #369's modules are on 2.2.2.

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.

5 participants