LSSTApplications  10.0-2-g4f67435,11.0.rc2+1,11.0.rc2+12,11.0.rc2+3,11.0.rc2+4,11.0.rc2+5,11.0.rc2+6,11.0.rc2+7,11.0.rc2+8
LSSTDataManagementBasePackage
mockObject.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 
23 import numpy
24 
25 import lsst.pex.config
26 import lsst.afw.table
27 import lsst.afw.geom
28 import lsst.afw.image
29 import lsst.pipe.base
30 
31 class MockObjectConfig(lsst.pex.config.Config):
32  minMag = lsst.pex.config.Field(dtype=float, default=18.0, doc="Minimum magnitude for mock objects")
33  maxMag = lsst.pex.config.Field(dtype=float, default=20.0, doc="Maximum magnitude for mock objects")
34  maxRadius = lsst.pex.config.Field(
35  dtype=float, default=10.0,
36  doc=("Maximum radius of an object in arcseconds; only used "
37  "when determining which objects are in an exposure.")
38  )
39  spacing = lsst.pex.config.Field(
40  dtype=float, default=20.0,
41  doc="Distance between objects (in arcseconds)."
42  )
43  seed = lsst.pex.config.Field(dtype=int, default=1, doc="Seed for numpy random number generator")
44 
45 class MockObjectTask(lsst.pipe.base.Task):
46  """Task that generates simple mock objects and draws them on images, intended as a subtask of
47  MockCoaddTask.
48 
49  May be subclassed to generate things other than stars.
50  """
51 
52  ConfigClass = MockObjectConfig
53 
54  def __init__(self, **kwds):
55  lsst.pipe.base.Task.__init__(self, **kwds)
57  self.center = lsst.afw.table.Point2DKey.addFields(self.schema, "center",
58  "center position in tract WCS", "pixels")
59  self.magKey = self.schema.addField("mag", type=float, doc="exact true magnitude")
60  self.rng = numpy.random.RandomState(self.config.seed)
61 
62  def run(self, tractInfo, catalog=None):
63  """Add records to the truth catalog and return it, delegating to makePositions and defineObject.
64 
65  If the given catalog is not None, add records to this catalog and return it instead
66  of creating a new one.
67 
68  Subclasses should generally not need to override this method.
69  """
70  if catalog is None:
71  catalog = lsst.afw.table.SimpleCatalog(self.schema)
72  else:
73  if not catalog.getSchema().contains(self.schema):
74  raise ValueError("Catalog schema does not match Task schema")
75  for coord, center in self.makePositions(tractInfo):
76  record = catalog.addNew()
77  record.setCoord(coord)
78  record.set(self.center, center)
79  self.defineObject(record)
80  return catalog
81 
82  def makePositions(self, tractInfo):
83  """Generate the centers (as a (coord, point) tuple) of mock objects (the point returned is
84  in the tract coordinate system).
85 
86  Default implementation puts objects on a grid that is square in the tract's image coordinate
87  system, with spacing approximately given by config.spacings.
88 
89  The return value is a Python iterable over (coord, point) pairs; the default implementation
90  is actually an iterator (i.e. the function is a "generator"), but derived-class overrides may
91  return any iterable.
92  """
93  wcs = tractInfo.getWcs()
94  spacing = self.config.spacing / wcs.pixelScale().asArcseconds() # get spacing in tract pixels
95  bbox = tractInfo.getBBox()
96  for y in numpy.arange(bbox.getMinY() + 0.5 * spacing, bbox.getMaxY(), spacing):
97  for x in numpy.arange(bbox.getMinX() + 0.5 * spacing, bbox.getMaxX(), spacing):
98  yield wcs.pixelToSky(x, y), lsst.afw.geom.Point2D(x, y),
99 
100  def defineObject(self, record):
101  """Fill in additional fields in a truth catalog record (id and coord will already have
102  been set).
103  """
104  mag = self.rng.rand() * (self.config.maxMag - self.config.minMag) + self.config.minMag
105  record.setD(self.magKey, mag)
106 
107  def drawSource(self, record, exposure, buffer=0):
108  """Draw the given truth catalog record on the given exposure, makings use of its Psf, Wcs,
109  Calib, and possibly filter to transform it appropriately.
110 
111  The mask and variance planes of the Exposure are ignored.
112 
113  The 'buffer' parameter is used to expand the source's bounding box when testing whether it
114  is considered fully part of the image.
115 
116  Returns 0 if the object does not appear on the given image at all, 1 if it appears partially,
117  and 2 if it appears fully (including the given buffer).
118  """
119  wcs = exposure.getWcs()
120  center = wcs.skyToPixel(record.getCoord())
121  try:
122  psfImage = exposure.getPsf().computeImage(center).convertF()
123  except:
124  return 0
125  psfBBox = psfImage.getBBox()
126  overlap = exposure.getBBox()
127  overlap.clip(psfBBox)
128  if overlap.isEmpty():
129  return 0
130  flux = exposure.getCalib().getFlux(record.getD(self.magKey))
131  normalization = flux / psfImage.getArray().sum()
132  if psfBBox != overlap:
133  psfImage = psfImage.Factory(psfImage, overlap)
134  result = 1
135  else:
136  result = 2
137  if buffer != 0:
138  bufferedBBox = lsst.afw.geom.Box2I(psfBBox)
139  bufferedBBox.grow(buffer)
140  bufferedOverlap = exposure.getBBox()
141  bufferedOverlap.clip(bufferedBBox)
142  if bufferedOverlap != bufferedBBox:
143  result = 1
144  image = exposure.getMaskedImage().getImage()
145  subImage = image.Factory(image, overlap)
146  subImage.scaledPlus(normalization, psfImage)
147  return result
static Schema makeMinimalSchema()
Return a minimal schema for Simple tables and records.
Definition: Simple.h:121
boost::enable_if< typename ExpressionTraits< Scalar >::IsScalar, Scalar >::type sum(Scalar const &scalar)
Definition: operators.h:1250
An integer coordinate rectangle.
Definition: Box.h:53
Custom catalog class for record/table subclasses that are guaranteed to have an ID, and should generally be sorted by that ID.
Definition: fwd.h:55