LSST Applications g00d0e8bbd7+edbf708997,g03191d30f7+9ce8016dbd,g1955dfad08+0bd186d245,g199a45376c+5137f08352,g1fd858c14a+a888a50aa2,g262e1987ae+45f9aba685,g29ae962dfc+1c7d47a24f,g2cef7863aa+73c82f25e4,g35bb328faa+edbf708997,g3fd5ace14f+eed17d2c67,g47891489e3+6dc8069a4c,g53246c7159+edbf708997,g64539dfbff+c4107e45b5,g67b6fd64d1+6dc8069a4c,g74acd417e5+f452e9c21a,g786e29fd12+af89c03590,g7ae74a0b1c+a25e60b391,g7aefaa3e3d+2025e9ce17,g7cc15d900a+2d158402f9,g87389fa792+a4172ec7da,g89139ef638+6dc8069a4c,g8d4809ba88+c4107e45b5,g8d7436a09f+e96c132b44,g8ea07a8fe4+db21c37724,g98df359435+aae6d409c1,ga2180abaac+edbf708997,gac66b60396+966efe6077,gb632fb1845+88945a90f8,gbaa8f7a6c5+38b34f4976,gbf99507273+edbf708997,gca7fc764a6+6dc8069a4c,gd7ef33dd92+6dc8069a4c,gda68eeecaf+7d1e613a8d,gdab6d2f7ff+f452e9c21a,gdbb4c4dda9+c4107e45b5,ge410e46f29+6dc8069a4c,ge41e95a9f2+c4107e45b5,geaed405ab2+e194be0d2b,w.2025.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
lsst.ip.isr.linearize.Linearizer Class Reference
Inheritance diagram for lsst.ip.isr.linearize.Linearizer:
lsst.ip.isr.calibType.IsrCalib

Public Member Functions

 __init__ (self, table=None, **kwargs)
 
 updateMetadata (self, setDate=False, **kwargs)
 
 fromDetector (self, detector)
 
 fromDict (cls, dictionary)
 
 toDict (self)
 
 fromTable (cls, tableList)
 
 toTable (self)
 
 getLinearityTypeByName (self, linearityTypeName)
 
 validate (self, detector=None, amplifier=None)
 
 applyLinearity (self, image, detector=None, log=None, gains=None)
 
 requiredAttributes (self)
 
 requiredAttributes (self, value)
 
 __str__ (self)
 
 __eq__ (self, other)
 
 metadata (self)
 
 getMetadata (self)
 
 setMetadata (self, metadata)
 
 updateMetadataFromExposures (self, exposures)
 
 calibInfoFromDict (self, dictionary)
 
 determineCalibClass (cls, metadata, message)
 
 readText (cls, filename, **kwargs)
 
 writeText (self, filename, format="auto")
 
 readFits (cls, filename, **kwargs)
 
 writeFits (self, filename)
 
 apply (self, target)
 

Public Attributes

bool hasLinearity = False
 
bool override = False
 
 ampNames = list()
 
 inputGain = dict()
 
 linearityCoeffs = dict()
 
 linearityType = dict()
 
 linearityBBox = dict()
 
 inputAbscissa = dict()
 
 inputOrdinate = dict()
 
 inputMask = dict()
 
 inputGroupingIndex = dict()
 
 inputNormalization = dict()
 
 fitParams = dict()
 
 fitParamsErr = dict()
 
 fitChiSq = dict()
 
 fitResiduals = dict()
 
 fitResidualsSigmaMad = dict()
 
 fitResidualsUnmasked = dict()
 
 fitResidualsModel = dict()
 
 linearFit = dict()
 
 linearityTurnoff = dict()
 
 linearityMaxSignal = dict()
 
str absoluteReferenceAmplifier = ""
 
 tableData = None
 
str linearityUnits = 'adu'
 
 requiredAttributes = set(["_OBSTYPE", "_SCHEMA", "_VERSION"])
 
 log = log if log else logging.getLogger(__name__)
 

Protected Attributes

 _instrument = None
 
 _raftName = None
 
 _slotName = None
 
 _detectorName = None
 
 _detectorSerial = None
 
 _detectorId = None
 
 _filter = None
 
str _calibId = None
 
 _seqfile = None
 
 _seqname = None
 
 _seqcksum = None
 
 _metadata = PropertyList()
 
 _requiredAttributes
 

Static Protected Attributes

str _OBSTYPE = "generic"
 
str _SCHEMA = "NO SCHEMA"
 
int _VERSION = 0
 

Detailed Description

Parameter set for linearization.

These parameters are included in `lsst.afw.cameraGeom.Amplifier`, but
should be accessible externally to allow for testing.

Parameters
----------
table : `numpy.array`, optional
    Lookup table; a 2-dimensional array of floats:

    - one row for each row index (value of coef[0] in the amplifier)
    - one column for each image value

    To avoid copying the table the last index should vary fastest
    (numpy default "C" order)
detector : `lsst.afw.cameraGeom.Detector`, optional
    Detector object.  Passed to self.fromDetector() on init.
log : `logging.Logger`, optional
    Logger to handle messages.
kwargs : `dict`, optional
    Other keyword arguments to pass to the parent init.

Raises
------
RuntimeError
    Raised if the supplied table is not 2D, or if the table has fewer
    columns than rows (indicating that the indices are swapped).

Notes
-----
The linearizer attributes stored are:

hasLinearity : `bool`
    Whether a linearity correction is defined for this detector.
override : `bool`
    Whether the detector parameters should be overridden.
ampNames : `list` [`str`]
    List of amplifier names to correct.
inputGain : `dict` [`str`, `float`]
    Dictionary keyed by amplifirer name containing the input
    gain from the PTC used to construct this linearizer.
linearityCoeffs : `dict` [`str`, `np.ndarray`]
    Coefficients to use in correction.  Indexed by amplifier
    names.  The format of the array depends on the type of
    correction to apply.
linearityType : `dict` [`str`, `str`]
    Type of correction to use, indexed by amplifier names.
linearityBBox : `dict` [`str`, `lsst.geom.Box2I`]
    Bounding box the correction is valid over, indexed by
    amplifier names.
fitParams : `dict` [`str`, `np.ndarray`], optional
    Linearity fit parameters used to construct the correction
    coefficients, indexed as above.
fitParamsErr : `dict` [`str`, `np.ndarray`], optional
    Uncertainty values of the linearity fit parameters used to
    construct the correction coefficients, indexed as above.
fitChiSq : `dict` [`str`, `float`], optional
    Chi-squared value of the linearity fit, indexed as above.
fitResiduals : `dict` [`str`, `np.ndarray`], optional
    Residuals of the fit, indexed as above. Used for
    calculating photodiode corrections
fitResidualsSigmaMad : `dict` [`str`, `float`], optional
    Robust median-absolute-deviation of fit residuals, scaled
    by the signal level.
fitResidualsUnmasked : `dict` [`str`, `np.ndarray`], optional
    Same as fitResiduals, but all outliers are included and
    not masked as nans.
fitResidualsModel : `dict` [`str`, `np.ndarray`], optional
    The model count level for each of the fitResiduals.
linearFit : The linear fit to the low flux region of the curve.
    [intercept, slope].
tableData : `np.ndarray`, optional
    Lookup table data for the linearity correction.
inputAbscissa : `dict` [`str`, `np.ndarray`], optional
    Input abscissa used to construct linearizer (usually photodiode
    or exposure time).
inputOrdinate : `dict` [`str`, `np.ndarray`], optional
    Input ordinate used to construct linearizer (raw mean counts).
inputMask : `dict` [`str`, `np.ndarray`], optional
    Input mask used for the fitting.
inputGroupingIndex : `dict` [`str`, `np.ndarray`], optional
    Input grouping index used for fitting.
inputNormalization : `dict` [`str`, `np.ndarray`], optional
    Input normalization that was applied to the abscissa for
    each pair from the PTC used for the linearization fit.
absoluteReferenceAmplifier : `str`, optional
    Amplifier used for the reference for absolute linearization
    (DoubleSpline) mode.

