Coverage for tests/surveyPropertyMapsTestUtils.py: 17%

61 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-10-20 11:05 +0000

1# This file is part of pipe_tasks. 

2# 

3# LSST Data Management System 

4# This product includes software developed by the 

5# LSST Project (http://www.lsst.org/). 

6# See COPYRIGHT file at the top of the source tree. 

7# 

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

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

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

11# (at your option) any later version. 

12# 

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

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

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

16# GNU General Public License for more details. 

17# 

18# You should have received a copy of the LSST License Statement and 

19# the GNU General Public License along with this program. If not, 

20# see <https://www.lsstcorp.org/LegalNotices/>. 

21# 

22"""Utilities for HealSparsePropertyMapTask and others.""" 

23import numpy as np 

24 

25import lsst.geom as geom 

26from lsst.daf.base import DateTime 

27from lsst.afw.coord import Observatory 

28from lsst.pipe.tasks.postprocess import ConsolidateVisitSummaryTask 

29import lsst.afw.table as afwTable 

30import lsst.afw.image as afwImage 

31import lsst.afw.geom as afwGeom 

32from lsst.afw.detection import GaussianPsf 

33 

34 

35__all__ = ['makeMockVisitSummary'] 

36 

37 

38def makeMockVisitSummary(visit, 

39 ra_center=0.0, 

40 dec_center=-45.0, 

41 physical_filter='TEST-I', 

42 band='i', 

43 mjd=59234.7083333334, 

44 psf_sigma=3.0, 

45 zenith_distance=45.0, 

46 zero_point=30.0, 

47 sky_background=100.0, 

48 sky_noise=10.0, 

49 mean_var=100.0, 

50 exposure_time=100.0, 

51 detector_size=200, 

52 pixel_scale=0.2): 

53 """Make a mock visit summary catalog. 

54 

55 This will contain two square detectors with the same metadata, 

56 with a small (20 pixel) gap between the detectors. There is no 

57 rotation, as each detector is simply offset in RA from the 

58 specified boresight. 

59 

60 Parameters 

61 ---------- 

62 visit : `int` 

63 Visit number. 

64 ra_center : `float` 

65 Right ascension of the center of the "camera" boresight (degrees). 

66 dec_center : `float` 

67 Declination of the center of the "camera" boresight (degrees). 

68 physical_filter : `str` 

69 Arbitrary name for the physical filter. 

70 band : `str` 

71 Name of the associated band. 

72 mjd : `float` 

73 Modified Julian Date. 

74 psf_sigma : `float` 

75 Sigma width of Gaussian psf. 

76 zenith_distance : `float` 

77 Distance from zenith of the visit (degrees). 

78 zero_point : `float` 

79 Constant zero point for the visit (magnitudes). 

80 sky_background : `float` 

81 Background level for the visit (counts). 

82 sky_noise : `float` 

83 Noise level for the background of the visit (counts). 

84 mean_var : `float` 

85 Mean of the variance plane of the visit (counts). 

86 exposure_time : `float` 

87 Exposure time of the visit (seconds). 

88 detector_size : `int` 

89 Size of each square detector in the visit (pixels). 

90 pixel_scale : `float` 

91 Size of the pixel in arcseconds per pixel. 

92 

93 Returns 

94 ------- 

95 visit_summary : `lsst.afw.table.ExposureCatalog` 

96 """ 

97 # We are making a 2 detector "camera" 

98 n_detector = 2 

99 

100 schema = ConsolidateVisitSummaryTask().schema 

101 visit_summary = afwTable.ExposureCatalog(schema) 

102 visit_summary.resize(n_detector) 

103 

104 bbox = geom.Box2I(x=geom.IntervalI(min=0, max=detector_size - 1), 

105 y=geom.IntervalI(min=0, max=detector_size - 1)) 

106 

107 for detector_id in range(n_detector): 

108 row = visit_summary[detector_id] 

109 

110 row['id'] = detector_id 

111 row.setBBox(bbox) 

112 row['visit'] = visit 

113 row['physical_filter'] = physical_filter 

114 row['band'] = band 

115 row['zenithDistance'] = zenith_distance 

116 row['zeroPoint'] = zero_point 

117 row['skyBg'] = sky_background 

118 row['skyNoise'] = sky_noise 

119 row['meanVar'] = mean_var 

120 

121 # Generate a photocalib 

122 instFluxMag0 = 10.**(zero_point/2.5) 

123 row.setPhotoCalib(afwImage.makePhotoCalibFromCalibZeroPoint(instFluxMag0)) 

124 

125 # Generate a WCS and set values accordingly 

126 crpix = geom.Point2D(detector_size/2., detector_size/2.) 

127 # Create a 20 pixel gap between the two detectors (each offset 10 pixels). 

128 if detector_id == 0: 

129 delta_ra = -1.0*((detector_size + 10)*pixel_scale/3600.)/np.cos(np.deg2rad(dec_center)) 

130 delta_dec = 0.0 

131 elif detector_id == 1: 

132 delta_ra = ((detector_size + 10)*pixel_scale/3600.)/np.cos(np.deg2rad(dec_center)) 

133 delta_dec = 0.0 

134 crval = geom.SpherePoint(ra_center + delta_ra, dec_center + delta_dec, geom.degrees) 

135 cd_matrix = afwGeom.makeCdMatrix(scale=pixel_scale*geom.arcseconds, orientation=0.0*geom.degrees) 

136 wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=crval, cdMatrix=cd_matrix) 

137 row.setWcs(wcs) 

138 

139 sph_pts = wcs.pixelToSky(geom.Box2D(bbox).getCorners()) 

140 row['raCorners'] = np.array([float(sph.getRa().asDegrees()) for sph in sph_pts]) 

141 row['decCorners'] = np.array([float(sph.getDec().asDegrees()) for sph in sph_pts]) 

142 sph_pt = wcs.pixelToSky(bbox.getCenter()) 

143 row['ra'] = sph_pt.getRa().asDegrees() 

144 row['dec'] = sph_pt.getDec().asDegrees() 

145 

146 # Generate a visitInfo. 

147 # This does not need to be consistent with the zenith angle in the table, 

148 # it just needs to be valid and have sufficient information to compute 

149 # exposure time and parallactic angle. 

150 date = DateTime(date=mjd, system=DateTime.DateSystem.MJD) 

151 visit_info = afwImage.VisitInfo(exposureTime=exposure_time, 

152 date=date, 

153 darkTime=0.0, 

154 boresightRaDec=geom.SpherePoint(ra_center, 

155 dec_center, 

156 geom.degrees), 

157 era=45.1*geom.degrees, 

158 observatory=Observatory( 

159 11.1*geom.degrees, 

160 0.0*geom.degrees, 

161 0.333), 

162 boresightRotAngle=0.0*geom.degrees, 

163 rotType=afwImage.RotType.SKY) 

164 row.setVisitInfo(visit_info) 

165 

166 # Generate a PSF and set values accordingly 

167 psf = GaussianPsf(15, 15, psf_sigma) 

168 row.setPsf(psf) 

169 psfAvgPos = psf.getAveragePosition() 

170 shape = psf.computeShape(psfAvgPos) 

171 row['psfSigma'] = psf.getSigma() 

172 row['psfIxx'] = shape.getIxx() 

173 row['psfIyy'] = shape.getIyy() 

174 row['psfIxy'] = shape.getIxy() 

175 row['psfArea'] = shape.getArea() 

176 

177 return visit_summary