235 Make a visit catalog with all the keys from each visit
239 camera : `lsst.afw.cameraGeom.Camera`
240 Camera from the butler
241 groupedHandles : `dict` [`list` [`lsst.daf.butler.DeferredDatasetHandle`]]
242 Dataset handles, grouped by visit.
243 useScienceDetectors : `bool`, optional
244 Limit to science detectors?
248 visitCat: `afw.table.BaseCatalog`
251 self.log.info(
"Assembling visitCatalog from %d visits", len(groupedHandles))
253 nCcd = countDetectors(camera, useScienceDetectors)
257 visitCat = afwTable.BaseCatalog(schema)
258 visitCat.reserve(len(groupedHandles))
259 visitCat.resize(len(groupedHandles))
261 visitCat[
'visit'] = list(groupedHandles.keys())
263 visitCat[
'sources_read'] =
False
265 defaultPixelScale = computeReferencePixelScale(camera, useScienceDetectors=useScienceDetectors)
275 Fill the visit catalog with visit metadata
279 visitCat : `afw.table.BaseCatalog`
280 Visit catalog. See _makeFgcmVisitSchema() for schema definition.
281 groupedHandles : `dict` [`list` [`lsst.daf.butler.DeferredDatasetHandle`]]
282 Dataset handles, grouped by visit.
283 defaultPixelScale : `float`
284 Default pixel scale to use if not in visit summary (arcsecond/pixel).
288 for i, visit
in enumerate(sorted(groupedHandles)):
289 if (i % self.config.nVisitsPerCheckpoint) == 0:
290 self.log.info(
"Retrieving metadata for visit %d (%d/%d)", visit, i, len(groupedHandles))
292 handle = groupedHandles[visit][0]
293 summary = handle.get()
295 summaryRow = summary.find(self.config.referenceCCD)
296 if summaryRow
is None:
298 summaryRow = summary[0]
300 visitInfo = summaryRow.getVisitInfo()
301 physicalFilter = summaryRow[
'physical_filter']
303 if 'pixelScale' in summary.schema:
305 pixelScales = summary[
'pixelScale']
307 pixelScales = np.full(len(summary[
'psfSigma']), defaultPixelScale)
308 psfSigmas = summary[
'psfSigma']
309 psfFwhms = psfSigmas * pixelScales * np.sqrt(8.*np.log(2.))
310 goodSigma = ((np.nan_to_num(psfSigmas) > 0) & (np.nan_to_num(pixelScales) > 0))
311 psfSigmas[~goodSigma] = -9999.0
312 psfFwhms[~goodSigma] = -9999.0
313 if goodSigma.size > 2:
314 psfSigma = np.median(psfSigmas[goodSigma])
315 psfFwhm = np.median(psfFwhms[goodSigma])
316 elif goodSigma.size > 0:
317 psfSigma = psfSigmas[goodSigma[0]]
318 psfFwhm = psfFwhms[goodSigma[0]]
320 self.log.warning(
"Could not find any good summary psfSigma for visit %d", visit)
324 goodBackground, = np.where(np.nan_to_num(summary[
'skyBg']) > 0.0)
325 if goodBackground.size > 2:
326 skyBackground = np.median(summary[
'skyBg'][goodBackground])
327 elif goodBackground.size > 0:
328 skyBackground = summary[
'skyBg'][goodBackground[0]]
330 self.log.warning(
'Could not find any good summary skyBg for visit %d', visit)
335 rec[
'physicalFilter'] = physicalFilter
337 radec = visitInfo.getBoresightRaDec()
338 rec[
'telra'] = radec.getRa().asDegrees()
339 rec[
'teldec'] = radec.getDec().asDegrees()
340 rec[
'telha'] = visitInfo.getBoresightHourAngle().asDegrees()
341 rec[
'telrot'] = visitInfo.getBoresightRotAngle().asDegrees()
342 rec[
'mjd'] = visitInfo.getDate().get(system=DateTime.MJD)
343 rec[
'exptime'] = visitInfo.getExposureTime()
346 rec[
'pmb'] = visitInfo.getWeather().getAirPressure() / 100
350 rec[
'scaling'][:] = 1.0
352 rec[
'deltaAper'] = -9999.0
353 rec[
'deltaAperDetector'][:] = -9999.0
354 rec[
'psfSigma'] = psfSigma.item()
355 rec[
'psfFwhm'] = psfFwhm.item()
357 rec[
'psfFwhmDetector'][summary[
"id"]] = psfFwhms
358 rec[
'skyBackground'] = skyBackground
363 Make a schema mapper for fgcm sources
367 sourceSchema: `afwTable.Schema`
368 Default source schema from the butler
372 sourceMapper: `afwTable.schemaMapper`
373 Mapper to the FGCM source schema
377 sourceMapper = afwTable.SchemaMapper(sourceSchema)
380 sourceMapper.addMapping(sourceSchema[
'coord_ra'].asKey(),
'ra')
381 sourceMapper.addMapping(sourceSchema[
'coord_dec'].asKey(),
'dec')
382 sourceMapper.addMapping(sourceSchema[
'slot_Centroid_x'].asKey(),
'x')
383 sourceMapper.addMapping(sourceSchema[
'slot_Centroid_y'].asKey(),
'y')
389 sourceMapper.addMapping(sourceSchema[self.config.psfCandidateName].asKey(),
392 sourceMapper.editOutputSchema().addField(
393 "psf_candidate", type=
'Flag',
394 doc=(
"Flag set if the source was a candidate for PSF determination, "
395 "as determined by the star selector."))
398 sourceMapper.editOutputSchema().addField(
399 "visit", type=np.int64, doc=
"Visit number")
400 sourceMapper.editOutputSchema().addField(
401 "ccd", type=np.int32, doc=
"CCD number")
402 sourceMapper.editOutputSchema().addField(
403 "instMag", type=np.float32, doc=
"Instrumental magnitude")
404 sourceMapper.editOutputSchema().addField(
405 "instMagErr", type=np.float32, doc=
"Instrumental magnitude error")
406 sourceMapper.editOutputSchema().addField(
407 "jacobian", type=np.float32, doc=
"Relative pixel scale from wcs jacobian")
408 sourceMapper.editOutputSchema().addField(
409 "deltaMagBkg", type=np.float32, doc=
"Change in magnitude due to local background offset")
410 sourceMapper.editOutputSchema().addField(
411 "deltaMagAper", type=np.float32, doc=
"Change in magnitude from larger to smaller aperture")
417 Use FGCM code to match observations into unique stars.
421 visitCat: `afw.table.BaseCatalog`
422 Catalog with visit data for fgcm
423 obsCat: `afw.table.BaseCatalog`
424 Full catalog of star observations for fgcm
425 lutHandle: `lsst.daf.butler.DeferredDatasetHandle`, optional
426 Data reference to fgcm look-up table (used if matching reference stars).
430 fgcmStarIdCat: `afw.table.BaseCatalog`
431 Catalog of unique star identifiers and index keys
432 fgcmStarIndicesCat: `afwTable.BaseCatalog`
433 Catalog of unique star indices
434 fgcmRefCat: `afw.table.BaseCatalog`
435 Catalog of matched reference stars.
436 Will be None if `config.doReferenceMatches` is False.
440 visitFilterNames = np.zeros(len(visitCat), dtype=
'S30')
441 for i
in range(len(visitCat)):
442 visitFilterNames[i] = visitCat[i][
'physicalFilter']
445 visitIndex = np.searchsorted(visitCat[
'visit'],
448 obsFilterNames = visitFilterNames[visitIndex]
450 if self.config.doReferenceMatches:
452 lutCat = lutHandle.get()
454 stdFilterDict = {filterName: stdFilter
for (filterName, stdFilter)
in
455 zip(lutCat[0][
'physicalFilters'].split(
','),
456 lutCat[0][
'stdPhysicalFilters'].split(
','))}
457 stdLambdaDict = {stdFilter: stdLambda
for (stdFilter, stdLambda)
in
458 zip(lutCat[0][
'stdPhysicalFilters'].split(
','),
459 lutCat[0][
'lambdaStdFilter'])}
466 self.log.info(
"Using the following reference filters: %s" %
467 (
', '.join(referenceFilterNames)))
471 referenceFilterNames = []
474 starConfig = {
'logger': self.log,
476 'filterToBand': self.config.physicalFilterMap,
477 'requiredBands': self.config.requiredBands,
478 'minPerBand': self.config.minPerBand,
479 'matchRadius': self.config.matchRadius,
480 'isolationRadius': self.config.isolationRadius,
481 'matchNSide': self.config.matchNside,
482 'coarseNSide': self.config.coarseNside,
483 'densNSide': self.config.densityCutNside,
484 'densMaxPerPixel': self.config.densityCutMaxPerPixel,
485 'randomSeed': self.config.randomSeed,
486 'primaryBands': self.config.primaryBands,
487 'referenceFilterNames': referenceFilterNames}
490 fgcmMakeStars = fgcm.FgcmMakeStars(starConfig)
498 conv = obsCat[0][
'ra'].asDegrees() / float(obsCat[0][
'ra'])
499 fgcmMakeStars.makePrimaryStars(obsCat[
'ra'] * conv,
500 obsCat[
'dec'] * conv,
501 filterNameArray=obsFilterNames,
505 fgcmMakeStars.makeMatchedStars(obsCat[
'ra'] * conv,
506 obsCat[
'dec'] * conv,
509 if self.config.doReferenceMatches:
517 fgcmStarIdCat = afwTable.BaseCatalog(objSchema)
518 fgcmStarIdCat.reserve(fgcmMakeStars.objIndexCat.size)
519 for i
in range(fgcmMakeStars.objIndexCat.size):
520 fgcmStarIdCat.addNew()
523 fgcmStarIdCat[
'fgcm_id'][:] = fgcmMakeStars.objIndexCat[
'fgcm_id']
524 fgcmStarIdCat[
'ra'][:] = fgcmMakeStars.objIndexCat[
'ra']
525 fgcmStarIdCat[
'dec'][:] = fgcmMakeStars.objIndexCat[
'dec']
526 fgcmStarIdCat[
'obsArrIndex'][:] = fgcmMakeStars.objIndexCat[
'obsarrindex']
527 fgcmStarIdCat[
'nObs'][:] = fgcmMakeStars.objIndexCat[
'nobs']
531 fgcmStarIndicesCat = afwTable.BaseCatalog(obsSchema)
532 fgcmStarIndicesCat.reserve(fgcmMakeStars.obsIndexCat.size)
533 for i
in range(fgcmMakeStars.obsIndexCat.size):
534 fgcmStarIndicesCat.addNew()
536 fgcmStarIndicesCat[
'obsIndex'][:] = fgcmMakeStars.obsIndexCat[
'obsindex']
538 if self.config.doReferenceMatches:
541 fgcmRefCat = afwTable.BaseCatalog(refSchema)
542 fgcmRefCat.reserve(fgcmMakeStars.referenceCat.size)
544 for i
in range(fgcmMakeStars.referenceCat.size):
547 fgcmRefCat[
'fgcm_id'][:] = fgcmMakeStars.referenceCat[
'fgcm_id']
548 fgcmRefCat[
'refMag'][:, :] = fgcmMakeStars.referenceCat[
'refMag']
549 fgcmRefCat[
'refMagErr'][:, :] = fgcmMakeStars.referenceCat[
'refMagErr']
552 md.set(
"REFSTARS_FORMAT_VERSION", REFSTARS_FORMAT_VERSION)
553 md.set(
"FILTERNAMES", referenceFilterNames)
554 fgcmRefCat.setMetadata(md)
559 return fgcmStarIdCat, fgcmStarIndicesCat, fgcmRefCat