Coverage for tests / test_inject_engine.py: 36%

55 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-21 10:57 +0000

1# This file is part of source_injection. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22import unittest 

23from types import GeneratorType 

24 

25import galsim 

26import numpy as np 

27from galsim import BoundsI, GSObject 

28 

29import lsst.utils.tests 

30from lsst.geom import Point2D, SpherePoint, degrees 

31from lsst.source.injection.inject_engine import ( 

32 generate_galsim_objects, 

33 inject_galsim_objects_into_exposure, 

34 make_galsim_object, 

35) 

36from lsst.source.injection.utils.test_utils import make_test_exposure, make_test_injection_catalog 

37from lsst.utils.tests import MemoryTestCase, TestCase 

38 

39 

40class InjectEngineTestCase(TestCase): 

41 """Test the inject_engine.py module.""" 

42 

43 def setUp(self): 

44 """Set up synthetic source injection inputs. 

45 

46 This method sets up a noisy synthetic image with Gaussian PSFs injected 

47 into the frame, an example source injection catalog, and a generator of 

48 GalSim objects intended for injection. 

49 """ 

50 self.exposure = make_test_exposure() 

51 self.injection_catalog = make_test_injection_catalog( 

52 self.exposure.getWcs(), 

53 self.exposure.getBBox(), 

54 ) 

55 self.galsim_objects = generate_galsim_objects( 

56 injection_catalog=self.injection_catalog, 

57 photo_calib=self.exposure.photoCalib, 

58 wcs=self.exposure.wcs, 

59 fits_alignment="wcs", 

60 stamp_prefix="", 

61 ) 

62 

63 def tearDown(self): 

64 del self.exposure 

65 del self.injection_catalog 

66 del self.galsim_objects 

67 

68 def test_make_galsim_object(self): 

69 source_data = self.injection_catalog[0] 

70 sky_coords = SpherePoint(float(source_data["ra"]), float(source_data["dec"]), degrees) 

71 pixel_coords = self.exposure.wcs.skyToPixel(sky_coords) 

72 inst_flux = self.exposure.photoCalib.magnitudeToInstFlux(source_data["mag"], pixel_coords) 

73 object = make_galsim_object( 

74 source_data=source_data, 

75 source_type=source_data["source_type"], 

76 inst_flux=inst_flux, 

77 ) 

78 self.assertIsInstance(object, GSObject) 

79 self.assertIsInstance(object, getattr(galsim, source_data["source_type"])) 

80 

81 def test_generate_galsim_objects(self): 

82 self.assertTrue(isinstance(self.galsim_objects, GeneratorType)) 

83 for galsim_object in self.galsim_objects: 

84 self.assertIsInstance(galsim_object, tuple) 

85 self.assertEqual(len(galsim_object), 4) 

86 self.assertIsInstance(galsim_object[0], SpherePoint) # RA/Dec 

87 self.assertIsInstance(galsim_object[1], Point2D) # x/y 

88 self.assertIsInstance(galsim_object[2], int) # draw size 

89 self.assertIsInstance(galsim_object[3], GSObject) # GSObject 

90 

91 def test_inject_galsim_objects_into_exposure(self): 

92 flux0 = np.sum(self.exposure.image.array) 

93 injected_outputs = inject_galsim_objects_into_exposure( 

94 exposure=self.exposure, 

95 objects=self.galsim_objects, 

96 mask_plane_name="INJECTED", 

97 calib_flux_radius=12.0, 

98 draw_size_max=1000, 

99 add_noise=False, 

100 ) 

101 pc = self.exposure.getPhotoCalib() 

102 inst_fluxes = [float(pc.magnitudeToInstFlux(mag)) for mag in self.injection_catalog["mag"]] 

103 self.assertAlmostEqual( 

104 np.sum(self.exposure.image.array) - flux0, 

105 np.sum(inst_fluxes), 

106 delta=0.00015 * np.sum(inst_fluxes), 

107 ) 

108 self.assertEqual(len(injected_outputs[0]), len(self.injection_catalog["ra"])) 

109 self.assertTrue(all(isinstance(injected_output, list) for injected_output in injected_outputs)) 

110 self.assertTrue(all(isinstance(item, int) for item in injected_outputs[0])) # draw sizes 

111 self.assertTrue(all(isinstance(item, BoundsI) for item in injected_outputs[1])) # common bounds 

112 self.assertTrue(all(isinstance(item, bool) for item in injected_outputs[2])) # FFT size errors 

113 self.assertTrue(all(isinstance(item, bool) for item in injected_outputs[3])) # PSF compute errors 

114 

115 

116class MemoryTestCase(MemoryTestCase): 

117 """Test memory usage of functions in this script.""" 

118 

119 pass 

120 

121 

122def setup_module(module): 

123 """Configure pytest.""" 

124 lsst.utils.tests.init() 

125 

126 

127if __name__ == "__main__": 127 ↛ 128line 127 didn't jump to line 128 because the condition on line 127 was never true

128 lsst.utils.tests.init() 

129 unittest.main()