LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
Public Member Functions | Static Public Member Functions | Public Attributes | List of all members
lsst.meas.base.tests.TestDataset Class Reference

Public Member Functions

def makeMinimalSchema (cls)
 
def __init__ (self, bbox, threshold=10.0, exposure=None, **kwds)
 
def addSource (self, instFlux, centroid, shape=None)
 
def addBlend (self)
 
def transform (self, wcs, **kwds)
 
def realize (self, noise, schema, randomSeed=1)
 

Static Public Member Functions

def makePerturbedWcs (oldWcs, minScaleFactor=1.2, maxScaleFactor=1.5, minRotation=None, maxRotation=None, minRefShift=None, maxRefShift=None, minPixShift=2.0, maxPixShift=4.0, randomSeed=1)
 
def makeEmptyExposure (bbox, wcs=None, crval=None, cdelt=None, psfSigma=2.0, psfDim=17, calibration=4)
 
def drawGaussian (bbox, instFlux, ellipse)
 

Public Attributes

 keys
 
 threshold
 
 exposure
 
 psfShape
 
 schema
 
 catalog
 

Detailed Description

A simulated dataset consisuting of test image and truth catalog.

TestDataset creates an idealized image made of pure Gaussians (including a
Gaussian PSF), with simple noise and idealized Footprints/HeavyFootprints
that simulated the outputs of detection and deblending.  Multiple noise
realizations can be created from the same underlying sources, allowing
uncertainty estimates to be verified via Monte Carlo.

Parameters
----------
bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
    Bounding box of the test image.
threshold : `float`
    Threshold absolute value used to determine footprints for
    simulated sources.  This thresholding will be applied before noise is
    actually added to images (or before the noise level is even known), so
    this will necessarily produce somewhat artificial footprints.
exposure : `lsst.afw.image.ExposureF`
    The image to which test sources should be added. Ownership should
    be considered transferred from the caller to the TestDataset.
    Must have a Gaussian PSF for truth catalog shapes to be exact.
**kwds
    Keyword arguments forwarded to makeEmptyExposure if exposure is `None`.

Notes
-----
Typical usage:

.. code-block: py

    bbox = lsst.geom.Box2I(lsst.geom.Point2I(0,0), lsst.geom.Point2I(100,
                                                                     100))
    dataset = TestDataset(bbox)
    dataset.addSource(instFlux=1E5, centroid=lsst.geom.Point2D(25, 26))
    dataset.addSource(instFlux=2E5, centroid=lsst.geom.Point2D(75, 24),
                    shape=lsst.afw.geom.Quadrupole(8, 7, 2))
    with dataset.addBlend() as family:
        family.addChild(instFlux=2E5, centroid=lsst.geom.Point2D(50, 72))
        family.addChild(instFlux=1.5E5, centroid=lsst.geom.Point2D(51, 74))
    exposure, catalog = dataset.realize(noise=100.0,
                                        schema=TestDataset.makeMinimalSchema())

Definition at line 122 of file tests.py.

Constructor & Destructor Documentation

◆ __init__()

def lsst.meas.base.tests.TestDataset.__init__ (   self,
  bbox,
  threshold = 10.0,
  exposure = None,
**  kwds 
)

Definition at line 381 of file tests.py.

381  def __init__(self, bbox, threshold=10.0, exposure=None, **kwds):
382  if exposure is None:
383  exposure = self.makeEmptyExposure(bbox, **kwds)
384  self.threshold = lsst.afw.detection.Threshold(threshold, lsst.afw.detection.Threshold.VALUE)
385  self.exposure = exposure
386  self.psfShape = self.exposure.getPsf().computeShape(bbox.getCenter())
387  self.schema = self.makeMinimalSchema()
388  self.catalog = lsst.afw.table.SourceCatalog(self.schema)
389 
A Threshold is used to pass a threshold value to detection algorithms.
Definition: Threshold.h:43

Member Function Documentation

◆ addBlend()

def lsst.meas.base.tests.TestDataset.addBlend (   self)
Return a context manager which can add a blend of multiple sources.

Notes
-----
Note that nothing stops you from creating overlapping sources just using the addSource() method,
but addBlend() is necesssary to create a parent object and deblended HeavyFootprints of the type
produced by the detection and deblending pipelines.

