1 from __future__
import absolute_import, division
24 from itertools
import izip
33 from lsst.afw.image import abMagFromFlux, abMagErrFromFluxErr, fluxFromABMag, Calib
36 from .colorterms
import ColortermLibrary
38 __all__ = [
"PhotoCalTask",
"PhotoCalConfig"]
42 """!Return True if the given source has all good flags set and none of the bad flags set.
44 \param[in] source SourceRecord object to process.
45 \param[in] sourceKeys Struct of source catalog keys, as returned by PhotCalTask.getSourceKeys()
47 for k
in sourceKeys.goodFlags:
50 if source.getPsfFluxFlag():
52 for k
in sourceKeys.badFlags:
59 """Config for PhotoCal"""
60 magLimit = pexConf.Field(
63 doc =
"Don't use objects fainter than this magnitude",
65 doWriteOutput = pexConf.Field(
68 doc =
"Write a field name astrom_usedByPhotoCal to the schema",
70 fluxField = pexConf.Field(
72 default =
"slot_CalibFlux_flux",
73 doc = (
"Name of the source flux field to use. The associated flag field\n"
74 "('<name>_flags') will be implicitly included in badFlags."),
76 applyColorTerms = pexConf.Field(
79 doc = (
"Apply photometric color terms to reference stars? One of:\n"
80 "None: apply if colorterms and photoCatName are not None;\n"
81 " fail if color term data is not available for the specified ref catalog and filter.\n"
82 "True: always apply colorterms; fail if color term data is not available for the\n"
83 " specified reference catalog and filter.\n"
84 "False: do not apply."),
87 goodFlags = pexConf.ListField(
90 doc =
"List of source flag fields that must be set for a source to be used.",
92 badFlags = pexConf.ListField(
94 default = [
"base_PixelFlags_flag_edge",
"base_PixelFlags_flag_interpolated",
95 "base_PixelFlags_flag_saturated"],
96 doc =
"List of source flag fields that will cause a source to be rejected when they are set.",
98 sigmaMax = pexConf.Field(
101 doc =
"maximum sigma to use when clipping",
104 nSigma = pexConf.Field(
107 doc =
"clip at nSigma",
109 useMedian = pexConf.Field(
112 doc =
"use median instead of mean to compute zeropoint",
114 nIter = pexConf.Field(
117 doc =
"number of iterations",
119 colorterms = pexConf.ConfigField(
120 dtype = ColortermLibrary,
121 doc =
"Library of photometric reference catalog name: color term dict",
123 photoCatName = pexConf.Field(
126 doc = (
"Name of photometric reference catalog; used to select a color term dict in colorterms."
127 " see also applyColorTerms"),
129 magErrFloor = pexConf.RangeField(
132 doc =
"Additional magnitude uncertainty to be added in quadrature with measurement errors.",
135 doSelectUnresolved = pexConf.Field(
138 doc = (
"Use the extendedness parameter to select objects to use in photometric calibration?\n"
139 "This applies only to the sources detected on the exposure, not the reference catalog"),
143 pexConf.Config.validate(self)
145 raise RuntimeError(
"applyColorTerms=True requires photoCatName is non-None")
147 raise RuntimeError(
"applyColorTerms=True requires colorterms be provided")
159 \anchor PhotoCalTask_
161 \brief Calculate the zero point of an exposure given a lsst.afw.table.ReferenceMatchVector.
163 \section pipe_tasks_photocal_Contents Contents
165 - \ref pipe_tasks_photocal_Purpose
166 - \ref pipe_tasks_photocal_Initialize
167 - \ref pipe_tasks_photocal_IO
168 - \ref pipe_tasks_photocal_Config
169 - \ref pipe_tasks_photocal_Debug
170 - \ref pipe_tasks_photocal_Example
172 \section pipe_tasks_photocal_Purpose Description
174 \copybrief PhotoCalTask
176 Calculate an Exposure's zero-point given a set of flux measurements of stars matched to an input catalogue.
177 The type of flux to use is specified by PhotoCalConfig.fluxField.
179 The algorithm clips outliers iteratively, with parameters set in the configuration.
181 \note This task can adds fields to the schema, so any code calling this task must ensure that
182 these columns are indeed present in the input match list; see \ref pipe_tasks_photocal_Example
184 \section pipe_tasks_photocal_Initialize Task initialisation
186 \copydoc \_\_init\_\_
188 \section pipe_tasks_photocal_IO Inputs/Outputs to the run method
192 \section pipe_tasks_photocal_Config Configuration parameters
194 See \ref PhotoCalConfig
196 \section pipe_tasks_photocal_Debug Debug variables
198 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
199 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py files.
201 The available variables in PhotoCalTask are:
204 <DD> If True enable other debug outputs
205 <DT> \c displaySources
206 <DD> If True, display the exposure on ds9's frame 1 and overlay the source catalogue:
211 <DD> Matched objects deemed unsuitable for photometric calibration.
212 Additional information is:
213 - a cyan o for galaxies
214 - a magenta o for variables
216 <DD> Objects that failed the flux cut
218 <DD> Objects used in the photometric calibration
221 <DD> Make a scatter plot of flux v. reference magnitude as a function of reference magnitude.
222 - good objects in blue
223 - rejected objects in red
224 (if \c scatterPlot is 2 or more, prompt to continue after each iteration)
227 \section pipe_tasks_photocal_Example A complete example of using PhotoCalTask
229 This code is in \link examples/photoCalTask.py\endlink, and can be run as \em e.g.
231 examples/photoCalTask.py
233 \dontinclude photoCalTask.py
235 Import the tasks (there are some other standard imports; read the file for details)
236 \skipline from lsst.pipe.tasks.astrometry
237 \skipline measPhotocal
239 We need to create both our tasks before processing any data as the task constructors
240 can add extra columns to the schema which we get from the input catalogue, \c scrCat:
244 \skip AstrometryTask.ConfigClass
246 (that \c filterMap line is because our test code doesn't use a filter that the reference catalogue recognises,
247 so we tell it to use the \c r band)
253 If the schema has indeed changed we need to add the new columns to the source table
254 (yes; this should be easier!)
258 We're now ready to process the data (we could loop over multiple exposures/catalogues using the same
263 We can then unpack and use the results:
268 To investigate the \ref pipe_tasks_photocal_Debug, put something like
272 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
273 if name.endswith(".PhotoCal"):
278 lsstDebug.Info = DebugInfo
280 into your debug.py file and run photoCalTask.py with the \c --debug flag.
282 ConfigClass = PhotoCalConfig
283 _DefaultName =
"photoCal"
286 """!Create the photometric calibration task. See PhotoCalTask.init for documentation
288 pipeBase.Task.__init__(self, **kwds)
291 if self.config.doWriteOutput:
292 self.
outputField = schema.addField(
"photocal_photometricStandard", type=
"Flag",
293 doc=
"set if source was used in photometric calibration")
298 """!Return a struct containing the source catalog keys for fields used by PhotoCalTask.
300 Returned fields include:
303 - goodFlags: a list of keys for field names in self.config.goodFlags
304 - badFlags: a list of keys for field names in self.config.badFlags
305 - starGal: key for star/galaxy classification
307 goodFlags = [schema.find(name).key
for name
in self.config.goodFlags]
308 flux = schema.find(self.config.fluxField).key
309 fluxErr = schema.find(self.config.fluxField +
"Sigma").key
310 badFlags = [schema.find(name).key
for name
in self.config.badFlags]
312 starGal = schema.find(
"base_ClassificationExtendedness_value").key
315 return pipeBase.Struct(flux=flux, fluxErr=fluxErr, goodFlags=goodFlags, badFlags=badFlags,
319 """!Return whether the provided source is unresolved or not
321 This particular implementation is designed to work with the
322 base_ClassificationExtendedness_value=0.0 or 1.0 scheme. Because
323 of the diversity of star/galaxy classification outputs (binary
324 decision vs probabilities; signs), it's difficult to make this
325 configurable without using code. This method should therefore
326 be overridden to use the appropriate classification output.
328 \param[in] source Source to test
329 \param[in] starGalKey Struct of schema keys for source
330 \return boolean value for starGalKey (True indicates Unresolved)
332 return source.get(starGalKey) < 0.5
if starGalKey
is not None else True
336 """!Select reference/source matches according the criteria specified in the config.
338 \param[in] matches ReferenceMatchVector (not modified)
339 \param[in] sourceKeys Struct of source catalog keys, as returned by getSourceKeys()
340 \param[in] filterName name of camera filter; used to obtain the reference flux field
341 \param[in] frame ds9 frame number to use for debugging display
342 if frame is non-None, display information about trimmed objects on that ds9 frame:
344 - Unsuitable objects: blue + (and a cyan o if a galaxy)
345 - Failed flux cut: magenta *
347 \return a \link lsst.afw.table.ReferenceMatchVector\endlink that contains only the selected matches.
348 If a schema was passed during task construction, a flag field will be set on sources
349 in the selected matches.
351 \throws ValueError There are no valid matches.
353 self.log.debug(
"Number of input matches: %d", len(matches))
355 if self.config.doSelectUnresolved:
357 matches = [m
for m
in matches
if self.
isUnresolved(m.second, sourceKeys.starGal)]
358 self.log.debug(
"Number of matches after culling resolved sources: %d", len(matches))
360 if len(matches) == 0:
361 raise ValueError(
"No input matches")
364 afterFlagCutInd = [i
for i, m
in enumerate(matches)
if checkSourceFlags(m.second, sourceKeys)]
365 afterFlagCut = [matches[i]
for i
in afterFlagCutInd]
366 self.log.debug(
"Number of matches after source flag cuts: %d", len(afterFlagCut))
368 if len(afterFlagCut) != len(matches):
369 if frame
is not None:
370 with ds9.Buffering():
371 for i, m
in enumerate(matches):
372 if i
not in afterFlagCutInd:
373 x, y = m.second.getCentroid()
374 ds9.dot(
"x", x, y, size=4, frame=frame, ctype=ds9.RED)
376 matches = afterFlagCut
378 if len(matches) == 0:
379 raise ValueError(
"All matches eliminated by source flags")
381 refSchema = matches[0].first.schema
383 photometricKey = refSchema.find(
"photometric").key
385 resolvedKey = refSchema.find(
"resolved").key
390 variableKey = refSchema.find(
"variable").key
394 self.log.warn(
"No 'photometric' flag key found in reference schema.")
395 photometricKey =
None
397 if photometricKey
is not None:
398 afterRefCutInd = [i
for i, m
in enumerate(matches)
if m.first.get(photometricKey)]
399 afterRefCut = [matches[i]
for i
in afterRefCutInd]
401 if len(afterRefCut) != len(matches):
402 if frame
is not None:
403 with ds9.Buffering():
404 for i, m
in enumerate(matches):
405 if i
not in afterRefCutInd:
406 x, y = m.second.getCentroid()
407 ds9.dot(
"+", x, y, size=4, frame=frame, ctype=ds9.BLUE)
409 if resolvedKey
and m.first.get(resolvedKey):
410 ds9.dot(
"o", x, y, size=6, frame=frame, ctype=ds9.CYAN)
411 if variableKey
and m.first.get(variableKey):
412 ds9.dot(
"o", x, y, size=6, frame=frame, ctype=ds9.MAGENTA)
414 matches = afterRefCut
416 self.log.debug(
"Number of matches after reference catalog cuts: %d", len(matches))
417 if len(matches) == 0:
418 raise RuntimeError(
"No sources remain in match list after reference catalog cuts.")
420 fluxKey = refSchema.find(fluxName).key
421 if self.config.magLimit
is not None:
424 afterMagCutInd = [i
for i, m
in enumerate(matches)
if (m.first.get(fluxKey) > fluxLimit
and
425 m.second.getPsfFlux() > 0.0)]
427 afterMagCutInd = [i
for i, m
in enumerate(matches)
if m.second.getPsfFlux() > 0.0]
429 afterMagCut = [matches[i]
for i
in afterMagCutInd]
431 if len(afterMagCut) != len(matches):
432 if frame
is not None:
433 with ds9.Buffering():
434 for i, m
in enumerate(matches):
435 if i
not in afterMagCutInd:
436 x, y = m.second.getCentroid()
437 ds9.dot(
"*", x, y, size=4, frame=frame, ctype=ds9.MAGENTA)
439 matches = afterMagCut
441 self.log.debug(
"Number of matches after magnitude limit cuts: %d", len(matches))
443 if len(matches) == 0:
444 raise RuntimeError(
"No sources remaining in match list after magnitude limit cuts.")
446 if frame
is not None:
447 with ds9.Buffering():
449 x, y = m.second.getCentroid()
450 ds9.dot(
"o", x, y, size=4, frame=frame, ctype=ds9.GREEN)
461 """!Extract magnitude and magnitude error arrays from the given matches.
463 \param[in] matches Reference/source matches, a \link lsst::afw::table::ReferenceMatchVector\endlink
464 \param[in] filterName Name of filter being calibrated
465 \param[in] sourceKeys Struct of source catalog keys, as returned by getSourceKeys()
467 \return Struct containing srcMag, refMag, srcMagErr, refMagErr, and magErr numpy arrays
468 where magErr is an error in the magnitude; the error in srcMag - refMag
469 If nonzero, config.magErrFloor will be added to magErr *only* (not srcMagErr or refMagErr), as
470 magErr is what is later used to determine the zero point.
471 Struct also contains refFluxFieldList: a list of field names of the reference catalog used for fluxes
473 \note These magnitude arrays are the \em inputs to the photometric calibration, some may have been
474 discarded by clipping while estimating the calibration (https://jira.lsstcorp.org/browse/DM-813)
476 srcFluxArr = np.array([m.second.get(sourceKeys.flux)
for m
in matches])
477 srcFluxErrArr = np.array([m.second.get(sourceKeys.fluxErr)
for m
in matches])
478 if not np.all(np.isfinite(srcFluxErrArr)):
480 self.log.warn(
"Source catalog does not have flux uncertainties; using sqrt(flux).")
481 srcFluxErrArr = np.sqrt(srcFluxArr)
484 JanskysPerABFlux = 3631.0
485 srcFluxArr = srcFluxArr * JanskysPerABFlux
486 srcFluxErrArr = srcFluxErrArr * JanskysPerABFlux
489 raise RuntimeError(
"No reference stars are available")
490 refSchema = matches[0].first.schema
492 applyColorTerms = self.config.applyColorTerms
493 applyCTReason =
"config.applyColorTerms is %s" % (self.config.applyColorTerms,)
494 if self.config.applyColorTerms
is None:
496 ctDataAvail = len(self.config.colorterms.data) > 0
497 photoCatSpecified = self.config.photoCatName
is not None
498 applyCTReason +=
" and data %s available" % (
"is" if ctDataAvail
else "is not")
499 applyCTReason +=
" and photoRefCat %s None" % (
"is not" if photoCatSpecified
else "is")
500 applyColorTerms = ctDataAvail
and photoCatSpecified
503 self.log.info(
"Applying color terms for filterName=%r, config.photoCatName=%s because %s",
504 filterName, self.config.photoCatName, applyCTReason)
505 ct = self.config.colorterms.getColorterm(
506 filterName=filterName, photoCatName=self.config.photoCatName, doRaise=
True)
508 self.log.info(
"Not applying color terms because %s", applyCTReason)
512 fluxFieldList = [
getRefFluxField(refSchema, filt)
for filt
in (ct.primary, ct.secondary)]
513 missingFluxFieldList = []
514 for fluxField
in fluxFieldList:
516 refSchema.find(fluxField).key
518 missingFluxFieldList.append(fluxField)
520 if missingFluxFieldList:
521 self.log.warn(
"Source catalog does not have fluxes for %s; ignoring color terms" %
522 " ".join(missingFluxFieldList))
529 refFluxErrArrList = []
530 for fluxField
in fluxFieldList:
531 fluxKey = refSchema.find(fluxField).key
532 refFluxArr = np.array([m.first.get(fluxKey)
for m
in matches])
534 fluxErrKey = refSchema.find(fluxField +
"Sigma").key
535 refFluxErrArr = np.array([m.first.get(fluxErrKey)
for m
in matches])
538 self.log.warn(
"Reference catalog does not have flux uncertainties for %s; using sqrt(flux).",
540 refFluxErrArr = np.sqrt(refFluxArr)
542 refFluxArrList.append(refFluxArr)
543 refFluxErrArrList.append(refFluxErrArr)
546 refMagArr1 = np.array([
abMagFromFlux(rf1)
for rf1
in refFluxArrList[0]])
547 refMagArr2 = np.array([
abMagFromFlux(rf2)
for rf2
in refFluxArrList[1]])
549 refMagArr = ct.transformMags(refMagArr1, refMagArr2)
550 refFluxErrArr = ct.propagateFluxErrors(refFluxErrArrList[0], refFluxErrArrList[1])
552 refMagArr = np.array([
abMagFromFlux(rf)
for rf
in refFluxArrList[0]])
554 srcMagArr = np.array([
abMagFromFlux(sf)
for sf
in srcFluxArr])
558 magErrArr = np.array([
abMagErrFromFluxErr(fe, sf)
for fe, sf
in izip(srcFluxErrArr, srcFluxArr)])
559 if self.config.magErrFloor != 0.0:
560 magErrArr = (magErrArr**2 + self.config.magErrFloor**2)**0.5
562 srcMagErrArr = np.array([
abMagErrFromFluxErr(sfe, sf)
for sfe, sf
in izip(srcFluxErrArr, srcFluxArr)])
563 refMagErrArr = np.array([
abMagErrFromFluxErr(rfe, rf)
for rfe, rf
in izip(refFluxErrArr, refFluxArr)])
565 return pipeBase.Struct(
569 srcMagErr = srcMagErrArr,
570 refMagErr = refMagErrArr,
571 refFluxFieldList = fluxFieldList,
575 def run(self, exposure, matches):
576 """!Do photometric calibration - select matches to use and (possibly iteratively) compute
579 \param[in] exposure Exposure upon which the sources in the matches were detected.
580 \param[in] matches Input lsst.afw.table.ReferenceMatchVector
581 (\em i.e. a list of lsst.afw.table.Match with
582 \c first being of type lsst.afw.table.SimpleRecord and \c second type lsst.afw.table.SourceRecord ---
583 the reference object and matched object respectively).
584 (will not be modified except to set the outputField if requested.).
587 - calib ------- \link lsst::afw::image::Calib\endlink object containing the zero point
588 - arrays ------ Magnitude arrays returned be PhotoCalTask.extractMagArrays
589 - matches ----- Final ReferenceMatchVector, as returned by PhotoCalTask.selectMatches.
590 - zp ---------- Photometric zero point (mag)
591 - sigma ------- Standard deviation of fit of photometric zero point (mag)
592 - ngood ------- Number of sources used to fit photometric zero point
594 The exposure is only used to provide the name of the filter being calibrated (it may also be
595 used to generate debugging plots).
597 The reference objects:
598 - Must include a field \c photometric; True for objects which should be considered as
599 photometric standards
600 - Must include a field \c flux; the flux used to impose a magnitude limit and also to calibrate
601 the data to (unless a color term is specified, in which case ColorTerm.primary is used;
602 See https://jira.lsstcorp.org/browse/DM-933)
603 - May include a field \c stargal; if present, True means that the object is a star
604 - May include a field \c var; if present, True means that the object is variable
606 The measured sources:
607 - Must include PhotoCalConfig.fluxField; the flux measurement to be used for calibration
609 \throws RuntimeError with the following strings:
612 <DT> `sources' schema does not contain the calibration object flag "XXX"`
613 <DD> The constructor added fields to the schema that aren't in the Sources
614 <DT> No input matches
615 <DD> The input match vector is empty
616 <DT> All matches eliminated by source flags
617 <DD> The flags specified by \c badFlags in the config eliminated all candidate objects
618 <DT> No sources remain in match list after reference catalog cuts
619 <DD> The reference catalogue has a column "photometric", but no matched objects have it set
620 <DT> No sources remaining in match list after magnitude limit cuts
621 <DD> All surviving matches are either too faint in the catalogue or have negative or \c NaN flux
622 <DT> No reference stars are available
623 <DD> No matches survive all the checks
629 displaySources = display
and lsstDebug.Info(__name__).displaySources
633 from matplotlib
import pyplot
637 self.
fig = pyplot.figure()
641 ds9.mtv(exposure, frame=frame, title=
"photocal")
645 filterName = exposure.getFilter().getName()
647 matches = self.
selectMatches(matches=matches, sourceKeys=sourceKeys, filterName=filterName,
649 arrays = self.
extractMagArrays(matches=matches, filterName=filterName, sourceKeys=sourceKeys)
655 matches[0].second.getSchema().find(self.
outputField)
657 raise RuntimeError(
"sources' schema does not contain the used-in-calibration flag \"%s\"" %
666 r = self.
getZeroPoint(arrays.srcMag, arrays.refMag, arrays.magErr, zp0=zp)
668 self.log.info(
"Magnitude zero point: %f +/- %f from %d stars", r.zp, r.sigma, r.ngood)
670 flux0 = 10**(0.4*r.zp)
671 flux0err = 0.4*math.log(10)*flux0*r.sigma
673 calib.setFluxMag0(flux0, flux0err)
675 return pipeBase.Struct(
685 """!Flux calibration code, returning (ZeroPoint, Distribution Width, Number of stars)
687 We perform nIter iterations of a simple sigma-clipping algorithm with a couple of twists:
688 1. We use the median/interquartile range to estimate the position to clip around, and the
690 2. We never allow sigma to go _above_ a critical value sigmaMax --- if we do, a sufficiently
691 large estimate will prevent the clipping from ever taking effect.
692 3. Rather than start with the median we start with a crude mode. This means that a set of magnitude
693 residuals with a tight core and asymmetrical outliers will start in the core. We use the width of
694 this core to set our maximum sigma (see 2.)
697 - zp ---------- Photometric zero point (mag)
698 - sigma ------- Standard deviation of fit of zero point (mag)
699 - ngood ------- Number of sources used to fit zero point
701 sigmaMax = self.config.sigmaMax
705 indArr = np.argsort(dmag)
708 if srcErr
is not None:
709 dmagErr = srcErr[indArr]
711 dmagErr = np.ones(len(dmag))
714 ind_noNan = np.array([i
for i
in range(len(dmag))
715 if (
not np.isnan(dmag[i])
and not np.isnan(dmagErr[i]))])
716 dmag = dmag[ind_noNan]
717 dmagErr = dmagErr[ind_noNan]
719 IQ_TO_STDEV = 0.741301109252802
724 for i
in range(self.config.nIter):
735 hist, edges = np.histogram(dmag, nhist, new=
True)
737 hist, edges = np.histogram(dmag, nhist)
738 imode = np.arange(nhist)[np.where(hist == hist.max())]
740 if imode[-1] - imode[0] + 1 == len(imode):
744 center = 0.5*(edges[imode[0]] + edges[imode[-1] + 1])
746 peak = sum(hist[imode])/len(imode)
750 while j >= 0
and hist[j] > 0.5*peak:
753 q1 = dmag[sum(hist[range(j)])]
756 while j < nhist
and hist[j] > 0.5*peak:
758 j = min(j, nhist - 1)
759 j = min(sum(hist[range(j)]), npt - 1)
763 q1 = dmag[int(0.25*npt)]
764 q3 = dmag[int(0.75*npt)]
771 self.log.debug(
"Photo calibration histogram: center = %.2f, sig = %.2f",
776 sigmaMax = dmag[-1] - dmag[0]
778 center = np.median(dmag)
779 q1 = dmag[int(0.25*npt)]
780 q3 = dmag[int(0.75*npt)]
785 if self.config.useMedian:
786 center = np.median(gdmag)
788 gdmagErr = dmagErr[good]
789 center = np.average(gdmag, weights=gdmagErr)
791 q3 = gdmag[min(int(0.75*npt + 0.5), npt - 1)]
792 q1 = gdmag[min(int(0.25*npt + 0.5), npt - 1)]
794 sig = IQ_TO_STDEV*(q3 - q1)
796 good = abs(dmag - center) < self.config.nSigma*min(sig, sigmaMax)
803 axes = self.fig.add_axes((0.1, 0.1, 0.85, 0.80))
805 axes.plot(ref[good], dmag[good] - center,
"b+")
806 axes.errorbar(ref[good], dmag[good] - center, yerr=dmagErr[good],
807 linestyle=
'', color=
'b')
809 bad = np.logical_not(good)
810 if len(ref[bad]) > 0:
811 axes.plot(ref[bad], dmag[bad] - center,
"r+")
812 axes.errorbar(ref[bad], dmag[bad] - center, yerr=dmagErr[bad],
813 linestyle=
'', color=
'r')
815 axes.plot((-100, 100), (0, 0), "g-")
817 axes.plot((-100, 100), x*0.05*np.ones(2),
"g--")
819 axes.set_ylim(-1.1, 1.1)
820 axes.set_xlim(24, 13)
821 axes.set_xlabel(
"Reference")
822 axes.set_ylabel(
"Reference - Instrumental")
828 while i == 0
or reply !=
"c":
830 reply = raw_input(
"Next iteration? [ynhpc] ")
835 print >> sys.stderr,
"Options: c[ontinue] h[elp] n[o] p[db] y[es]"
838 if reply
in (
"",
"c",
"n",
"p",
"y"):
841 print >> sys.stderr,
"Unrecognised response: %s" % reply
849 print >> sys.stderr,
"Error plotting in PhotoCal.getZeroPoint: %s" % e
856 msg =
"PhotoCal.getZeroPoint: no good stars remain"
859 center = np.average(dmag, weights=dmagErr)
860 msg +=
" on first iteration; using average of all calibration stars"
862 self.log.log(self.log.WARN, msg)
864 return pipeBase.Struct(
868 elif ngood == old_ngood:
874 dmagErr = dmagErr[good]
877 dmagErr = dmagErr[good]
878 zp, weightSum = np.average(dmag, weights=1/dmagErr**2, returned=
True)
879 sigma = np.sqrt(1.0/weightSum)
880 return pipeBase.Struct(
double abMagErrFromFluxErr(double fluxErr, double flux)
Compute AB magnitude error from flux and flux error in Janskys.
Calculate the zero point of an exposure given a lsst.afw.table.ReferenceMatchVector.
std::vector< ReferenceMatch > ReferenceMatchVector
def checkSourceFlags
Return True if the given source has all good flags set and none of the bad flags set.
double abMagFromFlux(double flux)
Compute AB magnitude from flux in Janskys.
double fluxFromABMag(double mag)
Compute flux in Janskys from AB magnitude.
def isUnresolved
Return whether the provided source is unresolved or not.
def run
Do photometric calibration - select matches to use and (possibly iteratively) compute the zero point...
def extractMagArrays
Extract magnitude and magnitude error arrays from the given matches.
def getRefFluxField
Get name of flux field in schema.
def __init__
Create the photometric calibration task.
def getZeroPoint
Flux calibration code, returning (ZeroPoint, Distribution Width, Number of stars) ...
def getSourceKeys
Return a struct containing the source catalog keys for fields used by PhotoCalTask.
def selectMatches
Select reference/source matches according the criteria specified in the config.