Skip to content

Commit d333fb1

Browse files
Jammy2211Jammy2211
authored andcommitted
fix: synthetic positions fallback in test mode and PYAUTO_SMALL_DATASETS
- Result.positions_likelihood_from: when PYAUTO_TEST_MODE is active and the resolved positions are empty / contain NaN / contain inf, substitute [(1.0, 0.0), (-1.0, 0.0)] so the threshold and PositionsLH still build. Outside test mode the behaviour is unchanged. - PointSolver.solve: when PYAUTO_SMALL_DATASETS=1, return [(1.0, 0.0), (0.0, 1.0)] immediately and skip the triangle-tiling solve. Lets simulator scripts drop their os.environ.pop("PYAUTO_SMALL_DATASETS") workarounds. - Adds one unit test for the test-mode fallback path. Closes #477.
1 parent 638d677 commit d333fb1

3 files changed

Lines changed: 71 additions & 1 deletion

File tree

autolens/analysis/result.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
)
3232
from autolens.lens.tracer import Tracer
3333
from autolens.point.solver import PointSolver
34-
from autoconf.test_mode import skip_checks
34+
from autoconf.test_mode import is_test_mode, skip_checks
3535

3636
logger = logging.getLogger(__name__)
3737

@@ -301,6 +301,19 @@ def positions_likelihood_from(
301301
system is being analysed where the specific plane via its redshift is required to define whihch source
302302
galaxy is used to compute the multiple images.
303303
304+
Notes
305+
-----
306+
Test-mode safeguard (``PYAUTO_TEST_MODE``): integration tests intentionally fit
307+
random / unphysical mass models and the resulting tracer often back-traces to
308+
zero, NaN, or inf image-plane positions. Computing a position threshold from
309+
such positions raises ``ValueError: zero-size array to reduction operation
310+
fmax`` (or propagates NaN) inside ``positions_threshold_from``. When test mode
311+
is active and the resolved positions are empty, contain NaN, or contain inf,
312+
we substitute the synthetic pair ``[(1.0, 0.0), (-1.0, 0.0)]`` so the threshold
313+
and ``PositionsLH`` still build cleanly and the script runs end-to-end.
314+
Outside test mode this branch is never taken — bad positions still surface as
315+
the original error, so production fits are not silently masked.
316+
304317
Returns
305318
-------
306319
The `PositionsLH` object used to apply a likelihood penalty or resample the positions.
@@ -330,6 +343,15 @@ def positions_likelihood_from(
330343
np.asarray(positions.array if hasattr(positions, "array") else positions)
331344
)
332345

346+
if is_test_mode():
347+
arr = positions.array
348+
if arr.shape[0] < 2 or np.isnan(arr).any() or np.isinf(arr).any():
349+
logger.warning(
350+
"positions_likelihood_from: empty/NaN/inf positions in PYAUTO_TEST_MODE — "
351+
"substituting synthetic fallback [(1.0, 0.0), (-1.0, 0.0)]."
352+
)
353+
positions = aa.Grid2DIrregular(values=[(1.0, 0.0), (-1.0, 0.0)])
354+
333355
threshold = self.positions_threshold_from(
334356
factor=factor,
335357
minimum_threshold=minimum_threshold,

autolens/point/solver/point_solver.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
default but can be retained for use inside a ``jax.jit``-traced function.
1818
"""
1919
import logging
20+
import os
2021
from typing import Tuple, Optional
2122

2223
import numpy as np
@@ -73,7 +74,22 @@ def solve(
7374
-------
7475
A ``Grid2DIrregular`` of image-plane coordinates, always numpy-backed even when the
7576
solver uses a JAX backend internally.
77+
78+
Notes
79+
-----
80+
Smoke-test short-circuit (``PYAUTO_SMALL_DATASETS``): the triangle-tiling solve
81+
is the dominant cost in many simulator scripts and is meaningless on the
82+
downsized grids used for fast smoke tests. When ``PYAUTO_SMALL_DATASETS=1`` is
83+
set the solver returns the fixed pair ``[(1.0, 0.0), (0.0, 1.0)]`` immediately,
84+
skipping ``solve_triangles`` entirely. The two coordinates are well separated
85+
so any downstream ``positions_likelihood_from`` / threshold calculation behaves
86+
normally. ``PYAUTO_SMALL_DATASETS`` is a smoke-test-only flag and is never set
87+
inside a ``jax.jit`` trace, so a plain numpy-backed ``Grid2DIrregular`` is safe
88+
here even when the surrounding analysis uses ``xp=jnp``.
7689
"""
90+
if os.environ.get("PYAUTO_SMALL_DATASETS") == "1":
91+
return aa.Grid2DIrregular(values=[(1.0, 0.0), (0.0, 1.0)])
92+
7793
kept_triangles = super().solve_triangles(
7894
tracer=tracer,
7995
shape=Point(*source_plane_coordinate),

test_autolens/analysis/test_result.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,38 @@ def test__positions_likelihood_from(analysis_imaging_7x7):
248248
assert positions_likelihood.threshold == pytest.approx(0.2, 1.0e-4)
249249

250250

251+
def test__positions_likelihood_from__test_mode_fallback(
252+
monkeypatch, analysis_imaging_7x7,
253+
):
254+
monkeypatch.setenv("PYAUTO_TEST_MODE", "2")
255+
256+
tracer = al.Tracer(
257+
galaxies=[
258+
al.Galaxy(
259+
redshift=0.5,
260+
mass=al.mp.Isothermal(
261+
centre=(0.1, 0.0), einstein_radius=1.0, ell_comps=(0.0, 0.0)
262+
),
263+
),
264+
al.Galaxy(redshift=1.0, bulge=al.lp.SersicSph(centre=(0.0, 0.0))),
265+
]
266+
)
267+
268+
samples_summary = al.m.MockSamplesSummary(max_log_likelihood_instance=tracer)
269+
result = res.Result(samples_summary=samples_summary, analysis=analysis_imaging_7x7)
270+
271+
empty_positions = al.Grid2DIrregular(np.empty((0, 2)))
272+
273+
positions_likelihood = result.positions_likelihood_from(
274+
factor=0.1, minimum_threshold=0.2, positions=empty_positions
275+
)
276+
277+
assert isinstance(positions_likelihood, al.PositionsLH)
278+
assert len(positions_likelihood.positions) == 2
279+
assert positions_likelihood.positions[0] == pytest.approx((1.0, 0.0))
280+
assert positions_likelihood.positions[1] == pytest.approx((-1.0, 0.0))
281+
282+
251283
def test__positions_likelihood_from__mass_centre_radial_distance_min(
252284
analysis_imaging_7x7,
253285
):

0 commit comments

Comments
 (0)