13 from lsst.verify
import Job, Measurement
18 from .dataIds
import PerTractCcdDataIdContainer
23 __all__ = [
"JointcalConfig",
"JointcalRunner",
"JointcalTask"]
25 Photometry = collections.namedtuple(
'Photometry', (
'fit',
'model'))
26 Astrometry = collections.namedtuple(
'Astrometry', (
'fit',
'model',
'sky_to_tan_projection'))
31 meas = Measurement(job.metrics[name], value)
32 job.measurements.insert(meas)
36 """Subclass of TaskRunner for jointcalTask 38 jointcalTask.runDataRef() takes a number of arguments, one of which is a list of dataRefs 39 extracted from the command line (whereas most CmdLineTasks' runDataRef methods take 40 single dataRef, are are called repeatedly). This class transforms the processed 41 arguments generated by the ArgumentParser into the arguments expected by 42 Jointcal.runDataRef(). 44 See pipeBase.TaskRunner for more information. 50 Return a list of tuples per tract, each containing (dataRefs, kwargs). 52 Jointcal operates on lists of dataRefs simultaneously. 54 kwargs[
'profile_jointcal'] = parsedCmd.profile_jointcal
55 kwargs[
'butler'] = parsedCmd.butler
59 for ref
in parsedCmd.id.refList:
60 refListDict.setdefault(ref.dataId[
"tract"], []).append(ref)
62 result = [(refListDict[tract], kwargs)
for tract
in sorted(refListDict.keys())]
70 Arguments for Task.runDataRef() 75 if self.doReturnResults is False: 77 - ``exitStatus``: 0 if the task completed successfully, 1 otherwise. 79 if self.doReturnResults is True: 81 - ``result``: the result of calling jointcal.runDataRef() 82 - ``exitStatus``: 0 if the task completed successfully, 1 otherwise. 87 dataRefList, kwargs = args
88 butler = kwargs.pop(
'butler')
89 task = self.TaskClass(config=self.config, log=self.log, butler=butler)
92 result = task.runDataRef(dataRefList, **kwargs)
93 exitStatus = result.exitStatus
94 job_path = butler.get(
'verify_job_filename')
95 result.job.write(job_path[0])
96 except Exception
as e:
101 eName = type(e).__name__
102 tract = dataRefList[0].dataId[
'tract']
103 task.log.fatal(
"Failed processing tract %s, %s: %s", tract, eName, e)
105 if self.doReturnResults:
106 return pipeBase.Struct(result=result, exitStatus=exitStatus)
108 return pipeBase.Struct(exitStatus=exitStatus)
112 """Config for JointcalTask""" 114 doAstrometry = pexConfig.Field(
115 doc=
"Fit astrometry and write the fitted result.",
119 doPhotometry = pexConfig.Field(
120 doc=
"Fit photometry and write the fitted result.",
124 coaddName = pexConfig.Field(
125 doc=
"Type of coadd, typically deep or goodSeeing",
129 positionErrorPedestal = pexConfig.Field(
130 doc=
"Systematic term to apply to the measured position error (pixels)",
134 photometryErrorPedestal = pexConfig.Field(
135 doc=
"Systematic term to apply to the measured error on flux or magnitude as a " 136 "fraction of source flux or magnitude delta (e.g. 0.05 is 5\% of flux or +50 millimag).",
141 matchCut = pexConfig.Field(
142 doc=
"Matching radius between fitted and reference stars (arcseconds)",
146 minMeasurements = pexConfig.Field(
147 doc=
"Minimum number of associated measured stars for a fitted star to be included in the fit",
151 minMeasuredStarsPerCcd = pexConfig.Field(
152 doc=
"Minimum number of measuredStars per ccdImage before printing warnings",
156 minRefStarsPerCcd = pexConfig.Field(
157 doc=
"Minimum number of measuredStars per ccdImage before printing warnings",
161 allowLineSearch = pexConfig.Field(
162 doc=
"Allow a line search during minimization, if it is reasonable for the model" 163 " (models with a significant non-linear component, e.g. constrainedPhotometry).",
167 astrometrySimpleOrder = pexConfig.Field(
168 doc=
"Polynomial order for fitting the simple astrometry model.",
172 astrometryChipOrder = pexConfig.Field(
173 doc=
"Order of the per-chip transform for the constrained astrometry model.",
177 astrometryVisitOrder = pexConfig.Field(
178 doc=
"Order of the per-visit transform for the constrained astrometry model.",
182 useInputWcs = pexConfig.Field(
183 doc=
"Use the input calexp WCSs to initialize a SimpleAstrometryModel.",
187 astrometryModel = pexConfig.ChoiceField(
188 doc=
"Type of model to fit to astrometry",
190 default=
"constrained",
191 allowed={
"simple":
"One polynomial per ccd",
192 "constrained":
"One polynomial per ccd, and one polynomial per visit"}
194 photometryModel = pexConfig.ChoiceField(
195 doc=
"Type of model to fit to photometry",
197 default=
"constrainedMagnitude",
198 allowed={
"simpleFlux":
"One constant zeropoint per ccd and visit, fitting in flux space.",
199 "constrainedFlux":
"Constrained zeropoint per ccd, and one polynomial per visit," 200 " fitting in flux space.",
201 "simpleMagnitude":
"One constant zeropoint per ccd and visit," 202 " fitting in magnitude space.",
203 "constrainedMagnitude":
"Constrained zeropoint per ccd, and one polynomial per visit," 204 " fitting in magnitude space.",
207 photometryVisitOrder = pexConfig.Field(
208 doc=
"Order of the per-visit polynomial transform for the constrained photometry model.",
212 photometryDoRankUpdate = pexConfig.Field(
213 doc=
"Do the rank update step during minimization. " 214 "Skipping this can help deal with models that are too non-linear.",
218 astrometryDoRankUpdate = pexConfig.Field(
219 doc=
"Do the rank update step during minimization (should not change the astrometry fit). " 220 "Skipping this can help deal with models that are too non-linear.",
224 outlierRejectSigma = pexConfig.Field(
225 doc=
"How many sigma to reject outliers at during minimization.",
229 maxPhotometrySteps = pexConfig.Field(
230 doc=
"Maximum number of minimize iterations to take when fitting photometry.",
234 maxAstrometrySteps = pexConfig.Field(
235 doc=
"Maximum number of minimize iterations to take when fitting photometry.",
239 astrometryRefObjLoader = pexConfig.ConfigurableField(
240 target=LoadIndexedReferenceObjectsTask,
241 doc=
"Reference object loader for astrometric fit",
243 photometryRefObjLoader = pexConfig.ConfigurableField(
244 target=LoadIndexedReferenceObjectsTask,
245 doc=
"Reference object loader for photometric fit",
247 sourceSelector = sourceSelectorRegistry.makeField(
248 doc=
"How to select sources for cross-matching",
251 writeInitMatrix = pexConfig.Field(
253 doc=
"Write the pre/post-initialization Hessian and gradient to text files, for debugging." 254 "The output files will be of the form 'astrometry_preinit-mat.txt', in the current directory." 255 "Note that these files are the dense versions of the matrix, and so may be very large.",
258 writeChi2ContributionFiles = pexConfig.Field(
260 doc=
"Write initial/final fit files containing the contributions to chi2.",
263 sourceFluxType = pexConfig.Field(
265 doc=
"Source flux field to use in source selection and to get fluxes from the catalog.",
271 sourceSelector.setDefaults()
273 sourceSelector.badFlags.extend([
"slot_Shape_flag"])
279 """Jointly astrometrically and photometrically calibrate a group of images.""" 281 ConfigClass = JointcalConfig
282 RunnerClass = JointcalRunner
283 _DefaultName =
"jointcal" 285 def __init__(self, butler=None, profile_jointcal=False, **kwargs):
287 Instantiate a JointcalTask. 291 butler : lsst.daf.persistence.Butler 292 The butler is passed to the refObjLoader constructor in case it is 293 needed. Ignored if the refObjLoader argument provides a loader directly. 294 Used to initialize the astrometry and photometry refObjLoaders. 295 profile_jointcal : bool 296 set to True to profile different stages of this jointcal run. 298 pipeBase.CmdLineTask.__init__(self, **kwargs)
300 self.makeSubtask(
"sourceSelector")
301 if self.config.doAstrometry:
302 self.makeSubtask(
'astrometryRefObjLoader', butler=butler)
303 if self.config.doPhotometry:
304 self.makeSubtask(
'photometryRefObjLoader', butler=butler)
307 self.
job = Job.load_metrics_package(subset=
'jointcal')
311 def _getConfigName(self):
314 def _getMetadataName(self):
318 def _makeArgumentParser(cls):
319 """Create an argument parser""" 321 parser.add_argument(
"--profile_jointcal", default=
False, action=
"store_true",
322 help=
"Profile steps of jointcal separately.")
323 parser.add_id_argument(
"--id",
"calexp", help=
"data ID, e.g. --id visit=6789 ccd=0..9",
324 ContainerClass=PerTractCcdDataIdContainer)
327 def _build_ccdImage(self, dataRef, associations, jointcalControl):
329 Extract the necessary things from this dataRef to add a new ccdImage. 333 dataRef : lsst.daf.persistence.ButlerDataRef 334 dataRef to extract info from. 335 associations : lsst.jointcal.Associations 336 object to add the info to, to construct a new CcdImage 337 jointcalControl : jointcal.JointcalControl 338 control object for associations management 343 wcs : lsst.afw.geom.SkyWcs 344 the TAN WCS of this image, read from the calexp 346 a key to identify this dataRef by its visit and ccd ids 350 if "visit" in dataRef.dataId.keys():
351 visit = dataRef.dataId[
"visit"]
353 visit = dataRef.getButler().queryMetadata(
"calexp", (
"visit"), dataRef.dataId)[0]
355 src = dataRef.get(
"src", flags=lsst.afw.table.SOURCE_IO_NO_FOOTPRINTS, immediate=
True)
357 visitInfo = dataRef.get(
'calexp_visitInfo')
358 detector = dataRef.get(
'calexp_detector')
359 ccdId = detector.getId()
360 calib = dataRef.get(
'calexp_calib')
361 tanWcs = dataRef.get(
'calexp_wcs')
362 bbox = dataRef.get(
'calexp_bbox')
363 filt = dataRef.get(
'calexp_filter')
364 filterName = filt.getName()
365 fluxMag0 = calib.getFluxMag0()
366 photoCalib = afwImage.PhotoCalib(1.0/fluxMag0[0], fluxMag0[1]/fluxMag0[0]**2, bbox)
368 goodSrc = self.sourceSelector.run(src)
370 if len(goodSrc.sourceCat) == 0:
371 self.log.warn(
"No sources selected in visit %s ccd %s", visit, ccdId)
373 self.log.info(
"%d sources selected in visit %d ccd %d", len(goodSrc.sourceCat), visit, ccdId)
374 associations.createCcdImage(goodSrc.sourceCat,
385 Result = collections.namedtuple(
'Result_from_build_CcdImage', (
'wcs',
'key',
'filter'))
386 Key = collections.namedtuple(
'Key', (
'visit',
'ccd'))
387 return Result(tanWcs, Key(visit, ccdId), filterName)
392 Jointly calibrate the astrometry and photometry across a set of images. 396 dataRefs : list of lsst.daf.persistence.ButlerDataRef 397 List of data references to the exposures to be fit. 398 profile_jointcal : bool 399 Profile the individual steps of jointcal. 405 * dataRefs: the provided data references that were fit (with updated WCSs) 406 * oldWcsList: the original WCS from each dataRef 407 * metrics: dictionary of internally-computed metrics for testing/validation. 409 if len(dataRefs) == 0:
410 raise ValueError(
'Need a non-empty list of data references!')
414 sourceFluxField =
"slot_%sFlux" % (self.config.sourceFluxType,)
418 visit_ccd_to_dataRef = {}
421 load_cat_prof_file =
'jointcal_build_ccdImage.prof' if profile_jointcal
else '' 422 with pipeBase.cmdLineTask.profile(load_cat_prof_file):
425 camera = dataRefs[0].get(
'camera', immediate=
True)
429 oldWcsList.append(result.wcs)
430 visit_ccd_to_dataRef[result.key] = ref
431 filters.append(result.filter)
432 filters = collections.Counter(filters)
434 associations.computeCommonTangentPoint()
439 bbox = associations.getRaDecBBox()
441 bboxCenter = bbox.getCenter()
442 center = afwGeom.SpherePoint(bboxCenter[0], bboxCenter[1], afwGeom.degrees)
443 bboxMax = bbox.getMax()
444 corner = afwGeom.SpherePoint(bboxMax[0], bboxMax[1], afwGeom.degrees)
445 radius = center.separation(corner).asRadians()
450 raise RuntimeError(
"astrometry_net_data is not setup")
453 defaultFilter = filters.most_common(1)[0][0]
454 self.log.debug(
"Using %s band for reference flux", defaultFilter)
457 tract = dataRefs[0].dataId[
'tract']
459 if self.config.doAstrometry:
462 refObjLoader=self.astrometryRefObjLoader,
464 profile_jointcal=profile_jointcal,
470 if self.config.doPhotometry:
473 refObjLoader=self.photometryRefObjLoader,
475 profile_jointcal=profile_jointcal,
478 reject_bad_fluxes=
True)
483 return pipeBase.Struct(dataRefs=dataRefs,
484 oldWcsList=oldWcsList,
486 exitStatus=exitStatus)
488 def _do_load_refcat_and_fit(self, associations, defaultFilter, center, radius,
489 name="", refObjLoader=None, filters=[], fit_function=None,
490 tract=None, profile_jointcal=False, match_cut=3.0,
491 reject_bad_fluxes=False):
492 """Load reference catalog, perform the fit, and return the result. 496 associations : lsst.jointcal.Associations 497 The star/reference star associations to fit. 499 filter to load from reference catalog. 500 center : lsst.afw.geom.SpherePoint 501 ICRS center of field to load from reference catalog. 502 radius : lsst.afw.geom.Angle 503 On-sky radius to load from reference catalog. 505 Name of thing being fit: "Astrometry" or "Photometry". 506 refObjLoader : lsst.meas.algorithms.LoadReferenceObjectsTask 507 Reference object loader to load from for fit. 508 filters : list of str, optional 509 List of filters to load from the reference catalog. 510 fit_function : function 511 function to call to perform fit (takes associations object). 513 Name of tract currently being fit. 514 profile_jointcal : bool, optional 515 Separately profile the fitting step. 516 match_cut : float, optional 517 Radius in arcseconds to find cross-catalog matches to during 518 associations.associateCatalogs. 519 reject_bad_fluxes : bool, optional 520 Reject refCat sources with NaN/inf flux or NaN/0 fluxErr. 524 Result of `fit_function()` 526 self.log.info(
"====== Now processing %s...", name)
529 associations.associateCatalogs(match_cut)
531 associations.fittedStarListSize())
533 skyCircle = refObjLoader.loadSkyCircle(center,
534 afwGeom.Angle(radius, afwGeom.radians),
538 if not skyCircle.refCat.isContiguous():
539 refCat = skyCircle.refCat.copy(deep=
True)
541 refCat = skyCircle.refCat
548 filtKeys = lsst.meas.algorithms.getRefFluxKeys(refCat.schema, filt)
549 refFluxes[filt] = refCat.get(filtKeys[0])
550 refFluxErrs[filt] = refCat.get(filtKeys[1])
552 associations.collectRefStars(refCat, self.config.matchCut*afwGeom.arcseconds,
553 skyCircle.fluxField, refFluxes, refFluxErrs, reject_bad_fluxes)
555 associations.refStarListSize())
557 associations.prepareFittedStars(self.config.minMeasurements)
561 associations.nFittedStarsWithAssociatedRefStar())
563 associations.fittedStarListSize())
565 associations.nCcdImagesValidForFit())
567 load_cat_prof_file =
'jointcal_fit_%s.prof'%name
if profile_jointcal
else '' 568 dataName =
"{}_{}".format(tract, defaultFilter)
569 with pipeBase.cmdLineTask.profile(load_cat_prof_file):
570 result = fit_function(associations, dataName)
573 if self.config.writeChi2ContributionFiles:
574 baseName =
"{}_final_chi2-{}.csv".format(name, dataName)
575 result.fit.saveChi2Contributions(baseName)
579 def _check_star_lists(self, associations, name):
581 if associations.nCcdImagesValidForFit() == 0:
582 raise RuntimeError(
'No images in the ccdImageList!')
583 if associations.fittedStarListSize() == 0:
584 raise RuntimeError(
'No stars in the {} fittedStarList!'.format(name))
585 if associations.refStarListSize() == 0:
586 raise RuntimeError(
'No stars in the {} reference star list!'.format(name))
588 def _fit_photometry(self, associations, dataName=None):
590 Fit the photometric data. 594 associations : lsst.jointcal.Associations 595 The star/reference star associations to fit. 597 Name of the data being processed (e.g. "1234_HSC-Y"), for 598 identifying debugging files. 603 fit : lsst.jointcal.PhotometryFit 604 The photometric fitter used to perform the fit. 605 model : lsst.jointcal.PhotometryModel 606 The photometric model that was fit. 608 self.log.info(
"=== Starting photometric fitting...")
611 if self.config.photometryModel ==
"constrainedFlux":
614 visitOrder=self.config.photometryVisitOrder,
615 errorPedestal=self.config.photometryErrorPedestal)
617 doLineSearch = self.config.allowLineSearch
618 elif self.config.photometryModel ==
"constrainedMagnitude":
621 visitOrder=self.config.photometryVisitOrder,
622 errorPedestal=self.config.photometryErrorPedestal)
624 doLineSearch = self.config.allowLineSearch
625 elif self.config.photometryModel ==
"simpleFlux":
627 errorPedestal=self.config.photometryErrorPedestal)
629 elif self.config.photometryModel ==
"simpleMagnitude":
631 errorPedestal=self.config.photometryErrorPedestal)
635 chi2 = fit.computeChi2()
638 if self.config.writeChi2ContributionFiles:
639 baseName =
"photometry_initial_chi2-{}.csv".format(dataName)
640 fit.saveChi2Contributions(baseName)
642 if not np.isfinite(chi2.chi2):
643 raise FloatingPointError(
'Initial chi2 is invalid: %s'%chi2)
644 self.log.info(
"Initialized: %s", str(chi2))
647 dumpMatrixFile =
"photometry_preinit" if self.config.writeInitMatrix
else "" 648 if self.config.photometryModel.startswith(
"constrained"):
651 fit.minimize(
"ModelVisit", dumpMatrixFile=dumpMatrixFile)
652 chi2 = fit.computeChi2()
653 self.log.info(str(chi2))
655 fit.minimize(
"Model", doLineSearch=doLineSearch, dumpMatrixFile=dumpMatrixFile)
656 chi2 = fit.computeChi2()
657 self.log.info(str(chi2))
658 fit.minimize(
"Fluxes")
659 chi2 = fit.computeChi2()
660 self.log.info(str(chi2))
661 fit.minimize(
"Model Fluxes", doLineSearch=doLineSearch)
662 chi2 = fit.computeChi2()
663 if not np.isfinite(chi2.chi2):
664 raise FloatingPointError(
'Pre-iteration chi2 is invalid: %s'%chi2)
665 self.log.info(
"Fit prepared with %s", str(chi2))
667 model.freezeErrorTransform()
668 self.log.debug(
"Photometry error scales are frozen.")
672 self.config.maxPhotometrySteps,
675 doRankUpdate=self.config.photometryDoRankUpdate,
676 doLineSearch=doLineSearch,
683 def _fit_astrometry(self, associations, dataName=None):
685 Fit the astrometric data. 689 associations : lsst.jointcal.Associations 690 The star/reference star associations to fit. 692 Name of the data being processed (e.g. "1234_HSC-Y"), for 693 identifying debugging files. 698 fit : lsst.jointcal.AstrometryFit 699 The astrometric fitter used to perform the fit. 700 model : lsst.jointcal.AstrometryModel 701 The astrometric model that was fit. 702 sky_to_tan_projection : lsst.jointcal.ProjectionHandler 703 The model for the sky to tangent plane projection that was used in the fit. 706 self.log.info(
"=== Starting astrometric fitting...")
708 associations.deprojectFittedStars()
715 if self.config.astrometryModel ==
"constrained":
717 sky_to_tan_projection,
718 chipOrder=self.config.astrometryChipOrder,
719 visitOrder=self.config.astrometryVisitOrder)
720 elif self.config.astrometryModel ==
"simple":
722 sky_to_tan_projection,
723 self.config.useInputWcs,
725 order=self.config.astrometrySimpleOrder)
728 chi2 = fit.computeChi2()
731 if self.config.writeChi2ContributionFiles:
732 baseName =
"astrometry_initial_chi2-{}.csv".format(dataName)
733 fit.saveChi2Contributions(baseName)
735 if not np.isfinite(chi2.chi2):
736 raise FloatingPointError(
'Initial chi2 is invalid: %s'%chi2)
737 self.log.info(
"Initialized: %s", str(chi2))
738 dumpMatrixFile =
"astrometry_preinit" if self.config.writeInitMatrix
else "" 741 if self.config.astrometryModel ==
"constrained":
742 fit.minimize(
"DistortionsVisit", dumpMatrixFile=dumpMatrixFile)
743 chi2 = fit.computeChi2()
744 self.log.info(str(chi2))
746 fit.minimize(
"Distortions", dumpMatrixFile=dumpMatrixFile)
747 chi2 = fit.computeChi2()
748 self.log.info(str(chi2))
749 fit.minimize(
"Positions")
750 chi2 = fit.computeChi2()
751 self.log.info(str(chi2))
752 fit.minimize(
"Distortions Positions")
753 chi2 = fit.computeChi2()
754 self.log.info(str(chi2))
755 if not np.isfinite(chi2.chi2):
756 raise FloatingPointError(
'Pre-iteration chi2 is invalid: %s'%chi2)
757 self.log.info(
"Fit prepared with %s", str(chi2))
761 self.config.maxAstrometrySteps,
763 "Distortions Positions",
764 doRankUpdate=self.config.astrometryDoRankUpdate,
770 return Astrometry(fit, model, sky_to_tan_projection)
772 def _check_stars(self, associations):
773 """Count measured and reference stars per ccd and warn/log them.""" 774 for ccdImage
in associations.getCcdImageList():
775 nMeasuredStars, nRefStars = ccdImage.countStars()
776 self.log.debug(
"ccdImage %s has %s measured and %s reference stars",
777 ccdImage.getName(), nMeasuredStars, nRefStars)
778 if nMeasuredStars < self.config.minMeasuredStarsPerCcd:
779 self.log.warn(
"ccdImage %s has only %s measuredStars (desired %s)",
780 ccdImage.getName(), nMeasuredStars, self.config.minMeasuredStarsPerCcd)
781 if nRefStars < self.config.minRefStarsPerCcd:
782 self.log.warn(
"ccdImage %s has only %s RefStars (desired %s)",
783 ccdImage.getName(), nRefStars, self.config.minRefStarsPerCcd)
785 def _iterate_fit(self, associations, fitter, max_steps, name, whatToFit,
789 """Run fitter.minimize up to max_steps times, returning the final chi2. 793 associations : `lsst.jointcal.Associations` 794 The star/reference star associations to fit. 795 fitter : `lsst.jointcal.FitterBase` 796 The fitter to use for minimization. 798 Maximum number of steps to run outlier rejection before declaring 800 name : {'photometry' or 'astrometry'} 801 What type of data are we fitting (for logs and debugging files). 803 Passed to ``fitter.minimize()`` to define the parameters to fit. 804 dataName : str, optional 805 Descriptive name for this dataset (e.g. tract and filter), 807 doRankUpdate : bool, optional 808 Do an Eigen rank update during minimization, or recompute the full 810 doLineSearch : bool, optional 811 Do a line search for the optimum step during minimization? 815 chi2: `lsst.jointcal.Chi2Statistic` 816 The final chi2 after the fit converges, or is forced to end. 821 Raised if the fitter fails with a non-finite value. 823 Raised if the fitter fails for some other reason; 824 log messages will provide further details. 826 dumpMatrixFile =
"%s_postinit" % name
if self.config.writeInitMatrix
else "" 827 for i
in range(max_steps):
828 result = fitter.minimize(whatToFit,
829 self.config.outlierRejectSigma,
830 doRankUpdate=doRankUpdate,
831 doLineSearch=doLineSearch,
832 dumpMatrixFile=dumpMatrixFile)
834 chi2 = fitter.computeChi2()
836 self.log.info(str(chi2))
837 if result == MinimizeResult.Converged:
839 self.log.debug(
"fit has converged - no more outliers - redo minimization " 840 "one more time in case we have lost accuracy in rank update.")
842 result = fitter.minimize(whatToFit, self.config.outlierRejectSigma)
843 chi2 = fitter.computeChi2()
844 self.log.info(
"Fit completed with: %s", str(chi2))
847 if chi2.chi2/chi2.ndof >= 4.0:
848 self.log.error(
"Potentially bad fit: High chi-squared/ndof.")
851 elif result == MinimizeResult.Chi2Increased:
852 self.log.warn(
"still some outliers but chi2 increases - retry")
853 elif result == MinimizeResult.NonFinite:
854 filename =
"{}_failure-nonfinite_chi2-{}.csv".format(name, dataName)
856 fitter.saveChi2Contributions(filename)
857 msg =
"Nonfinite value in chi2 minimization, cannot complete fit. Dumped star tables to: {}" 858 raise FloatingPointError(msg.format(filename))
859 elif result == MinimizeResult.Failed:
860 raise RuntimeError(
"Chi2 minimization failure, cannot complete fit.")
862 raise RuntimeError(
"Unxepected return code from minimize().")
864 self.log.error(
"%s failed to converge after %d steps"%(name, max_steps))
868 def _write_astrometry_results(self, associations, model, visit_ccd_to_dataRef):
870 Write the fitted astrometric results to a new 'jointcal_wcs' dataRef. 874 associations : lsst.jointcal.Associations 875 The star/reference star associations to fit. 876 model : lsst.jointcal.AstrometryModel 877 The astrometric model that was fit. 878 visit_ccd_to_dataRef : dict of Key: lsst.daf.persistence.ButlerDataRef 879 dict of ccdImage identifiers to dataRefs that were fit 882 ccdImageList = associations.getCcdImageList()
883 for ccdImage
in ccdImageList:
886 visit = ccdImage.visit
887 dataRef = visit_ccd_to_dataRef[(visit, ccd)]
888 self.log.info(
"Updating WCS for visit: %d, ccd: %d", visit, ccd)
889 skyWcs = model.makeSkyWcs(ccdImage)
891 dataRef.put(skyWcs,
'jointcal_wcs')
892 except pexExceptions.Exception
as e:
893 self.log.fatal(
'Failed to write updated Wcs: %s', str(e))
896 def _write_photometry_results(self, associations, model, visit_ccd_to_dataRef):
898 Write the fitted photometric results to a new 'jointcal_photoCalib' dataRef. 902 associations : lsst.jointcal.Associations 903 The star/reference star associations to fit. 904 model : lsst.jointcal.PhotometryModel 905 The photoometric model that was fit. 906 visit_ccd_to_dataRef : dict of Key: lsst.daf.persistence.ButlerDataRef 907 dict of ccdImage identifiers to dataRefs that were fit 910 ccdImageList = associations.getCcdImageList()
911 for ccdImage
in ccdImageList:
914 visit = ccdImage.visit
915 dataRef = visit_ccd_to_dataRef[(visit, ccd)]
916 self.log.info(
"Updating PhotoCalib for visit: %d, ccd: %d", visit, ccd)
917 photoCalib = model.toPhotoCalib(ccdImage)
919 dataRef.put(photoCalib,
'jointcal_photoCalib')
920 except pexExceptions.Exception
as e:
921 self.log.fatal(
'Failed to write updated PhotoCalib: %s', str(e))
def runDataRef(self, dataRefs, profile_jointcal=False)
def _build_ccdImage(self, dataRef, associations, jointcalControl)
def _fit_photometry(self, associations, dataName=None)
def getTargetList(parsedCmd, kwargs)
def _fit_astrometry(self, associations, dataName=None)
def _check_star_lists(self, associations, name)
The class that implements the relations between MeasuredStar and FittedStar.
A projection handler in which all CCDs from the same visit have the same tangent point.
std::string getPackageDir(std::string const &packageName)
this is the model used to fit independent CCDs, meaning that there is no instrument model...
def _iterate_fit(self, associations, fitter, max_steps, name, whatToFit, dataName="", doRankUpdate=True, doLineSearch=False)
def _write_photometry_results(self, associations, model, visit_ccd_to_dataRef)
def _check_stars(self, associations)
Class that handles the photometric least squares problem.
Class that handles the astrometric least squares problem.
def add_measurement(job, name, value)
def _do_load_refcat_and_fit(self, associations, defaultFilter, center, radius, name="", refObjLoader=None, filters=[], fit_function=None, tract=None, profile_jointcal=False, match_cut=3.0, reject_bad_fluxes=False)
This is the model used to fit mappings as the combination of a transformation depending on the chip n...
def _write_astrometry_results(self, associations, model, visit_ccd_to_dataRef)
def __init__(self, butler=None, profile_jointcal=False, kwargs)