Version 1.4 adds ``linearityTurnoff`` and ``linearityMaxSignal``.
Version 1.5 adds ``fitResidualsUnmasked``, ``inputAbscissa``,
    ``inputOrdinate``, ``inputMask``, ``inputGroupingIndex``,
    ``fitResidualsModel``, and ``inputNormalization``.
Version 1.6 adds ``absoluteReferenceAmplifier``.
Version 1.7 adds ``inputGain``.

Definition at line 48 of file linearize.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.ip.isr.linearize.Linearizer.__init__ ( self,
table = None,
** kwargs )

Definition at line 149 of file linearize.py.

149 def __init__(self, table=None, **kwargs):
150 self.hasLinearity = False
151 self.override = False
152
153 self.ampNames = list()
154 self.inputGain = dict()
155 self.linearityCoeffs = dict()
156 self.linearityType = dict()
157 self.linearityBBox = dict()
158 self.inputAbscissa = dict()
159 self.inputOrdinate = dict()
160 self.inputMask = dict()
161 self.inputGroupingIndex = dict()
162 self.inputNormalization = dict()
163 self.fitParams = dict()
164 self.fitParamsErr = dict()
165 self.fitChiSq = dict()
166 self.fitResiduals = dict()
167 self.fitResidualsSigmaMad = dict()
168 self.fitResidualsUnmasked = dict()
169 self.fitResidualsModel = dict()
170 self.linearFit = dict()
171 self.linearityTurnoff = dict()
172 self.linearityMaxSignal = dict()
173 self.absoluteReferenceAmplifier = ""
174 self.tableData = None
175 if table is not None:
176 if len(table.shape) != 2:
177 raise RuntimeError("table shape = %s; must have two dimensions" % (table.shape,))
178 if table.shape[1] < table.shape[0]:
179 raise RuntimeError("table shape = %s; indices are switched" % (table.shape,))
180 self.tableData = np.array(table, order="C")
181
182 # The linearizer is always natively in adu because it
183 # is computed prior to computing gains.
184 self.linearityUnits = 'adu'
185
186 super().__init__(**kwargs)
187 self.requiredAttributes.update(['hasLinearity', 'override',
188 'ampNames', 'inputGain',
189 'linearityCoeffs', 'linearityType', 'linearityBBox',
190 'fitParams', 'fitParamsErr', 'fitChiSq',
191 'fitResiduals', 'fitResidualsSigmaMad', 'linearFit', 'tableData',
192 'units', 'linearityTurnoff', 'linearityMaxSignal',
193 'fitResidualsUnmasked', 'inputAbscissa', 'inputOrdinate',
194 'inputMask', 'inputGroupingIndex', 'fitResidualsModel',
195 'inputNormalization', 'absoluteReferenceAmplifier'])
196

Member Function Documentation

◆ __eq__()

lsst.ip.isr.calibType.IsrCalib.__eq__ ( self,
other )
inherited
Calibration equivalence.

Running ``calib.log.setLevel(0)`` enables debug statements to
identify problematic fields.

Definition at line 105 of file calibType.py.

105 def __eq__(self, other):
106 """Calibration equivalence.
107
108 Running ``calib.log.setLevel(0)`` enables debug statements to
109 identify problematic fields.
110 """
111 if not isinstance(other, self.__class__):
112 self.log.debug("Incorrect class type: %s %s", self.__class__, other.__class__)
113 return False
114
115 for attr in self._requiredAttributes:
116 attrSelf = getattr(self, attr)
117 attrOther = getattr(other, attr)
118
119 if isinstance(attrSelf, dict):
120 # Dictionary of arrays.
121 if attrSelf.keys() != attrOther.keys():
122 self.log.debug("Dict Key Failure: %s %s %s", attr, attrSelf.keys(), attrOther.keys())
123 return False
124 for key in attrSelf:
125 try:
126 if not np.allclose(attrSelf[key], attrOther[key], equal_nan=True):
127 self.log.debug("Array Failure: %s %s %s", key, attrSelf[key], attrOther[key])
128 return False
129 except TypeError:
130 # If it is not something numpy can handle
131 # (it's not a number or array of numbers),
132 # then it needs to have its own equivalence
133 # operator.
134 if np.all(attrSelf[key] != attrOther[key]):
135 return False
136 elif (isinstance(attrSelf, np.ndarray) or isinstance(attrSelf, Column)
137 or isinstance(attrOther, np.ndarray) or isinstance(attrOther, Column)):
138 # Bare array.
139 if isinstance(attrSelf[0], (str, np.str_, np.bytes_)):
140 if not np.all(attrSelf == attrOther):
141 self.log.debug("Array Failure: %s %s %s", attr, attrSelf, attrOther)
142 return False
143 else:
144 if not np.allclose(attrSelf, attrOther, equal_nan=True):
145 self.log.debug("Array Failure: %s %s %s", attr, attrSelf, attrOther)
146 return False
147 elif type(attrSelf) is not type(attrOther):
148 if set([attrSelf, attrOther]) == set([None, ""]):
149 # Fits converts None to "", but None is not "".
150 continue
151 self.log.debug("Type Failure: %s %s %s %s %s", attr, type(attrSelf), type(attrOther),
152 attrSelf, attrOther)
153 return False
154 else:
155 if attrSelf != attrOther:
156 self.log.debug("Value Failure: %s %s %s", attr, attrSelf, attrOther)
157 return False
158
159 return True
160

◆ __str__()

lsst.ip.isr.calibType.IsrCalib.__str__ ( self)
inherited

Definition at line 102 of file calibType.py.

102 def __str__(self):
103 return f"{self.__class__.__name__}(obstype={self._OBSTYPE}, detector={self._detectorName}, )"
104

◆ apply()

lsst.ip.isr.calibType.IsrCalib.apply ( self,
target )
inherited
Method to apply the calibration to the target object.

Parameters
----------
target : `object`
    Thing to validate against.

Returns
-------
valid : `bool`
    Returns true if the calibration was applied correctly.

Raises
------
NotImplementedError
    Raised if not implemented.

Definition at line 704 of file calibType.py.

704 def apply(self, target):
705 """Method to apply the calibration to the target object.
706
707 Parameters
708 ----------
709 target : `object`
710 Thing to validate against.
711
712 Returns
713 -------
714 valid : `bool`
715 Returns true if the calibration was applied correctly.
716
717 Raises
718 ------
719 NotImplementedError
720 Raised if not implemented.
721 """
722 raise NotImplementedError("Must be implemented by subclass.")
723
724

◆ applyLinearity()

lsst.ip.isr.linearize.Linearizer.applyLinearity ( self,
image,
detector = None,
log = None,
gains = None )
Apply the linearity to an image.

If the linearity parameters are populated, use those,
otherwise use the values from the detector.

Parameters
----------
image : `~lsst.afw.image.image`
    Image to correct.
detector : `~lsst.afw.cameraGeom.detector`, optional
    Detector to use to determine exposure trimmed state.  If
    supplied, but no other linearity information is provided
    by the calibration, then the static solution stored in the
    detector will be used.
log : `~logging.Logger`, optional
    Log object to use for logging.
gains : `dict` [`str`, `float`], optional
    Dictionary of amp name to gain. If this is provided then
    linearity terms will be converted from adu to electrons.
    Only used for Spline linearity corrections.

Definition at line 605 of file linearize.py.

