LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
LSSTDataManagementBasePackage
Public Member Functions | Public Attributes | Static Public Attributes | Static Private Attributes | List of all members
lsst.pipe.tasks.calibrate.CalibrateTask Class Reference

Calibrate an exposure: measure PSF, subtract background, measure astrometry and photometry. More...

Inheritance diagram for lsst.pipe.tasks.calibrate.CalibrateTask:

Public Member Functions

def __init__
 Create the calibration task. More...
 
def getCalibKeys
 Return a sequence of schema keys that represent fields that should be propagated from icSrc to src by ProcessCcdTask. More...
 
def run
 Run the calibration task on an exposure. More...
 
def installInitialPsf
 Initialise the calibration procedure by setting the PSF to a configuration-defined guess. More...
 

Public Attributes

 schema1
 
 algMetadata
 
 schemaMapper
 
 schema
 

Static Public Attributes

 ConfigClass = CalibrateConfig
 

Static Private Attributes

string _DefaultName = "calibrate"
 

Detailed Description

Calibrate an exposure: measure PSF, subtract background, measure astrometry and photometry.

Contents

Description

CalibrateTask

Calculate an Exposure's zero-point given a set of flux measurements of stars matched to an input catalogue. The type of flux to use is specified by CalibrateConfig.fluxField.

The algorithm clips outliers iteratively, with parameters set in the configuration.

Note
This task can adds fields to the schema, so any code calling this task must ensure that these columns are indeed present in the input match list; see A complete example of using CalibrateTask

Task initialisation

Create the calibration task.

Parameters
**kwargskeyword arguments to be passed to lsst.pipe.base.task.Task.__init__

CalibrateTask delegates most of its work to a set of sub-Tasks:

repair RepairTask
Interpolate over defects such as bad columns and cosmic rays. This task is called twice; once before the measurePsf step and again after the PSF has been measured.
detection SourceDetectionTask
Initial (high-threshold) detection phase for calibration
initialMeasurement SingleFrameMeasurementTask
Make the initial measurements used to feed PSF determination and aperture correction determination
astrometry AstrometryTask
Solve the astrometry. May be disabled by setting CalibrateTaskConfig.doAstrometry to be False. This task is called twice; once before the measurePsf step and again after the PSF has been measured.
measurePsf MeasurePsfTask
Estimate the PSF. May be disabled by setting CalibrateTaskConfig.doPsf to be False. If requested the astrometry is solved before this is called, so if you disable the astrometry the measurePsf task won't have access to objects positions.
measurement SingleFrameMeasurementTask
Post-PSF-determination measurements used to feed other calibrations
photocal PhotoCalTask
Solve for the photometric zeropoint. May be disabled by setting CalibrateTaskConfig.doPhotoCal to be False. N.b. Requires that astrometry was successfully run.

You can replace any of these subtasks if you wish, see Using a Custom Astrometry Task.

Note
These task APIs are not well controlled, so replacing a task is a matter of matching a poorly specified interface. We will be working on this over the first year of construction.

Invoking the Task

Run the calibration task on an exposure.

Parameters
[in,out]exposureExposure to calibrate; measured PSF will be installed there as well
[in]defectsList of defects on exposure
[in]idFactoryafw.table.IdFactory to use for source catalog.
Returns
a pipeBase.Struct with fields:
  • exposure: Repaired exposure
  • backgrounds: A list of background models applied in the calibration phase
  • psf: Point spread function
  • sources: Sources used in calibration
  • matches: A list of reference object/source matches (an lsst.afw.table.ReferenceMatchVector)
  • matchMeta: Metadata about the field (an lsst.daf.base.PropertyList)
  • photocal: Output of photocal subtask

It is moderately important to provide a decent initial guess for the seeing if you want to deal with cosmic rays. If there's a PSF in the exposure it'll be used; failing that the CalibrateConfig.initialPsf is consulted (although the pixel scale will be taken from the WCS if available).

If the exposure contains an lsst.afw.image.Calib object with the exposure time set, MAGZERO will be set in the task metadata.

Configuration parameters

See CalibrateConfig

#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Quantities set in Metadata

Task metadata
MAGZERO
Measured zeropoint (DN per second)

Exposure metadata
MAGZERO_RMS
MAGZERO's RMS == return.sigma
MAGZERO_NOBJ
Number of stars used == return.ngood
COLORTERM1
?? (always 0.0)
COLORTERM2
?? (always 0.0)
COLORTERM3
?? (always 0.0)

#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Debug variables

The command line task interface supports a flag -d to import debug.py from your PYTHONPATH; see Using lsstDebug to control debugging output for more about debug.py files.

