23 """Make a look-up-table (LUT) for FGCM calibration.
25 This task computes a look-up-table for the range in expected atmosphere
26 variation and variation in instrumental throughput (as tracked by the
27 transmission_filter products). By pre-computing linearized integrals,
28 the FGCM fit is orders of magnitude faster for stars with a broad range
29 of colors and observing bands, yielding precision at the 1-2 mmag level.
31 Computing a LUT requires running MODTRAN or with a pre-generated
32 atmosphere table packaged with fgcm.
46 from .utilities
import lookupStaticCalibrations
50 __all__ = [
'FgcmMakeLutParametersConfig',
'FgcmMakeLutConfig',
'FgcmMakeLutTask',
55 dimensions=(
'instrument',),
57 camera = connectionTypes.PrerequisiteInput(
58 doc=
"Camera instrument",
60 storageClass=
"Camera",
61 dimensions=(
"instrument",),
62 lookupFunction=lookupStaticCalibrations,
66 transmission_optics = connectionTypes.PrerequisiteInput(
67 doc=
"Optics transmission curve information",
68 name=
"transmission_optics",
69 storageClass=
"TransmissionCurve",
70 dimensions=(
"instrument",),
71 lookupFunction=lookupStaticCalibrations,
76 transmission_sensor = connectionTypes.PrerequisiteInput(
77 doc=
"Sensor transmission curve information",
78 name=
"transmission_sensor",
79 storageClass=
"TransmissionCurve",
80 dimensions=(
"instrument",
"detector",),
81 lookupFunction=lookupStaticCalibrations,
87 transmission_filter = connectionTypes.PrerequisiteInput(
88 doc=
"Filter transmission curve information",
89 name=
"transmission_filter",
90 storageClass=
"TransmissionCurve",
91 dimensions=(
"band",
"instrument",
"physical_filter",),
92 lookupFunction=lookupStaticCalibrations,
98 fgcmLookUpTable = connectionTypes.Output(
99 doc=(
"Atmosphere + instrument look-up-table for FGCM throughput and "
100 "chromatic corrections."),
101 name=
"fgcmLookUpTable",
102 storageClass=
"Catalog",
103 dimensions=(
"instrument",),
108 """Config for parameters if atmosphereTableName not available"""
111 elevation = pexConfig.Field(
112 doc=
"Telescope elevation (m)",
116 pmbRange = pexConfig.ListField(
117 doc=(
"Barometric Pressure range (millibar) "
118 "Recommended range depends on the site."),
122 pmbSteps = pexConfig.Field(
123 doc=
"Barometric Pressure number of steps",
127 pwvRange = pexConfig.ListField(
128 doc=(
"Precipitable Water Vapor range (mm) "
129 "Recommended range depends on the site."),
133 pwvSteps = pexConfig.Field(
134 doc=
"Precipitable Water Vapor number of steps",
138 o3Range = pexConfig.ListField(
139 doc=
"Ozone range (dob)",
141 default=[220.0, 310.0],
143 o3Steps = pexConfig.Field(
144 doc=
"Ozone number of steps",
148 tauRange = pexConfig.ListField(
149 doc=
"Aerosol Optical Depth range (unitless)",
151 default=[0.002, 0.35],
153 tauSteps = pexConfig.Field(
154 doc=
"Aerosol Optical Depth number of steps",
158 alphaRange = pexConfig.ListField(
159 doc=
"Aerosol alpha range (unitless)",
163 alphaSteps = pexConfig.Field(
164 doc=
"Aerosol alpha number of steps",
168 zenithRange = pexConfig.ListField(
169 doc=
"Zenith angle range (degree)",
173 zenithSteps = pexConfig.Field(
174 doc=
"Zenith angle number of steps",
180 pmbStd = pexConfig.Field(
181 doc=(
"Standard Atmosphere pressure (millibar); "
182 "Recommended default depends on the site."),
186 pwvStd = pexConfig.Field(
187 doc=(
"Standard Atmosphere PWV (mm); "
188 "Recommended default depends on the site."),
192 o3Std = pexConfig.Field(
193 doc=
"Standard Atmosphere O3 (dob)",
197 tauStd = pexConfig.Field(
198 doc=
"Standard Atmosphere aerosol optical depth",
202 alphaStd = pexConfig.Field(
203 doc=
"Standard Atmosphere aerosol alpha",
207 airmassStd = pexConfig.Field(
208 doc=(
"Standard Atmosphere airmass; "
209 "Recommended default depends on the survey strategy."),
213 lambdaNorm = pexConfig.Field(
214 doc=
"Aerosol Optical Depth normalization wavelength (Angstrom)",
218 lambdaStep = pexConfig.Field(
219 doc=
"Wavelength step for generating atmospheres (nm)",
223 lambdaRange = pexConfig.ListField(
224 doc=
"Wavelength range for LUT (Angstrom)",
226 default=[3000.0, 11000.0],
231 pipelineConnections=FgcmMakeLutConnections):
232 """Config for FgcmMakeLutTask"""
234 filterNames = pexConfig.ListField(
235 doc=
"Filter names to build LUT ('short' names)",
238 deprecated=(
"This field is no longer used, and has been deprecated by "
239 "DM-28088. It will be removed after v22. Use "
240 "stdPhysicalFilterMap instead.")
242 stdFilterNames = pexConfig.ListField(
243 doc=(
"Standard filterNames ('short' names). "
244 "Each filter in filterName will be calibrated to a matched "
245 "stdFilterName. In regular usage, one has g->g, r->r, ... "
246 "In the case of HSC, one would have g->g, r->r2, r2->r2, ... "
247 "which allows replacement (or time-variable) filters to be "
248 "properly cross-calibrated."),
251 deprecated=(
"This field is no longer used, and has been deprecated by "
252 "DM-28088. It will be removed after v22. Use "
253 "stdPhysicalFilterMap instead.")
255 physicalFilters = pexConfig.ListField(
256 doc=
"List of physicalFilter labels to generate look-up table.",
260 stdPhysicalFilterOverrideMap = pexConfig.DictField(
261 doc=(
"Override mapping from physical filter labels to 'standard' physical "
262 "filter labels. The 'standard' physical filter defines the transmission "
263 "curve that the FGCM standard bandpass will be based on. "
264 "Any filter not listed here will be mapped to "
265 "itself (e.g. g->g or HSC-G->HSC-G). Use this override for cross-"
266 "filter calibration such as HSC-R->HSC-R2 and HSC-I->HSC-I2."),
271 atmosphereTableName = pexConfig.Field(
272 doc=
"FGCM name or filename of precomputed atmospheres",
277 parameters = pexConfig.ConfigField(
278 doc=
"Atmosphere parameters (required if no atmosphereTableName)",
279 dtype=FgcmMakeLutParametersConfig,
285 Validate the config parameters.
287 This method behaves differently from the parent validate in the case
288 that atmosphereTableName is set. In this case, the config values
289 for standard values, step sizes, and ranges are loaded
290 directly from the specified atmosphereTableName.
293 self._fields[
'physicalFilters'].
validate(self)
294 self._fields[
'stdPhysicalFilterOverrideMap'].
validate(self)
298 self._fields[
'parameters'].
validate(self)
302 """Subclass of TaskRunner for fgcmMakeLutTask
304 fgcmMakeLutTask.run() takes one argument, the butler, and
305 does not run on any data in the repository.
306 This runner does not use any parallelization.
312 Return a list with one element, the butler.
314 return [parsedCmd.butler]
320 butler: `lsst.daf.persistence.Butler`
324 exitStatus: `list` with `pipeBase.Struct`
325 exitStatus (0: success; 1: failure)
327 task = self.TaskClass(config=self.config, log=self.log)
331 task.runDataRef(butler)
334 task.runDataRef(butler)
335 except Exception
as e:
337 task.log.fatal(
"Failed: %s" % e)
338 if not isinstance(e, pipeBase.TaskError):
339 traceback.print_exc(file=sys.stderr)
341 task.writeMetadata(butler)
344 return [pipeBase.Struct(exitStatus=exitStatus)]
348 Run the task, with no multiprocessing
352 parsedCmd: ArgumentParser parsed command line
357 if self.precall(parsedCmd):
360 resultList = self(targetList[0])
367 Make Look-Up Table for FGCM.
369 This task computes a look-up-table for the range in expected atmosphere
370 variation and variation in instrumental throughput (as tracked by the
371 transmission_filter products). By pre-computing linearized integrals,
372 the FGCM fit is orders of magnitude faster for stars with a broad range
373 of colors and observing bands, yielding precision at the 1-2 mmag level.
375 Computing a LUT requires running MODTRAN or with a pre-generated
376 atmosphere table packaged with fgcm.
379 ConfigClass = FgcmMakeLutConfig
380 RunnerClass = FgcmMakeLutRunner
381 _DefaultName =
"fgcmMakeLut"
383 def __init__(self, butler=None, initInputs=None, **kwargs):
387 def _getMetadataName(self):
393 Make a Look-Up Table for FGCM
397 butler: `lsst.daf.persistence.Butler`
401 ValueError : Raised if configured filter name does not match any of the
402 available filter transmission curves.
404 camera = butler.get(
'camera')
405 opticsDataRef = butler.dataRef(
'transmission_optics')
407 sensorDataRefDict = {}
408 for detector
in camera:
409 sensorDataRefDict[detector.getId()] = butler.dataRef(
'transmission_sensor',
410 dataId={
'ccd': detector.getId()})
412 filterDataRefDict = {}
413 for physicalFilter
in self.config.physicalFilters:
417 dataRef = butler.dataRef(
'transmission_filter', filter=physicalFilter)
418 if not dataRef.datasetExists():
419 raise ValueError(f
"Could not find transmission for filter {physicalFilter}.")
420 filterDataRefDict[physicalFilter] = dataRef
426 butler.put(lutCat,
'fgcmLookUpTable')
429 camera = butlerQC.get(inputRefs.camera)
432 _ = Instrument.fromName(inputRefs.camera.dataId[
'instrument'],
434 opticsDataRef = butlerQC.get(inputRefs.transmission_optics)
436 sensorRefs = butlerQC.get(inputRefs.transmission_sensor)
437 sensorDataRefDict = {sensorRef.dataId.byName()[
'detector']: sensorRef
for
438 sensorRef
in sensorRefs}
440 filterRefs = butlerQC.get(inputRefs.transmission_filter)
441 filterDataRefDict = {filterRef.dataId[
'physical_filter']: filterRef
for
442 filterRef
in filterRefs}
448 butlerQC.put(lutCat, outputRefs.fgcmLookUpTable)
450 def _fgcmMakeLut(self, camera, opticsDataRef, sensorDataRefDict,
453 Make a FGCM Look-up Table
457 camera : `lsst.afw.cameraGeom.Camera`
458 Camera from the butler.
459 opticsDataRef : `lsst.daf.persistence.ButlerDataRef` or
460 `lsst.daf.butler.DeferredDatasetHandle`
461 Reference to optics transmission curve.
462 sensorDataRefDict : `dict` of [`int`, `lsst.daf.persistence.ButlerDataRef` or
463 `lsst.daf.butler.DeferredDatasetHandle`]
464 Dictionary of references to sensor transmission curves. Key will
466 filterDataRefDict : `dict` of [`str`, `lsst.daf.persistence.ButlerDataRef` or
467 `lsst.daf.butler.DeferredDatasetHandle`]
468 Dictionary of references to filter transmission curves. Key will
469 be physical filter label.
473 fgcmLookUpTable : `BaseCatalog`
474 The FGCM look-up table.
478 self.log.
info(
"Found %d ccds for look-up table" % (nCcd))
489 self.log.
info(
"Making the LUT maker object")
497 throughputLambda = np.arange(self.
fgcmLutMakerfgcmLutMaker.lambdaRange[0],
501 self.log.
info(
"Built throughput lambda, %.1f-%.1f, step %.2f" %
502 (throughputLambda[0], throughputLambda[-1],
503 throughputLambda[1] - throughputLambda[0]))
506 for i, physicalFilter
in enumerate(self.config.physicalFilters):
508 tDict[
'LAMBDA'] = throughputLambda
509 for ccdIndex, detector
in enumerate(camera):
510 tDict[ccdIndex] = self.
_getThroughputDetector_getThroughputDetector(detector, physicalFilter, throughputLambda)
511 throughputDict[physicalFilter] = tDict
514 self.
fgcmLutMakerfgcmLutMaker.setThroughputs(throughputDict)
517 self.log.
info(
"Making LUT")
524 physicalFilterString = comma.join(self.config.physicalFilters)
527 atmosphereTableName =
'NoTableWasUsed'
528 if self.config.atmosphereTableName
is not None:
529 atmosphereTableName = self.config.atmosphereTableName
531 lutSchema = self.
_makeLutSchema_makeLutSchema(physicalFilterString, stdPhysicalFilterString,
534 lutCat = self.
_makeLutCat_makeLutCat(lutSchema, physicalFilterString,
535 stdPhysicalFilterString, atmosphereTableName)
538 def _getStdPhysicalFilterList(self):
539 """Get the standard physical filter lists from config.physicalFilters
540 and config.stdPhysicalFilterOverrideMap
544 stdPhysicalFilters : `list`
546 override = self.config.stdPhysicalFilterOverrideMap
547 return [override.get(physicalFilter, physicalFilter)
for
548 physicalFilter
in self.config.physicalFilters]
550 def _createLutConfig(self, nCcd):
552 Create the fgcmLut config dictionary
557 Number of CCDs in the camera
562 lutConfig[
'logger'] = self.log
563 lutConfig[
'filterNames'] = self.config.physicalFilters
565 lutConfig[
'nCCD'] = nCcd
568 if self.config.atmosphereTableName
is not None:
569 lutConfig[
'atmosphereTableName'] = self.config.atmosphereTableName
572 lutConfig[
'elevation'] = self.config.parameters.elevation
573 lutConfig[
'pmbRange'] = self.config.parameters.pmbRange
574 lutConfig[
'pmbSteps'] = self.config.parameters.pmbSteps
575 lutConfig[
'pwvRange'] = self.config.parameters.pwvRange
576 lutConfig[
'pwvSteps'] = self.config.parameters.pwvSteps
577 lutConfig[
'o3Range'] = self.config.parameters.o3Range
578 lutConfig[
'o3Steps'] = self.config.parameters.o3Steps
579 lutConfig[
'tauRange'] = self.config.parameters.tauRange
580 lutConfig[
'tauSteps'] = self.config.parameters.tauSteps
581 lutConfig[
'alphaRange'] = self.config.parameters.alphaRange
582 lutConfig[
'alphaSteps'] = self.config.parameters.alphaSteps
583 lutConfig[
'zenithRange'] = self.config.parameters.zenithRange
584 lutConfig[
'zenithSteps'] = self.config.parameters.zenithSteps
585 lutConfig[
'pmbStd'] = self.config.parameters.pmbStd
586 lutConfig[
'pwvStd'] = self.config.parameters.pwvStd
587 lutConfig[
'o3Std'] = self.config.parameters.o3Std
588 lutConfig[
'tauStd'] = self.config.parameters.tauStd
589 lutConfig[
'alphaStd'] = self.config.parameters.alphaStd
590 lutConfig[
'airmassStd'] = self.config.parameters.airmassStd
591 lutConfig[
'lambdaRange'] = self.config.parameters.lambdaRange
592 lutConfig[
'lambdaStep'] = self.config.parameters.lambdaStep
593 lutConfig[
'lambdaNorm'] = self.config.parameters.lambdaNorm
597 def _loadThroughputs(self, camera, opticsDataRef, sensorDataRefDict, filterDataRefDict):
598 """Internal method to load throughput data for filters
602 camera: `lsst.afw.cameraGeom.Camera`
603 Camera from the butler
604 opticsDataRef : `lsst.daf.persistence.ButlerDataRef` or
605 `lsst.daf.butler.DeferredDatasetHandle`
606 Reference to optics transmission curve.
607 sensorDataRefDict : `dict` of [`int`, `lsst.daf.persistence.ButlerDataRef` or
608 `lsst.daf.butler.DeferredDatasetHandle`]
609 Dictionary of references to sensor transmission curves. Key will
611 filterDataRefDict : `dict` of [`str`, `lsst.daf.persistence.ButlerDataRef` or
612 `lsst.daf.butler.DeferredDatasetHandle`]
613 Dictionary of references to filter transmission curves. Key will
614 be physical filter label.
618 ValueError : Raised if configured filter name does not match any of the
619 available filter transmission curves.
624 for detector
in camera:
625 self.
_sensorsTransmission_sensorsTransmission[detector.getId()] = sensorDataRefDict[detector.getId()].get()
628 for physicalFilter
in self.config.physicalFilters:
629 self.
_filtersTransmission_filtersTransmission[physicalFilter] = filterDataRefDict[physicalFilter].get()
631 def _getThroughputDetector(self, detector, physicalFilter, throughputLambda):
632 """Internal method to get throughput for a detector.
634 Returns the throughput at the center of the detector for a given filter.
638 detector: `lsst.afw.cameraGeom._detector.Detector`
640 physicalFilter: `str`
641 Physical filter label
642 throughputLambda: `np.array(dtype=np.float64)`
643 Wavelength steps (Angstrom)
647 throughput: `np.array(dtype=np.float64)`
648 Throughput (max 1.0) at throughputLambda
651 c = detector.getCenter(afwCameraGeom.FOCAL_PLANE)
652 c.scale(1.0/detector.getPixelSize()[0])
655 wavelengths=throughputLambda)
657 throughput *= self.
_sensorsTransmission_sensorsTransmission[detector.getId()].sampleAt(position=c,
658 wavelengths=throughputLambda)
660 throughput *= self.
_filtersTransmission_filtersTransmission[physicalFilter].sampleAt(position=c,
661 wavelengths=throughputLambda)
664 throughput = np.clip(throughput, 0.0, 1.0)
668 def _makeLutSchema(self, physicalFilterString, stdPhysicalFilterString,
669 atmosphereTableName):
675 physicalFilterString: `str`
676 Combined string of all the physicalFilters
677 stdPhysicalFilterString: `str`
678 Combined string of all the standard physicalFilters
679 atmosphereTableName: `str`
680 Name of the atmosphere table used to generate LUT
684 lutSchema: `afwTable.schema`
689 lutSchema.addField(
'tablename', type=str, doc=
'Atmosphere table name',
690 size=len(atmosphereTableName))
691 lutSchema.addField(
'elevation', type=float, doc=
"Telescope elevation used for LUT")
692 lutSchema.addField(
'physicalFilters', type=str, doc=
'physicalFilters in LUT',
693 size=len(physicalFilterString))
694 lutSchema.addField(
'stdPhysicalFilters', type=str, doc=
'Standard physicalFilters in LUT',
695 size=len(stdPhysicalFilterString))
696 lutSchema.addField(
'pmb', type=
'ArrayD', doc=
'Barometric Pressure',
698 lutSchema.addField(
'pmbFactor', type=
'ArrayD', doc=
'PMB scaling factor',
700 lutSchema.addField(
'pmbElevation', type=np.float64, doc=
'PMB Scaling at elevation')
701 lutSchema.addField(
'pwv', type=
'ArrayD', doc=
'Preciptable Water Vapor',
703 lutSchema.addField(
'o3', type=
'ArrayD', doc=
'Ozone',
705 lutSchema.addField(
'tau', type=
'ArrayD', doc=
'Aerosol optical depth',
707 lutSchema.addField(
'lambdaNorm', type=np.float64, doc=
'AOD wavelength')
708 lutSchema.addField(
'alpha', type=
'ArrayD', doc=
'Aerosol alpha',
710 lutSchema.addField(
'zenith', type=
'ArrayD', doc=
'Zenith angle',
712 lutSchema.addField(
'nCcd', type=np.int32, doc=
'Number of CCDs')
715 lutSchema.addField(
'pmbStd', type=np.float64, doc=
'PMB Standard')
716 lutSchema.addField(
'pwvStd', type=np.float64, doc=
'PWV Standard')
717 lutSchema.addField(
'o3Std', type=np.float64, doc=
'O3 Standard')
718 lutSchema.addField(
'tauStd', type=np.float64, doc=
'Tau Standard')
719 lutSchema.addField(
'alphaStd', type=np.float64, doc=
'Alpha Standard')
720 lutSchema.addField(
'zenithStd', type=np.float64, doc=
'Zenith angle Standard')
721 lutSchema.addField(
'lambdaRange', type=
'ArrayD', doc=
'Wavelength range',
723 lutSchema.addField(
'lambdaStep', type=np.float64, doc=
'Wavelength step')
724 lutSchema.addField(
'lambdaStd', type=
'ArrayD', doc=
'Standard Wavelength',
726 lutSchema.addField(
'lambdaStdFilter', type=
'ArrayD', doc=
'Standard Wavelength (raw)',
728 lutSchema.addField(
'i0Std', type=
'ArrayD', doc=
'I0 Standard',
730 lutSchema.addField(
'i1Std', type=
'ArrayD', doc=
'I1 Standard',
732 lutSchema.addField(
'i10Std', type=
'ArrayD', doc=
'I10 Standard',
734 lutSchema.addField(
'i2Std', type=
'ArrayD', doc=
'I2 Standard',
736 lutSchema.addField(
'lambdaB', type=
'ArrayD', doc=
'Wavelength for passband (no atm)',
738 lutSchema.addField(
'atmLambda', type=
'ArrayD', doc=
'Atmosphere wavelengths (Angstrom)',
740 lutSchema.addField(
'atmStdTrans', type=
'ArrayD', doc=
'Standard Atmosphere Throughput',
744 lutSchema.addField(
'luttype', type=str, size=20, doc=
'Look-up table type')
745 lutSchema.addField(
'lut', type=
'ArrayF', doc=
'Look-up table for luttype',
750 def _makeLutCat(self, lutSchema, physicalFilterString, stdPhysicalFilterString,
751 atmosphereTableName):
757 lutSchema: `afwTable.schema`
759 physicalFilterString: `str`
760 Combined string of all the physicalFilters
761 stdPhysicalFilterString: `str`
762 Combined string of all the standard physicalFilters
763 atmosphereTableName: `str`
764 Name of the atmosphere table used to generate LUT
768 lutCat: `afwTable.BaseCatalog`
769 Lut catalog for persistence
777 lutCat.table.preallocate(14)
780 rec = lutCat.addNew()
782 rec[
'tablename'] = atmosphereTableName
783 rec[
'elevation'] = self.
fgcmLutMakerfgcmLutMaker.atmosphereTable.elevation
784 rec[
'physicalFilters'] = physicalFilterString
785 rec[
'stdPhysicalFilters'] = stdPhysicalFilterString
787 rec[
'pmbFactor'][:] = self.
fgcmLutMakerfgcmLutMaker.pmbFactor
788 rec[
'pmbElevation'] = self.
fgcmLutMakerfgcmLutMaker.pmbElevation
792 rec[
'lambdaNorm'] = self.
fgcmLutMakerfgcmLutMaker.lambdaNorm
801 rec[
'alphaStd'] = self.
fgcmLutMakerfgcmLutMaker.alphaStd
802 rec[
'zenithStd'] = self.
fgcmLutMakerfgcmLutMaker.zenithStd
803 rec[
'lambdaRange'][:] = self.
fgcmLutMakerfgcmLutMaker.lambdaRange
804 rec[
'lambdaStep'] = self.
fgcmLutMakerfgcmLutMaker.lambdaStep
805 rec[
'lambdaStd'][:] = self.
fgcmLutMakerfgcmLutMaker.lambdaStd
806 rec[
'lambdaStdFilter'][:] = self.
fgcmLutMakerfgcmLutMaker.lambdaStdFilter
811 rec[
'lambdaB'][:] = self.
fgcmLutMakerfgcmLutMaker.lambdaB
812 rec[
'atmLambda'][:] = self.
fgcmLutMakerfgcmLutMaker.atmLambda
813 rec[
'atmStdTrans'][:] = self.
fgcmLutMakerfgcmLutMaker.atmStdTrans
815 rec[
'luttype'] =
'I0'
816 rec[
'lut'][:] = self.
fgcmLutMakerfgcmLutMaker.lut[
'I0'].flatten()
819 rec = lutCat.addNew()
820 rec[
'luttype'] =
'I1'
821 rec[
'lut'][:] = self.
fgcmLutMakerfgcmLutMaker.lut[
'I1'].flatten()
823 derivTypes = [
'D_PMB',
'D_LNPWV',
'D_O3',
'D_LNTAU',
'D_ALPHA',
'D_SECZENITH',
824 'D_PMB_I1',
'D_LNPWV_I1',
'D_O3_I1',
'D_LNTAU_I1',
'D_ALPHA_I1',
826 for derivType
in derivTypes:
827 rec = lutCat.addNew()
828 rec[
'luttype'] = derivType
829 rec[
'lut'][:] = self.
fgcmLutMakerfgcmLutMaker.lutDeriv[derivType].flatten()
Defines the fields and offsets for a table.
def getTargetList(parsedCmd)
def __call__(self, butler)
def _makeLutCat(self, lutSchema, physicalFilterString, stdPhysicalFilterString, atmosphereTableName)
def _getStdPhysicalFilterList(self)
def _createLutConfig(self, nCcd)
def runDataRef(self, butler)
def _fgcmMakeLut(self, camera, opticsDataRef, sensorDataRefDict, filterDataRefDict)
def _makeLutSchema(self, physicalFilterString, stdPhysicalFilterString, atmosphereTableName)
def _getThroughputDetector(self, detector, physicalFilter, throughputLambda)
def runQuantum(self, butlerQC, inputRefs, outputRefs)
def _loadThroughputs(self, camera, opticsDataRef, sensorDataRefDict, filterDataRefDict)
def __init__(self, butler=None, initInputs=None, **kwargs)