Coverage for python/lsst/fgcmcal/fgcmMakeLut.py : 21%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# See COPYRIGHT file at the top of the source tree.
2#
3# This file is part of fgcmcal.
4#
5# Developed for the LSST Data Management System.
6# This product includes software developed by the LSST Project
7# (https://www.lsst.org).
8# See the COPYRIGHT file at the top-level directory of this distribution
9# for details of code ownership.
10#
11# This program is free software: you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation, either version 3 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program. If not, see <https://www.gnu.org/licenses/>.
23"""Make a look-up-table (LUT) for FGCM calibration.
25This task computes a look-up-table for the range in expected atmosphere
26variation and variation in instrumental throughput (as tracked by the
27transmission_filter products). By pre-computing linearized integrals,
28the FGCM fit is orders of magnitude faster for stars with a broad range
29of colors and observing bands, yielding precision at the 1-2 mmag level.
31Computing a LUT requires running MODTRAN or with a pre-generated
32atmosphere table packaged with fgcm.
33"""
35import sys
36import traceback
38import numpy as np
40import lsst.pex.config as pexConfig
41import lsst.pipe.base as pipeBase
42import lsst.afw.table as afwTable
43import lsst.afw.cameraGeom as afwCameraGeom
44from lsst.afw.image import Filter
45from lsst.daf.persistence import NoResults
47import fgcm
49__all__ = ['FgcmMakeLutParametersConfig', 'FgcmMakeLutConfig', 'FgcmMakeLutTask',
50 'FgcmMakeLutRunner']
53class FgcmMakeLutParametersConfig(pexConfig.Config):
54 """Config for parameters if atmosphereTableName not available"""
55 # TODO: When DM-16511 is done, it will be possible to get the
56 # telescope elevation directly from the camera.
57 elevation = pexConfig.Field(
58 doc="Telescope elevation (m)",
59 dtype=float,
60 default=None,
61 )
62 pmbRange = pexConfig.ListField(
63 doc=("Barometric Pressure range (millibar) "
64 "Recommended range depends on the site."),
65 dtype=float,
66 default=None,
67 )
68 pmbSteps = pexConfig.Field(
69 doc="Barometric Pressure number of steps",
70 dtype=int,
71 default=5,
72 )
73 pwvRange = pexConfig.ListField(
74 doc=("Precipitable Water Vapor range (mm) "
75 "Recommended range depends on the site."),
76 dtype=float,
77 default=None,
78 )
79 pwvSteps = pexConfig.Field(
80 doc="Precipitable Water Vapor number of steps",
81 dtype=int,
82 default=15,
83 )
84 o3Range = pexConfig.ListField(
85 doc="Ozone range (dob)",
86 dtype=float,
87 default=[220.0, 310.0],
88 )
89 o3Steps = pexConfig.Field(
90 doc="Ozone number of steps",
91 dtype=int,
92 default=3,
93 )
94 tauRange = pexConfig.ListField(
95 doc="Aerosol Optical Depth range (unitless)",
96 dtype=float,
97 default=[0.002, 0.35],
98 )
99 tauSteps = pexConfig.Field(
100 doc="Aerosol Optical Depth number of steps",
101 dtype=int,
102 default=11,
103 )
104 alphaRange = pexConfig.ListField(
105 doc="Aerosol alpha range (unitless)",
106 dtype=float,
107 default=[0.0, 2.0],
108 )
109 alphaSteps = pexConfig.Field(
110 doc="Aerosol alpha number of steps",
111 dtype=int,
112 default=9,
113 )
114 zenithRange = pexConfig.ListField(
115 doc="Zenith angle range (degree)",
116 dtype=float,
117 default=[0.0, 70.0],
118 )
119 zenithSteps = pexConfig.Field(
120 doc="Zenith angle number of steps",
121 dtype=int,
122 default=21,
123 )
124 # Note that the standard atmosphere parameters depend on the observatory
125 # and elevation, and so these should be set on a per-camera basis.
126 pmbStd = pexConfig.Field(
127 doc=("Standard Atmosphere pressure (millibar); "
128 "Recommended default depends on the site."),
129 dtype=float,
130 default=None,
131 )
132 pwvStd = pexConfig.Field(
133 doc=("Standard Atmosphere PWV (mm); "
134 "Recommended default depends on the site."),
135 dtype=float,
136 default=None,
137 )
138 o3Std = pexConfig.Field(
139 doc="Standard Atmosphere O3 (dob)",
140 dtype=float,
141 default=263.0,
142 )
143 tauStd = pexConfig.Field(
144 doc="Standard Atmosphere aerosol optical depth",
145 dtype=float,
146 default=0.03,
147 )
148 alphaStd = pexConfig.Field(
149 doc="Standard Atmosphere aerosol alpha",
150 dtype=float,
151 default=1.0,
152 )
153 airmassStd = pexConfig.Field(
154 doc=("Standard Atmosphere airmass; "
155 "Recommended default depends on the survey strategy."),
156 dtype=float,
157 default=None,
158 )
159 lambdaNorm = pexConfig.Field(
160 doc="Aerosol Optical Depth normalization wavelength (Angstrom)",
161 dtype=float,
162 default=7750.0,
163 )
164 lambdaStep = pexConfig.Field(
165 doc="Wavelength step for generating atmospheres (nm)",
166 dtype=float,
167 default=0.5,
168 )
169 lambdaRange = pexConfig.ListField(
170 doc="Wavelength range for LUT (Angstrom)",
171 dtype=float,
172 default=[3000.0, 11000.0],
173 )
176class FgcmMakeLutConfig(pexConfig.Config):
177 """Config for FgcmMakeLutTask"""
179 filterNames = pexConfig.ListField(
180 doc="Filter names to build LUT ('short' names)",
181 dtype=str,
182 default=None,
183 )
184 stdFilterNames = pexConfig.ListField(
185 doc=("Standard filterNames ('short' names). "
186 "Each filter in filterName will be calibrated to a matched "
187 "stdFilterName. In regular usage, one has g->g, r->r, ... "
188 "In the case of HSC, one would have g->g, r->r2, r2->r2, ... "
189 "which allows replacement (or time-variable) filters to be "
190 "properly cross-calibrated."),
191 dtype=str,
192 default=None,
193 )
194 atmosphereTableName = pexConfig.Field(
195 doc="FGCM name or filename of precomputed atmospheres",
196 dtype=str,
197 default=None,
198 optional=True,
199 )
200 parameters = pexConfig.ConfigField(
201 doc="Atmosphere parameters (required if no atmosphereTableName)",
202 dtype=FgcmMakeLutParametersConfig,
203 default=None,
204 check=None)
206 def validate(self):
207 """
208 Validate the config parameters.
210 This method behaves differently from the parent validate in the case
211 that atmosphereTableName is set. In this case, the config values
212 for standard values, step sizes, and ranges are loaded
213 directly from the specified atmosphereTableName.
214 """
215 # check that filterNames and stdFilterNames are okay
216 self._fields['filterNames'].validate(self)
217 self._fields['stdFilterNames'].validate(self)
219 # check if we have an atmosphereTableName, and if valid
220 if self.atmosphereTableName is not None:
221 try:
222 fgcm.FgcmAtmosphereTable.initWithTableName(self.atmosphereTableName)
223 except IOError:
224 raise RuntimeError("Could not find atmosphereTableName: %s" %
225 (self.atmosphereTableName))
226 else:
227 # Validate the parameters
228 self._fields['parameters'].validate(self)
231class FgcmMakeLutRunner(pipeBase.ButlerInitializedTaskRunner):
232 """Subclass of TaskRunner for fgcmMakeLutTask
234 fgcmMakeLutTask.run() takes one argument, the butler, and
235 does not run on any data in the repository.
236 This runner does not use any parallelization.
237 """
239 @staticmethod
240 def getTargetList(parsedCmd):
241 """
242 Return a list with one element, the butler.
243 """
244 return [parsedCmd.butler]
246 def __call__(self, butler):
247 """
248 Parameters
249 ----------
250 butler: `lsst.daf.persistence.Butler`
252 Returns
253 -------
254 exitStatus: `list` with `pipeBase.Struct`
255 exitStatus (0: success; 1: failure)
256 """
257 task = self.TaskClass(config=self.config, log=self.log)
259 exitStatus = 0
260 if self.doRaise:
261 task.runDataRef(butler)
262 else:
263 try:
264 task.runDataRef(butler)
265 except Exception as e:
266 exitStatus = 1
267 task.log.fatal("Failed: %s" % e)
268 if not isinstance(e, pipeBase.TaskError):
269 traceback.print_exc(file=sys.stderr)
271 task.writeMetadata(butler)
273 # The task does not return any results:
274 return [pipeBase.Struct(exitStatus=exitStatus)]
276 def run(self, parsedCmd):
277 """
278 Run the task, with no multiprocessing
280 Parameters
281 ----------
282 parsedCmd: ArgumentParser parsed command line
283 """
285 resultList = []
287 if self.precall(parsedCmd):
288 targetList = self.getTargetList(parsedCmd)
289 # make sure that we only get 1
290 resultList = self(targetList[0])
292 return resultList
295class FgcmMakeLutTask(pipeBase.CmdLineTask):
296 """
297 Make Look-Up Table for FGCM.
299 This task computes a look-up-table for the range in expected atmosphere
300 variation and variation in instrumental throughput (as tracked by the
301 transmission_filter products). By pre-computing linearized integrals,
302 the FGCM fit is orders of magnitude faster for stars with a broad range
303 of colors and observing bands, yielding precision at the 1-2 mmag level.
305 Computing a LUT requires running MODTRAN or with a pre-generated
306 atmosphere table packaged with fgcm.
307 """
309 ConfigClass = FgcmMakeLutConfig
310 RunnerClass = FgcmMakeLutRunner
311 _DefaultName = "fgcmMakeLut"
313 def __init__(self, butler=None, **kwargs):
314 """
315 Instantiate an fgcmMakeLutTask.
317 Parameters
318 ----------
319 butler: `lsst.daf.persistence.Butler`
320 """
322 pipeBase.CmdLineTask.__init__(self, **kwargs)
324 # no saving of metadata for now
325 def _getMetadataName(self):
326 return None
328 @pipeBase.timeMethod
329 def runDataRef(self, butler):
330 """
331 Make a Look-Up Table for FGCM
333 Parameters
334 ----------
335 butler: `lsst.daf.persistence.Butler`
336 """
338 self._fgcmMakeLut(butler)
340 def _fgcmMakeLut(self, butler):
341 """
342 Make a FGCM Look-up Table
344 Parameters
345 ----------
346 butler: `lsst.daf.persistence.Butler`
347 """
349 # need the camera for the detectors
350 camera = butler.get('camera')
352 # number of ccds from the length of the camera iterator
353 nCcd = len(camera)
354 self.log.info("Found %d ccds for look-up table" % (nCcd))
356 # Load in optics, etc.
357 self._loadThroughputs(butler, camera)
359 lutConfig = self._createLutConfig(nCcd)
361 # make the lut object
362 self.log.info("Making the LUT maker object")
363 self.fgcmLutMaker = fgcm.FgcmLUTMaker(lutConfig)
365 # generate the throughput dictionary.
367 # these will be in Angstroms
368 # note that lambdaStep is currently in nm, because of historical
369 # reasons in the code. Convert to Angstroms here.
370 throughputLambda = np.arange(self.fgcmLutMaker.lambdaRange[0],
371 self.fgcmLutMaker.lambdaRange[1]+self.fgcmLutMaker.lambdaStep*10,
372 self.fgcmLutMaker.lambdaStep*10.)
374 self.log.info("Built throughput lambda, %.1f-%.1f, step %.2f" %
375 (throughputLambda[0], throughputLambda[-1],
376 throughputLambda[1]-throughputLambda[0]))
378 throughputDict = {}
379 for i, filterName in enumerate(self.config.filterNames):
380 tDict = {}
381 tDict['LAMBDA'] = throughputLambda
382 for ccdIndex, detector in enumerate(camera):
383 tDict[ccdIndex] = self._getThroughputDetector(detector, filterName, throughputLambda)
384 throughputDict[filterName] = tDict
386 # set the throughputs
387 self.fgcmLutMaker.setThroughputs(throughputDict)
389 # make the LUT
390 self.log.info("Making LUT")
391 self.fgcmLutMaker.makeLUT()
393 # and save the LUT
395 # build the index values
396 comma = ','
397 filterNameString = comma.join(self.config.filterNames)
398 stdFilterNameString = comma.join(self.config.stdFilterNames)
400 atmosphereTableName = 'NoTableWasUsed'
401 if self.config.atmosphereTableName is not None:
402 atmosphereTableName = self.config.atmosphereTableName
404 lutSchema = self._makeLutSchema(filterNameString, stdFilterNameString,
405 atmosphereTableName)
407 lutCat = self._makeLutCat(lutSchema, filterNameString,
408 stdFilterNameString, atmosphereTableName)
409 butler.put(lutCat, 'fgcmLookUpTable')
411 def _createLutConfig(self, nCcd):
412 """
413 Create the fgcmLut config dictionary
415 Parameters
416 ----------
417 nCcd: `int`
418 Number of CCDs in the camera
419 """
421 # create the common stub of the lutConfig
422 lutConfig = {}
423 lutConfig['logger'] = self.log
424 lutConfig['filterNames'] = self.config.filterNames
425 lutConfig['stdFilterNames'] = self.config.stdFilterNames
426 lutConfig['nCCD'] = nCcd
428 # atmosphereTable already validated if available
429 if self.config.atmosphereTableName is not None:
430 lutConfig['atmosphereTableName'] = self.config.atmosphereTableName
431 else:
432 # use the regular paramters (also validated if needed)
433 lutConfig['elevation'] = self.config.parameters.elevation
434 lutConfig['pmbRange'] = self.config.parameters.pmbRange
435 lutConfig['pmbSteps'] = self.config.parameters.pmbSteps
436 lutConfig['pwvRange'] = self.config.parameters.pwvRange
437 lutConfig['pwvSteps'] = self.config.parameters.pwvSteps
438 lutConfig['o3Range'] = self.config.parameters.o3Range
439 lutConfig['o3Steps'] = self.config.parameters.o3Steps
440 lutConfig['tauRange'] = self.config.parameters.tauRange
441 lutConfig['tauSteps'] = self.config.parameters.tauSteps
442 lutConfig['alphaRange'] = self.config.parameters.alphaRange
443 lutConfig['alphaSteps'] = self.config.parameters.alphaSteps
444 lutConfig['zenithRange'] = self.config.parameters.zenithRange
445 lutConfig['zenithSteps'] = self.config.parameters.zenithSteps
446 lutConfig['pmbStd'] = self.config.parameters.pmbStd
447 lutConfig['pwvStd'] = self.config.parameters.pwvStd
448 lutConfig['o3Std'] = self.config.parameters.o3Std
449 lutConfig['tauStd'] = self.config.parameters.tauStd
450 lutConfig['alphaStd'] = self.config.parameters.alphaStd
451 lutConfig['airmassStd'] = self.config.parameters.airmassStd
452 lutConfig['lambdaRange'] = self.config.parameters.lambdaRange
453 lutConfig['lambdaStep'] = self.config.parameters.lambdaStep
454 lutConfig['lambdaNorm'] = self.config.parameters.lambdaNorm
456 return lutConfig
458 def _loadThroughputs(self, butler, camera):
459 """Internal method to load throughput data for filters
461 Parameters
462 ----------
463 butler: `lsst.daf.persistence.butler.Butler`
464 A butler with the transmission info
465 camera: `lsst.afw.cameraGeom.Camera`
466 """
468 self._opticsTransmission = butler.get('transmission_optics')
469 self._sensorsTransmission = {}
470 for detector in camera:
471 self._sensorsTransmission[detector.getId()] = butler.get('transmission_sensor',
472 dataId={'ccd': detector.getId()})
473 self._filtersTransmission = {}
474 for filterName in self.config.filterNames:
475 f = Filter(filterName)
476 foundTrans = False
477 # Get all possible aliases, and also try the short filterName
478 aliases = f.getAliases()
479 aliases.extend(filterName)
480 for alias in f.getAliases():
481 try:
482 self._filtersTransmission[filterName] = butler.get('transmission_filter',
483 dataId={'filter': alias})
484 foundTrans = True
485 break
486 except NoResults:
487 pass
488 if not foundTrans:
489 raise ValueError("Could not find transmission for filter %s via any alias." % (filterName))
491 def _getThroughputDetector(self, detector, filterName, throughputLambda):
492 """Internal method to get throughput for a detector.
494 Returns the throughput at the center of the detector for a given filter.
496 Parameters
497 ----------
498 detector: `lsst.afw.cameraGeom._detector.Detector`
499 Detector on camera
500 filterName: `str`
501 Short name for filter
502 throughputLambda: `np.array(dtype=np.float64)`
503 Wavelength steps (Angstrom)
505 Returns
506 -------
507 throughput: `np.array(dtype=np.float64)`
508 Throughput (max 1.0) at throughputLambda
509 """
511 c = detector.getCenter(afwCameraGeom.FOCAL_PLANE)
512 c.scale(1.0/detector.getPixelSize()[0]) # Assumes x and y pixel sizes in arcsec are the same
514 throughput = self._opticsTransmission.sampleAt(position=c,
515 wavelengths=throughputLambda)
517 throughput *= self._sensorsTransmission[detector.getId()].sampleAt(position=c,
518 wavelengths=throughputLambda)
520 throughput *= self._filtersTransmission[filterName].sampleAt(position=c,
521 wavelengths=throughputLambda)
523 # Clip the throughput from 0 to 1
524 throughput = np.clip(throughput, 0.0, 1.0)
526 return throughput
528 def _makeLutSchema(self, filterNameString, stdFilterNameString,
529 atmosphereTableName):
530 """
531 Make the LUT schema
533 Parameters
534 ----------
535 filterNameString: `str`
536 Combined string of all the filterNames
537 stdFilterNameString: `str`
538 Combined string of all the standard filterNames
539 atmosphereTableName: `str`
540 Name of the atmosphere table used to generate LUT
542 Returns
543 -------
544 lutSchema: `afwTable.schema`
545 """
547 lutSchema = afwTable.Schema()
549 lutSchema.addField('tablename', type=str, doc='Atmosphere table name',
550 size=len(atmosphereTableName))
551 lutSchema.addField('elevation', type=float, doc="Telescope elevation used for LUT")
552 lutSchema.addField('filterNames', type=str, doc='filterNames in LUT',
553 size=len(filterNameString))
554 lutSchema.addField('stdFilterNames', type=str, doc='Standard filterNames in LUT',
555 size=len(stdFilterNameString))
556 lutSchema.addField('pmb', type='ArrayD', doc='Barometric Pressure',
557 size=self.fgcmLutMaker.pmb.size)
558 lutSchema.addField('pmbFactor', type='ArrayD', doc='PMB scaling factor',
559 size=self.fgcmLutMaker.pmb.size)
560 lutSchema.addField('pmbElevation', type=np.float64, doc='PMB Scaling at elevation')
561 lutSchema.addField('pwv', type='ArrayD', doc='Preciptable Water Vapor',
562 size=self.fgcmLutMaker.pwv.size)
563 lutSchema.addField('o3', type='ArrayD', doc='Ozone',
564 size=self.fgcmLutMaker.o3.size)
565 lutSchema.addField('tau', type='ArrayD', doc='Aerosol optical depth',
566 size=self.fgcmLutMaker.tau.size)
567 lutSchema.addField('lambdaNorm', type=np.float64, doc='AOD wavelength')
568 lutSchema.addField('alpha', type='ArrayD', doc='Aerosol alpha',
569 size=self.fgcmLutMaker.alpha.size)
570 lutSchema.addField('zenith', type='ArrayD', doc='Zenith angle',
571 size=self.fgcmLutMaker.zenith.size)
572 lutSchema.addField('nCcd', type=np.int32, doc='Number of CCDs')
574 # and the standard values
575 lutSchema.addField('pmbStd', type=np.float64, doc='PMB Standard')
576 lutSchema.addField('pwvStd', type=np.float64, doc='PWV Standard')
577 lutSchema.addField('o3Std', type=np.float64, doc='O3 Standard')
578 lutSchema.addField('tauStd', type=np.float64, doc='Tau Standard')
579 lutSchema.addField('alphaStd', type=np.float64, doc='Alpha Standard')
580 lutSchema.addField('zenithStd', type=np.float64, doc='Zenith angle Standard')
581 lutSchema.addField('lambdaRange', type='ArrayD', doc='Wavelength range',
582 size=2)
583 lutSchema.addField('lambdaStep', type=np.float64, doc='Wavelength step')
584 lutSchema.addField('lambdaStd', type='ArrayD', doc='Standard Wavelength',
585 size=len(self.fgcmLutMaker.filterNames))
586 lutSchema.addField('lambdaStdFilter', type='ArrayD', doc='Standard Wavelength (raw)',
587 size=len(self.fgcmLutMaker.filterNames))
588 lutSchema.addField('i0Std', type='ArrayD', doc='I0 Standard',
589 size=len(self.fgcmLutMaker.filterNames))
590 lutSchema.addField('i1Std', type='ArrayD', doc='I1 Standard',
591 size=len(self.fgcmLutMaker.filterNames))
592 lutSchema.addField('i10Std', type='ArrayD', doc='I10 Standard',
593 size=len(self.fgcmLutMaker.filterNames))
594 lutSchema.addField('i2Std', type='ArrayD', doc='I2 Standard',
595 size=len(self.fgcmLutMaker.filterNames))
596 lutSchema.addField('lambdaB', type='ArrayD', doc='Wavelength for passband (no atm)',
597 size=len(self.fgcmLutMaker.filterNames))
598 lutSchema.addField('atmLambda', type='ArrayD', doc='Atmosphere wavelengths (Angstrom)',
599 size=self.fgcmLutMaker.atmLambda.size)
600 lutSchema.addField('atmStdTrans', type='ArrayD', doc='Standard Atmosphere Throughput',
601 size=self.fgcmLutMaker.atmStdTrans.size)
603 # and the look-up-tables
604 lutSchema.addField('luttype', type=str, size=20, doc='Look-up table type')
605 lutSchema.addField('lut', type='ArrayF', doc='Look-up table for luttype',
606 size=self.fgcmLutMaker.lut['I0'].size)
608 return lutSchema
610 def _makeLutCat(self, lutSchema, filterNameString, stdFilterNameString,
611 atmosphereTableName):
612 """
613 Make the LUT schema
615 Parameters
616 ----------
617 lutSchema: `afwTable.schema`
618 Lut catalog schema
619 filterNameString: `str`
620 Combined string of all the filterNames
621 stdFilterNameString: `str`
622 Combined string of all the standard filterNames
623 atmosphereTableName: `str`
624 Name of the atmosphere table used to generate LUT
626 Returns
627 -------
628 lutCat: `afwTable.BaseCatalog`
629 Lut catalog for persistence
630 """
632 # The somewhat strange format is to make sure that
633 # the rows of the afwTable do not get too large
634 # (see DM-11419)
636 lutCat = afwTable.BaseCatalog(lutSchema)
637 lutCat.table.preallocate(14)
639 # first fill the first index
640 rec = lutCat.addNew()
642 rec['tablename'] = atmosphereTableName
643 rec['elevation'] = self.fgcmLutMaker.atmosphereTable.elevation
644 rec['filterNames'] = filterNameString
645 rec['stdFilterNames'] = stdFilterNameString
646 rec['pmb'][:] = self.fgcmLutMaker.pmb
647 rec['pmbFactor'][:] = self.fgcmLutMaker.pmbFactor
648 rec['pmbElevation'] = self.fgcmLutMaker.pmbElevation
649 rec['pwv'][:] = self.fgcmLutMaker.pwv
650 rec['o3'][:] = self.fgcmLutMaker.o3
651 rec['tau'][:] = self.fgcmLutMaker.tau
652 rec['lambdaNorm'] = self.fgcmLutMaker.lambdaNorm
653 rec['alpha'][:] = self.fgcmLutMaker.alpha
654 rec['zenith'][:] = self.fgcmLutMaker.zenith
655 rec['nCcd'] = self.fgcmLutMaker.nCCD
657 rec['pmbStd'] = self.fgcmLutMaker.pmbStd
658 rec['pwvStd'] = self.fgcmLutMaker.pwvStd
659 rec['o3Std'] = self.fgcmLutMaker.o3Std
660 rec['tauStd'] = self.fgcmLutMaker.tauStd
661 rec['alphaStd'] = self.fgcmLutMaker.alphaStd
662 rec['zenithStd'] = self.fgcmLutMaker.zenithStd
663 rec['lambdaRange'][:] = self.fgcmLutMaker.lambdaRange
664 rec['lambdaStep'] = self.fgcmLutMaker.lambdaStep
665 rec['lambdaStd'][:] = self.fgcmLutMaker.lambdaStd
666 rec['lambdaStdFilter'][:] = self.fgcmLutMaker.lambdaStdFilter
667 rec['i0Std'][:] = self.fgcmLutMaker.I0Std
668 rec['i1Std'][:] = self.fgcmLutMaker.I1Std
669 rec['i10Std'][:] = self.fgcmLutMaker.I10Std
670 rec['i2Std'][:] = self.fgcmLutMaker.I2Std
671 rec['lambdaB'][:] = self.fgcmLutMaker.lambdaB
672 rec['atmLambda'][:] = self.fgcmLutMaker.atmLambda
673 rec['atmStdTrans'][:] = self.fgcmLutMaker.atmStdTrans
675 rec['luttype'] = 'I0'
676 rec['lut'][:] = self.fgcmLutMaker.lut['I0'].flatten()
678 # and add the rest
679 rec = lutCat.addNew()
680 rec['luttype'] = 'I1'
681 rec['lut'][:] = self.fgcmLutMaker.lut['I1'].flatten()
683 derivTypes = ['D_PMB', 'D_LNPWV', 'D_O3', 'D_LNTAU', 'D_ALPHA', 'D_SECZENITH',
684 'D_PMB_I1', 'D_LNPWV_I1', 'D_O3_I1', 'D_LNTAU_I1', 'D_ALPHA_I1',
685 'D_SECZENITH_I1']
686 for derivType in derivTypes:
687 rec = lutCat.addNew()
688 rec['luttype'] = derivType
689 rec['lut'][:] = self.fgcmLutMaker.lutDeriv[derivType].flatten()
691 return lutCat