The calibrate task has a debug dictionary with keys which correspond to stages of the CalibrationTask processing:

repair
Fixed defects and masked cosmic rays with a guessed PSF. Action: show the exposure.
background
Subtracted background (no sources masked). Action: show the exposure
PSF_repair
Fixed defects and removed cosmic rays with an estimated PSF. Action: show the exposure
PSF_background
Subtracted background (calibration sources masked). Action: show the exposure
calibrate
Just before astro/photo calibration. Action: show the exposure, and
  • sources as smallish green o
  • matches (if exposure has a Wcs).
    • catalog position as a largish yellow +
    • source position as a largish red x

The values are the ds9 frame to display in (if >= 1); if <= 0, nothing's displayed. There's an example here.

Some subtasks may also have their own debug information; see individual Task documentation.

A complete example of using CalibrateTask

This code is in calibrateTask.py in the examples directory, and can be run as e.g.

1 examples/calibrateTask.py --ds9

Import the task (there are some other standard imports; read the file if you're curious)

1 from lsst.pipe.tasks.calibrate import CalibrateTask

Create the detection task

1  config = CalibrateTask.ConfigClass()
2  config.initialPsf.pixelScale = 0.185 # arcsec per pixel
3  config.initialPsf.fwhm = 1.0
4  config.astrometry.retarget(MyAstrometryTask)
5  calibrateTask = CalibrateTask(config=config)
Note that we're using a custom AstrometryTask (because we don't have a valid astrometric catalogue handy); see Using a Custom Astrometry Task.

We're now ready to process the data (we could loop over multiple exposures/catalogues using the same task objects) and unpack the results

1  exposure = loadData(config.initialPsf.pixelScale)
2  result = calibrateTask.run(exposure)
3 
4  exposure0, exposure = exposure, result.exposure
5  sources = result.sources

We then might plot the results (e.g. if you set –ds9 on the command line)

1  if display: # display on ds9 (see also --debug argparse option)
2  frame = 1
3  ds9.mtv(exposure, frame=frame)
4 
5  with ds9.Buffering():
6  for s in sources:
7  xy = s.getCentroid()
8  ds9.dot('+', *xy, ctype=ds9.CYAN if s.get("flags.negative") else ds9.GREEN, frame=frame)

Using a Custom Astrometry Task

The first thing to do is define my own task:

1  # and a trivial WCS (needed by MyAstrometryTask)
2  pixelScale /= 3600.0 # degrees per pixel
4  pixelScale, 0.0, 0.0, pixelScale)
5  exposure.setWcs(wcs)
6 
7  return exposure
8 
9 class MyAstrometryTask(AstrometryTask):
10  """An override for CalibrateTask's astrometry task"""
11  def __init__(self, *args, **kwargs):
12  super(MyAstrometryTask, self).__init__(*args, **kwargs)

Then we need our own run method. First unpack the filtername and wcs

1  def run(self, exposure, sourceCat):
2  """My run method that totally fakes the astrometric solution"""
3 
4  filterName = exposure.getFilter().getName()
5  wcs = exposure.getWcs()
Then build a "reference catalog" by shamelessly copying the catalog of detected sources
1  schema = afwTable.SimpleTable.makeMinimalSchema()
2  schema.addField(afwTable.Field[float](filterName, "Flux in appropriate band"))
3  schema.addField(afwTable.Field[float]("flux", "Reference flux"))
4  schema.addField(afwTable.Field[float]("photometric", "I am a reference star"))
5  refCat = afwTable.SimpleCatalog(schema)
6 
7  for s in sourceCat:
8  m = refCat.addNew()
9  flux = 1e-3*s.getPsfFlux()*np.random.normal(1.0, 2e-2)
10  m.set(filterName, flux)
11  m.set("flux", flux)
12  m.set("coord", wcs.pixelToSky(s.getCentroid()))
13 
14  refCat.get("photometric")[:] = True
(you need to set "flux" as well as filterName due to a bug in the photometric calibration code; DM-933).

Then "match" by zipping up the two catalogs,

1  matches = []
3  for m, s in zip(refCat, sourceCat):
4  matches.append(afwTable.ReferenceMatch(m, s, 0.0))
and finally return the desired results.
1  return pipeBase.Struct(
2  matches=matches,
3  matchMeta=md
4  )


To investigate the Debug variables, put something like

1 import lsstDebug
2 def DebugInfo(name):
3  di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
4  if name == "lsst.pipe.tasks.calibrate":
5  di.display = dict(
6  repair = 1,
7  calibrate = 2,
8  )
9 
10  return di
11 
12 lsstDebug.Info = DebugInfo