605 def applyLinearity(self, image, detector=None, log=None, gains=None):
606 """Apply the linearity to an image.
607
608 If the linearity parameters are populated, use those,
609 otherwise use the values from the detector.
610
611 Parameters
612 ----------
613 image : `~lsst.afw.image.image`
614 Image to correct.
615 detector : `~lsst.afw.cameraGeom.detector`, optional
616 Detector to use to determine exposure trimmed state. If
617 supplied, but no other linearity information is provided
618 by the calibration, then the static solution stored in the
619 detector will be used.
620 log : `~logging.Logger`, optional
621 Log object to use for logging.
622 gains : `dict` [`str`, `float`], optional
623 Dictionary of amp name to gain. If this is provided then
624 linearity terms will be converted from adu to electrons.
625 Only used for Spline linearity corrections.
626 """
627 if log is None:
628 log = self.log
629 if detector and not self.hasLinearity:
630 self.fromDetector(detector)
631
632 self.validate(detector)
633
634 # Check if the image is trimmed.
635 isTrimmed = None
636 if detector:
637 isTrimmed = isTrimmedImage(image, detector)
638
639 numAmps = 0
640 numLinearized = 0
641 numOutOfRange = 0
642 for ampName in self.linearityType.keys():
643 linearizer = self.getLinearityTypeByName(self.linearityType[ampName])
644 numAmps += 1
645
646 if gains and self.linearityUnits == 'adu':
647 gainValue = gains[ampName]
648 else:
649 gainValue = 1.0
650
651 if linearizer is not None:
652 match isTrimmed:
653 case True:
654 bbox = detector[ampName].getBBox()
655 case False:
656 bbox = detector[ampName].getRawBBox()
657 case None:
658 bbox = self.linearityBBox[ampName]
659
660 ampView = image.Factory(image, bbox)
661 success, outOfRange = linearizer()(ampView, **{'coeffs': self.linearityCoeffs[ampName],
662 'table': self.tableData,
663 'log': self.log,
664 'gain': gainValue})
665 numOutOfRange += outOfRange
666 if success:
667 numLinearized += 1
668 elif log is not None:
669 log.warning("Amplifier %s did not linearize.",
670 ampName)
671 return Struct(
672 numAmps=numAmps,
673 numLinearized=numLinearized,
674 numOutOfRange=numOutOfRange
675 )
676
677

◆ calibInfoFromDict()

lsst.ip.isr.calibType.IsrCalib.calibInfoFromDict ( self,
dictionary )
inherited
Handle common keywords.

This isn't an ideal solution, but until all calibrations
expect to find everything in the metadata, they still need to
search through dictionaries.

Parameters
----------
dictionary : `dict` or `lsst.daf.base.PropertyList`
    Source for the common keywords.

Raises
------
RuntimeError
    Raised if the dictionary does not match the expected OBSTYPE.

Definition at line 325 of file calibType.py.

325 def calibInfoFromDict(self, dictionary):
326 """Handle common keywords.
327
328 This isn't an ideal solution, but until all calibrations
329 expect to find everything in the metadata, they still need to
330 search through dictionaries.
331
332 Parameters
333 ----------
334 dictionary : `dict` or `lsst.daf.base.PropertyList`
335 Source for the common keywords.
336
337 Raises
338 ------
339 RuntimeError
340 Raised if the dictionary does not match the expected OBSTYPE.
341 """
342
343 def search(haystack, needles):
344 """Search dictionary 'haystack' for an entry in 'needles'
345 """
346 test = [haystack.get(x) for x in needles]
347 test = set([x for x in test if x is not None])
348 if len(test) == 0:
349 if "metadata" in haystack:
350 return search(haystack["metadata"], needles)
351 else:
352 return None
353 elif len(test) == 1:
354 value = list(test)[0]
355 if value == "":
356 return None
357 else:
358 return value
359 else:
360 raise ValueError(f"Too many values found: {len(test)} {test} {needles}")
361
362 if "metadata" in dictionary:
363 metadata = dictionary["metadata"]
364
365 if self._OBSTYPE != metadata["OBSTYPE"]:
366 raise RuntimeError(f"Incorrect calibration supplied. Expected {self._OBSTYPE}, "
367 f"found {metadata['OBSTYPE']}")
368
369 if (value := search(dictionary, ["INSTRUME", "instrument"])) is not None:
370 self._instrument = value
371 if (value := search(dictionary, ["RAFTNAME"])) is not None:
372 self._slotName = value
373 if (value := search(dictionary, ["DETECTOR", "detectorId"])) is not None:
374 self._detectorId = value
375 if (value := search(dictionary, ["DET_NAME", "DETECTOR_NAME", "detectorName"])) is not None:
376 self._detectorName = value
377 if (value := search(dictionary, ["DET_SER", "DETECTOR_SERIAL", "detectorSerial"])) is not None:
378 self._detectorSerial = value
379 if (value := search(dictionary, ["FILTER", "filterName"])) is not None:
380 self._filter = value
381 if (value := search(dictionary, ["CALIB_ID"])) is not None:
382 self._calibId = value
383 if (value := search(dictionary, ["SEQFILE"])) is not None:
384 self._seqfile = value
385 if (value := search(dictionary, ["SEQNAME"])) is not None:
386 self._seqname = value
387 if (value := search(dictionary, ["SEQCKSUM"])) is not None:
388 self._seqcksum = value
389

◆ determineCalibClass()

lsst.ip.isr.calibType.IsrCalib.determineCalibClass ( cls,
metadata,
message )
inherited
Attempt to find calibration class in metadata.

Parameters
----------
metadata : `dict` or `lsst.daf.base.PropertyList`
    Metadata possibly containing a calibration class entry.
message : `str`
    Message to include in any errors.

Returns
-------
calibClass : `object`
    The class to use to read the file contents.  Should be an
    `lsst.ip.isr.IsrCalib` subclass.

Raises
------
ValueError
    Raised if the resulting calibClass is the base
    `lsst.ip.isr.IsrClass` (which does not implement the
    content methods).

Definition at line 391 of file calibType.py.

391 def determineCalibClass(cls, metadata, message):
392 """Attempt to find calibration class in metadata.
393
394 Parameters
395 ----------
396 metadata : `dict` or `lsst.daf.base.PropertyList`
397 Metadata possibly containing a calibration class entry.
398 message : `str`
399 Message to include in any errors.
400
401 Returns
402 -------
403 calibClass : `object`
404 The class to use to read the file contents. Should be an
405 `lsst.ip.isr.IsrCalib` subclass.
406
407 Raises
408 ------
409 ValueError
410 Raised if the resulting calibClass is the base
411 `lsst.ip.isr.IsrClass` (which does not implement the
412 content methods).
413 """
414 calibClassName = metadata.get("CALIBCLS")
415 if calibClassName is None:
416 calibClassName = metadata.get("fileType")
417 if calibClassName == "shutterMotionProfile":
418 calibClassName = "lsst.ip.isr.ShutterMotionProfile"
419 calibClass = doImport(calibClassName) if calibClassName is not None else cls
420 if calibClass is IsrCalib:
421 raise ValueError(f"Cannot use base class to read calibration data: {message}")
422 return calibClass
423

◆ fromDetector()

lsst.ip.isr.linearize.Linearizer.fromDetector ( self,
detector )
Read linearity parameters from a detector.

Parameters
----------
detector : `lsst.afw.cameraGeom.detector`
    Input detector with parameters to use.

Returns
-------
calib : `lsst.ip.isr.Linearizer`
    The calibration constructed from the detector.

Reimplemented from lsst.ip.isr.calibType.IsrCalib.

Definition at line 218 of file linearize.py.

218 def fromDetector(self, detector):
219 """Read linearity parameters from a detector.
220
221 Parameters
222 ----------
223 detector : `lsst.afw.cameraGeom.detector`
224 Input detector with parameters to use.
225
226 Returns
227 -------
228 calib : `lsst.ip.isr.Linearizer`
229 The calibration constructed from the detector.
230 """
231 self._detectorName = detector.getName()
232 self._detectorSerial = detector.getSerial()
233 self._detectorId = detector.getId()
234 self.hasLinearity = True
235
236 # Do not translate Threshold, Maximum, Units.
237 for amp in detector.getAmplifiers():
238 ampName = amp.getName()
239 self.ampNames.append(ampName)
240 self.linearityType[ampName] = amp.getLinearityType()
241 self.linearityCoeffs[ampName] = amp.getLinearityCoeffs()
242 self.linearityBBox[ampName] = amp.getBBox()
243
244 # Detector linearizers (legacy) are assumed to be adu units.
245 self.linearityUnits = 'adu'
246
247 return self
248

◆ fromDict()

lsst.ip.isr.linearize.Linearizer.fromDict ( cls,
dictionary )
Construct a calibration from a dictionary of properties

Parameters
----------
dictionary : `dict`
    Dictionary of properties

