LSST Applications  21.0.0-141-gec8a224e+c9dc52cf11,22.0.0+052faf71bd,22.0.0+1c4650f311,22.0.0+40ce427c77,22.0.0+5b6c068b1a,22.0.0+7589c3a021,22.0.0+b84b5806bd,22.0.1-1-g7d6de66+961d22230d,22.0.1-1-g87000a6+314cd8b7ea,22.0.1-1-g8760c09+052faf71bd,22.0.1-1-g8e32f31+5b6c068b1a,22.0.1-10-g779eefa+7d186d72ce,22.0.1-12-g3bd7ecb+bec1274511,22.0.1-15-g63cc0c1+2a7037787d,22.0.1-17-ge5a99e88+2652af7731,22.0.1-19-g88addfe+961d22230d,22.0.1-2-g1cb3e5b+9c7a6aab6f,22.0.1-2-g8ef0a89+961d22230d,22.0.1-2-g92698f7+1c4650f311,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gb66926d+5b6c068b1a,22.0.1-2-gcb770ba+0723a13595,22.0.1-2-ge470956+36d961e575,22.0.1-21-g532228a4+2ac85e833c,22.0.1-29-g184b6e44e+8b185d4e2d,22.0.1-3-g59f966b+89b97c2637,22.0.1-3-g8c1d971+f90df4c6d0,22.0.1-3-g997b569+d69a7aa2f8,22.0.1-3-gaaec9c0+4d194bf81c,22.0.1-4-g1930a60+283d9d2f1a,22.0.1-4-g5b7b756+c1283a92b8,22.0.1-4-g8623105+961d22230d,22.0.1-7-gba73697+283d9d2f1a,22.0.1-8-g47d23f5+39e151d95f,master-g5f2689bdc5+40ce427c77,w.2021.38
LSST Data Management Base Package
testUtils.py
Go to the documentation of this file.
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 
26 import numpy as np
27 
28 import lsst.geom
29 import lsst.afw.image as afwImage
30 from . import SingleGaussianPsf
31 from . import Defect
32 
33 
34 def 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 
98 def 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
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77
An integer coordinate rectangle.
Definition: Box.h:55
Encapsulate information about a bad portion of a detector.
Definition: Interp.h:72
Represent a PSF as a circularly symmetrical Gaussian.
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
std::shared_ptr< Exposure< ImagePixelT, MaskPixelT, VariancePixelT > > makeExposure(MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > &mimage, std::shared_ptr< geom::SkyWcs const > wcs=std::shared_ptr< geom::SkyWcs const >())
A function to return an Exposure of the correct type (cf.
Definition: Exposure.h:462
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