Skip to content

Image simulations workflow#766

Merged
cailmdaley merged 55 commits into
developfrom
im_sims
Jul 15, 2026
Merged

Image simulations workflow#766
cailmdaley merged 55 commits into
developfrom
im_sims

Conversation

@martinkilbinger

@martinkilbinger martinkilbinger commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Part of [Tracking] Image simulations (UNIONS-WL/MultiBand_ImSim#1).

Big picture

To measure the shear bias (m, c) of the ShapePipe chain, we run it end-to-end on simulated images with known injected shear and compare output to input. Each distinct injected-shear value defines a branch — the same sky simulated under a different applied shear. The work splits along the dependency arrow:

  • This PR (ShapePipe): everything the pipeline needs to measure shapes on simulated tiles — from raw sim images to per-tile catalogues and the merged per-branch catalogue.
  • Companion PR (sp_validation#225): the Snakemake orchestration that drives this pipeline, and the m-bias estimator that consumes its catalogues.

Boundary rule: ShapePipe owns its module configs (the .ini tree lives here, next to the code whose options it names, so code and config change in the same PR); the workflow selects and parameterizes that tree explicitly. Campaign facts — injected shear, branch naming — live upstream in the workflow's manifest and never appear in this repo.

What's here

Sim-specific modules and paths:

  • fake_psf module — per-galaxy PSF stamps from the sims' PSF dictionary, drop-in for psfex_interp's downstream format. The dictionary path is supplied by the workflow (environment-expanded in the config), not hardcoded.
  • BKG_SUB ngmix option — skip background subtraction for background-free sims; composes with ngmix_v2.0's vignette and centroid options.
  • Position-seeded fixnoise (SEED_FROM_POSITION, Seed fix based on position for Pujol noise cancellation for image simulations #796) — metacal's counter-noise RNG is seeded from each object's sky position, so the same object gets identical fixnoise across shear branches and the noise cancels in the branch difference (measured ~5–6× reduction in σ_m per tile). The seed formula is pinned by unit tests. Enabled only in the sims ngmix config.
  • Numeric sim-exposure-ID handling (exp_utils, sextractor_script, merge_headers WARN_MISSING_EXP) and batch-output dtype fix for nfev_fit ([BUG] ngmix crash #795).
  • cfis_image_sims/ module configs — the one .ini tree for sim runs — and create_final_cat's image_sims mode.
  • Empty-tile robustness + coverage tooling for sims with sparse or blank input tiles.

One runner path: run_job -t image_sims drives the full module chain and accepts --config_dir; the workflow passes it explicitly, so the workflow's choice of .ini tree governs every stage. Orchestration lives in sp_validation; the in-repo Snakemake pipeline has been retired on this branch, with its coverage-scan helper (check_tile_coverage.py) kept under scripts/python/.

Parallelism model: the orchestrator fans out per-tile jobs, and ShapePipe uses its own multiprocessing within a job; the sims chain launches no MPI.

Validation

The full chain (raw sim tile → per-tile catalogues → final_cat_<branch>.hdf5) runs on candide. Downstream, the companion PR's estimator measures the residual m left after ShapePipe's own response calibration; on one fiducial tile it is consistent with zero at the percent level, and that fixed-tile measurement serves as the regression check for changes on both branches.

— Fable, on behalf of Cail

@cailmdaley cailmdaley mentioned this pull request Jun 30, 2026
@cailmdaley cailmdaley linked an issue Jun 30, 2026 that may be closed by this pull request
6 tasks
cailmdaley and others added 7 commits July 10, 2026 07:53
)

Add an opt-in SEED_FROM_POSITION knob to the ngmix module (default False).
When on, the object loop replaces the tile-level RNG with a per-object
RandomState seeded from the object's sky position, and rebuilds the prior
from that same RNG, so every stochastic step of the fit is a deterministic
function of (ra, dec, ccd).

Why: image-sim m-bias uses the Pujol estimator — the same scene under
different applied shears, with shear response read from the branch difference
of the SAME objects. Metacal's fixnoise adds a counter-noise realisation from
an RNG seeded per tile, so an object gets different added noise in different
branches (detection order differs) and the noise fails to cancel in the
difference, inflating sigma_m. Seeding per object from position makes the same
object draw the same added noise AND the same fit guesses in every branch, so
both cancel and the m-bias error shrinks. Design and box math are Fabian's
issue #796.

The prior must be rebuilt per object, not just the RNG: the ngmix guesser
draws its initial guess via prior.sample(), which consumes the RNG the prior
was CONSTRUCTED with (ngmix 2.4.0 guessers.py / joint_prior.py). A per-object
RNG alone would leave the guess drawing from the shared tile stream and break
cancellation. The fixnoise counter-noise itself rides on the observation's
attached noise image (use_noise_image=True), which prepare_ngmix_weights draws
from the per-object RNG — so no fresh draw from the bootstrapper RNG is needed.

Deviation from #796: Fabian combines the 3-arcsec position boxes as
box_x + box_y, which collides along anti-diagonals — boxes (10,20) and (11,19)
both give seed 30, so two distinct objects share a noise stream. This replaces
the sum with a Cantor pairing (a bijection on the non-negative integers) after
a zig-zag fold that maps signed box indices (Dec can be negative) onto
non-negative ones, reduced mod 2**32 into the valid RandomState seed range.
The box math is kept exactly as his: floor(ra*3600/3)+(ccd+1),
floor(dec*3600/3)+(ccd+2), first-epoch coordinates (coord_list[0] convention),
so all epochs of one object share the stream.

Off by default => production path is byte-identical to develop (verified:
metacal g for all five types matches unmodified develop bit-for-bit; the full
fast suite passes, 326 tests). New property tests cover the seed's range,
sub-box jitter invariance, adjacent-box distinctness, and the resolved
anti-diagonal collision.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J9qEVRCWEekT5ACNB3rjkq
compile_results filled nfev_fit with np.nan on failed fits, the only
int-like column with a float fallback. With SAVE_BATCH enabled,
save_results locks column dtypes from batch 1; if that batch has no
failures the column locks to int64, and the first later batch with a
failure feeds NaN into it, raising "cannot convert float NaN to
integer" on append. Use ngmix's own -1 failed/absent-nfev sentinel
instead of NaN, keeping the column int64 across every batch.

Fixes #795
Companion to the coverage rule in the Snakefile: scans input weight
maps (subsampled), writes tile_coverage_grid_{num}.yaml with an
exclude list read at DAG-build time. Weight-map location is taken
from the get-images ini of the 1p2z variant. Plus two felt fibers
documenting the blank-tile and thread-exhaustion findings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ling) into im_sims

Resolutions:
- ngmix.py: Martin's zero-noise edge-stamp guard kept, generalized to
  np.all(sig_noise > 0) so it stays valid on the per-pixel bkg_rms path,
  composed with the #803 per-object rng draws (his branch predated #803).
- ngmix_runner.py: both imports (os + SqliteDict).
- scripts/image_sims_pipeline/*, docs, auxdir tile lists, init_run .sh->.py:
  Martin's side wholesale — his live operational tooling on candide. The
  shapepipe-produces/sp_validation-orchestrates consolidation is deferred
  to the #766 develop-merge review, not imposed on his working branch.
- fake_psf.py / vignetmaker.py auto-merges reviewed: robustness/logging
  only, no PSF content change.
- His .felt debug fibers ride along (grid_4 blank tiles, snakemake OMP
  thread exhaustion) — both operationally important.

Verified: tests/module/test_ngmix.py 22/22 in the runtime env (srun).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UvQvyJTEwYcLCwDEgpWMJ6
The image_sims_pipeline Snakefile invokes all container commands through
this wrapper; it strips SLURM/PMI/PMIX/OMPI env vars that crash OpenMPI
inside apptainer on SLURM compute nodes. No replacement exists in
run_scratch_local.sh or run_job_sp_canfar_v2.0.bash.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cailmdaley and others added 6 commits July 10, 2026 22:18
The image-simulation pipeline's orchestration now lives in sp_validation
(companion PR #225), which drives ShapePipe via `run_job -t image_sims
--config_dir`. The in-repo Snakemake driver under
scripts/image_sims_pipeline/ (Snakefile, info.py, monitor_mbias.py,
config.yaml.template) is superseded and removed to keep a single source
of orchestration truth.

Its coverage-scan helper, check_tile_coverage.py, is the one piece of
reusable logic with no equivalent elsewhere; it moves to scripts/python/
alongside the other run-directly helpers (create_final_cat.py, etc.) and
gains the executable bit to match that directory's convention and its own
shebang.

docs/source/image_sims_calibration.md documented only this retired
orchestrator (its Snakemake targets, info.py, monitor_mbias.py) and was
an orphan page not wired into any Sphinx toctree; it is removed with the
code it described. History of the old pipeline is preserved in the
.felt/ notes, which are left untouched as a chronological record.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Z3fwStiamMsEswbJ66BeF
The runner self-computes config_dir from --type (example/cfis for data,
example/cfis_image_sims for image_sims) and threads it through the cfis
symlinks, SP_CONFIG, and job_sp_canfar's own -c. That hardcodes the .ini
tree to the in-repo example dirs.

Add an optional -c/--config_dir that, when given, overrides the computed
config_dir uniformly for any --type. The override is applied after the
type branch, so when the flag is absent config_dir is byte-for-byte the
historical value and every existing caller (test_tile_det.py, functions.sh,
the sp_validation im_pipeline rule) is unaffected. This lets the
sp_validation workflow point every stage at an explicit .ini tree, per the
image-sims boundary rule (workflow selects and parameterizes the tree).

The flag name matches job_sp_canfar_v2.0.bash's own -c/--config_dir.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Z3fwStiamMsEswbJ66BeF
The cfis_image_sims fake_psf config hardcoded a collaborator-specific
absolute path to the SKiLLS PSF dictionary, coupling the in-repo config
tree to one machine's layout. Replace it with PSF_DICT_PATH = $PSF_DICT,
which the config layer's getexpanded (os.path.expandvars) resolves from
the environment. The orchestrating workflow now exports PSF_DICT from its
psf_dict config key, so the campaign fact lives upstream in the manifest,
not in this repo -- matching the module-config/workflow boundary rule.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Z3fwStiamMsEswbJ66BeF
Add a README to example/cfis_image_sims/ giving the accurate, per-bit
mapping of the image-sims chain: for each job bit (1..2048), the ShapePipe
module, the .ini file job_sp_canfar_v2.0.bash selects under sim settings,
and the special-casing run_job_sp_canfar_v2.0.bash applies. Every row is
derived by reading the two bash scripts, so the table stays a truthful
reference for the sims path rather than a guess.

Captures the parts that surprise: the faked weight-uncompress at bit 2,
the placeholder bit 64 with fake_psf actually running inside bit 512, the
dashed tile-id convention, forced tile_det=sx, and symlink retrieval. Adds
the parallelism model (per-tile fan-out, in-job SMP, no MPI) and the
$PSF_DICT env requirement for fake_psf.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Z3fwStiamMsEswbJ66BeF
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H2wXqsx5RprRXVh4MQsn6h
@martinkilbinger

Copy link
Copy Markdown
Contributor Author

@cailmdaley is this ready to be merged?

@cailmdaley

Copy link
Copy Markdown
Contributor

not yet, tests are failing and i have a big cleanup/redesign un-pushed. i was waiting for your comments or approval on the redesign, which i sketched out in the description of this PR and in the description of sp_validation PR 225 (the latter contains most of the important design logic). please tell me what you think or just give me the green light to go ahead, i didn't want to step on your toes again :)

@martinkilbinger

Copy link
Copy Markdown
Contributor Author

as fas as I can see the new design looks good, you have green light to go ahead

martinkilbinger and others added 7 commits July 15, 2026 12:09
Brings in the latest im_sims tip: the develop merge (ngmix v2.0 metacal
kernel selection, mask/sextractor/setools fixes, Renovate migration,
science guardrail suite) plus two new image-sims commits — info.py's
improved merged-HDF5 reading (8294fa5) and the Pujol citation comment
on config_tile_Ng_batch_psfex_sx.ini (3bc4729, which merged cleanly).

Two modify/delete conflicts, both resolved by keeping our deletions:
this branch retired the in-repo Snakemake orchestrator in f01344a, so
origin's edits to scripts/image_sims_pipeline/Snakefile (569ffe9) and
info.py (8294fa5) are dropped here (git rm). The Snakefile's operational
lore — SLURM runtime units, cpus_per_task>=12 vs `ulimit -u 1200` — is
ported to sp_validation's workflow, handled separately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The [tool.setuptools] script-files list referenced
scripts/sh/init_run_v2.0.sh, which was removed in b0804ce when the
im_sims retarget moved orchestration to sp_validation. setuptools'
build_editable errors on the missing file, breaking every Docker build
in CI (`uv pip install --no-deps -e .` → "file '...init_run_v2.0.sh'
does not exist").

The other three listed scripts (update_runs_log_file.py,
run_job_sp_canfar_v2.0.bash, job_sp_canfar_v2.0.bash) still exist, so
this removes only the stale entry. Verified with an editable-install
dry-run in the im_sims runtime container: resolves to shapepipe-1.1.0
with no build_editable error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cstring

Polish over the image-sims files this PR touches:

- check_tile_coverage.py: correct the module docstring's stale "the
  Snakefile reads the exclude list" wording — orchestration moved to
  sp_validation (f01344a), so the caller is now the sp_validation
  workflow, not an in-repo Snakefile.
- bin/shapepipe_run.py: drop the "MKDEBUG start/end" print statements
  that wrapped main().
- ngmix.py: drop two "# MKDEBUG TODO this needs to be checked!" tags
  appended to the zero-sigma / zero-noise weight guards; the preceding
  comments already explain why the guards exist.

Only strips MKDEBUG introduced by the im_sims merges; the pre-existing
marker in create_final_cat.py (also on develop) is left untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two private fiber notes (blank-input-tiles-grid-4, snakemake-crash-
runtimeerror) were committed on origin/im_sims in 9783a2e, before the
develop-side .felt untrack (3d56ec6) landed there, so they survived the
merge into this branch. The repo gitignores /.felt/ and treats it as a
machine-local symlink into the private loom store (see CLAUDE.md); these
tracked files bypass that ignore. Untrack them (kept on disk) so no
fiber content rides into the shared CosmoStat repo. Their operational
lore is preserved in sp_validation's workflow docs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cailmdaley

Copy link
Copy Markdown
Contributor

i merged in my redesign and reran the whole pipeline, with no changes to the m-bias that comes out, so i am going to merge this and the corresponding sp_validation PR.

@cailmdaley cailmdaley merged commit 84e40a5 into develop Jul 15, 2026
3 checks passed
@cailmdaley cailmdaley deleted the im_sims branch July 15, 2026 15:52
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.

Image simulations runnable by Martin & others

2 participants