Returns
-------
calib : `lsst.ip.isr.Linearity`
    Constructed calibration.

Raises
------
RuntimeError
    Raised if the supplied dictionary is for a different
    calibration.

Reimplemented from lsst.ip.isr.calibType.IsrCalib.

Definition at line 250 of file linearize.py.

250 def fromDict(cls, dictionary):
251 """Construct a calibration from a dictionary of properties
252
253 Parameters
254 ----------
255 dictionary : `dict`
256 Dictionary of properties
257
258 Returns
259 -------
260 calib : `lsst.ip.isr.Linearity`
261 Constructed calibration.
262
263 Raises
264 ------
265 RuntimeError
266 Raised if the supplied dictionary is for a different
267 calibration.
268 """
269
270 calib = cls()
271
272 if calib._OBSTYPE != dictionary['metadata']['OBSTYPE']:
273 raise RuntimeError(f"Incorrect linearity supplied. Expected {calib._OBSTYPE}, "
274 f"found {dictionary['metadata']['OBSTYPE']}")
275
276 calib.setMetadata(dictionary['metadata'])
277
278 calib.hasLinearity = dictionary.get('hasLinearity',
279 dictionary['metadata'].get('HAS_LINEARITY', False))
280 calib.override = dictionary.get('override', True)
281
282 # Old linearizers which do not have linearityUnits are
283 # assumed to be adu because that's all that has been
284 # supported.
285 calib.linearityUnits = dictionary.get('linearityUnits', 'adu')
286
287 if calib.hasLinearity:
288 for ampName in dictionary['amplifiers']:
289 amp = dictionary['amplifiers'][ampName]
290 calib.ampNames.append(ampName)
291 # If gain = None on isrFunction.gainContext(),
292 # the default amp geometry gains are used
293 # in IsrTask*
294 calib.inputGain[ampName] = amp.get('inputGain', np.nan)
295 calib.linearityCoeffs[ampName] = np.array(amp.get('linearityCoeffs', [0.0]))
296 calib.linearityType[ampName] = amp.get('linearityType', 'None')
297 calib.linearityBBox[ampName] = amp.get('linearityBBox', None)
298
299 calib.inputAbscissa[ampName] = np.array(amp.get('inputAbscissa', [0.0]))
300 calib.inputOrdinate[ampName] = np.array(amp.get('inputOrdinate', [0.0]))
301 calib.inputMask[ampName] = np.array(amp.get('inputMask', [False]))
302 calib.inputGroupingIndex[ampName] = np.array(amp.get('inputGroupingIndex', [0.0]))
303 calib.inputNormalization[ampName] = np.array(amp.get('inputNormalization', [1.0]))
304
305 calib.fitParams[ampName] = np.array(amp.get('fitParams', [0.0]))
306 calib.fitParamsErr[ampName] = np.array(amp.get('fitParamsErr', [0.0]))
307 calib.fitChiSq[ampName] = amp.get('fitChiSq', np.nan)
308 calib.fitResiduals[ampName] = np.array(amp.get('fitResiduals', [0.0]))
309 calib.fitResidualsSigmaMad[ampName] = np.array(amp.get('fitResidualsSigmaMad', np.nan))
310 calib.fitResidualsUnmasked[ampName] = np.array(amp.get('fitResidualsUnmasked', [0.0]))
311 calib.fitResidualsModel[ampName] = np.array(amp.get('fitResidualsModel', [0.0]))
312 calib.linearFit[ampName] = np.array(amp.get('linearFit', [0.0]))
313
314 calib.linearityTurnoff[ampName] = np.array(amp.get('linearityTurnoff', np.nan))
315 calib.linearityMaxSignal[ampName] = np.array(amp.get('linearityMaxSignal', np.nan))
316
317 calib.tableData = dictionary.get('tableData', None)
318 if calib.tableData:
319 calib.tableData = np.array(calib.tableData)
320
321 calib.absoluteReferenceAmplifier = dictionary.get(
322 'absoluteReferenceAmplifier', calib.absoluteReferenceAmplifier,
323 )
324
325 return calib
326

◆ fromTable()

lsst.ip.isr.linearize.Linearizer.fromTable ( cls,
tableList )
Read linearity from a FITS file.

This method uses the `fromDict` method to create the
calibration, after constructing an appropriate dictionary from
the input tables.

Parameters
----------
tableList : `list` [`astropy.table.Table`]
    afwTable read from input file name.

