LSSTApplications  16.0-10-g0ee56ad+5,16.0-11-ga33d1f2+5,16.0-12-g3ef5c14+3,16.0-12-g71e5ef5+18,16.0-12-gbdf3636+3,16.0-13-g118c103+3,16.0-13-g8f68b0a+3,16.0-15-gbf5c1cb+4,16.0-16-gfd17674+3,16.0-17-g7c01f5c+3,16.0-18-g0a50484+1,16.0-20-ga20f992+8,16.0-21-g0e05fd4+6,16.0-21-g15e2d33+4,16.0-22-g62d8060+4,16.0-22-g847a80f+4,16.0-25-gf00d9b8+1,16.0-28-g3990c221+4,16.0-3-gf928089+3,16.0-32-g88a4f23+5,16.0-34-gd7987ad+3,16.0-37-gc7333cb+2,16.0-4-g10fc685+2,16.0-4-g18f3627+26,16.0-4-g5f3a788+26,16.0-5-gaf5c3d7+4,16.0-5-gcc1f4bb+1,16.0-6-g3b92700+4,16.0-6-g4412fcd+3,16.0-6-g7235603+4,16.0-69-g2562ce1b+2,16.0-8-g14ebd58+4,16.0-8-g2df868b+1,16.0-8-g4cec79c+6,16.0-8-gadf6c7a+1,16.0-8-gfc7ad86,16.0-82-g59ec2a54a+1,16.0-9-g5400cdc+2,16.0-9-ge6233d7+5,master-g2880f2d8cf+3,v17.0.rc1
LSSTDataManagementBasePackage
mockObservation.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008, 2009, 2010, 2011, 2012 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
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 <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 import numpy as np
23 
24 import lsst.pex.config
25 import lsst.afw.table
26 import lsst.afw.geom
27 from lsst.afw.cameraGeom import PIXELS, FOCAL_PLANE
28 import lsst.afw.image
29 import lsst.afw.math
30 import lsst.afw.detection
31 import lsst.pipe.base
32 from lsst.meas.base.apCorrRegistry import getApCorrNameSet
33 from lsst.meas.algorithms.testUtils import makeRandomTransmissionCurve
34 
35 
37  pixelScale = lsst.pex.config.Field(
38  dtype=float, default=0.2, optional=False,
39  doc="Pixel scale for mock WCSs in arcseconds/pixel"
40  )
42  dtype=bool, default=True, optional=False,
43  doc="Whether to randomly rotate observations relative to the tract Wcs"
44  )
46  dtype=float, default=1E11, optional=False,
47  doc="Flux at zero magnitude used to define Calibs."
48  )
49  fluxMag0Err = lsst.pex.config.Field(
50  dtype=float, default=100.0, optional=False,
51  doc="Error on flux at zero magnitude used to define Calibs; used to add scatter as well."
52  )
54  dtype=float, default=60.0, optional=False,
55  doc="Exposure time set in generated Calibs (does not affect flux or noise level)"
56  )
57  psfImageSize = lsst.pex.config.Field(
58  dtype=int, default=21, optional=False,
59  doc="Image width and height of generated Psfs."
60  )
61  psfMinSigma = lsst.pex.config.Field(
62  dtype=float, default=1.5, optional=False,
63  doc="Minimum radius for generated Psfs."
64  )
65  psfMaxSigma = lsst.pex.config.Field(
66  dtype=float, default=3.0, optional=False,
67  doc="Maximum radius for generated Psfs."
68  )
69  apCorrOrder = lsst.pex.config.Field(
70  dtype=int, default=1, optional=False,
71  doc="Polynomial order for aperture correction fields"
72  )
73  seed = lsst.pex.config.Field(dtype=int, default=1, doc="Seed for numpy random number generator")
74 
75 
77  """Task to generate mock Exposure parameters (Wcs, Psf, Calib), intended for use as a subtask
78  of MockCoaddTask.
79 
80  @todo:
81  - document "pa" in detail; angle of what to what?
82  - document the catalog parameter of the run method
83  """
84 
85  ConfigClass = MockObservationConfig
86 
87  def __init__(self, **kwds):
88  lsst.pipe.base.Task.__init__(self, **kwds)
90  self.ccdKey = self.schema.addField("ccd", type=np.int32, doc="CCD number")
91  self.visitKey = self.schema.addField("visit", type=np.int32, doc="visit number")
92  self.pointingKey = lsst.afw.table.CoordKey.addFields(self.schema, "pointing", "center of visit")
93  self.filterKey = self.schema.addField("filter", type=str, doc="Bandpass filter name", size=16)
94  self.rng = np.random.RandomState(self.config.seed)
95 
96  def run(self, butler, n, tractInfo, camera, catalog=None):
97  """Driver that generates an ExposureCatalog of mock observations.
98 
99  @param[in] butler: a data butler
100  @param[in] n: number of pointings
101  @param[in] camera: camera geometry (an lsst.afw.cameraGeom.Camera)
102  @param[in] catalog: catalog to which to add observations (an ExposureCatalog);
103  if None then a new catalog is created.
104 
105  @todo figure out what `pa` is and use that knowledge to set `boresightRotAng` and `rotType`
106  """
107  if catalog is None:
108  catalog = lsst.afw.table.ExposureCatalog(self.schema)
109  else:
110  if not catalog.getSchema().contains(self.schema):
111  raise ValueError("Catalog schema does not match Task schema")
112  visit = 1
113 
114  for position, pa in self.makePointings(n, tractInfo):
115  visitInfo = lsst.afw.image.VisitInfo(
116  exposureTime=self.config.expTime,
118  boresightRaDec=position,
119  )
120  for detector in camera:
121  calib = self.buildCalib()
122  record = catalog.addNew()
123  record.setI(self.ccdKey, detector.getId())
124  record.setI(self.visitKey, visit)
125  record.set(self.filterKey, 'r')
126  record.set(self.pointingKey, position)
127  record.setWcs(self.buildWcs(position, pa, detector))
128  record.setCalib(calib)
129  record.setVisitInfo(visitInfo)
130  record.setPsf(self.buildPsf(detector))
131  record.setApCorrMap(self.buildApCorrMap(detector))
132  record.setTransmissionCurve(self.buildTransmissionCurve(detector))
133  record.setBBox(detector.getBBox())
134  detectorId = detector.getId()
135  obj = butler.get("ccdExposureId", visit=visit, ccd=detectorId, immediate=True)
136  record.setId(obj)
137  visit += 1
138  return catalog
139 
140  def makePointings(self, n, tractInfo):
141  """Generate (celestial) positions and rotation angles that define field locations.
142 
143  Default implementation draws random pointings that are uniform in the tract's image
144  coordinate system.
145 
146  @param[in] n: number of pointings
147  @param[in] tractInfo: skymap tract (a lsst.skymap.TractInfo)
148  @return a Python iterable over (coord, angle) pairs:
149  - coord is an ICRS object position (an lsst.afw.geom.SpherePoint)
150  - angle is a position angle (???) (an lsst.afw.geom.Angle)
151 
152  The default implementation returns an iterator (i.e. the function is a "generator"),
153  but derived-class overrides may return any iterable.
154  """
155  wcs = tractInfo.getWcs()
156  bbox = lsst.afw.geom.Box2D(tractInfo.getBBox())
157  bbox.grow(lsst.afw.geom.Extent2D(-0.1 * bbox.getWidth(), -0.1 * bbox.getHeight()))
158  for i in range(n):
159  x = self.rng.rand() * bbox.getWidth() + bbox.getMinX()
160  y = self.rng.rand() * bbox.getHeight() + bbox.getMinY()
161  pa = 0.0 * lsst.afw.geom.radians
162  if self.config.doRotate:
163  pa = self.rng.rand() * 2.0 * np.pi * lsst.afw.geom.radians
164  yield wcs.pixelToSky(x, y), pa
165 
166  def buildWcs(self, position, pa, detector):
167  """Build a simple TAN Wcs with no distortion and exactly-aligned CCDs.
168 
169  @param[in] position: ICRS object position on sky (on lsst.afw.geom.SpherePoint)
170  @param[in] pa: position angle (an lsst.afw.geom.Angle)
171  @param[in] detector: detector information (an lsst.afw.cameraGeom.Detector)
172  """
173  crval = position
174  pixelScale = (self.config.pixelScale * lsst.afw.geom.arcseconds).asDegrees()
175  cd = (lsst.afw.geom.LinearTransform.makeScaling(pixelScale) *
176  lsst.afw.geom.LinearTransform.makeRotation(pa))
177  crpix = detector.transform(lsst.afw.geom.Point2D(0, 0), FOCAL_PLANE, PIXELS)
178  wcs = lsst.afw.geom.makeSkyWcs(crpix=crpix, crval=crval, cdMatrix=cd.getMatrix())
179  return wcs
180 
181  def buildCalib(self):
182  """Build a simple Calib object with exposure time fixed by config, fluxMag0 drawn from
183  a Gaussian defined by config, and mid-time set to DateTime.now().
184  """
185  calib = lsst.afw.image.Calib()
186  calib.setFluxMag0(
187  self.rng.randn() * self.config.fluxMag0Err + self.config.fluxMag0,
188  self.config.fluxMag0Err
189  )
190  return calib
191 
192  def buildPsf(self, detector):
193  """Build a simple Gaussian Psf with linearly-varying ellipticity and size.
194 
195  The Psf pattern increases sigma_x linearly along the x direction, and sigma_y
196  linearly along the y direction.
197 
198  @param[in] detector: detector information (an lsst.afw.cameraGeom.Detector)
199  @return a psf (an instance of lsst.meas.algorithms.KernelPsf)
200  """
201  bbox = detector.getBBox()
202  dx = (self.config.psfMaxSigma - self.config.psfMinSigma) / bbox.getWidth()
203  dy = (self.config.psfMaxSigma - self.config.psfMinSigma) / bbox.getHeight()
204  sigmaXFunc = lsst.afw.math.PolynomialFunction2D(1)
205  sigmaXFunc.setParameter(0, self.config.psfMinSigma - dx * bbox.getMinX() - dy * bbox.getMinY())
206  sigmaXFunc.setParameter(1, dx)
207  sigmaXFunc.setParameter(2, 0.0)
208  sigmaYFunc = lsst.afw.math.PolynomialFunction2D(1)
209  sigmaYFunc.setParameter(0, self.config.psfMinSigma)
210  sigmaYFunc.setParameter(1, 0.0)
211  sigmaYFunc.setParameter(2, dy)
212  angleFunc = lsst.afw.math.PolynomialFunction2D(0)
213  spatialFuncList = []
214  spatialFuncList.append(sigmaXFunc)
215  spatialFuncList.append(sigmaYFunc)
216  spatialFuncList.append(angleFunc)
218  self.config.psfImageSize, self.config.psfImageSize,
219  lsst.afw.math.GaussianFunction2D(self.config.psfMinSigma, self.config.psfMinSigma),
220  spatialFuncList
221  )
222  return lsst.meas.algorithms.KernelPsf(kernel)
223 
224  def buildApCorrMap(self, detector):
225  """Build an ApCorrMap with random linearly-varying fields for all
226  flux fields registered for aperture correction.
227 
228  These flux field names are used only as strings; there is no
229  connection to any actual algorithms with those names or the PSF model.
230  """
231  order = self.config.apCorrOrder
232 
233  def makeRandomBoundedField():
234  """Make an upper-left triangular coefficient array appropriate
235  for a 2-d polynomial."""
236  array = np.zeros((order + 1, order + 1), dtype=float)
237  for n in range(order + 1):
238  array[n, 0:order + 1 - n] = self.rng.randn(order + 1 - n)
239  return lsst.afw.math.ChebyshevBoundedField(bbox, array)
240 
241  bbox = detector.getBBox()
242  apCorrMap = lsst.afw.image.ApCorrMap()
243  for name in getApCorrNameSet():
244  apCorrMap.set(name + "_instFlux", makeRandomBoundedField())
245  apCorrMap.set(name + "_instFluxErr", makeRandomBoundedField())
246  return apCorrMap
247 
248  def buildTransmissionCurve(self, detector):
249  """Build a random spacially-varying TransmissionCurve."""
250  bbox = detector.getBBox()
251  return makeRandomTransmissionCurve(rng=self.rng, maxRadius=max(bbox.getWidth(), bbox.getHeight()))
A Psf defined by a Kernel.
Definition: KernelPsf.h:36
bool contains(VertexIterator const begin, VertexIterator const end, UnitVector3d const &v)
A floating-point coordinate rectangle geometry.
Definition: Box.h:294
A thin wrapper around std::map to allow aperture corrections to be attached to Exposures.
Definition: ApCorrMap.h:44
Information about a single exposure of an imaging camera.
Definition: VisitInfo.h:67
static Schema makeMinimalSchema()
Return a minimal schema for Exposure tables and records.
Definition: Exposure.h:206
Describe an exposure&#39;s calibration.
Definition: Calib.h:95
def makeRandomTransmissionCurve(rng, minWavelength=4000.0, maxWavelength=7000.0, nWavelengths=200, maxRadius=80.0, nRadii=30, perturb=0.05)
Definition: testUtils.py:89
static DateTime now(void)
Return current time as a DateTime.
Definition: DateTime.cc:517
def run(self, butler, n, tractInfo, camera, catalog=None)
int max
std::shared_ptr< SkyWcs > makeSkyWcs(TransformPoint2ToPoint2 const &pixelsToFieldAngle, lsst::geom::Angle const &orientation, bool flipX, lsst::geom::SpherePoint const &boresight, std::string const &projection="TAN")
Construct a FITS SkyWcs from camera geometry.
Definition: SkyWcs.cc:486
A BoundedField based on 2-d Chebyshev polynomials of the first kind.
Custom catalog class for ExposureRecord/Table.
Definition: Exposure.h:67
static CoordKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc)
Add a pair of _ra, _dec fields to a Schema, and return a CoordKey that points to them.
Definition: aggregates.cc:83
A kernel described by a function.
Definition: Kernel.h:573