lsst.meas.algorithms gbe01a4569f+b3a0510b68
testUtils.py
Go to the documentation of this file.
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
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))),
153 lsst.geom.Extent2I(2, 4611))),
155 lsst.geom.Extent2I(4, 4611))),
157 lsst.geom.Extent2I(2, 4611))),
159 lsst.geom.Extent2I(2, 4359))),
161 lsst.geom.Extent2I(2, 3909))),
163 lsst.geom.Extent2I(2, 3471))),
165 lsst.geom.Extent2I(2, 2311))),
167 lsst.geom.Extent2I(2, 65))),
169 lsst.geom.Extent2I(1, 56))),
171 lsst.geom.Extent2I(4, 1814))),
173 lsst.geom.Extent2I(2, 1806))),
175 lsst.geom.Extent2I(2, 766))),
177 lsst.geom.Extent2I(2, 382))),
178 ]
179
180 return defectList
Encapsulate information about a bad portion of a detector.
Definition: Interp.h:72
Represent a PSF as a circularly symmetrical Gaussian.
def plantSources(bbox, kwid, sky, coordList, addPoissonNoise=True)
Definition: testUtils.py:34
def makeRandomTransmissionCurve(rng, minWavelength=4000.0, maxWavelength=7000.0, nWavelengths=200, maxRadius=80.0, nRadii=30, perturb=0.05)
Definition: testUtils.py:99