Returns
-------
linearity : `~lsst.ip.isr.linearize.Linearizer``
    Linearity parameters.

Notes
-----
The method reads a FITS file with 1 or 2 extensions. The metadata is
read from the header of extension 1, which must exist.  Then the table
is loaded, and  the ['AMPLIFIER_NAME', 'TYPE', 'COEFFS', 'BBOX_X0',
'BBOX_Y0', 'BBOX_DX', 'BBOX_DY'] columns are read and used to set each
dictionary by looping over rows.
Extension 2 is then attempted to read in the try block (which only
exists for lookup tables). It has a column named 'LOOKUP_VALUES' that
contains a vector of the lookup entries in each row.

Reimplemented from lsst.ip.isr.calibType.IsrCalib.

Definition at line 374 of file linearize.py.

374 def fromTable(cls, tableList):
375 """Read linearity from a FITS file.
376
377 This method uses the `fromDict` method to create the
378 calibration, after constructing an appropriate dictionary from
379 the input tables.
380
381 Parameters
382 ----------
383 tableList : `list` [`astropy.table.Table`]
384 afwTable read from input file name.
385
386 Returns
387 -------
388 linearity : `~lsst.ip.isr.linearize.Linearizer``
389 Linearity parameters.
390
391 Notes
392 -----
393 The method reads a FITS file with 1 or 2 extensions. The metadata is
394 read from the header of extension 1, which must exist. Then the table
395 is loaded, and the ['AMPLIFIER_NAME', 'TYPE', 'COEFFS', 'BBOX_X0',
396 'BBOX_Y0', 'BBOX_DX', 'BBOX_DY'] columns are read and used to set each
397 dictionary by looping over rows.
398 Extension 2 is then attempted to read in the try block (which only
399 exists for lookup tables). It has a column named 'LOOKUP_VALUES' that
400 contains a vector of the lookup entries in each row.
401 """
402 coeffTable = tableList[0]
403
404 metadata = coeffTable.meta
405 inDict = dict()
406 inDict['metadata'] = metadata
407 inDict['hasLinearity'] = metadata.get('HAS_LINEARITY', False)
408 inDict['amplifiers'] = dict()
409 inDict['linearityUnits'] = metadata.get('LINEARITY_UNITS', 'adu')
410
411 for record in coeffTable:
412 ampName = record['AMPLIFIER_NAME']
413 inputGain = record['INPUT_GAIN'] if 'INPUT_GAIN' in record.columns else np.nan
414 inputAbscissa = record['INP_ABSCISSA'] if 'INP_ABSCISSA' in record.columns else np.array([0.0])
415 inputOrdinate = record['INP_ORDINATE'] if 'INP_ORDINATE' in record.columns else np.array([0.0])
416 inputMask = record['INP_MASK'] if 'INP_MASK' in record.columns else np.array([False])
417 inputGroupingIndex = record['INP_GROUPING_INDEX'] if 'INP_GROUPING_INDEX' in record.columns \
418 else np.array([0])
419 inputNormalization = record['INP_NORMALIZATION'] if 'INP_NORMALIZATION' in record.columns \
420 else np.array([1.0])
421 fitParams = record['FIT_PARAMS'] if 'FIT_PARAMS' in record.columns else np.array([0.0])
422 fitParamsErr = record['FIT_PARAMS_ERR'] if 'FIT_PARAMS_ERR' in record.columns else np.array([0.0])
423 fitChiSq = record['RED_CHI_SQ'] if 'RED_CHI_SQ' in record.columns else np.nan
424 fitResiduals = record['FIT_RES'] if 'FIT_RES' in record.columns else np.array([0.0])
425 fitResidualsSigmaMad = record['FIT_RES_SIGMAD'] if 'FIT_RES_SIGMAD' in record.columns else np.nan
426 fitResidualsUnmasked = record['FIT_RES_UNMASKED'] \
427 if 'FIT_RES_UNMASKED' in record.columns else np.array([0.0])
428 fitResidualsModel = record['FIT_RES_MODEL'] \
429 if 'FIT_RES_MODEL' in record.columns else np.array([0.0])
430 linearFit = record['LIN_FIT'] if 'LIN_FIT' in record.columns else np.array([0.0])
431
432 linearityTurnoff = record['LINEARITY_TURNOFF'] if 'LINEARITY_TURNOFF' in record.columns \
433 else np.nan
434 linearityMaxSignal = record['LINEARITY_MAX_SIGNAL'] if 'LINEARITY_MAX_SIGNAL' in record.columns \
435 else np.nan
436
437 inDict['amplifiers'][ampName] = {
438 'inputGain': inputGain,
439 'linearityType': record['TYPE'],
440 'linearityCoeffs': record['COEFFS'],
441 'linearityBBox': Box2I(Point2I(record['BBOX_X0'], record['BBOX_Y0']),
442 Extent2I(record['BBOX_DX'], record['BBOX_DY'])),
443 'inputAbscissa': inputAbscissa,
444 'inputOrdinate': inputOrdinate,
445 'inputMask': inputMask,
446 'inputGroupingIndex': inputGroupingIndex,
447 'inputNormalization': inputNormalization,
448 'fitParams': fitParams,
449 'fitParamsErr': fitParamsErr,
450 'fitChiSq': fitChiSq,
451 'fitResiduals': fitResiduals,
452 'fitResidualsSigmaMad': fitResidualsSigmaMad,
453 'fitResidualsUnmasked': fitResidualsUnmasked,
454 'fitResidualsModel': fitResidualsModel,
455 'linearFit': linearFit,
456 'linearityTurnoff': linearityTurnoff,
457 'linearityMaxSignal': linearityMaxSignal,
458 }
459
460 if len(tableList) > 1:
461 tableData = tableList[1]
462 inDict['tableData'] = [record['LOOKUP_VALUES'] for record in tableData]
463
464 if 'ABS_REF_AMP' in coeffTable.columns:
465 inDict['absoluteReferenceAmplifier'] = str(coeffTable['ABS_REF_AMP'][0])
466 else:
467 inDict['absoluteReferenceAmplifier'] = ''
468
469 return cls().fromDict(inDict)
470

◆ getLinearityTypeByName()

lsst.ip.isr.linearize.Linearizer.getLinearityTypeByName ( self,
linearityTypeName )
Determine the linearity class to use from the type name.

Parameters
----------
linearityTypeName : str
    String name of the linearity type that is needed.

Returns
-------
linearityType : `~lsst.ip.isr.linearize.LinearizeBase`
    The appropriate linearity class to use.  If no matching class
    is found, `None` is returned.

Definition at line 520 of file linearize.py.

520 def getLinearityTypeByName(self, linearityTypeName):
521 """Determine the linearity class to use from the type name.
522
523 Parameters
524 ----------
525 linearityTypeName : str
526 String name of the linearity type that is needed.
527
528 Returns
529 -------
530 linearityType : `~lsst.ip.isr.linearize.LinearizeBase`
531 The appropriate linearity class to use. If no matching class
532 is found, `None` is returned.
533 """
534 for t in [LinearizeLookupTable,
535 LinearizeSquared,
536 LinearizePolynomial,
537 LinearizeProportional,
538 LinearizeSpline,
539 LinearizeDoubleSpline,
540 LinearizeNone]:
541 if t.LinearityType == linearityTypeName:
542 return t
543 return None
544

◆ getMetadata()

lsst.ip.isr.calibType.IsrCalib.getMetadata ( self)
inherited
Retrieve metadata associated with this calibration.

Returns
-------
meta : `lsst.daf.base.PropertyList`
    Metadata. The returned `~lsst.daf.base.PropertyList` can be
    modified by the caller and the changes will be written to
    external files.

Definition at line 174 of file calibType.py.

174 def getMetadata(self):
175 """Retrieve metadata associated with this calibration.
176
177 Returns
178 -------
179 meta : `lsst.daf.base.PropertyList`
180 Metadata. The returned `~lsst.daf.base.PropertyList` can be
181 modified by the caller and the changes will be written to
182 external files.
183 """
184 return self._metadata
185

◆ metadata()

lsst.ip.isr.calibType.IsrCalib.metadata ( self)
inherited

Definition at line 171 of file calibType.py.

171 def metadata(self):
172 return self._metadata
173

◆ readFits()

lsst.ip.isr.calibType.IsrCalib.readFits ( cls,
filename,
** kwargs )
inherited
Read calibration data from a FITS file.

Parameters
----------
filename : `str`
    Filename to read data from.
kwargs : `dict` or collections.abc.Mapping`, optional
    Set of key=value pairs to pass to the ``fromTable``
    method.

Returns
-------
calib : `lsst.ip.isr.IsrCalib`
    Calibration contained within the file.

Definition at line 517 of file calibType.py.

517 def readFits(cls, filename, **kwargs):
518 """Read calibration data from a FITS file.
519
520 Parameters
521 ----------
522 filename : `str`
523 Filename to read data from.
524 kwargs : `dict` or collections.abc.Mapping`, optional
525 Set of key=value pairs to pass to the ``fromTable``
526 method.
527
528 Returns
529 -------
530 calib : `lsst.ip.isr.IsrCalib`
531 Calibration contained within the file.
532 """
533 tableList = []
534 tableList.append(Table.read(filename, hdu=1, mask_invalid=False))
535 extNum = 2 # Fits indices start at 1, we've read one already.
536 keepTrying = True
537
538 while keepTrying:
539 with warnings.catch_warnings():
540 warnings.simplefilter("error")
541 try:
542 newTable = Table.read(filename, hdu=extNum, mask_invalid=False)
543 tableList.append(newTable)
544 extNum += 1
545 except Exception:
546 keepTrying = False
547
548 for table in tableList:
549 for k, v in table.meta.items():
550 if isinstance(v, fits.card.Undefined):
551 table.meta[k] = None
552
553 calibClass = cls.determineCalibClass(tableList[0].meta, "readFits")
554 if calibClass._OBSTYPE in ("PHOTODIODE", ):
555 # Merge primary header, as these types store information
556 # there.
557 with fits.open(filename) as hdul:
558 primaryHeader = hdul[0].header
559 tableList[0].meta = merge_headers([tableList[0].meta, primaryHeader], mode="first")
560
561 return calibClass.fromTable(tableList, **kwargs)
562

◆ readText()

lsst.ip.isr.calibType.IsrCalib.readText ( cls,
filename,
** kwargs )
inherited
Read calibration representation from a yaml/ecsv file.

Parameters
----------
filename : `str`
    Name of the file containing the calibration definition.
kwargs : `dict` or collections.abc.Mapping`, optional
    Set of key=value pairs to pass to the ``fromDict`` or
    ``fromTable`` methods.

Returns
-------
calib : `~lsst.ip.isr.IsrCalibType`
    Calibration class.

Raises
------
RuntimeError
    Raised if the filename does not end in ".ecsv" or ".yaml".

Definition at line 425 of file calibType.py.

425 def readText(cls, filename, **kwargs):
426 """Read calibration representation from a yaml/ecsv file.
427
428 Parameters
429 ----------
430 filename : `str`
431 Name of the file containing the calibration definition.
432 kwargs : `dict` or collections.abc.Mapping`, optional
433 Set of key=value pairs to pass to the ``fromDict`` or
434 ``fromTable`` methods.
435
436 Returns
437 -------
438 calib : `~lsst.ip.isr.IsrCalibType`
439 Calibration class.
440
441 Raises
442 ------
443 RuntimeError
444 Raised if the filename does not end in ".ecsv" or ".yaml".
445 """
446 if filename.endswith((".ecsv", ".ECSV")):
447 data = Table.read(filename, format="ascii.ecsv")
448 calibClass = cls.determineCalibClass(data.meta, "readText/ECSV")
449 return calibClass.fromTable([data], **kwargs)
450 elif filename.endswith((".yaml", ".YAML")):
451 with open(filename, "r") as f:
452 data = yaml.load(f, Loader=yaml.CLoader)
453 calibClass = cls.determineCalibClass(data["metadata"], "readText/YAML")
454 return calibClass.fromDict(data, **kwargs)
455 elif filename.endswith((".json", ".JSON")):
456 with open(filename, "r") as f:
457 data = json.load(f)
458 calibClass = cls.determineCalibClass(data, "readText/JSON")
459 return calibClass.fromDict(data, **kwargs)
460 else:
461 raise RuntimeError(f"Unknown filename extension: {filename}")
462

