Skip to content

Commit 345a737

Browse files
authored
Merge pull request #560 from PyAutoLabs/feature/howtolens-tutorial3-nan-axis-test
test: regression guard for HowToLens tutorial_3 NaN axis-limits crash
2 parents 6560762 + e738cae commit 345a737

1 file changed

Lines changed: 128 additions & 0 deletions

File tree

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"""
2+
Regression test for the HowToLens chapter-1 ``tutorial_3_more_ray_tracing``
3+
crash: ``ValueError: Axis limits cannot be NaN or Inf during plotting``.
4+
5+
The tutorial builds a multi-plane tracer whose lens mass profiles are singular
6+
isothermal spheres centred on grid pixels. Historically the deflection angles
7+
evaluated at those singular centres produced NaN/Inf, so the traced
8+
source-plane grid contained non-finite coordinates; the tracer plotters then
9+
derived their axis limits from those coordinates and matplotlib raised
10+
``ValueError: Axis limits cannot be NaN or Inf``.
11+
12+
The fix was made at the *producer*: the mass-profile deflection code now handles
13+
``r = 0`` (see autogalaxy "handle r=0 in ... deflections" and the NaN-safe
14+
masking changes), so the traced grids and images stay finite and the plotters
15+
receive finite extents.
16+
17+
These tests lock that in by reproducing the tutorial-3 four-galaxy, two-plane
18+
tracer on a grid whose pixels coincide with the singular mass centres, and
19+
asserting (a) the traced grids and image remain finite and (b) the tracer
20+
subplots render without raising.
21+
"""
22+
import numpy as np
23+
import pytest
24+
25+
import autolens as al
26+
from autolens.lens.plot.tracer_plots import (
27+
subplot_tracer,
28+
subplot_galaxies_images,
29+
)
30+
31+
32+
@pytest.fixture(name="grid_singular_centres")
33+
def make_grid_singular_centres():
34+
# An odd ``shape_native`` with 0.5" pixels places pixels exactly on the
35+
# singular mass centres at (0.0, 0.0) and (1.0, 0.0) -- the historical
36+
# NaN/Inf trigger for the deflection angles.
37+
return al.Grid2D.uniform(shape_native=(7, 7), pixel_scales=0.5)
38+
39+
40+
@pytest.fixture(name="tracer_tutorial_3")
41+
def make_tracer_tutorial_3():
42+
# The "Multi Galaxy Ray Tracing" tracer from HowToLens tutorial 3: two lens
43+
# galaxies at z=0.5 (a main lens with a singular isothermal + external shear
44+
# and a satellite) and two source galaxies at z=1.0.
45+
lens = al.Galaxy(
46+
redshift=0.5,
47+
bulge=al.lp.SersicSph(
48+
centre=(0.0, 0.0), intensity=2.0, effective_radius=0.5, sersic_index=2.5
49+
),
50+
mass=al.mp.Isothermal(
51+
centre=(0.0, 0.0), ell_comps=(0.0, -0.111111), einstein_radius=1.6
52+
),
53+
shear=al.mp.ExternalShear(gamma_1=0.05, gamma_2=0.0),
54+
)
55+
lens_satellite = al.Galaxy(
56+
redshift=0.5,
57+
bulge=al.lp.DevVaucouleursSph(
58+
centre=(1.0, 0.0), intensity=2.0, effective_radius=0.2
59+
),
60+
mass=al.mp.IsothermalSph(centre=(1.0, 0.0), einstein_radius=0.4),
61+
)
62+
source_0 = al.Galaxy(
63+
redshift=1.0,
64+
bulge=al.lp.DevVaucouleursSph(
65+
centre=(0.1, 0.2), intensity=0.3, effective_radius=0.3
66+
),
67+
disk=al.lp.ExponentialCore(
68+
centre=(0.1, 0.2),
69+
ell_comps=(0.111111, 0.0),
70+
intensity=3.0,
71+
effective_radius=2.0,
72+
),
73+
)
74+
source_1 = al.Galaxy(
75+
redshift=1.0,
76+
disk=al.lp.ExponentialCore(
77+
centre=(-0.3, -0.5),
78+
ell_comps=(0.1, 0.0),
79+
intensity=8.0,
80+
effective_radius=1.0,
81+
),
82+
)
83+
return al.Tracer(
84+
galaxies=[lens, lens_satellite, source_0, source_1],
85+
cosmology=al.cosmo.Planck15(),
86+
)
87+
88+
89+
def test__traced_grids_and_image_are_finite_at_singular_mass_centres(
90+
tracer_tutorial_3, grid_singular_centres
91+
):
92+
# Producer-side guard: deflections at the singular mass centres must not
93+
# introduce NaN/Inf, otherwise the plotters below would derive non-finite
94+
# axis limits and crash (the original tutorial-3 failure).
95+
traced = tracer_tutorial_3.traced_grid_2d_list_from(grid=grid_singular_centres)
96+
97+
for plane_grid in traced:
98+
assert np.isfinite(np.asarray(plane_grid.array)).all()
99+
100+
image = tracer_tutorial_3.image_2d_from(grid=grid_singular_centres)
101+
102+
assert np.isfinite(np.asarray(image.array)).all()
103+
104+
105+
def test__subplot_tracer__singular_mass_centres__does_not_raise(
106+
tracer_tutorial_3, grid_singular_centres, tmp_path, plot_patch
107+
):
108+
subplot_tracer(
109+
tracer=tracer_tutorial_3,
110+
grid=grid_singular_centres,
111+
output_path=tmp_path,
112+
output_format="png",
113+
)
114+
115+
assert str(tmp_path / "tracer.png") in plot_patch.paths
116+
117+
118+
def test__subplot_galaxies_images__singular_mass_centres__does_not_raise(
119+
tracer_tutorial_3, grid_singular_centres, tmp_path, plot_patch
120+
):
121+
subplot_galaxies_images(
122+
tracer=tracer_tutorial_3,
123+
grid=grid_singular_centres,
124+
output_path=tmp_path,
125+
output_format="png",
126+
)
127+
128+
assert str(tmp_path / "galaxies_images.png") in plot_patch.paths

0 commit comments

Comments
 (0)