Examples
--------
.. code-block: py
    d = TestDataset(...)
    with d.addBlend() as b:
        b.addChild(flux1, centroid1)
        b.addChild(flux2, centroid2, shape2)

Definition at line 450 of file tests.py.

450  def addBlend(self):
451  """Return a context manager which can add a blend of multiple sources.
452 
453  Notes
454  -----
455  Note that nothing stops you from creating overlapping sources just using the addSource() method,
456  but addBlend() is necesssary to create a parent object and deblended HeavyFootprints of the type
457  produced by the detection and deblending pipelines.
458 
459  Examples
460  --------
461  .. code-block: py
462  d = TestDataset(...)
463  with d.addBlend() as b:
464  b.addChild(flux1, centroid1)
465  b.addChild(flux2, centroid2, shape2)
466  """
467  return BlendContext(self)
468 

◆ addSource()

def lsst.meas.base.tests.TestDataset.addSource (   self,
  instFlux,
  centroid,
  shape = None 
)
Add a source to the simulation.

Parameters
----------
instFlux : `float`
    Total instFlux of the source to be added.
centroid : `lsst.geom.Point2D`
    Position of the source to be added.
shape : `lsst.afw.geom.Quadrupole`
    Second moments of the source before PSF convolution. Note that the
    truth catalog records post-convolution moments. If `None`, a point
    source will be added.

Returns
-------
record : `lsst.afw.table.SourceRecord`
    A truth catalog record.
image : `lsst.afw.image.ImageF`
    Single-source image corresponding to the new source.

Definition at line 406 of file tests.py.

406  def addSource(self, instFlux, centroid, shape=None):
407  """Add a source to the simulation.
408 
409  Parameters
410  ----------
411  instFlux : `float`
412  Total instFlux of the source to be added.
413  centroid : `lsst.geom.Point2D`
414  Position of the source to be added.
415  shape : `lsst.afw.geom.Quadrupole`
416  Second moments of the source before PSF convolution. Note that the
417  truth catalog records post-convolution moments. If `None`, a point
418  source will be added.
419 
420  Returns
421  -------
422  record : `lsst.afw.table.SourceRecord`
423  A truth catalog record.
424  image : `lsst.afw.image.ImageF`
425  Single-source image corresponding to the new source.
426  """
427  # Create and set the truth catalog fields
428  record = self.catalog.addNew()
429  record.set(self.keys["instFlux"], instFlux)
430  record.set(self.keys["centroid"], centroid)
431  covariance = np.random.normal(0, 0.1, 4).reshape(2, 2)
432  covariance[0, 1] = covariance[1, 0] # CovarianceMatrixKey assumes symmetric x_y_Cov
433  record.set(self.keys["centroid_sigma"], covariance.astype(np.float32))
434  if shape is None:
435  record.set(self.keys["isStar"], True)
436  fullShape = self.psfShape
437  else:
438  record.set(self.keys["isStar"], False)
439  fullShape = shape.convolve(self.psfShape)
440  record.set(self.keys["shape"], fullShape)
441  # Create an image containing just this source
442  image = self.drawGaussian(self.exposure.getBBox(), instFlux,
443  lsst.afw.geom.Ellipse(fullShape, centroid))
444  # Generate a footprint for this source
445  self._installFootprint(record, image)
446  # Actually add the source to the full exposure
447  self.exposure.getMaskedImage().getImage().getArray()[:, :] += image.getArray()
448  return record, image
449 
An ellipse defined by an arbitrary BaseCore and a center point.
Definition: Ellipse.h:51

◆ drawGaussian()

def lsst.meas.base.tests.TestDataset.drawGaussian (   bbox,
  instFlux,
  ellipse 
)
static
Create an image of an elliptical Gaussian.

Parameters
----------
bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
    Bounding box of image to create.
instFlux : `float`
    Total instrumental flux of the Gaussian (normalized analytically,
    not using pixel values).
ellipse : `lsst.afw.geom.Ellipse`
    Defines the centroid and shape.

Returns
-------
image : `lsst.afw.image.ImageF`
    An image of the Gaussian.

