Skip to content

fix: un-flake interferometer Delaunay test-mode FitException (+ NNLS NaN root cause) #640

Description

@Jammy2211

Overview

autolens_workspace/scripts/interferometer/features/pixelization/delaunay.py intermittently hard-fails CI smoke: the same commit (dce04672) failed one py3.12 run (ValueError: Points cannot contain NaN from the Delaunay/qhull triangulation) and passed another ~1 min apart, with no library merge in between — a true nondeterministic flake. The masked underlying cause is a NaN/non-PD in the interferometer Delaunay path; analysis.py:175-182 wraps ANY numpy-path error as af.exc.FitException (PR#607 parity guard so the sampler resamples), but under PYAUTO_TEST_MODE=2 there is no sampler, so a single unlucky eval hard-fails the script. The entry is currently parked in autolens_workspace/config/build/no_run.yaml.

Plan

  • Phase 1 — un-flake test-mode (PyAutoLens + autolens_workspace): make the TEST_MODE bypass tolerate a single-eval FitException the way a real sampler does (resample / sentinel low FOM, logged so it stays visible) instead of hard-failing. This un-flakes all FitException-prone pixelization scripts in test-mode without masking real breakage in a real fit. Then un-park the interferometer Delaunay no_run.yaml entry and add the script to smoke_tests.txt (imaging Delaunay was added in autolens_workspace#307).
  • Phase 2 — fix the numerical producer (PyAutoArray, separate PR): the smoking gun is fnnls.py:134 (alpha = np.min(d[q] / (d[q] - s_chol[q]))) — 45/250 local draws emit divide-by-zero/invalid RuntimeWarnings, usually benign but a candidate source of the fatal NaN/non-PD on CI. Guard/repair at the producer (no silent guards — fix the math) and/or the traced-mesh NaN conditioning.
Detailed implementation plan

Affected Repositories

  • PyAutoLens (primary — Phase 1 test-mode tolerance, interferometer/model/analysis.py)
  • autolens_workspace (Phase 1 — un-park marker + smoke)
  • PyAutoArray (Phase 2 — util/fnnls.py producer fix)

Branch Survey

Repository Current Branch Dirty?
./PyAutoLens docs/citations-exhaustive (other session) dirty
./PyAutoArray main clean
./autolens_workspace main clean

Suggested branch: interferometer-delaunay-flaky-fitexception

Reproduction evidence (2026-07-21)

  • True flake, not a library race: Feature/multi image visualization #307's two CI runs (same commit dce04672) ~1 min apart, one failed (qhull NaN) one passed, no PyAutoArray/PyAutoLens main merge between them.
  • Local repro hard: 250/250 random prior-instance fit_from draws clean on current main — CI-runner thread/BLAS-dependent.
  • Producer: 45/250 draws emit RuntimeWarning divide-by-zero at fnnls.py:134. Confirm which solver the script's modeling uses (use_positive_only_solver=False vs default positive/fnnls path).

Phase 1 steps

  1. PyAutoLens/autolens/interferometer/model/analysis.py:175-182 — in the TEST_MODE path, catch the single-eval FitException, log it, return a sentinel low figure-of-merit instead of propagating (mirror the real-sampler resample semantics). Check for a shared base-analysis test-mode hook so imaging/pixelization scripts benefit too.
  2. autolens_workspace/config/build/no_run.yaml — remove the interferometer Delaunay NEEDS_FIX entry.
  3. autolens_workspace/smoke_tests.txt — add interferometer/features/pixelization/delaunay.py.
  4. Verify: run the script in the exact CI smoke env repeatedly; run library unit tests; smoke.

Key Files

  • PyAutoLens/autolens/interferometer/model/analysis.py — test-mode FitException tolerance
  • PyAutoArray/autoarray/util/fnnls.py — Phase 2 divide-by-zero producer
  • autolens_workspace/config/build/no_run.yaml, smoke_tests.txt — un-park + guard

Testing

Library unit tests (numpy-only) for the test-mode tolerance path; repeated CI-env script runs to confirm the flake is gone; PyAutoHeart vitals GREEN/YELLOW before ship. Library-first: PyAutoLens PR merges before the autolens_workspace un-park.

Original Prompt

Click to expand

Filed as PyAutoMind/draft/bug/autoarray/interferometer_delaunay_intermittent_qhull_nan.md. Surfaced 2026-07-21 while un-parking the Delaunay cluster (autolens_workspace#307, follow-up to #300/#301). Two masked signatures (qhull NaN vertices + non-PD inversion), both wrapped as FitException by analysis.py:175-182. Refs (all closed): autolens_workspace#300/#307/#308/#309.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions