11import os
22from pathlib import Path
3+ import numpy as np
34import pytest
45
56from autonerves .dictable import output_to_json , from_json , from_dict
@@ -20,6 +21,46 @@ def test__check_positions_on_instantiation():
2021 al .PositionsLH (positions = al .Grid2DIrregular ([(1.0 , 2.0 )]), threshold = 0.1 )
2122
2223
24+ def _penalty (positions_lh , einstein_radius ):
25+ """The penalty for an isothermal lens of the given Einstein radius."""
26+ lens = al .Galaxy (
27+ redshift = 0.5 , mass = al .mp .Isothermal (centre = (0.0 , 0.0 ), einstein_radius = einstein_radius )
28+ )
29+ tracer = al .Tracer (galaxies = [lens , al .Galaxy (redshift = 1.0 )])
30+
31+ class MockAnalysis :
32+ def tracer_via_instance_from (self , instance ):
33+ return tracer
34+
35+ return float (
36+ positions_lh .log_likelihood_penalty_from (instance = None , analysis = MockAnalysis ())
37+ )
38+
39+
40+ def test__non_finite_positions_are_dropped_and_the_penalty_still_fires ():
41+ # `Result.positions_likelihood_from` pads the point solver's images with
42+ # (inf, inf). One such row used to make the max separation nan, so the
43+ # penalty was zero for every model.
44+ inf = np .inf
45+ positions = al .Grid2DIrregular ([(0.0 , 1.0 ), (inf , inf ), (0.0 , - 1.0 )] + [(inf , inf )] * 5 )
46+
47+ positions_lh = al .PositionsLH (positions = positions , threshold = 0.1 )
48+
49+ assert len (positions_lh .positions ) == 2
50+ # Images at +/-1" trace together only for theta_E = 1"; theta_E = 0.3" splits them.
51+ assert _penalty (positions_lh , einstein_radius = 1.0 ) == 0.0
52+ assert _penalty (positions_lh , einstein_radius = 0.3 ) > 0.0
53+
54+
55+ def test__fewer_than_two_finite_positions_raises ():
56+ inf = np .inf
57+
58+ with pytest .raises (exc .PositionsException ):
59+ al .PositionsLH (
60+ positions = al .Grid2DIrregular ([(0.0 , 1.0 ), (inf , inf ), (inf , inf )]), threshold = 0.1
61+ )
62+
63+
2364def test__output_positions_info ():
2465 output_path = Path (__file__ ).resolve ().parent / "files"
2566
0 commit comments