Definition at line 354 of file tests.py.

354  def drawGaussian(bbox, instFlux, ellipse):
355  """Create an image of an elliptical Gaussian.
356 
357  Parameters
358  ----------
359  bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
360  Bounding box of image to create.
361  instFlux : `float`
362  Total instrumental flux of the Gaussian (normalized analytically,
363  not using pixel values).
364  ellipse : `lsst.afw.geom.Ellipse`
365  Defines the centroid and shape.
366 
367  Returns
368  -------
369  image : `lsst.afw.image.ImageF`
370  An image of the Gaussian.
371  """
372  x, y = np.meshgrid(np.arange(bbox.getBeginX(), bbox.getEndX()),
373  np.arange(bbox.getBeginY(), bbox.getEndY()))
374  t = ellipse.getGridTransform()
375  xt = t[t.XX] * x + t[t.XY] * y + t[t.X]
376  yt = t[t.YX] * x + t[t.YY] * y + t[t.Y]
377  image = lsst.afw.image.ImageF(bbox)
378  image.getArray()[:, :] = np.exp(-0.5*(xt**2 + yt**2))*instFlux/(2.0*ellipse.getCore().getArea())
379  return image
380 

◆ makeEmptyExposure()

def lsst.meas.base.tests.TestDataset.makeEmptyExposure (   bbox,
  wcs = None,
  crval = None,
  cdelt = None,
  psfSigma = 2.0,
  psfDim = 17,
  calibration = 4 
)
static
Create an Exposure, with a PhotoCalib, Wcs, and Psf, but no pixel values.

Parameters
----------
bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
    Bounding box of the image in image coordinates.
wcs : `lsst.afw.geom.SkyWcs`, optional
    New WCS for the exposure (created from CRVAL and CDELT if `None`).
crval : `lsst.afw.geom.SpherePoint`, optional
    ICRS center of the TAN WCS attached to the image. If `None`, (45
    degrees, 45 degrees) is assumed.
cdelt : `lsst.geom.Angle`, optional
    Pixel scale of the image. If `None`, 0.2 arcsec is assumed.
psfSigma : `float`, optional
    Radius (sigma) of the Gaussian PSF attached to the image
psfDim : `int`, optional
    Width and height of the image's Gaussian PSF attached to the image
calibration : `float`, optional
    The spatially-constant calibration (in nJy/count) to set the
    PhotoCalib of the exposure.

Returns
-------
exposure : `lsst.age.image.ExposureF`
    An empty image.

Definition at line 310 of file tests.py.

310  def makeEmptyExposure(bbox, wcs=None, crval=None, cdelt=None, psfSigma=2.0, psfDim=17, calibration=4):
311  """Create an Exposure, with a PhotoCalib, Wcs, and Psf, but no pixel values.
312 
313  Parameters
314  ----------
315  bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
316  Bounding box of the image in image coordinates.
317  wcs : `lsst.afw.geom.SkyWcs`, optional
318  New WCS for the exposure (created from CRVAL and CDELT if `None`).
319  crval : `lsst.afw.geom.SpherePoint`, optional
320  ICRS center of the TAN WCS attached to the image. If `None`, (45
321  degrees, 45 degrees) is assumed.
322  cdelt : `lsst.geom.Angle`, optional
323  Pixel scale of the image. If `None`, 0.2 arcsec is assumed.
324  psfSigma : `float`, optional
325  Radius (sigma) of the Gaussian PSF attached to the image
326  psfDim : `int`, optional
327  Width and height of the image's Gaussian PSF attached to the image
328  calibration : `float`, optional
329  The spatially-constant calibration (in nJy/count) to set the
330  PhotoCalib of the exposure.
331 
332  Returns
333  -------
334  exposure : `lsst.age.image.ExposureF`
335  An empty image.
336  """
337  if wcs is None:
338  if crval is None:
339  crval = lsst.geom.SpherePoint(45.0, 45.0, lsst.geom.degrees)
340  if cdelt is None:
341  cdelt = 0.2*lsst.geom.arcseconds
342  crpix = lsst.geom.Box2D(bbox).getCenter()
343  wcs = lsst.afw.geom.makeSkyWcs(crpix=crpix, crval=crval,
344  cdMatrix=lsst.afw.geom.makeCdMatrix(scale=cdelt))
345  exposure = lsst.afw.image.ExposureF(bbox)
346  psf = lsst.afw.detection.GaussianPsf(psfDim, psfDim, psfSigma)
347  photoCalib = lsst.afw.image.PhotoCalib(calibration)
348  exposure.setWcs(wcs)
349  exposure.setPsf(psf)
350  exposure.setPhotoCalib(photoCalib)
351  return exposure
352 
A circularly symmetric Gaussian Psf class with no spatial variation, intended mostly for testing purp...
Definition: GaussianPsf.h:42
The photometric calibration of an exposure.
Definition: PhotoCalib.h:114
A floating-point coordinate rectangle geometry.
Definition: Box.h:413
Point in an unspecified spherical coordinate system.
Definition: SpherePoint.h:57
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.
Definition: SkyWcs.cc:521
Eigen::Matrix2d makeCdMatrix(lsst::geom::Angle const &scale, lsst::geom::Angle const &orientation=0 *lsst::geom::degrees, bool flipX=false)
Make a WCS CD matrix.
Definition: SkyWcs.cc:133

