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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions