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