◆ makeMinimalSchema()

def lsst.meas.base.tests.TestDataset.makeMinimalSchema (   cls)
Return the minimal schema needed to hold truth catalog fields.

Notes
-----
When `TestDataset.realize` is called, the schema must include at least
these fields.  Usually it will include additional fields for
measurement algorithm outputs, allowing the same catalog to be used
for both truth values (the fields from the minimal schema) and the
measurements.

Definition at line 167 of file tests.py.

167  def makeMinimalSchema(cls):
168  """Return the minimal schema needed to hold truth catalog fields.
169 
170  Notes
171  -----
172  When `TestDataset.realize` is called, the schema must include at least
173  these fields. Usually it will include additional fields for
174  measurement algorithm outputs, allowing the same catalog to be used
175  for both truth values (the fields from the minimal schema) and the
176  measurements.
177  """
178  if not hasattr(cls, "_schema"):
180  cls.keys = {}
181  cls.keys["parent"] = schema.find("parent").key
182  cls.keys["nChild"] = schema.addField("deblend_nChild", type=np.int32)
183  cls.keys["instFlux"] = schema.addField("truth_instFlux", type=np.float64,
184  doc="true instFlux", units="count")
185  cls.keys["centroid"] = lsst.afw.table.Point2DKey.addFields(
186  schema, "truth", "true simulated centroid", "pixel"
187  )
188  cls.keys["centroid_sigma"] = lsst.afw.table.CovarianceMatrix2fKey.addFields(
189  schema, "truth", ['x', 'y'], "pixel"
190  )
191  cls.keys["centroid_flag"] = schema.addField("truth_flag", type="Flag",
192  doc="set if the object is a star")
193  cls.keys["shape"] = lsst.afw.table.QuadrupoleKey.addFields(
194  schema, "truth", "true shape after PSF convolution", lsst.afw.table.CoordinateType.PIXEL
195  )
196  cls.keys["isStar"] = schema.addField("truth_isStar", type="Flag",
197  doc="set if the object is a star")
198  schema.getAliasMap().set("slot_Shape", "truth")
199  schema.getAliasMap().set("slot_Centroid", "truth")
200  schema.getAliasMap().set("slot_ModelFlux", "truth")
201  cls._schema = schema
202  schema = lsst.afw.table.Schema(cls._schema)
203  schema.disconnectAliases()
204  return schema
205 
static QuadrupoleKey addFields(Schema &schema, std::string const &name, std::string const &doc, CoordinateType coordType=CoordinateType::PIXEL)
Add a set of quadrupole subfields to a schema and return a QuadrupoleKey that points to them.
Definition: aggregates.cc:100
Defines the fields and offsets for a table.
Definition: Schema.h:51
static Schema makeMinimalSchema()
Return a minimal schema for Source tables and records.
Definition: Source.h:258
daf::base::PropertySet * set
Definition: fits.cc:912

◆ makePerturbedWcs()

