273 Fill the visit catalog with visit metadata
277 visitCat : `afw.table.BaseCatalog`
278 Visit catalog. See _makeFgcmVisitSchema() for schema definition.
279 groupedHandles : `dict` [`list` [`lsst.daf.butler.DeferredDatasetHandle`]]
280 Dataset handles, grouped by visit.
281 defaultPixelScale : `float`
282 Default pixel scale to use if not in visit summary (arcsecond/pixel).
286 for i, visit
in enumerate(sorted(groupedHandles)):
287 if (i % self.config.nVisitsPerCheckpoint) == 0:
288 self.log.info(
"Retrieving metadata for visit %d (%d/%d)", visit, i, len(groupedHandles))
290 handle = groupedHandles[visit][0]
291 summary = handle.get()
293 summaryRow = summary.find(self.config.referenceCCD)
294 if summaryRow
is None:
296 summaryRow = summary[0]
298 visitInfo = summaryRow.getVisitInfo()
299 physicalFilter = summaryRow[
'physical_filter']
301 if 'pixelScale' in summary.schema:
303 pixelScales = summary[
'pixelScale']
305 pixelScales = np.full(len(summary[
'psfSigma']), defaultPixelScale)
306 psfSigmas = summary[
'psfSigma']
307 goodSigma, = np.where((np.nan_to_num(psfSigmas) > 0) & (np.nan_to_num(pixelScales) > 0))
308 if goodSigma.size > 2:
309 psfSigma = np.median(psfSigmas[goodSigma])
310 psfFwhm = np.median(psfSigmas[goodSigma] * pixelScales[goodSigma]) * np.sqrt(8.*np.log(2.))
311 elif goodSigma.size > 0:
312 psfSigma = psfSigmas[goodSigma[0]]
313 psfFwhm = psfSigmas[goodSigma[0]] * pixelScales[goodSigma[0]] * np.sqrt(8.)*np.log(2.)
315 self.log.warning(
"Could not find any good summary psfSigma for visit %d", visit)
319 goodBackground, = np.where(np.nan_to_num(summary[
'skyBg']) > 0.0)
320 if goodBackground.size > 2:
321 skyBackground = np.median(summary[
'skyBg'][goodBackground])
322 elif goodBackground.size > 0:
323 skyBackground = summary[
'skyBg'][goodBackground[0]]
325 self.log.warning(
'Could not find any good summary skyBg for visit %d', visit)
330 rec[
'physicalFilter'] = physicalFilter
332 radec = visitInfo.getBoresightRaDec()
333 rec[
'telra'] = radec.getRa().asDegrees()
334 rec[
'teldec'] = radec.getDec().asDegrees()
335 rec[
'telha'] = visitInfo.getBoresightHourAngle().asDegrees()
336 rec[
'telrot'] = visitInfo.getBoresightRotAngle().asDegrees()
337 rec[
'mjd'] = visitInfo.getDate().get(system=DateTime.MJD)
338 rec[
'exptime'] = visitInfo.getExposureTime()
341 rec[
'pmb'] = visitInfo.getWeather().getAirPressure() / 100
345 rec[
'scaling'][:] = 1.0
347 rec[
'deltaAper'] = 0.0
348 rec[
'psfSigma'] = psfSigma
349 rec[
'psfFwhm'] = psfFwhm
350 rec[
'skyBackground'] = skyBackground
355 Make a schema mapper for fgcm sources
359 sourceSchema: `afwTable.Schema`
360 Default source schema from the butler
364 sourceMapper: `afwTable.schemaMapper`
365 Mapper to the FGCM source schema
372 sourceMapper.addMapping(sourceSchema[
'coord_ra'].asKey(),
'ra')
373 sourceMapper.addMapping(sourceSchema[
'coord_dec'].asKey(),
'dec')
374 sourceMapper.addMapping(sourceSchema[
'slot_Centroid_x'].asKey(),
'x')
375 sourceMapper.addMapping(sourceSchema[
'slot_Centroid_y'].asKey(),
'y')
381 sourceMapper.addMapping(sourceSchema[self.config.psfCandidateName].asKey(),
384 sourceMapper.editOutputSchema().addField(
385 "psf_candidate", type=
'Flag',
386 doc=(
"Flag set if the source was a candidate for PSF determination, "
387 "as determined by the star selector."))
390 sourceMapper.editOutputSchema().addField(
391 "visit", type=np.int64, doc=
"Visit number")
392 sourceMapper.editOutputSchema().addField(
393 "ccd", type=np.int32, doc=
"CCD number")
394 sourceMapper.editOutputSchema().addField(
395 "instMag", type=np.float32, doc=
"Instrumental magnitude")
396 sourceMapper.editOutputSchema().addField(
397 "instMagErr", type=np.float32, doc=
"Instrumental magnitude error")
398 sourceMapper.editOutputSchema().addField(
399 "jacobian", type=np.float32, doc=
"Relative pixel scale from wcs jacobian")
400 sourceMapper.editOutputSchema().addField(
401 "deltaMagBkg", type=np.float32, doc=
"Change in magnitude due to local background offset")
402 sourceMapper.editOutputSchema().addField(
403 "deltaMagAper", type=np.float32, doc=
"Change in magnitude from larger to smaller aperture")
409 Use FGCM code to match observations into unique stars.
413 visitCat: `afw.table.BaseCatalog`
414 Catalog with visit data for fgcm
415 obsCat: `afw.table.BaseCatalog`
416 Full catalog of star observations for fgcm
417 lutHandle: `lsst.daf.butler.DeferredDatasetHandle`, optional
418 Data reference to fgcm look-up table (used if matching reference stars).
422 fgcmStarIdCat: `afw.table.BaseCatalog`
423 Catalog of unique star identifiers and index keys
424 fgcmStarIndicesCat: `afwTable.BaseCatalog`
425 Catalog of unique star indices
426 fgcmRefCat: `afw.table.BaseCatalog`
427 Catalog of matched reference stars.
428 Will be None if `config.doReferenceMatches` is False.
432 visitFilterNames = np.zeros(len(visitCat), dtype=
'S30')
433 for i
in range(len(visitCat)):
434 visitFilterNames[i] = visitCat[i][
'physicalFilter']
437 visitIndex = np.searchsorted(visitCat[
'visit'],
440 obsFilterNames = visitFilterNames[visitIndex]
442 if self.config.doReferenceMatches:
444 lutCat = lutHandle.get()
446 stdFilterDict = {filterName: stdFilter
for (filterName, stdFilter)
in
447 zip(lutCat[0][
'physicalFilters'].split(
','),
448 lutCat[0][
'stdPhysicalFilters'].split(
','))}
449 stdLambdaDict = {stdFilter: stdLambda
for (stdFilter, stdLambda)
in
450 zip(lutCat[0][
'stdPhysicalFilters'].split(
','),
451 lutCat[0][
'lambdaStdFilter'])}
458 self.log.info(
"Using the following reference filters: %s" %
459 (
', '.join(referenceFilterNames)))
463 referenceFilterNames = []
466 starConfig = {
'logger': self.log,
468 'filterToBand': self.config.physicalFilterMap,
469 'requiredBands': self.config.requiredBands,
470 'minPerBand': self.config.minPerBand,
471 'matchRadius': self.config.matchRadius,
472 'isolationRadius': self.config.isolationRadius,
473 'matchNSide': self.config.matchNside,
474 'coarseNSide': self.config.coarseNside,
475 'densNSide': self.config.densityCutNside,
476 'densMaxPerPixel': self.config.densityCutMaxPerPixel,
477 'randomSeed': self.config.randomSeed,
478 'primaryBands': self.config.primaryBands,
479 'referenceFilterNames': referenceFilterNames}
482 fgcmMakeStars = fgcm.FgcmMakeStars(starConfig)
490 conv = obsCat[0][
'ra'].asDegrees() / float(obsCat[0][
'ra'])
491 fgcmMakeStars.makePrimaryStars(obsCat[
'ra'] * conv,
492 obsCat[
'dec'] * conv,
493 filterNameArray=obsFilterNames,
497 fgcmMakeStars.makeMatchedStars(obsCat[
'ra'] * conv,
498 obsCat[
'dec'] * conv,
501 if self.config.doReferenceMatches:
510 fgcmStarIdCat.reserve(fgcmMakeStars.objIndexCat.size)
511 for i
in range(fgcmMakeStars.objIndexCat.size):
512 fgcmStarIdCat.addNew()
515 fgcmStarIdCat[
'fgcm_id'][:] = fgcmMakeStars.objIndexCat[
'fgcm_id']
516 fgcmStarIdCat[
'ra'][:] = fgcmMakeStars.objIndexCat[
'ra']
517 fgcmStarIdCat[
'dec'][:] = fgcmMakeStars.objIndexCat[
'dec']
518 fgcmStarIdCat[
'obsArrIndex'][:] = fgcmMakeStars.objIndexCat[
'obsarrindex']
519 fgcmStarIdCat[
'nObs'][:] = fgcmMakeStars.objIndexCat[
'nobs']
524 fgcmStarIndicesCat.reserve(fgcmMakeStars.obsIndexCat.size)
525 for i
in range(fgcmMakeStars.obsIndexCat.size):
526 fgcmStarIndicesCat.addNew()
528 fgcmStarIndicesCat[
'obsIndex'][:] = fgcmMakeStars.obsIndexCat[
'obsindex']
530 if self.config.doReferenceMatches:
534 fgcmRefCat.reserve(fgcmMakeStars.referenceCat.size)
536 for i
in range(fgcmMakeStars.referenceCat.size):
539 fgcmRefCat[
'fgcm_id'][:] = fgcmMakeStars.referenceCat[
'fgcm_id']
540 fgcmRefCat[
'refMag'][:, :] = fgcmMakeStars.referenceCat[
'refMag']
541 fgcmRefCat[
'refMagErr'][:, :] = fgcmMakeStars.referenceCat[
'refMagErr']
544 md.set(
"REFSTARS_FORMAT_VERSION", REFSTARS_FORMAT_VERSION)
545 md.set(
"FILTERNAMES", referenceFilterNames)
546 fgcmRefCat.setMetadata(md)
551 return fgcmStarIdCat, fgcmStarIndicesCat, fgcmRefCat