into your debug.py file and run calibrateTask.py with the –debug flag.

Definition at line 155 of file calibrate.py.

Constructor & Destructor Documentation

def lsst.pipe.tasks.calibrate.CalibrateTask.__init__ (   self,
  kwargs 
)

Create the calibration task.

Parameters
**kwargskeyword arguments to be passed to lsst.pipe.base.task.Task.__init__

Definition at line 347 of file calibrate.py.

348  def __init__(self, **kwargs):
349  """!
350  Create the calibration task
351 
352  \param **kwargs keyword arguments to be passed to lsst.pipe.base.task.Task.__init__
353  """
354  pipeBase.Task.__init__(self, **kwargs)
355 
356  # the calibrate Source Catalog is divided into two catalogs to allow measurement to be run twice
357  # schema1 contains everything except what is added by the second measurement task.
358  # Before the second measurement task is run, self.schemaMapper transforms the sources into
359  # the final output schema, at the same time renaming the measurement fields to "initial_"
360  self.schema1 = afwTable.SourceTable.makeMinimalSchema()
362  self.makeSubtask("repair")
363  self.makeSubtask("detection", schema=self.schema1)
364  beginInitial = self.schema1.getFieldCount()
365  self.makeSubtask("initialMeasurement", schema=self.schema1, algMetadata=self.algMetadata)
366  endInitial = self.schema1.getFieldCount()
367 
368  # create subtasks that are run with schema1 (and possibly also the final schema)
369  self.makeSubtask("measurePsf", schema=self.schema1)
370  self.makeSubtask("astrometry", schema=self.schema1)
371 
372  # create a schemaMapper to map schema1 into the final schema
374  separator = "_"
375  count = 0
376  for item in self.schema1:
377  count = count + 1
378  field = item.getField()
379  name = field.getName()
380  if count > beginInitial and count <= endInitial:
381  name = "initial" + separator + name
382  self.schemaMapper.addMapping(item.key, name)
383 
384  # create subtasks that are run only with the final schema
385  schema = self.schemaMapper.editOutputSchema()
386  self.makeSubtask("measurement", schema=schema, algMetadata=self.algMetadata)
387  self.makeSubtask("measureApCorr", schema=schema)
388  self.makeSubtask("photocal", schema=schema)
389 
390  # the final schema is the same as the schemaMapper output
391  self.schema = self.schemaMapper.getOutputSchema()
def __init__
Create the calibration task.
Definition: calibrate.py:347
Class for storing ordered metadata with comments.
Definition: PropertyList.h:81
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:19

Member Function Documentation

def lsst.pipe.tasks.calibrate.CalibrateTask.getCalibKeys (   self)

Return a sequence of schema keys that represent fields that should be propagated from icSrc to src by ProcessCcdTask.

Definition at line 392 of file calibrate.py.

393  def getCalibKeys(self):
394  """!
395  Return a sequence of schema keys that represent fields that should be propagated from
396  icSrc to src by ProcessCcdTask.
397  """
398  if self.config.doPsf:
399  return (self.measurePsf.candidateKey, self.measurePsf.usedKey)
400  else:
401  return ()
def getCalibKeys
Return a sequence of schema keys that represent fields that should be propagated from icSrc to src by...
Definition: calibrate.py:392
def lsst.pipe.tasks.calibrate.CalibrateTask.installInitialPsf (   self,
  exposure 
)

Initialise the calibration procedure by setting the PSF to a configuration-defined guess.

Parameters
[in,out]exposureExposure to process; fake PSF will be installed here.
Exceptions
AssertionErrorIf exposure or exposure.getWcs() are None

Definition at line 554 of file calibrate.py.

555  def installInitialPsf(self, exposure):
556  """!Initialise the calibration procedure by setting the PSF to a configuration-defined guess.
557 
558  \param[in,out] exposure Exposure to process; fake PSF will be installed here.
559  \throws AssertionError If exposure or exposure.getWcs() are None
560  """
561  assert exposure, "No exposure provided"
562 
563  wcs = exposure.getWcs()
564  if wcs:
565  pixelScale = wcs.pixelScale().asArcseconds()
566  else:
567  pixelScale = self.config.initialPsf.pixelScale
568 
569  cls = getattr(measAlg, self.config.initialPsf.model + "Psf")
570 
571  fwhm = self.config.initialPsf.fwhm/pixelScale
572  size = self.config.initialPsf.size
573  self.log.info("installInitialPsf fwhm=%s pixels; size=%s pixels" % (fwhm, size))
574  psf = cls(size, size, fwhm/(2*math.sqrt(2*math.log(2))))
575  exposure.setPsf(psf)
def installInitialPsf
Initialise the calibration procedure by setting the PSF to a configuration-defined guess...
Definition: calibrate.py:554
def lsst.pipe.tasks.calibrate.CalibrateTask.run (   self,
  exposure,
  defects = None,
  idFactory = None 
)

