Metacal flags are nonzero whenever a type has no measured shear, using ngmix's own bits - #854
Merged
Merged
Conversation
mcal_flags (NGMIX_MCAL_FLAGS) faithfully recorded failures ngmix *reported*, but defaulted an absent metacal-type result or missing 'flags' key to 0 -- success -- so a fitter failing silently (sentinel outputs, flags never set) produced a fully-populated catalogue with an all-zero flag column. Close the hole three ways: * absent result / absent 'flags' now contributes FLAG_NO_RESULT (2^30) to mcal_flags and to mcal_types_fail instead of counting as success; * a nominally clean fit (mcal_flags == 0) whose noshear shear is non-finite is flagged FLAG_NO_RESULT -- that contradiction is always a silent failure; * end of loop: RuntimeError when objects were processed but none fitted, and a w_log.error line when 100% of fitted objects carry nonzero mcal_flags. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019dA9sas4vvNBcNKRmi973L
…one empty edge tile) The end-of-run 0-fitted guard from #854 raised RuntimeError, which would abort an entire multi-tile campaign job over a single tile with no valid objects. Demote to the same w_log.error used for the 100%-flagged case: loud enough to catch in review, not fatal to the run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_save_ngmix_data pre-fills every NGMIX_* column with sentinels and only overwrites objects present in the ngmix output. An object ngmix never fit (0 epoch to process, or an exception caught and skipped) was absent from that output and so kept the pre-fill default of MCAL_FLAGS = 0 -- read by sp_validation as "fit succeeded" (shapepipe#889). Default NGMIX_MCAL_FLAGS and the per-shear-type NGMIX_FLAGS_<SHEAR> to FLAG_NO_RESULT (imported from ngmix_package.ngmix, not duplicated), the same bit an absent per-type result gets in ngmix.get_mcal_flags. Default NGMIX_MCAL_TYPES_FAIL to len(METACAL_TYPES) (all types failed) rather than 0 failures, since sp_validation's classification_galaxy_ngmix also cuts on MCAL_TYPES_FAIL == 0. NGMIX_N_EPOCH is left at its existing 0 default, which is already the correct "never fit" value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
process()'s end-of-run 0-fitted / 100%-flagged checks were inline and only reachable through the full per-tile pipeline (Tile_cat, vignet catalogues, ...), with no unit coverage. Pull them into a module-level function taking just (w_log, count, n_fitted, n_flagged) so the 0-fitted-logs-not-raises contract can be tested directly. No behaviour change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- get_mcal_flags: an entirely absent metacal type, a result present but missing 'flags', and the mix of an absent type alongside a real failure all set FLAG_NO_RESULT rather than silently reading as success (shapepipe#853). - log_run_health: 0-fitted logs (not raises), 100%-flagged logs, and a healthy run logs nothing (shapepipe#854). - make_cat: an object absent from the ngmix output gets FLAG_NO_RESULT for MCAL_FLAGS and every FLAGS_<SHEAR> column, and len(METACAL_TYPES) for MCAL_TYPES_FAIL, while a present/clean object still reads 0 (shapepipe#889). - test_psf_averaging_properties.py's _SENTINELS contract updated to match (it previously pinned the pre-fix 0-default as the expected absent-object sentinel); its measured-row placeholder for mcal_types_fail moved off 5 now that 5 (== len(METACAL_TYPES)) is the absent sentinel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
get_type_flags is the single definition of a metacal type's success: its
fit ran, reported flags == 0 and returned a finite shear. An absent
result, a missing flags key, or flags == 0 with non-finite or missing g
all give FLAG_NO_RESULT.
compile_results now derives FLAGS_<SHEAR>, MCAL_FLAGS (OR) and
MCAL_TYPES_FAIL (count) from it, so the three columns agree by
construction. This extends the non-finite guard from noshear to all five
types (a NaN g in 1p/1m/2p/2m also poisons the response), counts such
types in MCAL_TYPES_FAIL, tolerates an absent type instead of raising
KeyError at save time, and drops compile_results' own
.get("mcal_flags", 0) absent-as-clean default.
make_cat's never-fit defaults are what ngmix derives for an empty result
(get_*({})), so the two sides cannot drift apart.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- mcal-flags-zero-means-measured (get_type_flags): 0 means the fit ran, succeeded and returned a finite shear; every NGMIX flag column derives from this, and sp_validation's galaxy cut trusts it. - never-fit-is-not-clean (_save_ngmix_data): rows ngmix never fit take the empty-result flags, never 0; couples to sp_validation's MCAL_FLAGS == 0 && MCAL_TYPES_FAIL == 0 cut. - run-health-logs-not-raises (log_run_health): wholesale failure is logged, never raised, so one tile cannot abort a campaign. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tements Add test_galaxy_cut_admits_only_measured_objects (contracts mcal-flags-zero-means-measured, never-fit-is-not-clean): synthetic metacal results covering every way a fit can fail to be a measurement, plus never-fit objects, go through compile_results/save_results and _save_ngmix_data; sp_validation's MCAL_FLAGS == 0 & MCAL_TYPES_FAIL == 0 cut must admit exactly the clean objects, each with N_EPOCH > 0 and a finite, non-sentinel shape in all five metacal types, and MCAL_FLAGS / MCAL_TYPES_FAIL must equal the OR / count of FLAGS_<SHEAR> on every row. Mutation-checked: it fails for each injected regression in get_type_flags, the aggregates, compile_results and make_cat's defaults. It subsumes test_get_mcal_flags_flags_absent_result_and_missing_flags_key (deleted) and the flag assertions added to the absent-objects test (reverted; test_absent_obj_id_keeps_sentinel_fill also pins them). The three log_run_health tests become one table over its failure modes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drive process() on a tile whose every object has no stamps: it must log the 0-fitted error and still write an empty catalogue. Catches the health check not being called and a raise re-added in process(), which the log_run_health table alone cannot see. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cailmdaley
force-pushed
the
ngmix-flag-wholesale-failure
branch
from
September 26, 2026 00:53
95d097e to
f4b2ada
Compare
centroid_source="wcs" reads the coadd-centroid OFFSET the stamp extractor writes into every vignette epoch entry. Vignettes cut before that extractor carry none, and until now that meant make_ngmix_observation raised for every object in turn while Ngmix.process's per-object exception handling quietly turned the whole tile into an empty catalogue. check_wcs_centroid_offset inspects the first object with epochs once, up front, and raises with the fix (re-extract with the current vignetmaker, or set centroid_source='hsm') instead of letting the run masquerade as healthy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cailmdaley
marked this pull request as ready for review
September 26, 2026 01:18
Move the all-empty-store guard from ngmix_runner's SqliteDict pre-scan
into Ngmix.process itself: a tile whose galaxy entries are all 'empty',
or whose PSF entries are all {}, now takes the same per-object skip path
as any other unfittable object, reaches log_run_health, and writes the
five-HDU empty catalogue campaign completeness checks expect. The runner
no longer returns early (and no longer needs sqlitedict directly).
Adds an end-to-end test through the shipped shapepipe_run launcher,
covering both the empty-galaxy-store and empty-PSF-store cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_galaxy_cut_rejects_each_nonfinite_shear_component parametrizes the existing non-finite-shear invariant over both g components (not just g1/mixed cases) and every metacal type, so a first-component-only guard in get_mcal_flags would leave a g2-only NaN/inf clean. test_process_counts_flagged_fits_across_batches drives Ngmix.process through real batched saves with known fitter outcomes and asserts the run-health error line only appears when every fitted object is flagged, closing the gap where n_flagged going disconnected from the fit loop left the whole suite green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6272edc removed both of 84e40a5's runner-level early returns for a wholesale-empty tile (all PSF entries {}, or all galaxy entries "empty"), moving the check into Ngmix.process's per-object loop so the empty catalogue and run-health log still got written. But the first of those returns was a crash guard: it must run before anything reads the galaxy vignette store, because unpickling that store's many-epoch arrays can trigger a C-level malloc crash. Nobody reproduced the crash, but the original ordering was deliberate and a malloc crash kills a campaign job, so restore it instead of trusting that Ngmix.process's later read is safe. Both guards are back in ngmix_runner, at their original position and in their original order (PSF first), with Martin's comment intact. Instead of returning silently, each now writes the same five-HDU empty catalogue and run-health error line that a zero-fitted Ngmix.process run produces, via a new write_empty_tile_output helper -- so #879's completeness check still sees a catalogue for a wholesale-empty tile, without ever constructing an Ngmix instance (which would open the galaxy vignette store) to get it. write_empty_tile_output, and the empty_metacal_output/write_ngmix_fits helpers it's built from, are shared with Ngmix.compile_results/save_results so both paths produce byte-identical empty catalogues from one source. 6272edc's other change -- checking an object's PSF entry before its galaxy entry inside Ngmix.process's per-object loop, to skip allocating the galaxy stamp when the PSF alone is already empty -- is a genuine per-object optimisation for a tile that is only partly empty, independent of the tile-wide crash guard, and is kept. Added a test asserting the PSF-all-empty guard never opens the galaxy store: the galaxy store is a corrupted (non-sqlite) file, so opening it would raise. Checked by hand that swapping the two guards' order turns this red with the expected sqlite3.DatabaseError. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cailmdaley
requested review from
fabianhervaspeters and
martinkilbinger
and removed request for
fabianhervaspeters and
martinkilbinger
September 26, 2026 12:06
Contributor
Author
|
see question on CosmoStat/sp_validation#354 (comment) |
Conflicts were docstring-adjacent: keep both this branch's text and develop's @sc decision tags in Ngmix.process and ngmix_runner, and keep both the galaxy-cut tests and develop's N_EPOCH_SLOTS tests in test_make_cat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uemfjv9ybCwtKtprksZbVY
Drop the ShapePipe-only FLAG_NO_RESULT = 2**30. get_type_flags keeps a fitter's own flags and maps every case with no finite shear -- a type reporting flags == 0 without a finite g, a result without flags, an absent type, and hence an object ngmix never fit -- to ngmix.flags.LM_FUNC_NOTFINITE (2**12). Every flag column now carries only ngmix's own bits. The never-fit contract folds into make_cat's failure-sentinel site, and astra.yaml's catalogue_assembly.failure_sentinels rationale records that never-fit rows fail the MCAL_FLAGS == 0 cut rather than passing it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uemfjv9ybCwtKtprksZbVY
Contributor
Author
|
@martinkilbinger in the end I mapped our failure cases onto the existing ngmix bits so the dtype doesn't need to be changed in sp_validation. however there were other problems with the bit-writing on the SP_validation side, so CosmoStat/sp_validation#354 still fixes these but is not high-priority. |
cailmdaley
added a commit
that referenced
this pull request
Sep 28, 2026
Resolve tests/module/test_make_cat.py by keeping both the make_cat_runner end-to-end test (no spread-model column) and #854's metacal-flag tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uemfjv9ybCwtKtprksZbVY
cailmdaley
added a commit
that referenced
this pull request
Sep 28, 2026
Picks up #854 (metacal flags). Two conflicts, both sides kept: Ngmix.process ends with the epoch-cuts info log followed by log_run_health, and ngmix_runner imports both the EPOCH_* constants and write_empty_tile_output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cailmdaley
added a commit
that referenced
this pull request
Sep 28, 2026
* fix(make_cat): return actual saved count from save_sm_data save_sm_data returned the n_obj argument it was given instead of the number of rows it actually saved, so the runner's SExtractor-vs- spread-model size check compared a value with itself and could never detect a mismatch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014bvNTrAmZxcfb1ee83ApPK * fix(make_cat): fix crashing size-mismatch log and honest spread-model logging - The size-mismatch warning called w_log(...) directly; w_log is a logger, not a callable, so a real mismatch crashed instead of being reported. Use w_log.warning(...), matching other runners, and fix the malformed message. - With no spread-model input, the runner logged "setting spread model to 99" but wrote no SPREAD_MODEL column at all. The log now says what actually happens; behaviour for the committed three-input path (SM_DO_CLASSIFICATION off) is unchanged. - SM_DO_CLASSIFICATION = True with no spread-model input is now a config error (there is nothing to classify on), raised clearly instead of being silently ignored. - A missing SM_STAR_THRESH/SM_GAL_THRESH under classification now raises a clear ValueError instead of a bare configparser.NoOptionError. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014bvNTrAmZxcfb1ee83ApPK * test(make_cat): cover spread-model path defects in save_sm_data/make_cat_runner One test per defect fixed in make_cat_runner/save_sm_data, each verified to fail against the pre-fix code and pass after: save_sm_data returning its true saved count, the size-mismatch warning logging without crashing, honest no-input logging with no SPREAD_MODEL column written (matching the committed three-input path), refusing SM_DO_CLASSIFICATION without a spread-model input, and a clear error for a missing SM_STAR_THRESH/SM_GAL_THRESH. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014bvNTrAmZxcfb1ee83ApPK * test(make_cat): fix fixture defects flagged in review - The classification-without-input test never wrote its ngmix catalogue, so on the pre-fix code it failed with catalogueFileNotFound instead of exercising the intended assertion. It now writes a matching ngmix catalogue and fails with "DID NOT RAISE ValueError" against the pre-fix runner, confirmed locally. - Single-field structured arrays (NUMBER only) get collapsed by FITSCatalogue._save_to_fits into one row with a vector-valued column whenever save_sextractor_data re-saves them, so every SExtractor-like fixture now carries a second scalar field (_numbered_data) and tests assert the NUMBER column comes back as scalar ids matching the input. - Present tense throughout: docstrings describe what each test protects, not the prior buggy behaviour; the section heading drops the branch-name reference. - New tests grouped under TestSpreadModelPathDefects so a concurrent append to this file's end (PR #854) merges as one class-sized block. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014bvNTrAmZxcfb1ee83ApPK * Remove the spread model from ShapePipe The spread-model star/galaxy classifier did not work reliably when last run and separates stars from galaxies worse than the downstream (sp_validation, size-based) classification, so ShapePipe no longer computes or carries it. - Delete spread_model_runner and spread_model_package. - make_cat_runner takes exactly three inputs (tile sexcat, galaxy PSF, ngmix); save_sm_data and the SM_DO_CLASSIFICATION / SM_STAR_THRESH / SM_GAL_THRESH keys are gone, along with the tests of that path. - Drop SM_DO_CLASSIFICATION from the committed and image-sims make_cat configs and the SPREAD_* columns from final_cat.param and example/unions_800/cat_matched.param; tidy docs and refs.bib. - astra.yaml: star_galaxy_classification is now [HARDCODED]; the spread_model_inline option is excluded, with the reasons. - A make_cat_runner end-to-end test checks every detection is kept with no classification column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
cailmdaley
added a commit
that referenced
this pull request
Sep 28, 2026
… feat/wire-external-masks Resolved by keeping develop's side everywhere #879's pre-squash content conflicted, then re-applying this branch's own changes (a846e08..dc11dab): - astra.yaml: the mask-cut decision moves into the masking sub-analysis as masking.mask_default_cut, in the #875 format (no Anchor sentence; the make_cat contract tag cites it). masking.sky_mask_application now selects catalogue_columns, since the committed config sets MASK_EXT_PATHS; config_tile_Mc.ini's MASK_EXT_PATHS carries its tag. universes pinned. - cfis_image_sims/config_tile_Mc.ini: rebuilt from develop's cfis copy (spread model gone), still without MASK_EXT_PATHS or per-epoch slots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cailmdaley
added a commit
that referenced
this pull request
Sep 28, 2026
… feat/retire-versioning Resolved by keeping develop's side where #879's pre-squash content conflicted, then re-applying this branch's own changes (a846e08..bfb7efc). Two by hand: docs/source/pipeline_canfar.md stays retired (develop's one-line path fix goes with it), and the rebuilt tutorial drops the spread-model step that #911 removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cailmdaley
added a commit
that referenced
this pull request
Sep 28, 2026
Brings in #879 (campaign merges), #911 (spread model removed), #854, #905 and #923. - run_config: input_types:/machines: table resolver kept; develop's required `run:` and unresolved-$ check folded in (now over every non-table key). - create_final_cat.read_data keeps develop's raise on a missing column; the branch's skip-missing path is dropped (final_cat_merge is the one producer of final_cat_<run>.hdf5). - final_cat.param carries both NUMBER and TILE_UNIQUE_ID. - DAG tests follow the committed tile_detection default (data plans tile_get_catalogue); params pin regenerated for the tile_detect switch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DksuyF9YrZAwHQeAMXsxp4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #853. Closes #889.
sp_validation keeps a galaxy only if
NGMIX_MCAL_FLAGS == 0andNGMIX_MCAL_TYPES_FAIL == 0, i.e. metacal succeeded. ShapePipe writes 0 in two cases where it did not:-10sentinel check keeps them out of the shear sample.flags == 0with a non-finite or missing shear. It counts as a success.Design. One function,
get_type_flagsinngmix.py, decides whether a metacal type succeeded.NGMIX_FLAGS_<SHEAR>,NGMIX_MCAL_FLAGS(their OR) andNGMIX_MCAL_TYPES_FAIL(the count of nonzero types) all derive from it, including the values make_cat writes for never-fit objects, so the three columns cannot disagree. Every failure carries one of ngmix's own flag bits; ShapePipe adds none, so every nonzero value decodes withngmix.flags.flags, unchangedflags == 0butgnon-finite or missingngmix.flags.LM_FUNC_NOTFINITE(2**12)flagskey, or metacal type absentLM_FUNC_NOTFINITELM_FUNC_NOTFINITEin all fiveFLAGS_<SHEAR>andMCAL_FLAGS;MCAL_TYPES_FAIL = 5A genuine LM fit can also set
LM_FUNC_NOTFINITE;NGMIX_N_EPOCH == 0identifies never-fit rows. The consumer cut is== 0, so it rejects both either way.Also in this PR
centroid_source = "wcs"(the default) and the vignettes lackOFFSET(cut by an older vignetmaker). Otherwise every fit raises and the tile silently yields an empty catalogue.ngmix_runner's early exits for tiles whose PSF or galaxy stamps are all empty now log the same error and write the empty catalogue the workflow's completeness check expects.astra.yaml: thecatalogue_assembly.failure_sentinelsrationale and option label describe the new flag values; the pinned option is unchanged.Tests. Synthetic results for each failure path, plus two never-fit objects, go through ngmix's writer and make_cat. The test asserts that the galaxy cut keeps exactly the two clean objects, checks each object's exact
MCAL_FLAGS, thatMCAL_FLAGSandMCAL_TYPES_FAILequal the OR and count of the per-type columns, and that no bit outsidengmix.flagsappears. A parametrised test checks that NaN or ±inf in either shear component of any type yieldsLM_FUNC_NOTFINITE. An end-to-endshapepipe_runon an all-empty tile must write one empty catalogue and log the error once. Full suite: 689 passed, 1 skipped (plus the 2 known errors intests/cluster/test_star_shear_response.py).For reviewers
== 0cut rejects these objects even when the value wraps; only the decodable bit content needs Tutorial updates #354.ngmix.py(end ofNgmix.process) andngmix_runner.py(import line), from this PR's run-health and empty-tile changes. Keeping both sides resolves both.— Claude (Opus) on behalf of Cail
🤖 Generated with Claude Code