lsst.meas.algorithms  14.0-21-ge7d40960+3
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 from __future__ import absolute_import, division, print_function
24 
25 import numpy as np
26 
27 import lsst.afw.image as afwImage
28 import lsst.afw.geom as afwGeom
29 from . import SingleGaussianPsf
30 
31 
32 def plantSources(bbox, kwid, sky, coordList, addPoissonNoise=True):
33  """Make an exposure with stars (modelled as Gaussians)
34 
35  @param bbox: parent bbox of exposure
36  @param kwid: kernel width (and height; kernel is square)
37  @param sky: amount of sky background (counts)
38  @param coordList: a list of [x, y, counts, sigma], where:
39  * x,y are relative to exposure origin
40  * counts is the integrated counts for the star
41  * sigma is the Gaussian sigma in pixels
42  @param addPoissonNoise: add Poisson noise to the exposure?
43  """
44  # make an image with sources
45  img = afwImage.ImageD(bbox)
46  meanSigma = 0.0
47  for coord in coordList:
48  x, y, counts, sigma = coord
49  meanSigma += sigma
50 
51  # make a single gaussian psf
52  psf = SingleGaussianPsf(kwid, kwid, sigma)
53 
54  # make an image of it and scale to the desired number of counts
55  thisPsfImg = psf.computeImage(afwGeom.PointD(x, y))
56  thisPsfImg *= counts
57 
58  # bbox a window in our image and add the fake star image
59  psfBox = thisPsfImg.getBBox()
60  psfBox.clip(bbox)
61  if psfBox != thisPsfImg.getBBox():
62  thisPsfImg = thisPsfImg[psfBox, afwImage.PARENT]
63  imgSeg = img[psfBox, afwImage.PARENT]
64  imgSeg += thisPsfImg
65  meanSigma /= len(coordList)
66 
67  img += sky
68 
69  # add Poisson noise
70  if (addPoissonNoise):
71  np.random.seed(seed=1) # make results reproducible
72  imgArr = img.getArray()
73  imgArr[:] = np.random.poisson(imgArr)
74 
75  # bundle into a maskedimage and an exposure
76  mask = afwImage.Mask(bbox)
77  var = img.convertFloat()
78  img -= sky
79  mimg = afwImage.MaskedImageF(img.convertFloat(), mask, var)
80  exposure = afwImage.makeExposure(mimg)
81 
82  # insert an approximate psf
83  psf = SingleGaussianPsf(kwid, kwid, meanSigma)
84  exposure.setPsf(psf)
85 
86  return exposure
87 
88 
89 def makeRandomTransmissionCurve(rng, minWavelength=4000.0, maxWavelength=7000.0, nWavelengths=200,
90  maxRadius=80.0, nRadii=30, perturb=0.05):
91  """Create a random TransmissionCurve with nontrivial spatial and
92  wavelength variation.
93 
94  Parameters
95  ----------
96  rng : numpy.random.RandomState
97  Random number generator.
98  minWavelength : float
99  Average minimum wavelength for generated TransmissionCurves (will be
100  randomly perturbed).
101  maxWavelength : float
102  Average maximum wavelength for generated TransmissionCurves (will be
103  randomly perturbed).
104  nWavelengths : int
105  Number of samples in the wavelength dimension.
106  maxRadius : float
107  Average maximum radius for spatial variation (will be perturbed).
108  nRadii : int
109  Number of samples in the radial dimension.
110  perturb: float
111  Fraction by which wavelength and radius bounds should be randomly
112  perturbed.
113  """
114  dWavelength = maxWavelength - minWavelength
115 
116  def perturbed(x, s=perturb*dWavelength):
117  return x + 2.0*s*(rng.rand() - 0.5)
118 
119  wavelengths = np.linspace(perturbed(minWavelength), perturbed(maxWavelength), nWavelengths)
120  radii = np.linspace(0.0, perturbed(maxRadius, perturb*maxRadius), nRadii)
121  throughput = np.zeros(wavelengths.shape + radii.shape, dtype=float)
122  # throughput will be a rectangle in wavelength, shifting to higher wavelengths and shrinking
123  # in height with radius, going to zero at all bounds.
124  peak0 = perturbed(0.9, 0.05)
125  start0 = perturbed(minWavelength + 0.25*dWavelength)
126  stop0 = perturbed(minWavelength + 0.75*dWavelength)
127  for i, r in enumerate(radii):
128  mask = np.logical_and(wavelengths >= start0 + r, wavelengths <= stop0 + r)
129  throughput[mask, i] = peak0*(1.0 - r/1000.0)
130  return afwImage.TransmissionCurve.makeRadial(throughput, wavelengths, radii)
def plantSources(bbox, kwid, sky, coordList, addPoissonNoise=True)
Definition: testUtils.py:32
def makeRandomTransmissionCurve(rng, minWavelength=4000.0, maxWavelength=7000.0, nWavelengths=200, maxRadius=80.0, nRadii=30, perturb=0.05)
Definition: testUtils.py:90
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 >())