Run the calibration task on an exposure.

Parameters
[in,out]exposureExposure to calibrate; measured PSF will be installed there as well
[in]defectsList of defects on exposure
[in]idFactoryafw.table.IdFactory to use for source catalog.
Returns
a pipeBase.Struct with fields:
  • exposure: Repaired exposure
  • backgrounds: A list of background models applied in the calibration phase
  • psf: Point spread function
  • sources: Sources used in calibration
  • matches: A list of reference object/source matches (an lsst.afw.table.ReferenceMatchVector)
  • matchMeta: Metadata about the field (an lsst.daf.base.PropertyList)
  • photocal: Output of photocal subtask

It is moderately important to provide a decent initial guess for the seeing if you want to deal with cosmic rays. If there's a PSF in the exposure it'll be used; failing that the CalibrateConfig.initialPsf is consulted (although the pixel scale will be taken from the WCS if available).

If the exposure contains an lsst.afw.image.Calib object with the exposure time set, MAGZERO will be set in the task metadata.

Definition at line 403 of file calibrate.py.

404  def run(self, exposure, defects=None, idFactory=None):
405  """!Run the calibration task on an exposure
406 
407  \param[in,out] exposure Exposure to calibrate; measured PSF will be installed there as well
408  \param[in] defects List of defects on exposure
409  \param[in] idFactory afw.table.IdFactory to use for source catalog.
410  \return a pipeBase.Struct with fields:
411  - exposure: Repaired exposure
412  - backgrounds: A list of background models applied in the calibration phase
413  - psf: Point spread function
414  - sources: Sources used in calibration
415  - matches: A list of reference object/source matches (an lsst.afw.table.ReferenceMatchVector)
416  - matchMeta: Metadata about the field (an lsst.daf.base.PropertyList)
417  - photocal: Output of photocal subtask
418 
419  It is moderately important to provide a decent initial guess for the seeing if you want to
420  deal with cosmic rays. If there's a PSF in the exposure it'll be used; failing that the
421  CalibrateConfig.initialPsf is consulted (although the pixel scale will be taken from the
422  WCS if available).
423 
424  If the exposure contains an lsst.afw.image.Calib object with the exposure time set, MAGZERO
425  will be set in the task metadata.
426  """
427  assert exposure is not None, "No exposure provided"
428 
429  if not exposure.hasPsf():
430  self.installInitialPsf(exposure)
431  if idFactory is None:
432  idFactory = afwTable.IdFactory.makeSimple()
433  backgrounds = afwMath.BackgroundList()
434  keepCRs = True # At least until we know the PSF
435  self.repair.run(exposure, defects=defects, keepCRs=keepCRs)
436  self.display('repair', exposure=exposure)
437 
438  if self.config.doBackground:
439  with self.timer("background"):
440  bg, exposure = measAlg.estimateBackground(exposure, self.config.background, subtract=True)
441  backgrounds.append(bg)
442  self.display('background', exposure=exposure)
443 
444  # Make both tables from the same detRet, since detection can only be run once
445  table1 = afwTable.SourceTable.make(self.schema1, idFactory)
446  table1.setMetadata(self.algMetadata)
447  detRet = self.detection.makeSourceCatalog(table1, exposure)
448  sources1 = detRet.sources
449  if detRet.fpSets.background:
450  backgrounds.append(detRet.fpSets.background)
451 
452  # do the initial measurement. This is normally done for star selection, but do it
453  # even if the psf is not going to be calculated for consistency
454  self.initialMeasurement.run(exposure, sources1, allowApCorr=False)
455 
456  if self.config.doPsf:
457  if self.config.doAstrometry:
458  astromRet = self.astrometry.run(exposure, sources1)
459  matches = astromRet.matches
460  else:
461  # If doAstrometry is False, we force the Star Selector to either make them itself
462  # or hope it doesn't need them.
463  matches = None
464  psfRet = self.measurePsf.run(exposure, sources1, matches=matches)
465  psf = psfRet.psf
466  elif exposure.hasPsf():
467  psf = exposure.getPsf()
468  else:
469  psf = None
470 
471  # Wash, rinse, repeat with proper PSF
472 
473  if self.config.doPsf:
474  self.repair.run(exposure, defects=defects, keepCRs=None)
475  self.display('PSF_repair', exposure=exposure)
476 
477  if self.config.doBackground:
478  # Background estimation ignores (by default) pixels with the
479  # DETECTED bit set, so now we re-estimate the background,
480  # ignoring sources. (see BackgroundConfig.ignoredPixelMask)
481  with self.timer("background"):
482  # Subtract background
483  bg, exposure = measAlg.estimateBackground(
484  exposure, self.config.background, subtract=True,
485  statsKeys=('BGMEAN2', 'BGVAR2'))
486  self.log.info("Fit and subtracted background")
487  backgrounds.append(bg)
488 
489  self.display('PSF_background', exposure=exposure)
490 
491  # make a second table with which to do the second measurement
492  # the schemaMapper will copy the footprints and ids, which is all we need.
493  table2 = afwTable.SourceTable.make(self.schema, idFactory)
494  table2.setMetadata(self.algMetadata)
495  sources = afwTable.SourceCatalog(table2)
496  # transfer to a second table -- note that the slots do not have to be reset here
497  # as long as measurement.run follows immediately
498  sources.extend(sources1, self.schemaMapper)
499 
500  if self.config.doMeasureApCorr:
501  # Run measurement through all flux measurements (all have the same execution order),
502  # then apply aperture corrections, then run the rest of the measurements
503  self.measurement.run(exposure, sources, endOrder=BasePlugin.APCORR_ORDER)
504  apCorrMap = self.measureApCorr.run(bbox=exposure.getBBox(), catalog=sources).apCorrMap
505  exposure.getInfo().setApCorrMap(apCorrMap)
506  self.measurement.run(exposure, sources, beginOrder=BasePlugin.APCORR_ORDER)
507  else:
508  self.measurement.run(exposure, sources)
509 
510  if self.config.doAstrometry:
511  astromRet = self.astrometry.run(exposure, sources)
512  matches = astromRet.matches
513  matchMeta = astromRet.matchMeta
514  else:
515  matches, matchMeta = None, None
516 
517  if self.config.doPhotoCal:
518  assert(matches is not None)
519  try:
520  photocalRet = self.photocal.run(exposure, matches)
521  except Exception, e:
522  self.log.warn("Failed to determine photometric zero-point: %s" % e)
523  photocalRet = None
524  self.metadata.set('MAGZERO', float("NaN"))
525 
526  if photocalRet:
527  self.log.info("Photometric zero-point: %f" % photocalRet.calib.getMagnitude(1.0))
528  exposure.getCalib().setFluxMag0(photocalRet.calib.getFluxMag0())
529  metadata = exposure.getMetadata()
530  # convert to (mag/sec/adu) for metadata
531  try:
532  magZero = photocalRet.zp - 2.5 * math.log10(exposure.getCalib().getExptime() )
533  metadata.set('MAGZERO', magZero)
534  except:
535  self.log.warn("Could not set normalized MAGZERO in header: no exposure time")
536  metadata.set('MAGZERO_RMS', photocalRet.sigma)
537  metadata.set('MAGZERO_NOBJ', photocalRet.ngood)
538  metadata.set('COLORTERM1', 0.0)
539  metadata.set('COLORTERM2', 0.0)
540  metadata.set('COLORTERM3', 0.0)
541  else:
542  photocalRet = None
543  self.display('calibrate', exposure=exposure, sources=sources, matches=matches)
544 
545  return pipeBase.Struct(
546  exposure = exposure,
547  backgrounds = backgrounds,
548  psf = psf,
549  sources = sources,
550  matches = matches,
551  matchMeta = matchMeta,
552  photocal = photocalRet,
553  )
def installInitialPsf
Initialise the calibration procedure by setting the PSF to a configuration-defined guess...
Definition: calibrate.py:554
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
def run
Run the calibration task on an exposure.
Definition: calibrate.py:403

Member Data Documentation

string lsst.pipe.tasks.calibrate.CalibrateTask._DefaultName = "calibrate"
staticprivate

Definition at line 345 of file calibrate.py.

lsst.pipe.tasks.calibrate.CalibrateTask.algMetadata

Definition at line 360 of file calibrate.py.

lsst.pipe.tasks.calibrate.CalibrateTask.ConfigClass = CalibrateConfig
static

Definition at line 344 of file calibrate.py.

lsst.pipe.tasks.calibrate.CalibrateTask.schema

Definition at line 390 of file calibrate.py.

lsst.pipe.tasks.calibrate.CalibrateTask.schema1

Definition at line 359 of file calibrate.py.

lsst.pipe.tasks.calibrate.CalibrateTask.schemaMapper

Definition at line 372 of file calibrate.py.


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