def lsst.meas.base.tests.TestDataset.makePerturbedWcs (   oldWcs,
  minScaleFactor = 1.2,
  maxScaleFactor = 1.5,
  minRotation = None,
  maxRotation = None,
  minRefShift = None,
  maxRefShift = None,
  minPixShift = 2.0,
  maxPixShift = 4.0,
  randomSeed = 1 
)
static
Return a perturbed version of the input WCS.

Create a new undistorted TAN WCS that is similar but not identical to
another, with random scaling, rotation, and offset (in both pixel
position and reference position).

Parameters
----------
oldWcs : `lsst.afw.geom.SkyWcs`
    The input WCS.
minScaleFactor : `float`
    Minimum scale factor to apply to the input WCS.
maxScaleFactor : `float`
    Maximum scale factor to apply to the input WCS.
minRotation : `lsst.geom.Angle` or `None`
    Minimum rotation to apply to the input WCS. If `None`, defaults to
    30 degrees.
maxRotation : `lsst.geom.Angle` or `None`
    Minimum rotation to apply to the input WCS. If `None`, defaults to
    60 degrees.
minRefShift : `lsst.geom.Angle` or `None`
    Miniumum shift to apply to the input WCS reference value. If
    `None`, defaults to 0.5 arcsec.
maxRefShift : `lsst.geom.Angle` or `None`
    Miniumum shift to apply to the input WCS reference value. If
    `None`, defaults to 1.0 arcsec.
minPixShift : `float`
    Minimum shift to apply to the input WCS reference pixel.
maxPixShift : `float`
    Maximum shift to apply to the input WCS reference pixel.
randomSeed : `int`
    Random seed.

Returns
-------
newWcs : `lsst.afw.geom.SkyWcs`
    A perturbed version of the input WCS.

Notes
-----
The maximum and minimum arguments are interpreted as absolute values
for a split range that covers both positive and negative values (as
this method is used in testing, it is typically most important to
avoid perturbations near zero). Scale factors are treated somewhat
differently: the actual scale factor is chosen between
``minScaleFactor`` and ``maxScaleFactor`` OR (``1/maxScaleFactor``)
and (``1/minScaleFactor``).

The default range for rotation is 30-60 degrees, and the default range
for reference shift is 0.5-1.0 arcseconds (these cannot be safely
included directly as default values because Angle objects are
mutable).

The random number generator is primed with the seed given. If
`None`, a seed is automatically chosen.

Definition at line 207 of file tests.py.

