345 camera = butlerQC.get(inputRefs.camera)
347 if self.config.doOpticsTransmission:
348 opticsHandle = butlerQC.get(inputRefs.transmission_optics)
352 if self.config.doSensorTransmission:
353 sensorHandles = butlerQC.get(inputRefs.transmission_sensor)
354 sensorHandleDict = {sensorHandle.dataId[
'detector']: sensorHandle
for
355 sensorHandle
in sensorHandles}
357 sensorHandleDict = {}
359 filterHandles = butlerQC.get(inputRefs.transmission_filter)
360 filterHandleDict = {filterHandle.dataId[
'physical_filter']: filterHandle
for
361 filterHandle
in filterHandles}
368 butlerQC.put(struct.fgcmLookUpTable, outputRefs.fgcmLookUpTable)
369 butlerQC.put(struct.fgcmStandardAtmosphere, outputRefs.fgcmStandardAtmosphere)
371 refDict = {passbandRef.dataId[
'physical_filter']: passbandRef
for
372 passbandRef
in outputRefs.fgcmStandardPassbands}
373 for physical_filter, passband
in struct.fgcmStandardPassbands.items():
374 butlerQC.put(passband, refDict[physical_filter])
379 Make a FGCM Look-up Table
383 camera : `lsst.afw.cameraGeom.Camera`
384 Camera from the butler.
385 opticsHandle : `lsst.daf.butler.DeferredDatasetHandle`
386 Reference to optics transmission curve.
387 sensorHandleDict : `dict` of [`int`, `lsst.daf.butler.DeferredDatasetHandle`]
388 Dictionary of references to sensor transmission curves. Key will
390 filterHandleDict : `dict` of [`str`, `lsst.daf.butler.DeferredDatasetHandle`]
391 Dictionary of references to filter transmission curves. Key will
392 be physical filter label.
396 retStruct : `lsst.pipe.base.Struct`
397 Output structure with keys:
399 fgcmLookUpTable : `BaseCatalog`
400 The FGCM look-up table.
401 fgcmStandardAtmosphere : `lsst.afw.image.TransmissionCurve`
402 Transmission curve for the FGCM standard atmosphere.
403 fgcmStandardPassbands : `dict` [`str`, `lsst.afw.image.TransmissionCurve`]
404 Dictionary of standard passbands, with the key as the
405 physical filter name.
409 self.log.info(
"Found %d ccds for look-up table" % (nCcd))
420 self.log.info(
"Making the LUT maker object")
428 throughputLambda = np.arange(self.
fgcmLutMaker.lambdaRange[0],
432 self.log.info(
"Built throughput lambda, %.1f-%.1f, step %.2f" %
433 (throughputLambda[0], throughputLambda[-1],
434 throughputLambda[1] - throughputLambda[0]))
437 for i, physicalFilter
in enumerate(self.config.physicalFilters):
439 tDict[
'LAMBDA'] = throughputLambda
440 for ccdIndex, detector
in enumerate(camera):
442 throughputDict[physicalFilter] = tDict
448 self.log.info(
"Making LUT")
455 physicalFilterString = comma.join(self.config.physicalFilters)
458 atmosphereTableName =
'NoTableWasUsed'
459 if self.config.atmosphereTableName
is not None:
460 atmosphereTableName = self.config.atmosphereTableName
462 lutSchema = self.
_makeLutSchema(physicalFilterString, stdPhysicalFilterString,
465 lutCat = self.
_makeLutCat(lutSchema, physicalFilterString,
466 stdPhysicalFilterString, atmosphereTableName)
468 atmStd = TransmissionCurve.makeSpatiallyConstant(
469 throughput=self.
fgcmLutMaker.atmStdTrans.astype(np.float64),
470 wavelengths=self.
fgcmLutMaker.atmLambda.astype(np.float64),
475 fgcmStandardPassbands = {}
476 for i, physical_filter
in enumerate(self.
fgcmLutMaker.filterNames):
478 fgcmStandardPassbands[physical_filter] = TransmissionCurve.makeSpatiallyConstant(
479 throughput=passband.astype(np.float64),
480 wavelengths=self.
fgcmLutMaker.atmLambda.astype(np.float64),
481 throughputAtMin=passband[0],
482 throughputAtMax=passband[-1],
485 retStruct = pipeBase.Struct(
486 fgcmLookUpTable=lutCat,
487 fgcmStandardAtmosphere=atmStd,
488 fgcmStandardPassbands=fgcmStandardPassbands,
507 Create the fgcmLut config dictionary
512 Number of CCDs in the camera
517 lutConfig[
'logger'] = self.log
518 lutConfig[
'filterNames'] = self.config.physicalFilters
520 lutConfig[
'nCCD'] = nCcd
523 if self.config.atmosphereTableName
is not None:
524 lutConfig[
'atmosphereTableName'] = self.config.atmosphereTableName
527 lutConfig[
'elevation'] = self.config.parameters.elevation
528 lutConfig[
'pmbRange'] = self.config.parameters.pmbRange
529 lutConfig[
'pmbSteps'] = self.config.parameters.pmbSteps
530 lutConfig[
'pwvRange'] = self.config.parameters.pwvRange
531 lutConfig[
'pwvSteps'] = self.config.parameters.pwvSteps
532 lutConfig[
'o3Range'] = self.config.parameters.o3Range
533 lutConfig[
'o3Steps'] = self.config.parameters.o3Steps
534 lutConfig[
'tauRange'] = self.config.parameters.tauRange
535 lutConfig[
'tauSteps'] = self.config.parameters.tauSteps
536 lutConfig[
'alphaRange'] = self.config.parameters.alphaRange
537 lutConfig[
'alphaSteps'] = self.config.parameters.alphaSteps
538 lutConfig[
'zenithRange'] = self.config.parameters.zenithRange
539 lutConfig[
'zenithSteps'] = self.config.parameters.zenithSteps
540 lutConfig[
'pmbStd'] = self.config.parameters.pmbStd
541 lutConfig[
'pwvStd'] = self.config.parameters.pwvStd
542 lutConfig[
'o3Std'] = self.config.parameters.o3Std
543 lutConfig[
'tauStd'] = self.config.parameters.tauStd
544 lutConfig[
'alphaStd'] = self.config.parameters.alphaStd
545 lutConfig[
'airmassStd'] = self.config.parameters.airmassStd
546 lutConfig[
'lambdaRange'] = self.config.parameters.lambdaRange
547 lutConfig[
'lambdaStep'] = self.config.parameters.lambdaStep
548 lutConfig[
'lambdaNorm'] = self.config.parameters.lambdaNorm
552 if self.config.sensorCorrectionTermDict:
553 lutConfig[
'sensorCTerms'] = {}
554 for key, value
in self.config.sensorCorrectionTermDict.items():
555 lutConfig[
'sensorCTerms'][key] = (
557 dict(value.correctionTermDict),
563 """Internal method to load throughput data for filters
567 camera: `lsst.afw.cameraGeom.Camera`
568 Camera from the butler
569 opticsHandle : `lsst.daf.butler.DeferredDatasetHandle`
570 Reference to optics transmission curve.
571 sensorHandleDict : `dict` of [`int`, `lsst.daf.butler.DeferredDatasetHandle`]
572 Dictionary of references to sensor transmission curves. Key will
574 filterHandleDict : `dict` of [`str`, `lsst.daf.butler.DeferredDatasetHandle`]
575 Dictionary of references to filter transmission curves. Key will
576 be physical filter label.
580 ValueError : Raised if configured filter name does not match any of the
581 available filter transmission curves.
583 if self.config.doOpticsTransmission:
587 throughput=np.ones(100),
588 wavelengths=np.linspace(
589 self.config.parameters.lambdaRange[0],
590 self.config.parameters.lambdaRange[1],
598 for detector
in camera:
599 if self.config.doSensorTransmission:
603 throughput=np.ones(100),
604 wavelengths=np.linspace(
605 self.config.parameters.lambdaRange[0],
606 self.config.parameters.lambdaRange[1],
614 for physicalFilter
in self.config.physicalFilters:
618 """Internal method to get throughput for a detector.
620 Returns the throughput at the center of the detector for a given filter.
624 detector: `lsst.afw.cameraGeom._detector.Detector`
626 physicalFilter: `str`
627 Physical filter label
628 throughputLambda: `np.array(dtype=np.float64)`
629 Wavelength steps (Angstrom)
633 throughput: `np.array(dtype=np.float64)`
634 Throughput (max 1.0) at throughputLambda
637 c = detector.getCenter(afwCameraGeom.FOCAL_PLANE)
638 c.scale(1.0/detector.getPixelSize()[0])
641 wavelengths=throughputLambda)
644 wavelengths=throughputLambda)
647 wavelengths=throughputLambda)
650 throughput = np.clip(throughput, 0.0, 1.0)
655 atmosphereTableName):
661 physicalFilterString: `str`
662 Combined string of all the physicalFilters
663 stdPhysicalFilterString: `str`
664 Combined string of all the standard physicalFilters
665 atmosphereTableName: `str`
666 Name of the atmosphere table used to generate LUT
670 lutSchema: `afwTable.schema`
673 lutSchema = afwTable.Schema()
675 lutSchema.addField(
'tablename', type=str, doc=
'Atmosphere table name',
676 size=len(atmosphereTableName))
677 lutSchema.addField(
'elevation', type=float, doc=
"Telescope elevation used for LUT")
678 lutSchema.addField(
'physicalFilters', type=str, doc=
'physicalFilters in LUT',
679 size=len(physicalFilterString))
680 lutSchema.addField(
'stdPhysicalFilters', type=str, doc=
'Standard physicalFilters in LUT',
681 size=len(stdPhysicalFilterString))
682 lutSchema.addField(
'pmb', type=
'ArrayD', doc=
'Barometric Pressure',
684 lutSchema.addField(
'pmbFactor', type=
'ArrayD', doc=
'PMB scaling factor',
686 lutSchema.addField(
'pmbElevation', type=np.float64, doc=
'PMB Scaling at elevation')
687 lutSchema.addField(
'pwv', type=
'ArrayD', doc=
'Preciptable Water Vapor',
689 lutSchema.addField(
'o3', type=
'ArrayD', doc=
'Ozone',
691 lutSchema.addField(
'tau', type=
'ArrayD', doc=
'Aerosol optical depth',
693 lutSchema.addField(
'lambdaNorm', type=np.float64, doc=
'AOD wavelength')
694 lutSchema.addField(
'alpha', type=
'ArrayD', doc=
'Aerosol alpha',
696 lutSchema.addField(
'zenith', type=
'ArrayD', doc=
'Zenith angle',
698 lutSchema.addField(
'nCcd', type=np.int32, doc=
'Number of CCDs')
701 lutSchema.addField(
'pmbStd', type=np.float64, doc=
'PMB Standard')
702 lutSchema.addField(
'pwvStd', type=np.float64, doc=
'PWV Standard')
703 lutSchema.addField(
'o3Std', type=np.float64, doc=
'O3 Standard')
704 lutSchema.addField(
'tauStd', type=np.float64, doc=
'Tau Standard')
705 lutSchema.addField(
'alphaStd', type=np.float64, doc=
'Alpha Standard')
706 lutSchema.addField(
'zenithStd', type=np.float64, doc=
'Zenith angle Standard')
707 lutSchema.addField(
'lambdaRange', type=
'ArrayD', doc=
'Wavelength range',
709 lutSchema.addField(
'lambdaStep', type=np.float64, doc=
'Wavelength step')
710 lutSchema.addField(
'lambdaStd', type=
'ArrayD', doc=
'Standard Wavelength',
712 lutSchema.addField(
'lambdaStdFilter', type=
'ArrayD', doc=
'Standard Wavelength (raw)',
714 lutSchema.addField(
'i0Std', type=
'ArrayD', doc=
'I0 Standard',
716 lutSchema.addField(
'i1Std', type=
'ArrayD', doc=
'I1 Standard',
718 lutSchema.addField(
'i10Std', type=
'ArrayD', doc=
'I10 Standard',
720 lutSchema.addField(
'i2Std', type=
'ArrayD', doc=
'I2 Standard',
722 lutSchema.addField(
'lambdaB', type=
'ArrayD', doc=
'Wavelength for passband (no atm)',
724 lutSchema.addField(
'atmLambda', type=
'ArrayD', doc=
'Atmosphere wavelengths (Angstrom)',
726 lutSchema.addField(
'atmStdTrans', type=
'ArrayD', doc=
'Standard Atmosphere Throughput',
730 lutSchema.addField(
'luttype', type=str, size=20, doc=
'Look-up table type')
731 lutSchema.addField(
'lut', type=
'ArrayF', doc=
'Look-up table for luttype',
736 def _makeLutCat(self, lutSchema, physicalFilterString, stdPhysicalFilterString,
737 atmosphereTableName):
743 lutSchema: `afwTable.schema`
745 physicalFilterString: `str`
746 Combined string of all the physicalFilters
747 stdPhysicalFilterString: `str`
748 Combined string of all the standard physicalFilters
749 atmosphereTableName: `str`
750 Name of the atmosphere table used to generate LUT
754 lutCat: `afwTable.BaseCatalog`
755 Look-up table catalog for persistence.
762 lutCat = afwTable.BaseCatalog(lutSchema)
763 lutCat.table.preallocate(14)
766 rec = lutCat.addNew()
768 rec[
'tablename'] = atmosphereTableName
769 rec[
'elevation'] = self.
fgcmLutMaker.atmosphereTable.elevation
770 rec[
'physicalFilters'] = physicalFilterString
771 rec[
'stdPhysicalFilters'] = stdPhysicalFilterString
792 rec[
'lambdaStdFilter'][:] = self.
fgcmLutMaker.lambdaStdFilter
801 rec[
'luttype'] =
'I0'
805 rec = lutCat.addNew()
806 rec[
'luttype'] =
'I1'
809 derivTypes = [
'D_PMB',
'D_LNPWV',
'D_O3',
'D_LNTAU',
'D_ALPHA',
'D_SECZENITH',
810 'D_PMB_I1',
'D_LNPWV_I1',
'D_O3_I1',
'D_LNTAU_I1',
'D_ALPHA_I1',
812 for derivType
in derivTypes:
813 rec = lutCat.addNew()
814 rec[
'luttype'] = derivType
815 rec[
'lut'][:] = self.
fgcmLutMaker.lutDeriv[derivType].flatten()