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