◆ requiredAttributes() [1/2]

lsst.ip.isr.calibType.IsrCalib.requiredAttributes ( self)
inherited

Definition at line 162 of file calibType.py.

162 def requiredAttributes(self):
163 return self._requiredAttributes
164

◆ requiredAttributes() [2/2]

lsst.ip.isr.calibType.IsrCalib.requiredAttributes ( self,
value )
inherited

Definition at line 166 of file calibType.py.

166 def requiredAttributes(self, value):
167 self._requiredAttributes = value
168

◆ setMetadata()

lsst.ip.isr.calibType.IsrCalib.setMetadata ( self,
metadata )
inherited
Store a copy of the supplied metadata with this calibration.

Parameters
----------
metadata : `lsst.daf.base.PropertyList`
    Metadata to associate with the calibration.  Will be copied and
    overwrite existing metadata.

Reimplemented in lsst.ip.isr.transmissionCurve.IntermediateTransmissionCurve.

Definition at line 186 of file calibType.py.

186 def setMetadata(self, metadata):
187 """Store a copy of the supplied metadata with this calibration.
188
189 Parameters
190 ----------
191 metadata : `lsst.daf.base.PropertyList`
192 Metadata to associate with the calibration. Will be copied and
193 overwrite existing metadata.
194 """
195 if metadata is not None:
196 self._metadata.update(metadata)
197
198 # Ensure that we have the obs type required by calibration ingest
199 self._metadata["OBSTYPE"] = self._OBSTYPE
200 self._metadata[self._OBSTYPE + "_SCHEMA"] = self._SCHEMA
201 self._metadata[self._OBSTYPE + "_VERSION"] = self._VERSION
202
203 if isinstance(metadata, dict):
204 self.calibInfoFromDict(metadata)
205 elif isinstance(metadata, PropertyList):
206 self.calibInfoFromDict(metadata.toDict())
207

◆ toDict()

lsst.ip.isr.linearize.Linearizer.toDict ( self)
Return linearity parameters as a dict.

Returns
-------
outDict : `dict`:

Reimplemented from lsst.ip.isr.calibType.IsrCalib.

Definition at line 327 of file linearize.py.

327 def toDict(self):
328 """Return linearity parameters as a dict.
329
330 Returns
331 -------
332 outDict : `dict`:
333 """
334 self.updateMetadata()
335
336 outDict = {'metadata': self.getMetadata(),
337 'detectorName': self._detectorName,
338 'detectorSerial': self._detectorSerial,
339 'detectorId': self._detectorId,
340 'hasTable': self.tableData is not None,
341 'amplifiers': dict(),
342 'linearityUnits': self.linearityUnits,
343 }
344 for ampName in self.linearityType:
345 outDict['amplifiers'][ampName] = {
346 'inputGain': self.inputGain[ampName],
347 'linearityType': self.linearityType[ampName],
348 'linearityCoeffs': self.linearityCoeffs[ampName].tolist(),
349 'linearityBBox': self.linearityBBox[ampName],
350 'inputAbscissa': self.inputAbscissa[ampName].tolist(),
351 'inputOrdinate': self.inputOrdinate[ampName].tolist(),
352 'inputMask': self.inputMask[ampName].tolist(),
353 'inputGroupingIndex': self.inputGroupingIndex[ampName].tolist(),
354 'inputNormalization': self.inputNormalization[ampName].tolist(),
355 'fitParams': self.fitParams[ampName].tolist(),
356 'fitParamsErr': self.fitParamsErr[ampName].tolist(),
357 'fitChiSq': self.fitChiSq[ampName],
358 'fitResiduals': self.fitResiduals[ampName].tolist(),
359 'fitResidualsSigmaMad': self.fitResidualsSigmaMad[ampName],
360 'fitResidualsUnmasked': self.fitResidualsUnmasked[ampName].tolist(),
361 'fitResidualsModel': self.fitResidualsModel[ampName].tolist(),
362 'linearFit': self.linearFit[ampName].tolist(),
363 'linearityTurnoff': self.linearityTurnoff[ampName],
364 'linearityMaxSignal': self.linearityMaxSignal[ampName],
365 }
366 if self.tableData is not None:
367 outDict['tableData'] = self.tableData.tolist()
368
369 outDict['absoluteReferenceAmplifier'] = self.absoluteReferenceAmplifier
370
371 return outDict
372

◆ toTable()

lsst.ip.isr.linearize.Linearizer.toTable ( self)
Construct a list of tables containing the information in this
calibration.

The list of tables should create an identical calibration
after being passed to this class's fromTable method.

Returns
-------
tableList : `list` [`astropy.table.Table`]
    List of tables containing the linearity calibration
    information.

Reimplemented from lsst.ip.isr.calibType.IsrCalib.

Definition at line 471 of file linearize.py.

471 def toTable(self):
472 """Construct a list of tables containing the information in this
473 calibration.
474
475 The list of tables should create an identical calibration
476 after being passed to this class's fromTable method.
477
478 Returns
479 -------
480 tableList : `list` [`astropy.table.Table`]
481 List of tables containing the linearity calibration
482 information.
483 """
484
485 tableList = []
486 self.updateMetadata()
487 catalog = Table([{'AMPLIFIER_NAME': ampName,
488 'INPUT_GAIN': self.inputGain[ampName],
489 'TYPE': self.linearityType[ampName],
490 'COEFFS': self.linearityCoeffs[ampName],
491 'BBOX_X0': self.linearityBBox[ampName].getMinX(),
492 'BBOX_Y0': self.linearityBBox[ampName].getMinY(),
493 'BBOX_DX': self.linearityBBox[ampName].getWidth(),
494 'BBOX_DY': self.linearityBBox[ampName].getHeight(),
495 'INP_ABSCISSA': self.inputAbscissa[ampName],
496 'INP_ORDINATE': self.inputOrdinate[ampName],
497 'INP_MASK': self.inputMask[ampName],
498 'INP_GROUPING_INDEX': self.inputGroupingIndex[ampName],
499 'INP_NORMALIZATION': self.inputNormalization[ampName],
500 'FIT_PARAMS': self.fitParams[ampName],
501 'FIT_PARAMS_ERR': self.fitParamsErr[ampName],
502 'RED_CHI_SQ': self.fitChiSq[ampName],
503 'FIT_RES': self.fitResiduals[ampName],
504 'FIT_RES_SIGMAD': self.fitResidualsSigmaMad[ampName],
505 'FIT_RES_UNMASKED': self.fitResidualsUnmasked[ampName],
506 'FIT_RES_MODEL': self.fitResidualsModel[ampName],
507 'LIN_FIT': self.linearFit[ampName],
508 'LINEARITY_TURNOFF': self.linearityTurnoff[ampName],
509 'LINEARITY_MAX_SIGNAL': self.linearityMaxSignal[ampName],
510 'ABS_REF_AMP': self.absoluteReferenceAmplifier,
511 } for ampName in self.ampNames])
512 catalog.meta = self.getMetadata().toDict()
513 tableList.append(catalog)
514
515 if self.tableData is not None:
516 catalog = Table([{'LOOKUP_VALUES': value} for value in self.tableData])
517 tableList.append(catalog)
518 return tableList
519

◆ updateMetadata()

lsst.ip.isr.linearize.Linearizer.updateMetadata ( self,
setDate = False,
** kwargs )
Update metadata keywords with new values.

This calls the base class's method after ensuring the required
calibration keywords will be saved.

