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
fgcmCalibrateTractBase.py
Go to the documentation of this file.
1 # This file is part of fgcmcal.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (https://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 """Base class for running fgcmcal on a single tract using src tables
22 or sourceTable_visit tables.
23 """
24 
25 import sys
26 import traceback
27 import abc
28 
29 import numpy as np
30 
31 import lsst.daf.persistence as dafPersist
32 import lsst.pex.config as pexConfig
33 import lsst.pipe.base as pipeBase
34 from lsst.utils.timer import timeMethod
35 
36 from .fgcmBuildStars import FgcmBuildStarsTask, FgcmBuildStarsConfig
37 from .fgcmFitCycle import FgcmFitCycleConfig
38 from .fgcmOutputProducts import FgcmOutputProductsTask
39 from .utilities import makeConfigDict, translateFgcmLut, translateVisitCatalog
40 from .utilities import computeApertureRadiusFromDataRef, extractReferenceMags
41 from .utilities import makeZptSchema, makeZptCat
42 from .utilities import makeAtmSchema, makeAtmCat
43 from .utilities import makeStdSchema, makeStdCat
44 from .focalPlaneProjector import FocalPlaneProjector
45 
46 import fgcm
47 
48 __all__ = ['FgcmCalibrateTractConfigBase', 'FgcmCalibrateTractBaseTask', 'FgcmCalibrateTractRunner']
49 
50 
51 class FgcmCalibrateTractConfigBase(pexConfig.Config):
52  """Config for FgcmCalibrateTract"""
53 
54  fgcmBuildStars = pexConfig.ConfigurableField(
55  target=FgcmBuildStarsTask,
56  doc="Task to load and match stars for fgcm",
57  )
58  fgcmFitCycle = pexConfig.ConfigField(
59  dtype=FgcmFitCycleConfig,
60  doc="Config to run a single fgcm fit cycle",
61  )
62  fgcmOutputProducts = pexConfig.ConfigurableField(
63  target=FgcmOutputProductsTask,
64  doc="Task to output fgcm products",
65  )
66  convergenceTolerance = pexConfig.Field(
67  doc="Tolerance on repeatability convergence (per band)",
68  dtype=float,
69  default=0.005,
70  )
71  maxFitCycles = pexConfig.Field(
72  doc="Maximum number of fit cycles",
73  dtype=int,
74  default=5,
75  )
76  doDebuggingPlots = pexConfig.Field(
77  doc="Make plots for debugging purposes?",
78  dtype=bool,
79  default=False,
80  )
81 
82  def setDefaults(self):
83  pexConfig.Config.setDefaults(self)
84 
85  self.fgcmFitCyclefgcmFitCycle.quietMode = True
86  self.fgcmFitCyclefgcmFitCycle.doPlots = False
87  self.fgcmOutputProductsfgcmOutputProducts.doReferenceCalibration = False
88  self.fgcmOutputProductsfgcmOutputProducts.doRefcatOutput = False
89  self.fgcmOutputProductsfgcmOutputProducts.cycleNumber = 0
90  self.fgcmOutputProductsfgcmOutputProducts.photoCal.applyColorTerms = False
91 
92  def validate(self):
93  super().validate()
94 
95  for band in self.fgcmFitCyclefgcmFitCycle.bands:
96  if not self.fgcmFitCyclefgcmFitCycle.useRepeatabilityForExpGrayCutsDict[band]:
97  msg = 'Must set useRepeatabilityForExpGrayCutsDict[band]=True for all bands'
98  raise pexConfig.FieldValidationError(FgcmFitCycleConfig.useRepeatabilityForExpGrayCutsDict,
99  self, msg)
100 
101 
102 class FgcmCalibrateTractRunner(pipeBase.ButlerInitializedTaskRunner):
103  """Subclass of TaskRunner for FgcmCalibrateTractTask
104 
105  fgcmCalibrateTractTask.run() takes a number of arguments, one of which is
106  the butler (for persistence and mapper data), and a list of dataRefs
107  extracted from the command line. This task runs on a constrained set
108  of dataRefs, typically a single tract.
109  This class transforms the process arguments generated by the ArgumentParser
110  into the arguments expected by FgcmCalibrateTractTask.run().
111  This runner does not use any parallelization.
112  """
113 
114  @staticmethod
115  def getTargetList(parsedCmd):
116  """
117  Return a list with one element: a tuple with the butler and
118  list of dataRefs.
119  """
120  return [(parsedCmd.butler, parsedCmd.id.refList)]
121 
122  def __call__(self, args):
123  """
124  Parameters
125  ----------
126  args: `tuple` with (butler, dataRefList)
127 
128  Returns
129  -------
130  exitStatus: `list` with `lsst.pipe.base.Struct`
131  exitStatus (0: success; 1: failure)
132  May also contain results if `self.doReturnResults` is `True`.
133  """
134  butler, dataRefList = args
135 
136  task = self.TaskClass(config=self.config, log=self.log)
137 
138  exitStatus = 0
139  if self.doRaise:
140  results = task.runDataRef(butler, dataRefList)
141  else:
142  try:
143  results = task.runDataRef(butler, dataRefList)
144  except Exception as e:
145  exitStatus = 1
146  task.log.fatal("Failed: %s" % e)
147  if not isinstance(e, pipeBase.TaskError):
148  traceback.print_exc(file=sys.stderr)
149 
150  task.writeMetadata(butler)
151 
152  if self.doReturnResults:
153  return [pipeBase.Struct(exitStatus=exitStatus,
154  results=results)]
155  else:
156  return [pipeBase.Struct(exitStatus=exitStatus)]
157 
158  def run(self, parsedCmd):
159  """
160  Run the task, with no multiprocessing
161 
162  Parameters
163  ----------
164  parsedCmd: `lsst.pipe.base.ArgumentParser` parsed command line
165  """
166 
167  resultList = []
168 
169  if self.precall(parsedCmd):
170  targetList = self.getTargetListgetTargetList(parsedCmd)
171  resultList = self(targetList[0])
172 
173  return resultList
174 
175 
176 class FgcmCalibrateTractBaseTask(pipeBase.PipelineTask, pipeBase.CmdLineTask, abc.ABC):
177  """Base class to calibrate a single tract using fgcmcal
178  """
179  def __init__(self, initInputs=None, butler=None, **kwargs):
180  """
181  Instantiate an `FgcmCalibrateTractTask`.
182 
183  Parameters
184  ----------
185  butler : `lsst.daf.persistence.Butler`, optional
186  """
187  super().__init__(**kwargs)
188  self.makeSubtask("fgcmBuildStars", initInputs=initInputs, butler=butler)
189  self.makeSubtask("fgcmOutputProducts", butler=butler)
190 
191  # no saving of metadata for now
192  def _getMetadataName(self):
193  return None
194 
195  @timeMethod
196  def runDataRef(self, butler, dataRefs):
197  """
198  Run full FGCM calibration on a single tract, including building star list,
199  fitting multiple cycles, and making outputs.
200 
201  Parameters
202  ----------
203  butler: `lsst.daf.persistence.Butler`
204  dataRefs: `list` of `lsst.daf.persistence.ButlerDataRef`
205  Data references for the input visits.
206  These may be either per-ccd "src" or per-visit"sourceTable_visit"
207  references.
208 
209  Raises
210  ------
211  RuntimeError: Raised if `config.fgcmBuildStars.doReferenceMatches` is
212  not True, or if fgcmLookUpTable is not available, or if
213  doSubtractLocalBackground is True and aperture radius cannot be
214  determined.
215  """
216  datasetType = dataRefs[0].butlerSubset.datasetType
217  self.log.info("Running with %d %s dataRefs" % (len(dataRefs), datasetType))
218 
219  if not butler.datasetExists('fgcmLookUpTable'):
220  raise RuntimeError("Must run FgcmCalibrateTract with an fgcmLookUpTable")
221 
222  if not self.config.fgcmBuildStars.doReferenceMatches:
223  raise RuntimeError("Must run FgcmCalibrateTract with fgcmBuildStars.doReferenceMatches")
224  if isinstance(self.config.fgcmBuildStars, FgcmBuildStarsConfig):
225  if self.config.fgcmBuildStars.checkAllCcds:
226  raise RuntimeError("Cannot run FgcmCalibrateTract with "
227  "fgcmBuildStars.checkAllCcds set to True")
228 
229  tract = int(dataRefs[0].dataId['tract'])
230  camera = butler.get('camera')
231 
232  dataRefDict = {}
233  dataRefDict['camera'] = camera
234  dataRefDict['source_catalogs'] = dataRefs
235  dataRefDict['sourceSchema'] = butler.get('src_schema', immediate=True).schema
236  dataRefDict['fgcmLookUpTable'] = butler.dataRef('fgcmLookUpTable')
237 
238  struct = self.runrun(dataRefDict, tract, butler=butler, returnCatalogs=False)
239 
240  visitDataRefName = self.config.fgcmBuildStars.visitDataRefName
241  ccdDataRefName = self.config.fgcmBuildStars.ccdDataRefName
242 
243  if struct.photoCalibs is not None:
244  self.log.info("Outputting photoCalib files.")
245 
246  for visit, detector, physicalFilter, photoCalib in struct.photoCalibs:
247  butler.put(photoCalib, 'fgcm_tract_photoCalib',
248  dataId={visitDataRefName: visit,
249  ccdDataRefName: detector,
250  'filter': physicalFilter,
251  'tract': tract})
252 
253  self.log.info("Done outputting photoCalib files.")
254 
255  if struct.atmospheres is not None:
256  self.log.info("Outputting atmosphere files.")
257  for visit, atm in struct.atmospheres:
258  butler.put(atm, "transmission_atmosphere_fgcm_tract",
259  dataId={visitDataRefName: visit,
260  'tract': tract})
261  self.log.info("Done outputting atmosphere transmissions.")
262 
263  return pipeBase.Struct(repeatability=struct.repeatability)
264 
265  def run(self, dataRefDict, tract,
266  buildStarsRefObjLoader=None, returnCatalogs=True, butler=None):
267  """Run the calibrations for a single tract with fgcm.
268 
269  Parameters
270  ----------
271  dataRefDict : `dict`
272  All dataRefs are `lsst.daf.persistence.ButlerDataRef` (gen2) or
273  `lsst.daf.butler.DeferredDatasetHandle` (gen3)
274  dataRef dictionary with the following keys. Note that all
275  keys need not be set based on config parameters.
276 
277  ``"camera"``
278  Camera object (`lsst.afw.cameraGeom.Camera`)
279  ``"source_catalogs"``
280  `list` of dataRefs for input source catalogs.
281  ``"sourceSchema"``
282  Schema for the source catalogs.
283  ``"fgcmLookUpTable"``
284  dataRef for the FGCM look-up table.
285  ``"calexps"``
286  `list` of dataRefs for the input calexps (Gen3 only)
287  ``"fgcmPhotoCalibs"``
288  `dict` of output photoCalib dataRefs. Key is
289  (tract, visit, detector). (Gen3 only)
290  Present if doZeropointOutput is True.
291  ``"fgcmTransmissionAtmospheres"``
292  `dict` of output atmosphere transmission dataRefs.
293  Key is (tract, visit). (Gen3 only)
294  Present if doAtmosphereOutput is True.
295  tract : `int`
296  Tract number
297  buildStarsRefObjLoader : `lsst.meas.algorithms.ReferenceObjectLoader`, optional
298  Reference object loader object for fgcmBuildStars.
299  returnCatalogs : `bool`, optional
300  Return photoCalibs as per-visit exposure catalogs.
301  butler : `lsst.daf.persistence.Butler`, optional
302  Gen2 butler used for reference star outputs
303 
304  Returns
305  -------
306  outstruct : `lsst.pipe.base.Struct`
307  Output structure with keys:
308 
309  offsets : `np.ndarray`
310  Final reference offsets, per band.
311  repeatability : `np.ndarray`
312  Raw fgcm repeatability for bright stars, per band.
313  atmospheres : `generator` [(`int`, `lsst.afw.image.TransmissionCurve`)]
314  Generator that returns (visit, transmissionCurve) tuples.
315  photoCalibs : `generator` [(`int`, `int`, `str`, `lsst.afw.image.PhotoCalib`)]
316  Generator that returns (visit, ccd, filtername, photoCalib) tuples.
317  (returned if returnCatalogs is False).
318  photoCalibCatalogs : `generator` [(`int`, `lsst.afw.table.ExposureCatalog`)]
319  Generator that returns (visit, exposureCatalog) tuples.
320  (returned if returnCatalogs is True).
321  """
322  self.log.info("Running on tract %d", (tract))
323 
324  # Compute the aperture radius if necessary. This is useful to do now before
325  # any heavy lifting has happened (fail early).
326  calibFluxApertureRadius = None
327  if self.config.fgcmBuildStars.doSubtractLocalBackground:
328  try:
329  field = self.config.fgcmBuildStars.instFluxField
330  calibFluxApertureRadius = computeApertureRadiusFromDataRef(dataRefDict['source_catalogs'][0],
331  field)
332  except RuntimeError:
333  raise RuntimeError("Could not determine aperture radius from %s. "
334  "Cannot use doSubtractLocalBackground." %
335  (field))
336 
337  # Run the build stars tasks
338 
339  # Note that we will need visitCat at the end of the procedure for the outputs
340  if isinstance(butler, dafPersist.Butler):
341  # Gen2
342  groupedDataRefs = self.fgcmBuildStars._findAndGroupDataRefsGen2(butler, dataRefDict['camera'],
343  dataRefDict['source_catalogs'])
344  else:
345  # Gen3
346  groupedDataRefs = self.fgcmBuildStars._groupDataRefs(dataRefDict['sourceTableDataRefDict'],
347  dataRefDict['visitSummaryDataRefDict'])
348  visitCat = self.fgcmBuildStars.fgcmMakeVisitCatalog(dataRefDict['camera'], groupedDataRefs)
349  rad = calibFluxApertureRadius
350  fgcmStarObservationCat = self.fgcmBuildStars.fgcmMakeAllStarObservations(groupedDataRefs,
351  visitCat,
352  dataRefDict['sourceSchema'],
353  dataRefDict['camera'],
354  calibFluxApertureRadius=rad)
355 
356  if self.fgcmBuildStars.config.doReferenceMatches:
357  lutDataRef = dataRefDict['fgcmLookUpTable']
358  if buildStarsRefObjLoader is not None:
359  self.fgcmBuildStars.makeSubtask("fgcmLoadReferenceCatalog",
360  refObjLoader=buildStarsRefObjLoader)
361  else:
362  self.fgcmBuildStars.makeSubtask("fgcmLoadReferenceCatalog", butler=butler)
363  else:
364  lutDataRef = None
365 
366  fgcmStarIdCat, fgcmStarIndicesCat, fgcmRefCat = \
367  self.fgcmBuildStars.fgcmMatchStars(visitCat,
368  fgcmStarObservationCat,
369  lutDataRef=lutDataRef)
370 
371  # Load the LUT
372  lutCat = dataRefDict['fgcmLookUpTable'].get()
373  fgcmLut, lutIndexVals, lutStd = translateFgcmLut(lutCat,
374  dict(self.config.fgcmFitCycle.physicalFilterMap))
375  del lutCat
376 
377  # Translate the visit catalog into fgcm format
378  fgcmExpInfo = translateVisitCatalog(visitCat)
379 
380  configDict = makeConfigDict(self.config.fgcmFitCycle, self.log, dataRefDict['camera'],
381  self.config.fgcmFitCycle.maxIterBeforeFinalCycle,
382  True, False, lutIndexVals[0]['FILTERNAMES'],
383  tract=tract)
384 
385  focalPlaneProjector = FocalPlaneProjector(dataRefDict['camera'],
386  self.config.fgcmFitCycle.defaultCameraOrientation)
387 
388  # Set up the fit cycle task
389 
390  noFitsDict = {'lutIndex': lutIndexVals,
391  'lutStd': lutStd,
392  'expInfo': fgcmExpInfo,
393  'focalPlaneProjector': focalPlaneProjector}
394 
395  fgcmFitCycle = fgcm.FgcmFitCycle(configDict, useFits=False,
396  noFitsDict=noFitsDict, noOutput=True)
397 
398  # We determine the conversion from the native units (typically radians) to
399  # degrees for the first star. This allows us to treat coord_ra/coord_dec as
400  # numpy arrays rather than Angles, which would we approximately 600x slower.
401  conv = fgcmStarObservationCat[0]['ra'].asDegrees() / float(fgcmStarObservationCat[0]['ra'])
402 
403  # To load the stars, we need an initial parameter object
404  fgcmPars = fgcm.FgcmParameters.newParsWithArrays(fgcmFitCycle.fgcmConfig,
405  fgcmLut,
406  fgcmExpInfo)
407 
408  # Match star observations to visits
409  # Only those star observations that match visits from fgcmExpInfo['VISIT'] will
410  # actually be transferred into fgcm using the indexing below.
411 
412  obsIndex = fgcmStarIndicesCat['obsIndex']
413  visitIndex = np.searchsorted(fgcmExpInfo['VISIT'],
414  fgcmStarObservationCat['visit'][obsIndex])
415 
416  refMag, refMagErr = extractReferenceMags(fgcmRefCat,
417  self.config.fgcmFitCycle.bands,
418  self.config.fgcmFitCycle.physicalFilterMap)
419  refId = fgcmRefCat['fgcm_id'][:]
420 
421  fgcmStars = fgcm.FgcmStars(fgcmFitCycle.fgcmConfig)
422  fgcmStars.loadStars(fgcmPars,
423  fgcmStarObservationCat['visit'][obsIndex],
424  fgcmStarObservationCat['ccd'][obsIndex],
425  fgcmStarObservationCat['ra'][obsIndex] * conv,
426  fgcmStarObservationCat['dec'][obsIndex] * conv,
427  fgcmStarObservationCat['instMag'][obsIndex],
428  fgcmStarObservationCat['instMagErr'][obsIndex],
429  fgcmExpInfo['FILTERNAME'][visitIndex],
430  fgcmStarIdCat['fgcm_id'][:],
431  fgcmStarIdCat['ra'][:],
432  fgcmStarIdCat['dec'][:],
433  fgcmStarIdCat['obsArrIndex'][:],
434  fgcmStarIdCat['nObs'][:],
435  obsX=fgcmStarObservationCat['x'][obsIndex],
436  obsY=fgcmStarObservationCat['y'][obsIndex],
437  obsDeltaMagBkg=fgcmStarObservationCat['deltaMagBkg'][obsIndex],
438  psfCandidate=fgcmStarObservationCat['psf_candidate'][obsIndex],
439  refID=refId,
440  refMag=refMag,
441  refMagErr=refMagErr,
442  flagID=None,
443  flagFlag=None,
444  computeNobs=True)
445 
446  # Clear out some memory
447  del fgcmStarIdCat
448  del fgcmStarIndicesCat
449  del fgcmRefCat
450 
451  fgcmFitCycle.setLUT(fgcmLut)
452  fgcmFitCycle.setStars(fgcmStars, fgcmPars)
453 
454  converged = False
455  cycleNumber = 0
456 
457  previousReservedRawRepeatability = np.zeros(fgcmPars.nBands) + 1000.0
458  previousParInfo = None
459  previousParams = None
460  previousSuperStar = None
461 
462  while (not converged and cycleNumber < self.config.maxFitCycles):
463 
464  fgcmFitCycle.fgcmConfig.updateCycleNumber(cycleNumber)
465 
466  if cycleNumber > 0:
467  # Use parameters from previous cycle
468  fgcmPars = fgcm.FgcmParameters.loadParsWithArrays(fgcmFitCycle.fgcmConfig,
469  fgcmExpInfo,
470  previousParInfo,
471  previousParams,
472  previousSuperStar)
473  # We need to reset the star magnitudes and errors for the next
474  # cycle
475  fgcmFitCycle.fgcmStars.reloadStarMagnitudes(fgcmStarObservationCat['instMag'][obsIndex],
476  fgcmStarObservationCat['instMagErr'][obsIndex])
477  fgcmFitCycle.initialCycle = False
478 
479  fgcmFitCycle.setPars(fgcmPars)
480  fgcmFitCycle.finishSetup()
481 
482  fgcmFitCycle.run()
483 
484  # Grab the parameters for the next cycle
485  previousParInfo, previousParams = fgcmFitCycle.fgcmPars.parsToArrays()
486  previousSuperStar = fgcmFitCycle.fgcmPars.parSuperStarFlat.copy()
487 
488  self.log.info("Raw repeatability after cycle number %d is:" % (cycleNumber))
489  for i, band in enumerate(fgcmFitCycle.fgcmPars.bands):
490  if not fgcmFitCycle.fgcmPars.hasExposuresInBand[i]:
491  continue
492  rep = fgcmFitCycle.fgcmPars.compReservedRawRepeatability[i] * 1000.0
493  self.log.info(" Band %s, repeatability: %.2f mmag" % (band, rep))
494 
495  # Check for convergence
496  if np.alltrue((previousReservedRawRepeatability
497  - fgcmFitCycle.fgcmPars.compReservedRawRepeatability)
498  < self.config.convergenceTolerance):
499  self.log.info("Raw repeatability has converged after cycle number %d." % (cycleNumber))
500  converged = True
501  else:
502  fgcmFitCycle.fgcmConfig.expGrayPhotometricCut[:] = fgcmFitCycle.updatedPhotometricCut
503  fgcmFitCycle.fgcmConfig.expGrayHighCut[:] = fgcmFitCycle.updatedHighCut
504  fgcmFitCycle.fgcmConfig.precomputeSuperStarInitialCycle = False
505  fgcmFitCycle.fgcmConfig.freezeStdAtmosphere = False
506  previousReservedRawRepeatability[:] = fgcmFitCycle.fgcmPars.compReservedRawRepeatability
507  self.log.info("Setting exposure gray photometricity cuts to:")
508  for i, band in enumerate(fgcmFitCycle.fgcmPars.bands):
509  if not fgcmFitCycle.fgcmPars.hasExposuresInBand[i]:
510  continue
511  cut = fgcmFitCycle.updatedPhotometricCut[i] * 1000.0
512  self.log.info(" Band %s, photometricity cut: %.2f mmag" % (band, cut))
513 
514  cycleNumber += 1
515 
516  # Log warning if not converged
517  if not converged:
518  self.log.warning("Maximum number of fit cycles exceeded (%d) without convergence.", cycleNumber)
519 
520  # Do final clean-up iteration
521  fgcmFitCycle.fgcmConfig.freezeStdAtmosphere = False
522  fgcmFitCycle.fgcmConfig.resetParameters = False
523  fgcmFitCycle.fgcmConfig.maxIter = 0
524  fgcmFitCycle.fgcmConfig.outputZeropoints = True
525  fgcmFitCycle.fgcmConfig.outputStandards = True
526  fgcmFitCycle.fgcmConfig.doPlots = self.config.doDebuggingPlots
527  fgcmFitCycle.fgcmConfig.updateCycleNumber(cycleNumber)
528  fgcmFitCycle.initialCycle = False
529 
530  fgcmPars = fgcm.FgcmParameters.loadParsWithArrays(fgcmFitCycle.fgcmConfig,
531  fgcmExpInfo,
532  previousParInfo,
533  previousParams,
534  previousSuperStar)
535  fgcmFitCycle.fgcmStars.reloadStarMagnitudes(fgcmStarObservationCat['instMag'][obsIndex],
536  fgcmStarObservationCat['instMagErr'][obsIndex])
537  fgcmFitCycle.setPars(fgcmPars)
538  fgcmFitCycle.finishSetup()
539 
540  self.log.info("Running final clean-up fit cycle...")
541  fgcmFitCycle.run()
542 
543  self.log.info("Raw repeatability after clean-up cycle is:")
544  for i, band in enumerate(fgcmFitCycle.fgcmPars.bands):
545  if not fgcmFitCycle.fgcmPars.hasExposuresInBand[i]:
546  continue
547  rep = fgcmFitCycle.fgcmPars.compReservedRawRepeatability[i] * 1000.0
548  self.log.info(" Band %s, repeatability: %.2f mmag" % (band, rep))
549 
550  # Do the outputs. Need to keep track of tract.
551 
552  superStarChebSize = fgcmFitCycle.fgcmZpts.zpStruct['FGCM_FZPT_SSTAR_CHEB'].shape[1]
553  zptChebSize = fgcmFitCycle.fgcmZpts.zpStruct['FGCM_FZPT_CHEB'].shape[1]
554 
555  zptSchema = makeZptSchema(superStarChebSize, zptChebSize)
556  zptCat = makeZptCat(zptSchema, fgcmFitCycle.fgcmZpts.zpStruct)
557 
558  atmSchema = makeAtmSchema()
559  atmCat = makeAtmCat(atmSchema, fgcmFitCycle.fgcmZpts.atmStruct)
560 
561  stdStruct, goodBands = fgcmFitCycle.fgcmStars.retrieveStdStarCatalog(fgcmFitCycle.fgcmPars)
562  stdSchema = makeStdSchema(len(goodBands))
563  stdCat = makeStdCat(stdSchema, stdStruct, goodBands)
564 
565  outStruct = self.fgcmOutputProducts.generateTractOutputProducts(dataRefDict,
566  tract,
567  visitCat,
568  zptCat, atmCat, stdCat,
569  self.config.fgcmBuildStars,
570  returnCatalogs=returnCatalogs,
571  butler=butler)
572 
573  outStruct.repeatability = fgcmFitCycle.fgcmPars.compReservedRawRepeatability
574 
575  fgcmFitCycle.freeSharedMemory()
576 
577  return outStruct
def __init__(self, initInputs=None, butler=None, **kwargs)
def run(self, dataRefDict, tract, buildStarsRefObjLoader=None, returnCatalogs=True, butler=None)
def extractReferenceMags(refStars, bands, filterMap)
Definition: utilities.py:887
def computeApertureRadiusFromDataRef(dataRef, fluxField)
Definition: utilities.py:812
def makeStdSchema(nBands)
Definition: utilities.py:742
def makeAtmCat(atmSchema, atmStruct)
Definition: utilities.py:709
def makeConfigDict(config, log, camera, maxIter, resetFitParameters, outputZeropoints, lutFilterNames, tract=None)
Definition: utilities.py:52
def translateFgcmLut(lutCat, physicalFilterMap)
Definition: utilities.py:220
def makeZptCat(zptSchema, zpStruct)
Definition: utilities.py:630
def makeStdCat(stdSchema, stdStruct, goodBands)
Definition: utilities.py:774
def makeZptSchema(superStarChebyshevSize, zptChebyshevSize)
Definition: utilities.py:544
def translateVisitCatalog(visitCat)
Definition: utilities.py:350