@@ -81,6 +81,130 @@ def test__perfect_fit__simulate_and_reload__chi_squared_zero():
8181 shutil .rmtree (file_path )
8282
8383
84+ def _perfect_fit_dataset (galaxies , grid ):
85+ """Helper: simulate noiseless imaging and zero out the noise map for chi^2 tests."""
86+ psf = ag .Convolver .from_gaussian (
87+ shape_native = (3 , 3 ), pixel_scales = grid .pixel_scales [0 ], sigma = 0.05 , normalize = True
88+ )
89+ simulator = ag .SimulatorImaging (
90+ exposure_time = 300.0 , psf = psf , add_poisson_noise_to_data = False
91+ )
92+ dataset = simulator .via_galaxies_from (galaxies = galaxies , grid = grid )
93+ dataset .noise_map = ag .Array2D .ones (
94+ shape_native = dataset .data .shape_native , pixel_scales = grid .pixel_scales
95+ )
96+ return dataset
97+
98+
99+ def test__perfect_fit__sim_offset_centre__fit_with_dataset_model_grid_offset__chi_squared_zero ():
100+ """Sim a profile with offset centre; fit with origin profile + DatasetModel.grid_offset."""
101+ grid = ag .Grid2D .uniform (shape_native = (31 , 31 ), pixel_scales = 0.2 , over_sample_size = 1 )
102+ centre = (0.3 , 0.2 )
103+
104+ sim_galaxy = ag .Galaxy (
105+ redshift = 0.5 ,
106+ light = ag .lp .Sersic (centre = centre , intensity = 0.5 , effective_radius = 0.5 ),
107+ )
108+ dataset = _perfect_fit_dataset ([sim_galaxy ], grid )
109+ mask = ag .Mask2D .circular (
110+ shape_native = dataset .data .shape_native , pixel_scales = 0.2 , radius = 2.5
111+ )
112+ masked = dataset .apply_mask (mask = mask )
113+
114+ fit_galaxy = ag .Galaxy (
115+ redshift = 0.5 ,
116+ light = ag .lp .Sersic (centre = (0.0 , 0.0 ), intensity = 0.5 , effective_radius = 0.5 ),
117+ )
118+ dataset_model = ag .DatasetModel (grid_offset = centre )
119+ fit = ag .FitImaging (
120+ dataset = masked , galaxies = [fit_galaxy ], dataset_model = dataset_model
121+ )
122+
123+ assert fit .chi_squared == pytest .approx (0.0 , abs = 1e-4 )
124+
125+
126+ def test__perfect_fit__sim_rotated_ellipse__fit_with_dataset_model_grid_rotation__chi_squared_zero ():
127+ """Sim a rotated ellipse; fit with axis-aligned profile + DatasetModel.grid_rotation_angle.
128+
129+ Convention: profile with ell-angle theta is equivalent to grid rotated by -theta,
130+ so fit with grid_rotation_angle=-theta to recover chi^2 = 0.
131+ """
132+ grid = ag .Grid2D .uniform (shape_native = (31 , 31 ), pixel_scales = 0.2 , over_sample_size = 1 )
133+ theta = 15.0
134+
135+ sim_galaxy = ag .Galaxy (
136+ redshift = 0.5 ,
137+ light = ag .lp .Sersic (
138+ centre = (0.0 , 0.0 ),
139+ ell_comps = ag .convert .ell_comps_from (axis_ratio = 0.6 , angle = theta ),
140+ intensity = 0.5 ,
141+ effective_radius = 0.5 ,
142+ ),
143+ )
144+ dataset = _perfect_fit_dataset ([sim_galaxy ], grid )
145+ mask = ag .Mask2D .circular (
146+ shape_native = dataset .data .shape_native , pixel_scales = 0.2 , radius = 2.5
147+ )
148+ masked = dataset .apply_mask (mask = mask )
149+
150+ fit_galaxy = ag .Galaxy (
151+ redshift = 0.5 ,
152+ light = ag .lp .Sersic (
153+ centre = (0.0 , 0.0 ),
154+ ell_comps = ag .convert .ell_comps_from (axis_ratio = 0.6 , angle = 0.0 ),
155+ intensity = 0.5 ,
156+ effective_radius = 0.5 ,
157+ ),
158+ )
159+ dataset_model = ag .DatasetModel (grid_rotation_angle = - theta )
160+ fit = ag .FitImaging (
161+ dataset = masked , galaxies = [fit_galaxy ], dataset_model = dataset_model
162+ )
163+
164+ assert fit .chi_squared == pytest .approx (0.0 , abs = 1e-4 )
165+
166+
167+ def test__perfect_fit__sim_offset_and_rotated__fit_with_dataset_model_offset_and_rotation__chi_squared_zero ():
168+ """Combined: sim with offset centre AND rotated ellipse, fit with identity profile +
169+ DatasetModel(grid_offset, grid_rotation_angle)."""
170+ grid = ag .Grid2D .uniform (shape_native = (31 , 31 ), pixel_scales = 0.2 , over_sample_size = 1 )
171+ centre = (0.3 , 0.2 )
172+ theta = 12.0
173+
174+ sim_galaxy = ag .Galaxy (
175+ redshift = 0.5 ,
176+ light = ag .lp .Sersic (
177+ centre = centre ,
178+ ell_comps = ag .convert .ell_comps_from (axis_ratio = 0.6 , angle = theta ),
179+ intensity = 0.5 ,
180+ effective_radius = 0.5 ,
181+ ),
182+ )
183+ dataset = _perfect_fit_dataset ([sim_galaxy ], grid )
184+ mask = ag .Mask2D .circular (
185+ shape_native = dataset .data .shape_native , pixel_scales = 0.2 , radius = 2.5
186+ )
187+ masked = dataset .apply_mask (mask = mask )
188+
189+ fit_galaxy = ag .Galaxy (
190+ redshift = 0.5 ,
191+ light = ag .lp .Sersic (
192+ centre = (0.0 , 0.0 ),
193+ ell_comps = ag .convert .ell_comps_from (axis_ratio = 0.6 , angle = 0.0 ),
194+ intensity = 0.5 ,
195+ effective_radius = 0.5 ,
196+ ),
197+ )
198+ dataset_model = ag .DatasetModel (
199+ grid_offset = centre , grid_rotation_angle = - theta
200+ )
201+ fit = ag .FitImaging (
202+ dataset = masked , galaxies = [fit_galaxy ], dataset_model = dataset_model
203+ )
204+
205+ assert fit .chi_squared == pytest .approx (0.0 , abs = 1e-4 )
206+
207+
84208def test__simulate_imaging_data_and_fit__standard_galaxies__known_figure_of_merit ():
85209 grid = ag .Grid2D .uniform (shape_native = (31 , 31 ), pixel_scales = 0.2 )
86210
0 commit comments