Parameters
----------
setDate : `bool`, optional
    Update the CALIBDATE fields in the metadata to the current
    time. Defaults to False.
kwargs :
    Other keyword parameters to set in the metadata.

Reimplemented from lsst.ip.isr.calibType.IsrCalib.

Definition at line 197 of file linearize.py.

197 def updateMetadata(self, setDate=False, **kwargs):
198 """Update metadata keywords with new values.
199
200 This calls the base class's method after ensuring the required
201 calibration keywords will be saved.
202
203 Parameters
204 ----------
205 setDate : `bool`, optional
206 Update the CALIBDATE fields in the metadata to the current
207 time. Defaults to False.
208 kwargs :
209 Other keyword parameters to set in the metadata.
210 """
211 kwargs['HAS_LINEARITY'] = self.hasLinearity
212 kwargs['OVERRIDE'] = self.override
213 kwargs['HAS_TABLE'] = self.tableData is not None
214 kwargs['LINEARITY_UNITS'] = self.linearityUnits
215
216 super().updateMetadata(setDate=setDate, **kwargs)
217

◆ updateMetadataFromExposures()

lsst.ip.isr.calibType.IsrCalib.updateMetadataFromExposures ( self,
exposures )
inherited
Extract and unify metadata information.

Parameters
----------
exposures : `list`
    Exposures or other calibrations to scan.

Definition at line 294 of file calibType.py.

294 def updateMetadataFromExposures(self, exposures):
295 """Extract and unify metadata information.
296
297 Parameters
298 ----------
299 exposures : `list`
300 Exposures or other calibrations to scan.
301 """
302 # This list of keywords is the set of header entries that
303 # should be checked and propagated. Not having an entry is
304 # not a failure, as they may not be defined for the exposures
305 # being used.
306 keywords = ["SEQNAME", "SEQFILE", "SEQCKSUM", "ODP", "AP0_RC"]
307 metadata = {}
308
309 for exp in exposures:
310 try:
311 expMeta = exp.getMetadata()
312 except AttributeError:
313 continue
314 for key in keywords:
315 if key in expMeta:
316 if key in metadata:
317 if metadata[key] != expMeta[key]:
318 self.log.warning("Metadata mismatch! Have: %s Found %s",
319 metadata[key], expMeta[key])
320 else:
321 metadata[key] = expMeta[key]
322
323 self.updateMetadata(**metadata, setCalibInfo=True)
324

◆ validate()

lsst.ip.isr.linearize.Linearizer.validate ( self,
detector = None,
amplifier = None )
Validate linearity for a detector/amplifier.

Parameters
----------
detector : `lsst.afw.cameraGeom.Detector`, optional
    Detector to validate, along with its amplifiers.
amplifier : `lsst.afw.cameraGeom.Amplifier`, optional
    Single amplifier to validate.

Raises
------
RuntimeError
    Raised if there is a mismatch in linearity parameters, and
    the cameraGeom parameters are not being overridden.

Reimplemented from lsst.ip.isr.calibType.IsrCalib.

Definition at line 545 of file linearize.py.

545 def validate(self, detector=None, amplifier=None):
546 """Validate linearity for a detector/amplifier.
547
548 Parameters
549 ----------
550 detector : `lsst.afw.cameraGeom.Detector`, optional
551 Detector to validate, along with its amplifiers.
552 amplifier : `lsst.afw.cameraGeom.Amplifier`, optional
553 Single amplifier to validate.
554
555 Raises
556 ------
557 RuntimeError
558 Raised if there is a mismatch in linearity parameters, and
559 the cameraGeom parameters are not being overridden.
560 """
561 amplifiersToCheck = []
562 if detector:
563 if self._detectorName != detector.getName():
564 raise RuntimeError("Detector names don't match: %s != %s" %
565 (self._detectorName, detector.getName()))
566 if int(self._detectorId) != int(detector.getId()):
567 raise RuntimeError("Detector IDs don't match: %s != %s" %
568 (int(self._detectorId), int(detector.getId())))
569 # TODO: DM-38778: This check fails on LATISS due to an
570 # error in the camera configuration.
571 # if self._detectorSerial != detector.getSerial():
572 # raise RuntimeError(
573 # "Detector serial numbers don't match: %s != %s" %
574 # (self._detectorSerial, detector.getSerial()))
575 if len(detector.getAmplifiers()) != len(self.linearityCoeffs.keys()):
576 raise RuntimeError("Detector number of amps = %s does not match saved value %s" %
577 (len(detector.getAmplifiers()),
578 len(self.linearityCoeffs.keys())))
579 amplifiersToCheck.extend(detector.getAmplifiers())
580
581 if amplifier:
582 amplifiersToCheck.extend(amplifier)
583
584 for amp in amplifiersToCheck:
585 ampName = amp.getName()
586 if ampName not in self.linearityCoeffs.keys():
587 raise RuntimeError("Amplifier %s is not in linearity data" %
588 (ampName, ))
589 if amp.getLinearityType() != self.linearityType[ampName]:
590 if self.override:
591 self.log.debug("Overriding amplifier defined linearityType (%s) for %s",
592 self.linearityType[ampName], ampName)
593 else:
594 raise RuntimeError("Amplifier %s type %s does not match saved value %s" %
595 (ampName, amp.getLinearityType(), self.linearityType[ampName]))
596 if (amp.getLinearityCoeffs().shape != self.linearityCoeffs[ampName].shape or not
597 np.allclose(amp.getLinearityCoeffs(), self.linearityCoeffs[ampName], equal_nan=True)):
598 if self.override:
599 self.log.debug("Overriding amplifier defined linearityCoeffs (%s) for %s",
600 self.linearityCoeffs[ampName], ampName)
601 else:
602 raise RuntimeError("Amplifier %s coeffs %s does not match saved value %s" %
603 (ampName, amp.getLinearityCoeffs(), self.linearityCoeffs[ampName]))
604

◆ writeFits()

lsst.ip.isr.calibType.IsrCalib.writeFits ( self,
filename )
inherited
Write calibration data to a FITS file.

Parameters
----------
filename : `str`
    Filename to write data to.

Returns
-------
used : `str`
    The name of the file used to write the data.

Reimplemented in lsst.ip.isr.transmissionCurve.IntermediateTransmissionCurve.

Definition at line 563 of file calibType.py.

563 def writeFits(self, filename):
564 """Write calibration data to a FITS file.
565
566 Parameters
567 ----------
568 filename : `str`
569 Filename to write data to.
570
571 Returns
572 -------
573 used : `str`
574 The name of the file used to write the data.
575 """
576 tableList = self.toTable()
577 with warnings.catch_warnings():
578 warnings.filterwarnings("ignore", category=Warning, module="astropy.io")
579 astropyList = [fits.table_to_hdu(table) for table in tableList]
580 astropyList.insert(0, fits.PrimaryHDU())
581
582 writer = fits.HDUList(astropyList)
583 writer.writeto(filename, overwrite=True)
584 return filename
585

◆ writeText()

lsst.ip.isr.calibType.IsrCalib.writeText ( self,
filename,
format = "auto" )
inherited
Write the calibration data to a text file.

Parameters
----------
filename : `str`
    Name of the file to write.
format : `str`
    Format to write the file as.  Supported values are:
        ``"auto"`` : Determine filetype from filename.
        ``"yaml"`` : Write as yaml.
        ``"ecsv"`` : Write as ecsv.

Returns
-------
used : `str`
    The name of the file used to write the data.  This may
    differ from the input if the format is explicitly chosen.

Raises
------
RuntimeError
    Raised if filename does not end in a known extension, or
    if all information cannot be written.

Notes
-----
The file is written to YAML/ECSV format and will include any
associated metadata.

Definition at line 463 of file calibType.py.

