Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# 

2# LSST Data Management System 

3# 

4# Copyright 2008-2017 AURA/LSST. 

5# 

6# This product includes software developed by the 

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

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 LSST License Statement and 

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

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

22# 

23 

24__all__ = ["plantSources", "makeRandomTransmissionCurve", "makeDefectList"] 

25 

26import numpy as np 

27 

28import lsst.geom 

29import lsst.afw.image as afwImage 

30from . import SingleGaussianPsf 

31from . import Defect 

32 

33 

34def plantSources(bbox, kwid, sky, coordList, addPoissonNoise=True): 

35 """Make an exposure with stars (modelled as Gaussians) 

36 

37 Parameters 

38 ---------- 

39 bbox : `lsst.geom.Box2I` 

40 Parent bbox of exposure 

41 kwid : `int` 

42 Kernal width (and height; kernal is square) 

43 sky : `float` 

44 Amount of sky background (counts) 

45 coordList : `list [tuple]` 

46 A list of [x, y, counts, sigma] where: 

47 * x,y are relative to exposure origin 

48 * counts is the integrated counts for the star 

49 * sigma is the Gaussian sigma in pixels 

50 addPoissonNoise : `bool` 

51 If True: add Poisson noise to the exposure 

52 """ 

53 # make an image with sources 

54 img = afwImage.ImageD(bbox) 

55 meanSigma = 0.0 

56 for coord in coordList: 

57 x, y, counts, sigma = coord 

58 meanSigma += sigma 

59 

60 # make a single gaussian psf 

61 psf = SingleGaussianPsf(kwid, kwid, sigma) 

62 

63 # make an image of it and scale to the desired number of counts 

64 thisPsfImg = psf.computeImage(lsst.geom.PointD(x, y)) 

65 thisPsfImg *= counts 

66 

67 # bbox a window in our image and add the fake star image 

68 psfBox = thisPsfImg.getBBox() 

69 psfBox.clip(bbox) 

70 if psfBox != thisPsfImg.getBBox(): 

71 thisPsfImg = thisPsfImg[psfBox, afwImage.PARENT] 

72 imgSeg = img[psfBox, afwImage.PARENT] 

73 imgSeg += thisPsfImg 

74 meanSigma /= len(coordList) 

75 

76 img += sky 

77 

78 # add Poisson noise 

79 if (addPoissonNoise): 

80 np.random.seed(seed=1) # make results reproducible 

81 imgArr = img.getArray() 

82 imgArr[:] = np.random.poisson(imgArr) 

83 

84 # bundle into a maskedimage and an exposure 

85 mask = afwImage.Mask(bbox) 

86 var = img.convertFloat() 

87 img -= sky 

88 mimg = afwImage.MaskedImageF(img.convertFloat(), mask, var) 

89 exposure = afwImage.makeExposure(mimg) 

90 

91 # insert an approximate psf 

92 psf = SingleGaussianPsf(kwid, kwid, meanSigma) 

93 exposure.setPsf(psf) 

94 

95 return exposure 

96 

97 

98def makeRandomTransmissionCurve(rng, minWavelength=4000.0, maxWavelength=7000.0, nWavelengths=200, 

99 maxRadius=80.0, nRadii=30, perturb=0.05): 

100 """Create a random TransmissionCurve with nontrivial spatial and 

101 wavelength variation. 

102 

103 Parameters 

104 ---------- 

105 rng : numpy.random.RandomState 

106 Random number generator. 

107 minWavelength : float 

108 Average minimum wavelength for generated TransmissionCurves (will be 

109 randomly perturbed). 

110 maxWavelength : float 

111 Average maximum wavelength for generated TransmissionCurves (will be 

112 randomly perturbed). 

113 nWavelengths : int 

114 Number of samples in the wavelength dimension. 

115 maxRadius : float 

116 Average maximum radius for spatial variation (will be perturbed). 

117 nRadii : int 

118 Number of samples in the radial dimension. 

119 perturb: float 

120 Fraction by which wavelength and radius bounds should be randomly 

121 perturbed. 

122 """ 

123 dWavelength = maxWavelength - minWavelength 

124 

125 def perturbed(x, s=perturb*dWavelength): 

126 return x + 2.0*s*(rng.rand() - 0.5) 

127 

128 wavelengths = np.linspace(perturbed(minWavelength), perturbed(maxWavelength), nWavelengths) 

129 radii = np.linspace(0.0, perturbed(maxRadius, perturb*maxRadius), nRadii) 

130 throughput = np.zeros(wavelengths.shape + radii.shape, dtype=float) 

131 # throughput will be a rectangle in wavelength, shifting to higher wavelengths and shrinking 

132 # in height with radius, going to zero at all bounds. 

133 peak0 = perturbed(0.9, 0.05) 

134 start0 = perturbed(minWavelength + 0.25*dWavelength) 

135 stop0 = perturbed(minWavelength + 0.75*dWavelength) 

136 for i, r in enumerate(radii): 

137 mask = np.logical_and(wavelengths >= start0 + r, wavelengths <= stop0 + r) 

138 throughput[mask, i] = peak0*(1.0 - r/1000.0) 

139 return afwImage.TransmissionCurve.makeRadial(throughput, wavelengths, radii) 

140 

141 

142def makeDefectList(): 

143 """Create a list of defects that can be used for testing. 

144 

145 Returns 

146 ------- 

147 defectList = `list` [`lsst.meas.algorithms.Defect`] 

148 The list of defects. 

149 """ 

150 defectList = [Defect(lsst.geom.Box2I(lsst.geom.Point2I(962, 0), 

151 lsst.geom.Extent2I(2, 4611))), 

152 Defect(lsst.geom.Box2I(lsst.geom.Point2I(1316, 0), 

153 lsst.geom.Extent2I(2, 4611))), 

154 Defect(lsst.geom.Box2I(lsst.geom.Point2I(1576, 0), 

155 lsst.geom.Extent2I(4, 4611))), 

156 Defect(lsst.geom.Box2I(lsst.geom.Point2I(1626, 0), 

157 lsst.geom.Extent2I(2, 4611))), 

158 Defect(lsst.geom.Box2I(lsst.geom.Point2I(1994, 252), 

159 lsst.geom.Extent2I(2, 4359))), 

160 Defect(lsst.geom.Box2I(lsst.geom.Point2I(1426, 702), 

161 lsst.geom.Extent2I(2, 3909))), 

162 Defect(lsst.geom.Box2I(lsst.geom.Point2I(1526, 1140), 

163 lsst.geom.Extent2I(2, 3471))), 

164 Defect(lsst.geom.Box2I(lsst.geom.Point2I(856, 2300), 

165 lsst.geom.Extent2I(2, 2311))), 

166 Defect(lsst.geom.Box2I(lsst.geom.Point2I(858, 2328), 

167 lsst.geom.Extent2I(2, 65))), 

168 Defect(lsst.geom.Box2I(lsst.geom.Point2I(859, 2328), 

169 lsst.geom.Extent2I(1, 56))), 

170 Defect(lsst.geom.Box2I(lsst.geom.Point2I(844, 2796), 

171 lsst.geom.Extent2I(4, 1814))), 

172 Defect(lsst.geom.Box2I(lsst.geom.Point2I(1366, 2804), 

173 lsst.geom.Extent2I(2, 1806))), 

174 Defect(lsst.geom.Box2I(lsst.geom.Point2I(1766, 3844), 

175 lsst.geom.Extent2I(2, 766))), 

176 Defect(lsst.geom.Box2I(lsst.geom.Point2I(1872, 4228), 

177 lsst.geom.Extent2I(2, 382))), 

178 ] 

179 

180 return defectList