Skip to content

Commit 8f56d36

Browse files
author
Ruo-yu Shang
committed
modified unit test
1 parent 09dd230 commit 8f56d36

File tree

1 file changed

+37
-76
lines changed

1 file changed

+37
-76
lines changed

src/ctapipe/image/tests/test_hillas.py

Lines changed: 37 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -269,92 +269,53 @@ def test_psi_uncertainty():
269269
pix_area=np.full(9, 1.0) * u.cm**2,
270270
)
271271

272-
# symmetric image should have large uncertainty
272+
image = np.zeros((3, 3))
273+
image[0, 0] = 2
274+
image[0, 1] = 0
275+
image[0, 2] = 0
276+
image[1, 0] = 0
277+
image[1, 1] = 5
278+
image[1, 2] = 0
279+
image[2, 0] = 0
280+
image[2, 1] = 0
281+
image[2, 2] = 2
282+
image = image.ravel()
283+
hillas = hillas_parameters(geom, image)
284+
assert np.isclose(
285+
hillas.psi_uncertainty.to_value(u.deg), 20.25711711353489, rtol=1e-05
286+
)
287+
273288
image = np.zeros((3, 3))
274289
image[0, 0] = 5
275-
image[0, 1] = 5
276-
image[0, 2] = 5
277-
image[1, 0] = 5
290+
image[0, 1] = 0
291+
image[0, 2] = 0
292+
image[1, 0] = 0
278293
image[1, 1] = 10
279-
image[1, 2] = 5
280-
image[2, 0] = 5
281-
image[2, 1] = 5
294+
image[1, 2] = 0
295+
image[2, 0] = 0
296+
image[2, 1] = 0
282297
image[2, 2] = 5
283298
image = image.ravel()
284299
hillas = hillas_parameters(geom, image)
285-
assert hillas.psi_uncertainty.value > 1e10
286-
287-
# check two images with identical morphology but different intensities
288-
image1 = np.zeros((3, 3))
289-
image1[0, 0] = 5
290-
image1[1, 1] = 10
291-
image1[2, 2] = 5
292-
image2 = np.zeros((3, 3))
293-
intensity_scaling = 2.0
294-
image2 += image1 * intensity_scaling
295-
image1 = image1.ravel()
296-
image2 = image2.ravel()
297-
hillas1 = hillas_parameters(geom, image1)
298-
hillas2 = hillas_parameters(geom, image2)
299-
assert (
300-
abs(
301-
hillas1.psi_uncertainty.value / hillas2.psi_uncertainty.value
302-
- np.sqrt(intensity_scaling)
303-
)
304-
< 1e-4
300+
assert np.isclose(
301+
hillas.psi_uncertainty.to_value(u.deg), 12.811725781509189, rtol=1e-05
305302
)
306303

307-
# check psi uncertainty for a random image with the manual calculation
308-
image = np.random.random((3, 3)) * 100.0
304+
image = np.zeros((3, 3))
305+
image[0, 0] = 5
306+
image[0, 1] = 0
307+
image[0, 2] = 2
308+
image[1, 0] = 0
309+
image[1, 1] = 10
310+
image[1, 2] = 0
311+
image[2, 0] = 0
312+
image[2, 1] = 2
313+
image[2, 2] = 5
309314
image = image.ravel()
310315
hillas = hillas_parameters(geom, image)
311-
# Now calculate the uncertainty manually
312-
unit = geom.pix_x.unit
313-
pix_x = geom.pix_x.to_value(unit)
314-
pix_y = geom.pix_y.to_value(unit)
315-
pix_area = geom.pix_area.to_value(unit**2)
316-
image = np.asanyarray(image, dtype=np.float64)
317-
# calculate the cog as the mean of the coordinates weighted with the image
318-
cog_x = np.average(pix_x, weights=image)
319-
cog_y = np.average(pix_y, weights=image)
320-
delta_x = pix_x - cog_x
321-
delta_y = pix_y - cog_y
322-
cov = np.cov(delta_x, delta_y, aweights=image, ddof=0)
323-
eig_vals, eig_vecs = np.linalg.eigh(cov)
324-
# round eig_vals to get rid of nans when eig val is something like -8.47032947e-22
325-
HILLAS_ATOL = np.finfo(np.float64).eps
326-
near_zero = np.isclose(eig_vals, 0, atol=HILLAS_ATOL)
327-
eig_vals[near_zero] = 0
328-
# width and length are eigen values of the PCA
329-
width, length = np.sqrt(eig_vals)
330-
# psi is the angle of the eigenvector to length to the x-axis
331-
vx, vy = eig_vecs[0, 1], eig_vecs[1, 1]
332-
# psi will be consistently defined in the range (-pi/2, pi/2)
333-
if length == 0:
334-
psi = psi_uncert = np.nan
335-
else:
336-
if vx != 0:
337-
psi = np.arctan(vy / vx)
338-
else:
339-
psi = np.pi / 2
340-
# calculate higher order moments along shower axes
341-
cos_psi = np.cos(psi)
342-
sin_psi = np.sin(psi)
343-
longi = delta_x * cos_psi + delta_y * sin_psi
344-
trans = delta_x * -sin_psi + delta_y * cos_psi
345-
# lsq solution to determine uncertainty on phi
346-
W = np.diag(image / pix_area)
347-
X = np.column_stack([longi, np.ones_like(longi)])
348-
lsq_cov = np.linalg.inv(X.T @ W @ X)
349-
p = lsq_cov @ X.T @ W @ trans
350-
# p[0] is the psi angle in the rotated frame, which should be zero.
351-
# Now we add the non-zero residual psi angle in the rotated frame to psi uncertainty
352-
# We also add additional uncertainty to account for elongation of the image (i.e. width / length)
353-
psi_uncert = np.sqrt(lsq_cov[0, 0] + p[0] * p[0]) * (
354-
1.0 + pow(np.tan(width / length * np.pi / 2.0), 2)
355-
)
356-
357-
assert abs(hillas.psi_uncertainty.value - psi_uncert) / psi_uncert < 0.01
316+
assert np.isclose(
317+
hillas.psi_uncertainty.to_value(u.deg), 23.560635267712282, rtol=1e-05
318+
)
358319

359320

360321
def test_reconstruction_in_telescope_frame(prod5_lst):

0 commit comments

Comments
 (0)