463 def writeText(self, filename, format="auto"):
464 """Write the calibration data to a text file.
465
466 Parameters
467 ----------
468 filename : `str`
469 Name of the file to write.
470 format : `str`
471 Format to write the file as. Supported values are:
472 ``"auto"`` : Determine filetype from filename.
473 ``"yaml"`` : Write as yaml.
474 ``"ecsv"`` : Write as ecsv.
475
476 Returns
477 -------
478 used : `str`
479 The name of the file used to write the data. This may
480 differ from the input if the format is explicitly chosen.
481
482 Raises
483 ------
484 RuntimeError
485 Raised if filename does not end in a known extension, or
486 if all information cannot be written.
487
488 Notes
489 -----
490 The file is written to YAML/ECSV format and will include any
491 associated metadata.
492 """
493 if format == "yaml" or (format == "auto" and filename.lower().endswith((".yaml", ".YAML"))):
494 outDict = self.toDict()
495 path, ext = os.path.splitext(filename)
496 filename = path + ".yaml"
497 with open(filename, "w") as f:
498 yaml.dump(outDict, f)
499 elif format == "ecsv" or (format == "auto" and filename.lower().endswith((".ecsv", ".ECSV"))):
500 tableList = self.toTable()
501 if len(tableList) > 1:
502 # ECSV doesn't support multiple tables per file, so we
503 # can only write the first table.
504 raise RuntimeError(f"Unable to persist {len(tableList)}tables in ECSV format.")
505
506 table = tableList[0]
507 path, ext = os.path.splitext(filename)
508 filename = path + ".ecsv"
509 table.write(filename, format="ascii.ecsv")
510 else:
511 raise RuntimeError(f"Attempt to write to a file {filename} "
512 "that does not end in '.yaml' or '.ecsv'")
513
514 return filename
515

Member Data Documentation

◆ _calibId

str lsst.ip.isr.calibType.IsrCalib._calibId = None
protectedinherited

Definition at line 76 of file calibType.py.

◆ _detectorId

lsst.ip.isr.calibType.IsrCalib._detectorId = None
protectedinherited

Definition at line 74 of file calibType.py.

◆ _detectorName

lsst.ip.isr.calibType.IsrCalib._detectorName = None
protectedinherited

Definition at line 72 of file calibType.py.

◆ _detectorSerial

lsst.ip.isr.calibType.IsrCalib._detectorSerial = None
protectedinherited

Definition at line 73 of file calibType.py.

◆ _filter

lsst.ip.isr.calibType.IsrCalib._filter = None
protectedinherited

Definition at line 75 of file calibType.py.

◆ _instrument

lsst.ip.isr.calibType.IsrCalib._instrument = None
protectedinherited

Definition at line 69 of file calibType.py.

◆ _metadata

lsst.ip.isr.calibType.IsrCalib._metadata = PropertyList()
protectedinherited

Definition at line 80 of file calibType.py.

◆ _OBSTYPE

str lsst.ip.isr.calibType.IsrCalib._OBSTYPE = "generic"
staticprotectedinherited

Definition at line 64 of file calibType.py.

◆ _raftName

lsst.ip.isr.calibType.IsrCalib._raftName = None
protectedinherited

Definition at line 70 of file calibType.py.

◆ _requiredAttributes

lsst.ip.isr.calibType.IsrCalib._requiredAttributes
protectedinherited

Definition at line 115 of file calibType.py.

◆ _SCHEMA

str lsst.ip.isr.calibType.IsrCalib._SCHEMA = "NO SCHEMA"
staticprotectedinherited

Definition at line 65 of file calibType.py.

◆ _seqcksum

lsst.ip.isr.calibType.IsrCalib._seqcksum = None
protectedinherited

Definition at line 79 of file calibType.py.

◆ _seqfile

lsst.ip.isr.calibType.IsrCalib._seqfile = None
protectedinherited

Definition at line 77 of file calibType.py.

◆ _seqname

lsst.ip.isr.calibType.IsrCalib._seqname = None
protectedinherited

Definition at line 78 of file calibType.py.

◆ _slotName

lsst.ip.isr.calibType.IsrCalib._slotName = None
protectedinherited

Definition at line 71 of file calibType.py.

◆ _VERSION

int lsst.ip.isr.calibType.IsrCalib._VERSION = 0
staticprotectedinherited

Definition at line 66 of file calibType.py.

◆ absoluteReferenceAmplifier

str lsst.ip.isr.linearize.Linearizer.absoluteReferenceAmplifier = ""

Definition at line 173 of file linearize.py.

◆ ampNames

lsst.ip.isr.linearize.Linearizer.ampNames = list()

Definition at line 153 of file linearize.py.

◆ fitChiSq

lsst.ip.isr.linearize.Linearizer.fitChiSq = dict()

Definition at line 165 of file linearize.py.

◆ fitParams

lsst.ip.isr.linearize.Linearizer.fitParams = dict()

Definition at line 163 of file linearize.py.

◆ fitParamsErr

lsst.ip.isr.linearize.Linearizer.fitParamsErr = dict()

Definition at line 164 of file linearize.py.

◆ fitResiduals

lsst.ip.isr.linearize.Linearizer.fitResiduals = dict()

Definition at line 166 of file linearize.py.

◆ fitResidualsModel

lsst.ip.isr.linearize.Linearizer.fitResidualsModel = dict()

Definition at line 169 of file linearize.py.

◆ fitResidualsSigmaMad

lsst.ip.isr.linearize.Linearizer.fitResidualsSigmaMad = dict()

Definition at line 167 of file linearize.py.

◆ fitResidualsUnmasked

lsst.ip.isr.linearize.Linearizer.fitResidualsUnmasked = dict()

Definition at line 168 of file linearize.py.

◆ hasLinearity

bool lsst.ip.isr.linearize.Linearizer.hasLinearity = False

Definition at line 150 of file linearize.py.

◆ inputAbscissa

lsst.ip.isr.linearize.Linearizer.inputAbscissa = dict()

Definition at line 158 of file linearize.py.

◆ inputGain

lsst.ip.isr.linearize.Linearizer.inputGain = dict()

Definition at line 154 of file linearize.py.

◆ inputGroupingIndex

lsst.ip.isr.linearize.Linearizer.inputGroupingIndex = dict()

Definition at line 161 of file linearize.py.

◆ inputMask

lsst.ip.isr.linearize.Linearizer.inputMask = dict()

Definition at line 160 of file linearize.py.

◆ inputNormalization

lsst.ip.isr.linearize.Linearizer.inputNormalization = dict()

Definition at line 162 of file linearize.py.

◆ inputOrdinate

lsst.ip.isr.linearize.Linearizer.inputOrdinate = dict()

Definition at line 159 of file linearize.py.

◆ linearFit

lsst.ip.isr.linearize.Linearizer.linearFit = dict()

Definition at line 170 of file linearize.py.

◆ linearityBBox

lsst.ip.isr.linearize.Linearizer.linearityBBox = dict()

Definition at line 157 of file linearize.py.

◆ linearityCoeffs

lsst.ip.isr.linearize.Linearizer.linearityCoeffs = dict()

Definition at line 155 of file linearize.py.

◆ linearityMaxSignal

lsst.ip.isr.linearize.Linearizer.linearityMaxSignal = dict()

Definition at line 172 of file linearize.py.

◆ linearityTurnoff

lsst.ip.isr.linearize.Linearizer.linearityTurnoff = dict()

Definition at line 171 of file linearize.py.

◆ linearityType

lsst.ip.isr.linearize.Linearizer.linearityType = dict()

Definition at line 156 of file linearize.py.

◆ linearityUnits

str lsst.ip.isr.linearize.Linearizer.linearityUnits = 'adu'

Definition at line 184 of file linearize.py.

◆ log

lsst.ip.isr.calibType.IsrCalib.log = log if log else logging.getLogger(__name__)
inherited

Definition at line 96 of file calibType.py.

◆ override

bool lsst.ip.isr.linearize.Linearizer.override = False

Definition at line 151 of file linearize.py.

◆ requiredAttributes

lsst.ip.isr.calibType.IsrCalib.requiredAttributes = set(["_OBSTYPE", "_SCHEMA", "_VERSION"])
inherited

Definition at line 90 of file calibType.py.

◆ tableData

lsst.ip.isr.linearize.Linearizer.tableData = None

Definition at line 174 of file linearize.py.


The documentation for this class was generated from the following file: