From 895f8e9442d78630c99c0b90ef38f60ec0022884 Mon Sep 17 00:00:00 2001 From: James Chiang Date: Wed, 31 Jan 2024 13:13:40 -0800 Subject: [PATCH 1/4] add test for negative pixels from bleed trail code --- tests/data/neg_pixel_bleed.pickle | Bin 0 -> 16162 bytes tests/test_bleed_trails.py | 13 +++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 tests/data/neg_pixel_bleed.pickle diff --git a/tests/data/neg_pixel_bleed.pickle b/tests/data/neg_pixel_bleed.pickle new file mode 100644 index 0000000000000000000000000000000000000000..f520e55ac62b1aab1a1a465be43063b21b682d4c GIT binary patch literal 16162 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 hoUd?q@A$i~-tfOffBoIzcYb{N)zALNpLp|${|| 0)) + def test_find_channels_with_saturation(self): """ Test the function to find channels in an image that have pixels From 0a235fc2d31af15cfb80d48843443e3d463839ab Mon Sep 17 00:00:00 2001 From: Mike Jarvis Date: Fri, 2 Feb 2024 15:37:09 -0500 Subject: [PATCH 2/4] Fix oversubtraction of excess charge when off the bottom --- imsim/bleed_trails.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imsim/bleed_trails.py b/imsim/bleed_trails.py index 3388f862..cb8db97c 100644 --- a/imsim/bleed_trails.py +++ b/imsim/bleed_trails.py @@ -144,7 +144,7 @@ def __call__(self, ypix): # Off the bottom end, the charge escapes into the electronics. # We can reduce the excess charge by one full-well-worth. # These electrons are not added to any pixel though. - self.excess_charge -= self.full_well + self.excess_charge -= min(self.full_well, self.excess_charge) else: # Electrons do not escape off the top end, so excess charge is not reduced # when trying to bleed past the end of the channel. From 9bdee71a6f8953ead3cfc0a1e12c437306cab814 Mon Sep 17 00:00:00 2001 From: Mike Jarvis Date: Fri, 2 Feb 2024 16:47:05 -0500 Subject: [PATCH 3/4] Minor bug fix. obj doesn't necessarily have attribute original. --- imsim/lsst_image.py | 7 ++++++- imsim/stamp.py | 2 +- tests/test_fringing.py | 8 +++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/imsim/lsst_image.py b/imsim/lsst_image.py index e08f89db..5b49c337 100644 --- a/imsim/lsst_image.py +++ b/imsim/lsst_image.py @@ -1,4 +1,5 @@ import numpy as np +import hashlib import logging import galsim from galsim.config import RegisterImageType, GetAllParams, GetSky, AddNoise @@ -293,11 +294,15 @@ def addNoise(self, image, config, base, image_num, obj_num, current_var, logger) camera = get_camera(self.camera_name) det_name = base['det_name'] serial_number = camera[det_name].getSerial() + # Note: the regular Python hash function is non-derterministic, which is not good. + # Instead we use hashlib.sha256, which is deterministic and convert that to an integer. + # https://stackoverflow.com/questions/27954892/deterministic-hashing-in-python-3 + seed = int(hashlib.sha256(serial_number.encode('UTF-8')).hexdigest(), 16) & 0xFFFFFFFF # Only apply fringing to e2v sensors. if serial_number[:3] == 'E2V': ccd_fringing = CCD_Fringing(true_center=image.wcs.toWorld(image.true_center), boresight=self.boresight, - seed=hash(serial_number), spatial_vary=True) + seed=seed, spatial_vary=True) ny, nx = sky.array.shape xarr, yarr = np.meshgrid(range(nx), range(ny)) logger.info("Apply fringing") diff --git a/imsim/stamp.py b/imsim/stamp.py index 2913b22f..d6043cb8 100644 --- a/imsim/stamp.py +++ b/imsim/stamp.py @@ -293,7 +293,7 @@ def _getGoodPhotImageSize1(self, obj, keep_sb_level, pixel_scale): else: obj_list.append(item) obj = galsim.Add(obj_list) - elif isinstance(obj.original, galsim.RandomKnots): + elif hasattr(obj, 'original') and isinstance(obj.original, galsim.RandomKnots): # Handle RandomKnots object directly obj = obj.original._profile diff --git a/tests/test_fringing.py b/tests/test_fringing.py index 9bd0cba2..1dfcb598 100644 --- a/tests/test_fringing.py +++ b/tests/test_fringing.py @@ -1,4 +1,5 @@ import numpy as np +import hashlib import pytest from imsim import make_batoid_wcs, CCD_Fringing, get_camera import galsim @@ -18,6 +19,7 @@ def test_fringing(): camera = get_camera() det_name = 'R22_S11' serial_num = camera[det_name].getSerial() + seed = int(hashlib.sha256(serial_num.encode('UTF-8')).hexdigest(), 16) & 0xFFFFFFFF xarr, yarr = np.meshgrid(range(4096), range(4004)) @@ -41,7 +43,7 @@ def test_fringing(): ccd_fringing = CCD_Fringing(true_center=image.wcs.toWorld(image.true_center), boresight=world_center, - seed=hash(serial_num), spatial_vary=True) + seed=seed, spatial_vary=True) # Test zero value error with pytest.raises(ValueError): ccd_fringing.calculate_fringe_amplitude(xarr, yarr, amplitude=0) @@ -91,7 +93,7 @@ def test_fringing(): ccd_fringing_1 = CCD_Fringing(true_center=image.wcs.toWorld(image.true_center), boresight=world_center, - seed=hash(serial_num), spatial_vary=False) + seed=seed, spatial_vary=False) fringe_map1 = ccd_fringing_1.calculate_fringe_amplitude(xarr,yarr) # Try another random location on the focal plane. @@ -101,7 +103,7 @@ def test_fringing(): ccd_fringing_2 = CCD_Fringing(true_center=image.wcs.toWorld(image.true_center), boresight=world_center, - seed=hash(serial_num), spatial_vary=False) + seed=seed, spatial_vary=False) fringe_map2 = ccd_fringing_2.calculate_fringe_amplitude(xarr,yarr) # Check if the two fringing maps are indentical. if np.array_equal(fringe_map1,fringe_map2) != True: From 57ec5c377fbaa452671ab3246809765b4e01a602 Mon Sep 17 00:00:00 2001 From: Mike Jarvis Date: Fri, 2 Feb 2024 22:31:17 -0500 Subject: [PATCH 4/4] Update imsim/lsst_image.py --- imsim/lsst_image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imsim/lsst_image.py b/imsim/lsst_image.py index 5b49c337..027495f0 100644 --- a/imsim/lsst_image.py +++ b/imsim/lsst_image.py @@ -294,7 +294,7 @@ def addNoise(self, image, config, base, image_num, obj_num, current_var, logger) camera = get_camera(self.camera_name) det_name = base['det_name'] serial_number = camera[det_name].getSerial() - # Note: the regular Python hash function is non-derterministic, which is not good. + # Note: the regular Python hash function is non-deterministic, which is not good. # Instead we use hashlib.sha256, which is deterministic and convert that to an integer. # https://stackoverflow.com/questions/27954892/deterministic-hashing-in-python-3 seed = int(hashlib.sha256(serial_number.encode('UTF-8')).hexdigest(), 16) & 0xFFFFFFFF