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)
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 goodSigma, = np.where((np.nan_to_num(psfSigmas) > 0) & (np.nan_to_num(pixelScales) > 0))
310 if goodSigma.size > 2:
311 psfSigma = np.median(psfSigmas[goodSigma])
312 psfFwhm = np.median(psfSigmas[goodSigma] * pixelScales[goodSigma]) * np.sqrt(8.*np.log(2.))
313 elif goodSigma.size > 0:
314 psfSigma = psfSigmas[goodSigma[0]]
315 psfFwhm = psfSigmas[goodSigma[0]] * pixelScales[goodSigma[0]] * np.sqrt(8.)*np.log(2.)
317 self.log.warning(
"Could not find any good summary psfSigma for visit %d", visit)
321 goodBackground, = np.where(np.nan_to_num(summary[
'skyBg']) > 0.0)
322 if goodBackground.size > 2:
323 skyBackground = np.median(summary[
'skyBg'][goodBackground])
324 elif goodBackground.size > 0:
325 skyBackground = summary[
'skyBg'][goodBackground[0]]
327 self.log.warning(
'Could not find any good summary skyBg for visit %d', visit)
332 rec[
'physicalFilter'] = physicalFilter
334 radec = visitInfo.getBoresightRaDec()
335 rec[
'telra'] = radec.getRa().asDegrees()
336 rec[
'teldec'] = radec.getDec().asDegrees()
337 rec[
'telha'] = visitInfo.getBoresightHourAngle().asDegrees()
338 rec[
'telrot'] = visitInfo.getBoresightRotAngle().asDegrees()
339 rec[
'mjd'] = visitInfo.getDate().get(system=DateTime.MJD)
340 rec[
'exptime'] = visitInfo.getExposureTime()
343 rec[
'pmb'] = visitInfo.getWeather().getAirPressure() / 100
347 rec[
'scaling'][:] = 1.0
349 rec[
'deltaAper'] = -9999.0
350 rec[
'deltaAperDetector'][:] = -9999.0
351 rec[
'psfSigma'] = psfSigma
352 rec[
'psfFwhm'] = psfFwhm
353 rec[
'skyBackground'] = skyBackground
358 Make a schema mapper for fgcm sources
362 sourceSchema: `afwTable.Schema`
363 Default source schema from the butler
367 sourceMapper: `afwTable.schemaMapper`
368 Mapper to the FGCM source schema
375 sourceMapper.addMapping(sourceSchema[
'coord_ra'].asKey(),
'ra')
376 sourceMapper.addMapping(sourceSchema[
'coord_dec'].asKey(),
'dec')
377 sourceMapper.addMapping(sourceSchema[
'slot_Centroid_x'].asKey(),
'x')
378 sourceMapper.addMapping(sourceSchema[
'slot_Centroid_y'].asKey(),
'y')
384 sourceMapper.addMapping(sourceSchema[self.config.psfCandidateName].asKey(),
387 sourceMapper.editOutputSchema().addField(
388 "psf_candidate", type=
'Flag',
389 doc=(
"Flag set if the source was a candidate for PSF determination, "
390 "as determined by the star selector."))
393 sourceMapper.editOutputSchema().addField(
394 "visit", type=np.int64, doc=
"Visit number")
395 sourceMapper.editOutputSchema().addField(
396 "ccd", type=np.int32, doc=
"CCD number")
397 sourceMapper.editOutputSchema().addField(
398 "instMag", type=np.float32, doc=
"Instrumental magnitude")
399 sourceMapper.editOutputSchema().addField(
400 "instMagErr", type=np.float32, doc=
"Instrumental magnitude error")
401 sourceMapper.editOutputSchema().addField(
402 "jacobian", type=np.float32, doc=
"Relative pixel scale from wcs jacobian")
403 sourceMapper.editOutputSchema().addField(
404 "deltaMagBkg", type=np.float32, doc=
"Change in magnitude due to local background offset")
405 sourceMapper.editOutputSchema().addField(
406 "deltaMagAper", type=np.float32, doc=
"Change in magnitude from larger to smaller aperture")
412 Use FGCM code to match observations into unique stars.
416 visitCat: `afw.table.BaseCatalog`
417 Catalog with visit data for fgcm
418 obsCat: `afw.table.BaseCatalog`
419 Full catalog of star observations for fgcm
420 lutHandle: `lsst.daf.butler.DeferredDatasetHandle`, optional
421 Data reference to fgcm look-up table (used if matching reference stars).
425 fgcmStarIdCat: `afw.table.BaseCatalog`
426 Catalog of unique star identifiers and index keys
427 fgcmStarIndicesCat: `afwTable.BaseCatalog`
428 Catalog of unique star indices
429 fgcmRefCat: `afw.table.BaseCatalog`
430 Catalog of matched reference stars.
431 Will be None if `config.doReferenceMatches` is False.
435 visitFilterNames = np.zeros(len(visitCat), dtype=
'S30')
436 for i
in range(len(visitCat)):
437 visitFilterNames[i] = visitCat[i][
'physicalFilter']
440 visitIndex = np.searchsorted(visitCat[
'visit'],
443 obsFilterNames = visitFilterNames[visitIndex]
445 if self.config.doReferenceMatches:
447 lutCat = lutHandle.get()
449 stdFilterDict = {filterName: stdFilter
for (filterName, stdFilter)
in
450 zip(lutCat[0][
'physicalFilters'].split(
','),
451 lutCat[0][
'stdPhysicalFilters'].split(
','))}
452 stdLambdaDict = {stdFilter: stdLambda
for (stdFilter, stdLambda)
in
453 zip(lutCat[0][
'stdPhysicalFilters'].split(
','),
454 lutCat[0][
'lambdaStdFilter'])}
461 self.log.info(
"Using the following reference filters: %s" %
462 (
', '.join(referenceFilterNames)))
466 referenceFilterNames = []
469 starConfig = {
'logger': self.log,
471 'filterToBand': self.config.physicalFilterMap,
472 'requiredBands': self.config.requiredBands,
473 'minPerBand': self.config.minPerBand,
474 'matchRadius': self.config.matchRadius,
475 'isolationRadius': self.config.isolationRadius,
476 'matchNSide': self.config.matchNside,
477 'coarseNSide': self.config.coarseNside,
478 'densNSide': self.config.densityCutNside,
479 'densMaxPerPixel': self.config.densityCutMaxPerPixel,
480 'randomSeed': self.config.randomSeed,
481 'primaryBands': self.config.primaryBands,
482 'referenceFilterNames': referenceFilterNames}
485 fgcmMakeStars = fgcm.FgcmMakeStars(starConfig)
493 conv = obsCat[0][
'ra'].asDegrees() / float(obsCat[0][
'ra'])
494 fgcmMakeStars.makePrimaryStars(obsCat[
'ra'] * conv,
495 obsCat[
'dec'] * conv,
496 filterNameArray=obsFilterNames,
500 fgcmMakeStars.makeMatchedStars(obsCat[
'ra'] * conv,
501 obsCat[
'dec'] * conv,
504 if self.config.doReferenceMatches:
513 fgcmStarIdCat.reserve(fgcmMakeStars.objIndexCat.size)
514 for i
in range(fgcmMakeStars.objIndexCat.size):
515 fgcmStarIdCat.addNew()
518 fgcmStarIdCat[
'fgcm_id'][:] = fgcmMakeStars.objIndexCat[
'fgcm_id']
519 fgcmStarIdCat[
'ra'][:] = fgcmMakeStars.objIndexCat[
'ra']
520 fgcmStarIdCat[
'dec'][:] = fgcmMakeStars.objIndexCat[
'dec']
521 fgcmStarIdCat[
'obsArrIndex'][:] = fgcmMakeStars.objIndexCat[
'obsarrindex']
522 fgcmStarIdCat[
'nObs'][:] = fgcmMakeStars.objIndexCat[
'nobs']
527 fgcmStarIndicesCat.reserve(fgcmMakeStars.obsIndexCat.size)
528 for i
in range(fgcmMakeStars.obsIndexCat.size):
529 fgcmStarIndicesCat.addNew()
531 fgcmStarIndicesCat[
'obsIndex'][:] = fgcmMakeStars.obsIndexCat[
'obsindex']
533 if self.config.doReferenceMatches:
537 fgcmRefCat.reserve(fgcmMakeStars.referenceCat.size)
539 for i
in range(fgcmMakeStars.referenceCat.size):
542 fgcmRefCat[
'fgcm_id'][:] = fgcmMakeStars.referenceCat[
'fgcm_id']
543 fgcmRefCat[
'refMag'][:, :] = fgcmMakeStars.referenceCat[
'refMag']
544 fgcmRefCat[
'refMagErr'][:, :] = fgcmMakeStars.referenceCat[
'refMagErr']
547 md.set(
"REFSTARS_FORMAT_VERSION", REFSTARS_FORMAT_VERSION)
548 md.set(
"FILTERNAMES", referenceFilterNames)
549 fgcmRefCat.setMetadata(md)
554 return fgcmStarIdCat, fgcmStarIndicesCat, fgcmRefCat