210  minPixShift=2.0, maxPixShift=4.0, randomSeed=1):
211  """Return a perturbed version of the input WCS.
212 
213  Create a new undistorted TAN WCS that is similar but not identical to
214  another, with random scaling, rotation, and offset (in both pixel
215  position and reference position).
216 
217  Parameters
218  ----------
219  oldWcs : `lsst.afw.geom.SkyWcs`
220  The input WCS.
221  minScaleFactor : `float`
222  Minimum scale factor to apply to the input WCS.
223  maxScaleFactor : `float`
224  Maximum scale factor to apply to the input WCS.
225  minRotation : `lsst.geom.Angle` or `None`
226  Minimum rotation to apply to the input WCS. If `None`, defaults to
227  30 degrees.
228  maxRotation : `lsst.geom.Angle` or `None`
229  Minimum rotation to apply to the input WCS. If `None`, defaults to
230  60 degrees.
231  minRefShift : `lsst.geom.Angle` or `None`
232  Miniumum shift to apply to the input WCS reference value. If
233  `None`, defaults to 0.5 arcsec.
234  maxRefShift : `lsst.geom.Angle` or `None`
235  Miniumum shift to apply to the input WCS reference value. If
236  `None`, defaults to 1.0 arcsec.
237  minPixShift : `float`
238  Minimum shift to apply to the input WCS reference pixel.
239  maxPixShift : `float`
240  Maximum shift to apply to the input WCS reference pixel.
241  randomSeed : `int`
242  Random seed.
243 
244  Returns
245  -------
246  newWcs : `lsst.afw.geom.SkyWcs`
247  A perturbed version of the input WCS.
248 
249  Notes
250  -----
251  The maximum and minimum arguments are interpreted as absolute values
252  for a split range that covers both positive and negative values (as
253  this method is used in testing, it is typically most important to
254  avoid perturbations near zero). Scale factors are treated somewhat
255  differently: the actual scale factor is chosen between
256  ``minScaleFactor`` and ``maxScaleFactor`` OR (``1/maxScaleFactor``)
257  and (``1/minScaleFactor``).
258 
259  The default range for rotation is 30-60 degrees, and the default range
260  for reference shift is 0.5-1.0 arcseconds (these cannot be safely
261  included directly as default values because Angle objects are
262  mutable).
263 
264  The random number generator is primed with the seed given. If
265  `None`, a seed is automatically chosen.
266  """
267  random_state = np.random.RandomState(randomSeed)
268  if minRotation is None:
269  minRotation = 30.0*lsst.geom.degrees
270  if maxRotation is None:
271  maxRotation = 60.0*lsst.geom.degrees
272  if minRefShift is None:
273  minRefShift = 0.5*lsst.geom.arcseconds
274  if maxRefShift is None:
275  maxRefShift = 1.0*lsst.geom.arcseconds
276 
277  def splitRandom(min1, max1, min2=None, max2=None):
278  if min2 is None:
279  min2 = -max1
280  if max2 is None:
281  max2 = -min1
282  if random_state.uniform() > 0.5:
283  return float(random_state.uniform(min1, max1))
284  else:
285  return float(random_state.uniform(min2, max2))
286  # Generate random perturbations
287  scaleFactor = splitRandom(minScaleFactor, maxScaleFactor, 1.0/maxScaleFactor, 1.0/minScaleFactor)
288  rotation = splitRandom(minRotation.asRadians(), maxRotation.asRadians())*lsst.geom.radians
289  refShiftRa = splitRandom(minRefShift.asRadians(), maxRefShift.asRadians())*lsst.geom.radians
290  refShiftDec = splitRandom(minRefShift.asRadians(), maxRefShift.asRadians())*lsst.geom.radians
291  pixShiftX = splitRandom(minPixShift, maxPixShift)
292  pixShiftY = splitRandom(minPixShift, maxPixShift)
293  # Compute new CD matrix
294  oldTransform = lsst.geom.LinearTransform(oldWcs.getCdMatrix())
295  rTransform = lsst.geom.LinearTransform.makeRotation(rotation)
296  sTransform = lsst.geom.LinearTransform.makeScaling(scaleFactor)
297  newTransform = oldTransform*rTransform*sTransform
298  matrix = newTransform.getMatrix()
299  # Compute new coordinate reference pixel (CRVAL)
300  oldSkyOrigin = oldWcs.getSkyOrigin()
301  newSkyOrigin = lsst.geom.SpherePoint(oldSkyOrigin.getRa() + refShiftRa,
302  oldSkyOrigin.getDec() + refShiftDec)
303  # Compute new pixel reference pixel (CRPIX)
304  oldPixOrigin = oldWcs.getPixelOrigin()
305  newPixOrigin = lsst.geom.Point2D(oldPixOrigin.getX() + pixShiftX,
306  oldPixOrigin.getY() + pixShiftY)
307  return lsst.afw.geom.makeSkyWcs(crpix=newPixOrigin, crval=newSkyOrigin, cdMatrix=matrix)
308 
A 2D linear coordinate transformation.
static LinearTransform makeRotation(Angle t) noexcept
static LinearTransform makeScaling(double s) noexcept

◆ realize()

def lsst.meas.base.tests.TestDataset.realize (   self,
  noise,
  schema,
  randomSeed = 1 
)
Simulate an exposure and detection catalog for this dataset.

The simulation includes noise, and the detection catalog includes
`~lsst.afw.detection.heavyFootprint.HeavyFootprint`\ s.

Parameters
----------
noise : `float`
    Standard deviation of noise to be added to the exposure.  The
    noise will be Gaussian and constant, appropriate for the
    sky-limited regime.
schema : `lsst.afw.table.Schema`
    Schema of the new catalog to be created.  Must start with
    ``self.schema`` (i.e. ``schema.contains(self.schema)`` must be
    `True`), but typically contains fields for already-configured
    measurement algorithms as well.
randomSeed : `int`, optional
    Seed for the random number generator.
    If `None`, a seed is chosen automatically.

Returns
-------
`exposure` : `lsst.afw.image.ExposureF`
    Simulated image.
`catalog` : `lsst.afw.table.SourceCatalog`
    Simulated detection catalog.

Definition at line 518 of file tests.py.

518  def realize(self, noise, schema, randomSeed=1):
519  r"""Simulate an exposure and detection catalog for this dataset.
520 
521  The simulation includes noise, and the detection catalog includes
522  `~lsst.afw.detection.heavyFootprint.HeavyFootprint`\ s.
523 
524  Parameters
525  ----------
526  noise : `float`
527  Standard deviation of noise to be added to the exposure. The
528  noise will be Gaussian and constant, appropriate for the
529  sky-limited regime.
530  schema : `lsst.afw.table.Schema`
531  Schema of the new catalog to be created. Must start with
532  ``self.schema`` (i.e. ``schema.contains(self.schema)`` must be
533  `True`), but typically contains fields for already-configured
534  measurement algorithms as well.
535  randomSeed : `int`, optional
536  Seed for the random number generator.
537  If `None`, a seed is chosen automatically.
538 
539  Returns
540  -------
541  `exposure` : `lsst.afw.image.ExposureF`
542  Simulated image.
543  `catalog` : `lsst.afw.table.SourceCatalog`
544  Simulated detection catalog.
545  """
546  random_state = np.random.RandomState(randomSeed)
547  assert schema.contains(self.schema)
548  mapper = lsst.afw.table.SchemaMapper(self.schema)
549  mapper.addMinimalSchema(self.schema, True)
550  exposure = self.exposure.clone()
551  exposure.getMaskedImage().getVariance().getArray()[:, :] = noise**2
552  exposure.getMaskedImage().getImage().getArray()[:, :] \
553  += random_state.randn(exposure.getHeight(), exposure.getWidth())*noise
554  catalog = lsst.afw.table.SourceCatalog(schema)
555  catalog.extend(self.catalog, mapper=mapper)
556  # Loop over sources and generate new HeavyFootprints that divide up
557  # the noisy pixels, not the ideal no-noise pixels.
558  for record in catalog:
559  # parent objects have non-Heavy Footprints, which don't need to be
560  # updated after adding noise.
561  if record.getParent() == 0:
562  continue
563  # get flattened arrays that correspond to the no-noise and noisy
564  # parent images
565  parent = catalog.find(record.getParent())
566  footprint = parent.getFootprint()
567  parentFluxArrayNoNoise = np.zeros(footprint.getArea(), dtype=np.float32)
568  footprint.spans.flatten(parentFluxArrayNoNoise,
569  self.exposure.getMaskedImage().getImage().getArray(),
570  self.exposure.getXY0())
571  parentFluxArrayNoisy = np.zeros(footprint.getArea(), dtype=np.float32)
572  footprint.spans.flatten(parentFluxArrayNoisy,
573  exposure.getMaskedImage().getImage().getArray(),
574  exposure.getXY0())
575  oldHeavy = record.getFootprint()
576  fraction = (oldHeavy.getImageArray() / parentFluxArrayNoNoise)
577  # N.B. this isn't a copy ctor - it's a copy from a vanilla
578  # Footprint, so it doesn't copy the arrays we don't want to
579  # change, and hence we have to do that ourselves below.
580  newHeavy = lsst.afw.detection.HeavyFootprintF(oldHeavy)
581  newHeavy.getImageArray()[:] = parentFluxArrayNoisy*fraction
582  newHeavy.getMaskArray()[:] = oldHeavy.getMaskArray()
583  newHeavy.getVarianceArray()[:] = oldHeavy.getVarianceArray()
584  record.setFootprint(newHeavy)
585  return exposure, catalog
586 
587 
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:21

◆ transform()

def lsst.meas.base.tests.TestDataset.transform (   self,
  wcs,
**  kwds 
)
Copy this dataset transformed to a new WCS, with new Psf and PhotoCalib.

Parameters
----------
wcs : `lsst.afw.geom.SkyWcs`
    WCS for the new dataset.
**kwds
    Additional keyword arguments passed on to
    `TestDataset.makeEmptyExposure`.  If not specified, these revert
    to the defaults for `~TestDataset.makeEmptyExposure`, not the
    values in the current dataset.

Returns
-------
newDataset : `TestDataset`
    Transformed copy of this dataset.

Definition at line 469 of file tests.py.

469  def transform(self, wcs, **kwds):
470  """Copy this dataset transformed to a new WCS, with new Psf and PhotoCalib.
471 
472  Parameters
473  ----------
474  wcs : `lsst.afw.geom.SkyWcs`
475  WCS for the new dataset.
476  **kwds
477  Additional keyword arguments passed on to
478  `TestDataset.makeEmptyExposure`. If not specified, these revert
479  to the defaults for `~TestDataset.makeEmptyExposure`, not the
480  values in the current dataset.
481 
482  Returns
483  -------
484  newDataset : `TestDataset`
485  Transformed copy of this dataset.
486  """
487  bboxD = lsst.geom.Box2D()
488  xyt = lsst.afw.geom.makeWcsPairTransform(self.exposure.getWcs(), wcs)
489  for corner in lsst.geom.Box2D(self.exposure.getBBox()).getCorners():
490  bboxD.include(xyt.applyForward(lsst.geom.Point2D(corner)))
491  bboxI = lsst.geom.Box2I(bboxD)
492  result = TestDataset(bbox=bboxI, wcs=wcs, **kwds)
493  oldPhotoCalib = self.exposure.getPhotoCalib()
494  newPhotoCalib = result.exposure.getPhotoCalib()
495  oldPsfShape = self.exposure.getPsf().computeShape(bboxD.getCenter())
496  for record in self.catalog:
497  if record.get(self.keys["nChild"]):
498  raise NotImplementedError("Transforming blended sources in TestDatasets is not supported")
499  magnitude = oldPhotoCalib.instFluxToMagnitude(record.get(self.keys["instFlux"]))
500  newFlux = newPhotoCalib.magnitudeToInstFlux(magnitude)
501  oldCentroid = record.get(self.keys["centroid"])
502  newCentroid = xyt.applyForward(oldCentroid)
503  if record.get(self.keys["isStar"]):
504  newDeconvolvedShape = None
505  else:
506  affine = lsst.afw.geom.linearizeTransform(xyt, oldCentroid)
507  oldFullShape = record.get(self.keys["shape"])
508  oldDeconvolvedShape = lsst.afw.geom.Quadrupole(
509  oldFullShape.getIxx() - oldPsfShape.getIxx(),
510  oldFullShape.getIyy() - oldPsfShape.getIyy(),
511  oldFullShape.getIxy() - oldPsfShape.getIxy(),
512  False
513  )
514  newDeconvolvedShape = oldDeconvolvedShape.transform(affine.getLinear())
515  result.addSource(newFlux, newCentroid, newDeconvolvedShape)
516  return result
517 
table::Key< int > transform
An ellipse core with quadrupole moments as parameters.
Definition: Quadrupole.h:47
An integer coordinate rectangle.
Definition: Box.h:55
std::shared_ptr< TransformPoint2ToPoint2 > makeWcsPairTransform(SkyWcs const &src, SkyWcs const &dst)
A Transform obtained by putting two SkyWcs objects "back to back".
Definition: SkyWcs.cc:146
lsst::geom::AffineTransform linearizeTransform(TransformPoint2ToPoint2 const &original, lsst::geom::Point2D const &inPoint)
Approximate a Transform by its local linearization.

Member Data Documentation

◆ catalog

lsst.meas.base.tests.TestDataset.catalog

Definition at line 388 of file tests.py.

◆ exposure

lsst.meas.base.tests.TestDataset.exposure

Definition at line 385 of file tests.py.

◆ keys

lsst.meas.base.tests.TestDataset.keys

Definition at line 180 of file tests.py.

◆ psfShape

lsst.meas.base.tests.TestDataset.psfShape

Definition at line 386 of file tests.py.

◆ schema

lsst.meas.base.tests.TestDataset.schema

Definition at line 387 of file tests.py.

◆ threshold

lsst.meas.base.tests.TestDataset.threshold

Definition at line 384 of file tests.py.


The documentation for this class was generated from the following file: