LSSTApplications  17.0+11,17.0+35,17.0+60,17.0+61,17.0+63,17.0+7,17.0-1-g377950a+35,17.0.1-1-g114240f+2,17.0.1-1-g4d4fbc4+30,17.0.1-1-g55520dc+55,17.0.1-1-g5f4ed7e+59,17.0.1-1-g6dd7d69+22,17.0.1-1-g8de6c91+11,17.0.1-1-gb9095d2+7,17.0.1-1-ge9fec5e+5,17.0.1-1-gf4e0155+63,17.0.1-1-gfc65f5f+56,17.0.1-1-gfc6fb1f+20,17.0.1-10-g87f9f3f+9,17.0.1-12-g112a4bc+3,17.0.1-17-gab9750a3+5,17.0.1-17-gdae4c4a+16,17.0.1-19-g3a24bb2+2,17.0.1-2-g26618f5+35,17.0.1-2-g54f2ebc+9,17.0.1-2-gf403422+1,17.0.1-21-g52a398f+5,17.0.1-26-gd98a1d13,17.0.1-3-g7e86b59+45,17.0.1-3-gb5ca14a,17.0.1-3-gd08d533+46,17.0.1-31-gb0791f330,17.0.1-4-g59d126d+10,17.0.1-5-g3877d06+2,17.0.1-7-g35889ee+7,17.0.1-7-gc7c8782+20,17.0.1-7-gcb7da53+5,17.0.1-9-gc4bbfb2+10,w.2019.24
LSSTDataManagementBasePackage
Public Member Functions | Public Attributes | Static Public Attributes | List of all members
lsst.ip.isr.isrTask.IsrTask Class Reference
Inheritance diagram for lsst.ip.isr.isrTask.IsrTask:

Public Member Functions

def __init__ (self, kwargs)
 
def getInputDatasetTypes (cls, config)
 
def getOutputDatasetTypes (cls, config)
 
def getPrerequisiteDatasetTypes (cls, config)
 
def getPerDatasetTypeDimensions (cls, config)
 
def adaptArgsAndRun (self, inputData, inputDataIds, outputDataIds, butler)
 
def makeDatasetType (self, dsConfig)
 
def readIsrData (self, dataRef, rawExposure)
 Retrieve necessary frames for instrument signature removal. More...
 
def run (self, ccdExposure, camera=None, bias=None, linearizer=None, crosstalkSources=None, dark=None, flat=None, bfKernel=None, defects=None, fringes=None, opticsTransmission=None, filterTransmission=None, sensorTransmission=None, atmosphereTransmission=None, detectorNum=None, strayLightData=None, illumMaskedImage=None, isGen3=False)
 Perform instrument signature removal on an exposure. More...
 
def runDataRef (self, sensorRef)
 
def getIsrExposure (self, dataRef, datasetType, immediate=True)
 Retrieve a calibration dataset for removing instrument signature. More...
 
def ensureExposure (self, inputExp, camera, detectorNum)
 
def convertIntToFloat (self, exposure)
 
def maskAmplifier (self, ccdExposure, amp, defects)
 
def overscanCorrection (self, ccdExposure, amp)
 
def updateVariance (self, ampExposure, amp, overscanImage=None)
 
def darkCorrection (self, exposure, darkExposure, invert=False)
 Apply dark correction in place. More...
 
def doLinearize (self, detector)
 Check if linearization is needed for the detector cameraGeom. More...
 
def flatCorrection (self, exposure, flatExposure, invert=False)
 Apply flat correction in place. More...
 
def saturationDetection (self, exposure, amp)
 Detect saturated pixels and mask them using mask plane config.saturatedMaskName, in place. More...
 
def saturationInterpolation (self, exposure)
 Interpolate over saturated pixels, in place. More...
 
def suspectDetection (self, exposure, amp)
 Detect suspect pixels and mask them using mask plane config.suspectMaskName, in place. More...
 
def maskDefect (self, exposure, defectBaseList)
 Mask defects using mask plane "BAD", in place. More...
 
def maskAndInterpolateDefects (self, exposure, defectBaseList)
 
def maskNan (self, exposure)
 
def maskAndInterpolateNan (self, exposure)
 
def measureBackground (self, exposure, IsrQaConfig=None)
 
def roughZeroPoint (self, exposure)
 
def setValidPolygonIntersect (self, ccdExposure, fpPolygon)
 Set the valid polygon as the intersection of fpPolygon and the ccd corners. More...
 
def flatContext (self, exp, flat, dark=None)
 
def debugView (self, exposure, stepname)
 

Public Attributes

 vignettePolygon
 

Static Public Attributes

 ConfigClass = IsrTaskConfig
 

Detailed Description

Apply common instrument signature correction algorithms to a raw frame.

The process for correcting imaging data is very similar from
camera to camera.  This task provides a vanilla implementation of
doing these corrections, including the ability to turn certain
corrections off if they are not needed.  The inputs to the primary
method, `run()`, are a raw exposure to be corrected and the
calibration data products. The raw input is a single chip sized
mosaic of all amps including overscans and other non-science
pixels.  The method `runDataRef()` identifies and defines the
calibration data products, and is intended for use by a
`lsst.pipe.base.cmdLineTask.CmdLineTask` and takes as input only a
`daf.persistence.butlerSubset.ButlerDataRef`.  This task may be
subclassed for different camera, although the most camera specific
methods have been split into subtasks that can be redirected
appropriately.

The __init__ method sets up the subtasks for ISR processing, using
the defaults from `lsst.ip.isr`.

Parameters
----------
args : `list`
    Positional arguments passed to the Task constructor. None used at this time.
kwargs : `dict`, optional
    Keyword arguments passed on to the Task constructor. None used at this time.

Definition at line 728 of file isrTask.py.

Constructor & Destructor Documentation

◆ __init__()

def lsst.ip.isr.isrTask.IsrTask.__init__ (   self,
  kwargs 
)

Definition at line 759 of file isrTask.py.

759  def __init__(self, **kwargs):
760  super().__init__(**kwargs)
761  self.makeSubtask("assembleCcd")
762  self.makeSubtask("crosstalk")
763  self.makeSubtask("strayLight")
764  self.makeSubtask("fringe")
765  self.makeSubtask("masking")
766  self.makeSubtask("vignette")
767 
def __init__(self, minimum, dataRange, Q)

Member Function Documentation

◆ adaptArgsAndRun()

def lsst.ip.isr.isrTask.IsrTask.adaptArgsAndRun (   self,
  inputData,
  inputDataIds,
  outputDataIds,
  butler 
)

Definition at line 838 of file isrTask.py.

838  def adaptArgsAndRun(self, inputData, inputDataIds, outputDataIds, butler):
839  try:
840  inputData['detectorNum'] = int(inputDataIds['ccdExposure']['detector'])
841  except Exception as e:
842  raise ValueError(f"Failure to find valid detectorNum value for Dataset {inputDataIds}: {e}")
843 
844  inputData['isGen3'] = True
845 
846  if self.config.doLinearize is True:
847  if 'linearizer' not in inputData.keys():
848  detector = inputData['camera'][inputData['detectorNum']]
849  linearityName = detector.getAmpInfoCatalog()[0].getLinearityType()
850  inputData['linearizer'] = linearize.getLinearityTypeByName(linearityName)()
851 
852  if inputData['defects'] is not None:
853  # defects is loaded as a BaseCatalog with columns x0, y0, width, height.
854  # masking expects a list of defects defined by their bounding box
855  if not isinstance(inputData["defects"], Defects):
856  inputData["defects"] = Defects.fromTable(inputData["defects"])
857 
858  # Broken: DM-17169
859  # ci_hsc does not use crosstalkSources, as it's intra-CCD CT only. This needs to be
860  # fixed for non-HSC cameras in the future.
861  # inputData['crosstalkSources'] = (self.crosstalk.prepCrosstalk(inputDataIds['ccdExposure'])
862  # if self.config.doCrosstalk else None)
863 
864  # Broken: DM-17152
865  # Fringes are not tested to be handled correctly by Gen3 butler.
866  # inputData['fringes'] = (self.fringe.readFringes(inputDataIds['ccdExposure'],
867  # assembler=self.assembleCcd
868  # if self.config.doAssembleIsrExposures else None)
869  # if self.config.doFringe and
870  # self.fringe.checkFilter(inputData['ccdExposure'])
871  # else pipeBase.Struct(fringes=None))
872 
873  return super().adaptArgsAndRun(inputData, inputDataIds, outputDataIds, butler)
874 

◆ convertIntToFloat()

def lsst.ip.isr.isrTask.IsrTask.convertIntToFloat (   self,
  exposure 
)
Convert exposure image from uint16 to float.

If the exposure does not need to be converted, the input is
immediately returned.  For exposures that are converted to use
floating point pixels, the variance is set to unity and the
mask to zero.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
   The raw exposure to be converted.

Returns
-------
newexposure : `lsst.afw.image.Exposure`
   The input ``exposure``, converted to floating point pixels.

Raises
------
RuntimeError
    Raised if the exposure type cannot be converted to float.

Definition at line 1585 of file isrTask.py.

1585  def convertIntToFloat(self, exposure):
1586  """Convert exposure image from uint16 to float.
1587 
1588  If the exposure does not need to be converted, the input is
1589  immediately returned. For exposures that are converted to use
1590  floating point pixels, the variance is set to unity and the
1591  mask to zero.
1592 
1593  Parameters
1594  ----------
1595  exposure : `lsst.afw.image.Exposure`
1596  The raw exposure to be converted.
1597 
1598  Returns
1599  -------
1600  newexposure : `lsst.afw.image.Exposure`
1601  The input ``exposure``, converted to floating point pixels.
1602 
1603  Raises
1604  ------
1605  RuntimeError
1606  Raised if the exposure type cannot be converted to float.
1607 
1608  """
1609  if isinstance(exposure, afwImage.ExposureF):
1610  # Nothing to be done
1611  return exposure
1612  if not hasattr(exposure, "convertF"):
1613  raise RuntimeError("Unable to convert exposure (%s) to float" % type(exposure))
1614 
1615  newexposure = exposure.convertF()
1616  newexposure.variance[:] = 1
1617  newexposure.mask[:] = 0x0
1618 
1619  return newexposure
1620 
table::Key< int > type
Definition: Detector.cc:167

◆ darkCorrection()

def lsst.ip.isr.isrTask.IsrTask.darkCorrection (   self,
  exposure,
  darkExposure,
  invert = False 
)

Apply dark correction in place.

Parameters

exposure : lsst.afw.image.Exposure Exposure to process. darkExposure : lsst.afw.image.Exposure Dark exposure of the same size as exposure. invert : Bool, optional If True, re-add the dark to an already corrected image.

Raises

RuntimeError Raised if either exposure or darkExposure do not have their dark time defined.

See Also

lsst.ip.isr.isrFunctions.darkCorrection

Definition at line 1878 of file isrTask.py.

1878  def darkCorrection(self, exposure, darkExposure, invert=False):
1879  """!Apply dark correction in place.
1880 
1881  Parameters
1882  ----------
1883  exposure : `lsst.afw.image.Exposure`
1884  Exposure to process.
1885  darkExposure : `lsst.afw.image.Exposure`
1886  Dark exposure of the same size as ``exposure``.
1887  invert : `Bool`, optional
1888  If True, re-add the dark to an already corrected image.
1889 
1890  Raises
1891  ------
1892  RuntimeError
1893  Raised if either ``exposure`` or ``darkExposure`` do not
1894  have their dark time defined.
1895 
1896  See Also
1897  --------
1898  lsst.ip.isr.isrFunctions.darkCorrection
1899  """
1900  expScale = exposure.getInfo().getVisitInfo().getDarkTime()
1901  if math.isnan(expScale):
1902  raise RuntimeError("Exposure darktime is NAN")
1903  if darkExposure.getInfo().getVisitInfo() is not None:
1904  darkScale = darkExposure.getInfo().getVisitInfo().getDarkTime()
1905  else:
1906  # DM-17444: darkExposure.getInfo.getVisitInfo() is None
1907  # so getDarkTime() does not exist.
1908  darkScale = 1.0
1909 
1910  if math.isnan(darkScale):
1911  raise RuntimeError("Dark calib darktime is NAN")
1912  isrFunctions.darkCorrection(
1913  maskedImage=exposure.getMaskedImage(),
1914  darkMaskedImage=darkExposure.getMaskedImage(),
1915  expScale=expScale,
1916  darkScale=darkScale,
1917  invert=invert,
1918  trimToFit=self.config.doTrimToMatchCalib
1919  )
1920 
def darkCorrection(maskedImage, darkMaskedImage, expScale, darkScale, invert=False, trimToFit=False)

◆ debugView()

def lsst.ip.isr.isrTask.IsrTask.debugView (   self,
  exposure,
  stepname 
)
Utility function to examine ISR exposure at different stages.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to view.
stepname : `str`
    State of processing to view.

Definition at line 2288 of file isrTask.py.

2288  def debugView(self, exposure, stepname):
2289  """Utility function to examine ISR exposure at different stages.
2290 
2291  Parameters
2292  ----------
2293  exposure : `lsst.afw.image.Exposure`
2294  Exposure to view.
2295  stepname : `str`
2296  State of processing to view.
2297  """
2298  frame = getDebugFrame(self._display, stepname)
2299  if frame:
2300  display = getDisplay(frame)
2301  display.scale('asinh', 'zscale')
2302  display.mtv(exposure)
2303 
2304 
def getDebugFrame(debugDisplay, name)
Definition: lsstDebug.py:90

◆ doLinearize()

def lsst.ip.isr.isrTask.IsrTask.doLinearize (   self,
  detector 
)

Check if linearization is needed for the detector cameraGeom.

Checks config.doLinearize and the linearity type of the first amplifier.

Parameters

detector : lsst.afw.cameraGeom.Detector Detector to get linearity type from.

Returns

doLinearize : Bool If True, linearization should be performed.

Definition at line 1921 of file isrTask.py.

1921  def doLinearize(self, detector):
1922  """!Check if linearization is needed for the detector cameraGeom.
1923 
1924  Checks config.doLinearize and the linearity type of the first
1925  amplifier.
1926 
1927  Parameters
1928  ----------
1929  detector : `lsst.afw.cameraGeom.Detector`
1930  Detector to get linearity type from.
1931 
1932  Returns
1933  -------
1934  doLinearize : `Bool`
1935  If True, linearization should be performed.
1936  """
1937  return self.config.doLinearize and \
1938  detector.getAmpInfoCatalog()[0].getLinearityType() != NullLinearityType
1939 

◆ ensureExposure()

def lsst.ip.isr.isrTask.IsrTask.ensureExposure (   self,
  inputExp,
  camera,
  detectorNum 
)
Ensure that the data returned by Butler is a fully constructed exposure.

ISR requires exposure-level image data for historical reasons, so if we did
not recieve that from Butler, construct it from what we have, modifying the
input in place.

Parameters
----------
inputExp : `lsst.afw.image.Exposure`, `lsst.afw.image.DecoratedImageU`, or
   `lsst.afw.image.ImageF`
    The input data structure obtained from Butler.
camera : `lsst.afw.cameraGeom.camera`
    The camera associated with the image.  Used to find the appropriate
    detector.
detectorNum : `int`
    The detector this exposure should match.

Returns
-------
inputExp : `lsst.afw.image.Exposure`
    The re-constructed exposure, with appropriate detector parameters.

Raises
------
TypeError
    Raised if the input data cannot be used to construct an exposure.

Definition at line 1538 of file isrTask.py.

1538  def ensureExposure(self, inputExp, camera, detectorNum):
1539  """Ensure that the data returned by Butler is a fully constructed exposure.
1540 
1541  ISR requires exposure-level image data for historical reasons, so if we did
1542  not recieve that from Butler, construct it from what we have, modifying the
1543  input in place.
1544 
1545  Parameters
1546  ----------
1547  inputExp : `lsst.afw.image.Exposure`, `lsst.afw.image.DecoratedImageU`, or
1548  `lsst.afw.image.ImageF`
1549  The input data structure obtained from Butler.
1550  camera : `lsst.afw.cameraGeom.camera`
1551  The camera associated with the image. Used to find the appropriate
1552  detector.
1553  detectorNum : `int`
1554  The detector this exposure should match.
1555 
1556  Returns
1557  -------
1558  inputExp : `lsst.afw.image.Exposure`
1559  The re-constructed exposure, with appropriate detector parameters.
1560 
1561  Raises
1562  ------
1563  TypeError
1564  Raised if the input data cannot be used to construct an exposure.
1565  """
1566  if isinstance(inputExp, afwImage.DecoratedImageU):
1567  inputExp = afwImage.makeExposure(afwImage.makeMaskedImage(inputExp))
1568  elif isinstance(inputExp, afwImage.ImageF):
1569  inputExp = afwImage.makeExposure(afwImage.makeMaskedImage(inputExp))
1570  elif isinstance(inputExp, afwImage.MaskedImageF):
1571  inputExp = afwImage.makeExposure(inputExp)
1572  elif isinstance(inputExp, afwImage.Exposure):
1573  pass
1574  elif inputExp is None:
1575  # Assume this will be caught by the setup if it is a problem.
1576  return inputExp
1577  else:
1578  raise TypeError(f"Input Exposure is not known type in isrTask.ensureExposure: {type(inputExp)}")
1579 
1580  if inputExp.getDetector() is None:
1581  inputExp.setDetector(camera[detectorNum])
1582 
1583  return inputExp
1584 
A class to contain the data, WCS, and other information needed to describe an image of the sky...
Definition: Exposure.h:72
MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > * makeMaskedImage(typename std::shared_ptr< Image< ImagePixelT >> image, typename std::shared_ptr< Mask< MaskPixelT >> mask=Mask< MaskPixelT >(), typename std::shared_ptr< Image< VariancePixelT >> variance=Image< VariancePixelT >())
A function to return a MaskedImage of the correct type (cf.
Definition: MaskedImage.h:1280
std::shared_ptr< Exposure< ImagePixelT, MaskPixelT, VariancePixelT > > makeExposure(MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > &mimage, std::shared_ptr< geom::SkyWcs const > wcs=std::shared_ptr< geom::SkyWcs const >())
A function to return an Exposure of the correct type (cf.
Definition: Exposure.h:457

◆ flatContext()

def lsst.ip.isr.isrTask.IsrTask.flatContext (   self,
  exp,
  flat,
  dark = None 
)
Context manager that applies and removes flats and darks,
if the task is configured to apply them.

Parameters
----------
exp : `lsst.afw.image.Exposure`
    Exposure to process.
flat : `lsst.afw.image.Exposure`
    Flat exposure the same size as ``exp``.
dark : `lsst.afw.image.Exposure`, optional
    Dark exposure the same size as ``exp``.

Yields
------
exp : `lsst.afw.image.Exposure`
    The flat and dark corrected exposure.

Definition at line 2258 of file isrTask.py.

2258  def flatContext(self, exp, flat, dark=None):
2259  """Context manager that applies and removes flats and darks,
2260  if the task is configured to apply them.
2261 
2262  Parameters
2263  ----------
2264  exp : `lsst.afw.image.Exposure`
2265  Exposure to process.
2266  flat : `lsst.afw.image.Exposure`
2267  Flat exposure the same size as ``exp``.
2268  dark : `lsst.afw.image.Exposure`, optional
2269  Dark exposure the same size as ``exp``.
2270 
2271  Yields
2272  ------
2273  exp : `lsst.afw.image.Exposure`
2274  The flat and dark corrected exposure.
2275  """
2276  if self.config.doDark and dark is not None:
2277  self.darkCorrection(exp, dark)
2278  if self.config.doFlat:
2279  self.flatCorrection(exp, flat)
2280  try:
2281  yield exp
2282  finally:
2283  if self.config.doFlat:
2284  self.flatCorrection(exp, flat, invert=True)
2285  if self.config.doDark and dark is not None:
2286  self.darkCorrection(exp, dark, invert=True)
2287 

◆ flatCorrection()

def lsst.ip.isr.isrTask.IsrTask.flatCorrection (   self,
  exposure,
  flatExposure,
  invert = False 
)

Apply flat correction in place.

Parameters

exposure : lsst.afw.image.Exposure Exposure to process. flatExposure : lsst.afw.image.Exposure Flat exposure of the same size as exposure. invert : Bool, optional If True, unflatten an already flattened image.

See Also

lsst.ip.isr.isrFunctions.flatCorrection

Definition at line 1940 of file isrTask.py.

1940  def flatCorrection(self, exposure, flatExposure, invert=False):
1941  """!Apply flat correction in place.
1942 
1943  Parameters
1944  ----------
1945  exposure : `lsst.afw.image.Exposure`
1946  Exposure to process.
1947  flatExposure : `lsst.afw.image.Exposure`
1948  Flat exposure of the same size as ``exposure``.
1949  invert : `Bool`, optional
1950  If True, unflatten an already flattened image.
1951 
1952  See Also
1953  --------
1954  lsst.ip.isr.isrFunctions.flatCorrection
1955  """
1956  isrFunctions.flatCorrection(
1957  maskedImage=exposure.getMaskedImage(),
1958  flatMaskedImage=flatExposure.getMaskedImage(),
1959  scalingType=self.config.flatScalingType,
1960  userScale=self.config.flatUserScale,
1961  invert=invert,
1962  trimToFit=self.config.doTrimToMatchCalib
1963  )
1964 
def flatCorrection(maskedImage, flatMaskedImage, scalingType, userScale=1.0, invert=False, trimToFit=False)

◆ getInputDatasetTypes()

def lsst.ip.isr.isrTask.IsrTask.getInputDatasetTypes (   cls,
  config 
)

Definition at line 769 of file isrTask.py.

769  def getInputDatasetTypes(cls, config):
770  inputTypeDict = super().getInputDatasetTypes(config)
771 
772  # Delete entries from the dictionary of InputDatasetTypes that we know we don't
773  # need because the configuration tells us we will not be bothering with the
774  # correction that uses that IDT.
775  if config.doBias is not True:
776  inputTypeDict.pop("bias", None)
777  if config.doLinearize is not True:
778  inputTypeDict.pop("linearizer", None)
779  if config.doCrosstalk is not True:
780  inputTypeDict.pop("crosstalkSources", None)
781  if config.doBrighterFatter is not True:
782  inputTypeDict.pop("bfKernel", None)
783  if config.doDefect is not True:
784  inputTypeDict.pop("defects", None)
785  if config.doDark is not True:
786  inputTypeDict.pop("dark", None)
787  if config.doFlat is not True:
788  inputTypeDict.pop("flat", None)
789  if config.doAttachTransmissionCurve is not True:
790  inputTypeDict.pop("opticsTransmission", None)
791  inputTypeDict.pop("filterTransmission", None)
792  inputTypeDict.pop("sensorTransmission", None)
793  inputTypeDict.pop("atmosphereTransmission", None)
794  if config.doUseOpticsTransmission is not True:
795  inputTypeDict.pop("opticsTransmission", None)
796  if config.doUseFilterTransmission is not True:
797  inputTypeDict.pop("filterTransmission", None)
798  if config.doUseSensorTransmission is not True:
799  inputTypeDict.pop("sensorTransmission", None)
800  if config.doUseAtmosphereTransmission is not True:
801  inputTypeDict.pop("atmosphereTransmission", None)
802  if config.doIlluminationCorrection is not True:
803  inputTypeDict.pop("illuminationCorrection", None)
804 
805  return inputTypeDict
806 

◆ getIsrExposure()

def lsst.ip.isr.isrTask.IsrTask.getIsrExposure (   self,
  dataRef,
  datasetType,
  immediate = True 
)

Retrieve a calibration dataset for removing instrument signature.

Parameters

dataRef : daf.persistence.butlerSubset.ButlerDataRef DataRef of the detector data to find calibration datasets for. datasetType : str Type of dataset to retrieve (e.g. 'bias', 'flat', etc). immediate : Bool If True, disable butler proxies to enable error handling within this routine.

Returns

exposure : lsst.afw.image.Exposure Requested calibration frame.

Raises

RuntimeError Raised if no matching calibration frame can be found.

Definition at line 1497 of file isrTask.py.

1497  def getIsrExposure(self, dataRef, datasetType, immediate=True):
1498  """!Retrieve a calibration dataset for removing instrument signature.
1499 
1500  Parameters
1501  ----------
1502 
1503  dataRef : `daf.persistence.butlerSubset.ButlerDataRef`
1504  DataRef of the detector data to find calibration datasets
1505  for.
1506  datasetType : `str`
1507  Type of dataset to retrieve (e.g. 'bias', 'flat', etc).
1508  immediate : `Bool`
1509  If True, disable butler proxies to enable error handling
1510  within this routine.
1511 
1512  Returns
1513  -------
1514  exposure : `lsst.afw.image.Exposure`
1515  Requested calibration frame.
1516 
1517  Raises
1518  ------
1519  RuntimeError
1520  Raised if no matching calibration frame can be found.
1521  """
1522  try:
1523  exp = dataRef.get(datasetType, immediate=immediate)
1524  except Exception as exc1:
1525  if not self.config.fallbackFilterName:
1526  raise RuntimeError("Unable to retrieve %s for %s: %s" % (datasetType, dataRef.dataId, exc1))
1527  try:
1528  exp = dataRef.get(datasetType, filter=self.config.fallbackFilterName, immediate=immediate)
1529  except Exception as exc2:
1530  raise RuntimeError("Unable to retrieve %s for %s, even with fallback filter %s: %s AND %s" %
1531  (datasetType, dataRef.dataId, self.config.fallbackFilterName, exc1, exc2))
1532  self.log.warn("Using fallback calibration from filter %s" % self.config.fallbackFilterName)
1533 
1534  if self.config.doAssembleIsrExposures:
1535  exp = self.assembleCcd.assembleCcd(exp)
1536  return exp
1537 

◆ getOutputDatasetTypes()

def lsst.ip.isr.isrTask.IsrTask.getOutputDatasetTypes (   cls,
  config 
)

Definition at line 808 of file isrTask.py.

808  def getOutputDatasetTypes(cls, config):
809  outputTypeDict = super().getOutputDatasetTypes(config)
810 
811  if config.qa.doThumbnailOss is not True:
812  outputTypeDict.pop("outputOssThumbnail", None)
813  if config.qa.doThumbnailFlattened is not True:
814  outputTypeDict.pop("outputFlattenedThumbnail", None)
815  if config.doWrite is not True:
816  outputTypeDict.pop("outputExposure", None)
817 
818  return outputTypeDict
819 

◆ getPerDatasetTypeDimensions()

def lsst.ip.isr.isrTask.IsrTask.getPerDatasetTypeDimensions (   cls,
  config 
)

Definition at line 831 of file isrTask.py.

831  def getPerDatasetTypeDimensions(cls, config):
832  # Input calibration datasets of different types (i.e. flat, bias) need
833  # not have the same validity range. That makes calibration_label
834  # (which maps directly to a validity range) a "per-DatasetType
835  # dimension".
836  return frozenset(["calibration_label"])
837 

◆ getPrerequisiteDatasetTypes()

def lsst.ip.isr.isrTask.IsrTask.getPrerequisiteDatasetTypes (   cls,
  config 
)

Definition at line 821 of file isrTask.py.

821  def getPrerequisiteDatasetTypes(cls, config):
822  # Input calibration datasets should not constrain the QuantumGraph
823  # (it'd be confusing if not having flats just silently resulted in no
824  # data being processed). Our nomenclature for that is that these are
825  # "prerequisite" datasets (only "ccdExposure" == "raw" isn't).
826  names = set(cls.getInputDatasetTypes(config))
827  names.remove("ccdExposure")
828  return names
829 
daf::base::PropertySet * set
Definition: fits.cc:884

◆ makeDatasetType()

def lsst.ip.isr.isrTask.IsrTask.makeDatasetType (   self,
  dsConfig 
)

Definition at line 875 of file isrTask.py.

875  def makeDatasetType(self, dsConfig):
876  return super().makeDatasetType(dsConfig)
877 

◆ maskAmplifier()

def lsst.ip.isr.isrTask.IsrTask.maskAmplifier (   self,
  ccdExposure,
  amp,
  defects 
)
Identify bad amplifiers, saturated and suspect pixels.

Parameters
----------
ccdExposure : `lsst.afw.image.Exposure`
    Input exposure to be masked.
amp : `lsst.afw.table.AmpInfoCatalog`
    Catalog of parameters defining the amplifier on this
    exposure to mask.
defects : `lsst.meas.algorithms.Defects`
    List of defects.  Used to determine if the entire
    amplifier is bad.

Returns
-------
badAmp : `Bool`
    If this is true, the entire amplifier area is covered by
    defects and unusable.

Definition at line 1621 of file isrTask.py.

1621  def maskAmplifier(self, ccdExposure, amp, defects):
1622  """Identify bad amplifiers, saturated and suspect pixels.
1623 
1624  Parameters
1625  ----------
1626  ccdExposure : `lsst.afw.image.Exposure`
1627  Input exposure to be masked.
1628  amp : `lsst.afw.table.AmpInfoCatalog`
1629  Catalog of parameters defining the amplifier on this
1630  exposure to mask.
1631  defects : `lsst.meas.algorithms.Defects`
1632  List of defects. Used to determine if the entire
1633  amplifier is bad.
1634 
1635  Returns
1636  -------
1637  badAmp : `Bool`
1638  If this is true, the entire amplifier area is covered by
1639  defects and unusable.
1640 
1641  """
1642  maskedImage = ccdExposure.getMaskedImage()
1643 
1644  badAmp = False
1645 
1646  # Check if entire amp region is defined as a defect (need to use amp.getBBox() for correct
1647  # comparison with current defects definition.
1648  if defects is not None:
1649  badAmp = bool(sum([v.getBBox().contains(amp.getBBox()) for v in defects]))
1650 
1651  # In the case of a bad amp, we will set mask to "BAD" (here use amp.getRawBBox() for correct
1652  # association with pixels in current ccdExposure).
1653  if badAmp:
1654  dataView = afwImage.MaskedImageF(maskedImage, amp.getRawBBox(),
1655  afwImage.PARENT)
1656  maskView = dataView.getMask()
1657  maskView |= maskView.getPlaneBitMask("BAD")
1658  del maskView
1659  return badAmp
1660 
1661  # Mask remaining defects after assembleCcd() to allow for defects that cross amplifier boundaries.
1662  # Saturation and suspect pixels can be masked now, though.
1663  limits = dict()
1664  if self.config.doSaturation and not badAmp:
1665  limits.update({self.config.saturatedMaskName: amp.getSaturation()})
1666  if self.config.doSuspect and not badAmp:
1667  limits.update({self.config.suspectMaskName: amp.getSuspectLevel()})
1668  if math.isfinite(self.config.saturation):
1669  limits.update({self.config.saturatedMaskName: self.config.saturation})
1670 
1671  for maskName, maskThreshold in limits.items():
1672  if not math.isnan(maskThreshold):
1673  dataView = maskedImage.Factory(maskedImage, amp.getRawBBox())
1674  isrFunctions.makeThresholdMask(
1675  maskedImage=dataView,
1676  threshold=maskThreshold,
1677  growFootprints=0,
1678  maskName=maskName
1679  )
1680 
1681  # Determine if we've fully masked this amplifier with SUSPECT and SAT pixels.
1682  maskView = afwImage.Mask(maskedImage.getMask(), amp.getRawDataBBox(),
1683  afwImage.PARENT)
1684  maskVal = maskView.getPlaneBitMask([self.config.saturatedMaskName,
1685  self.config.suspectMaskName])
1686  if numpy.all(maskView.getArray() & maskVal > 0):
1687  badAmp = True
1688 
1689  return badAmp
1690 
bool contains(VertexIterator const begin, VertexIterator const end, UnitVector3d const &v)
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:78

◆ maskAndInterpolateDefects()

def lsst.ip.isr.isrTask.IsrTask.maskAndInterpolateDefects (   self,
  exposure,
  defectBaseList 
)
Mask and interpolate defects using mask plane "BAD", in place.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to process.
defectBaseList : `List` of `Defects`

Definition at line 2083 of file isrTask.py.

2083  def maskAndInterpolateDefects(self, exposure, defectBaseList):
2084  """Mask and interpolate defects using mask plane "BAD", in place.
2085 
2086  Parameters
2087  ----------
2088  exposure : `lsst.afw.image.Exposure`
2089  Exposure to process.
2090  defectBaseList : `List` of `Defects`
2091 
2092  """
2093  self.maskDefects(exposure, defectBaseList)
2094  isrFunctions.interpolateFromMask(
2095  maskedImage=exposure.getMaskedImage(),
2096  fwhm=self.config.fwhm,
2097  growSaturatedFootprints=0,
2098  maskNameList=["BAD"],
2099  )
2100 

◆ maskAndInterpolateNan()

def lsst.ip.isr.isrTask.IsrTask.maskAndInterpolateNan (   self,
  exposure 
)
"Mask and interpolate NaNs using mask plane "UNMASKEDNAN", in place.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to process.

See Also
--------
lsst.ip.isr.isrTask.maskNan()

Definition at line 2127 of file isrTask.py.

2127  def maskAndInterpolateNan(self, exposure):
2128  """"Mask and interpolate NaNs using mask plane "UNMASKEDNAN", in place.
2129 
2130  Parameters
2131  ----------
2132  exposure : `lsst.afw.image.Exposure`
2133  Exposure to process.
2134 
2135  See Also
2136  --------
2137  lsst.ip.isr.isrTask.maskNan()
2138  """
2139  self.maskNan(exposure)
2140  isrFunctions.interpolateFromMask(
2141  maskedImage=exposure.getMaskedImage(),
2142  fwhm=self.config.fwhm,
2143  growSaturatedFootprints=0,
2144  maskNameList=["UNMASKEDNAN"],
2145  )
2146 

◆ maskDefect()

def lsst.ip.isr.isrTask.IsrTask.maskDefect (   self,
  exposure,
  defectBaseList 
)

Mask defects using mask plane "BAD", in place.

Parameters

exposure : lsst.afw.image.Exposure Exposure to process. defectBaseList : lsst.meas.algorithms.Defects or list of lsst.afw.image.DefectBase. List of defects to mask and interpolate.

Notes

Call this after CCD assembly, since defects may cross amplifier boundaries.

Definition at line 2049 of file isrTask.py.

2049  def maskDefect(self, exposure, defectBaseList):
2050  """!Mask defects using mask plane "BAD", in place.
2051 
2052  Parameters
2053  ----------
2054  exposure : `lsst.afw.image.Exposure`
2055  Exposure to process.
2056  defectBaseList : `lsst.meas.algorithms.Defects` or `list` of
2057  `lsst.afw.image.DefectBase`.
2058  List of defects to mask and interpolate.
2059 
2060  Notes
2061  -----
2062  Call this after CCD assembly, since defects may cross amplifier boundaries.
2063  """
2064  maskedImage = exposure.getMaskedImage()
2065  if not isinstance(defectBaseList, Defects):
2066  # Promotes DefectBase to Defect
2067  defectList = Defects(defectBaseList)
2068  else:
2069  defectList = defectBaseList
2070  defectList.maskPixels(maskedImage, maskName="BAD")
2071 
2072  if self.config.numEdgeSuspect > 0:
2073  goodBBox = maskedImage.getBBox()
2074  # This makes a bbox numEdgeSuspect pixels smaller than the image on each side
2075  goodBBox.grow(-self.config.numEdgeSuspect)
2076  # Mask pixels outside goodBBox as SUSPECT
2077  SourceDetectionTask.setEdgeBits(
2078  maskedImage,
2079  goodBBox,
2080  maskedImage.getMask().getPlaneBitMask("SUSPECT")
2081  )
2082 

◆ maskNan()

def lsst.ip.isr.isrTask.IsrTask.maskNan (   self,
  exposure 
)
Mask NaNs using mask plane "UNMASKEDNAN", in place.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to process.

Notes
-----
We mask over all NaNs, including those that are masked with
other bits (because those may or may not be interpolated over
later, and we want to remove all NaNs).  Despite this
behaviour, the "UNMASKEDNAN" mask plane is used to preserve
the historical name.

Definition at line 2101 of file isrTask.py.

2101  def maskNan(self, exposure):
2102  """Mask NaNs using mask plane "UNMASKEDNAN", in place.
2103 
2104  Parameters
2105  ----------
2106  exposure : `lsst.afw.image.Exposure`
2107  Exposure to process.
2108 
2109  Notes
2110  -----
2111  We mask over all NaNs, including those that are masked with
2112  other bits (because those may or may not be interpolated over
2113  later, and we want to remove all NaNs). Despite this
2114  behaviour, the "UNMASKEDNAN" mask plane is used to preserve
2115  the historical name.
2116  """
2117  maskedImage = exposure.getMaskedImage()
2118 
2119  # Find and mask NaNs
2120  maskedImage.getMask().addMaskPlane("UNMASKEDNAN")
2121  maskVal = maskedImage.getMask().getPlaneBitMask("UNMASKEDNAN")
2122  numNans = maskNans(maskedImage, maskVal)
2123  self.metadata.set("NUMNANS", numNans)
2124  if numNans > 0:
2125  self.log.warn(f"There were {numNans} unmasked NaNs")
2126 
daf::base::PropertySet * set
Definition: fits.cc:884
size_t maskNans(afw::image::MaskedImage< PixelT > const &mi, afw::image::MaskPixel maskVal, afw::image::MaskPixel allow=0)
Mask NANs in an image.
Definition: Isr.cc:35

◆ measureBackground()

def lsst.ip.isr.isrTask.IsrTask.measureBackground (   self,
  exposure,
  IsrQaConfig = None 
)
Measure the image background in subgrids, for quality control purposes.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to process.
IsrQaConfig : `lsst.ip.isr.isrQa.IsrQaConfig`
    Configuration object containing parameters on which background
    statistics and subgrids to use.

Definition at line 2147 of file isrTask.py.

2147  def measureBackground(self, exposure, IsrQaConfig=None):
2148  """Measure the image background in subgrids, for quality control purposes.
2149 
2150  Parameters
2151  ----------
2152  exposure : `lsst.afw.image.Exposure`
2153  Exposure to process.
2154  IsrQaConfig : `lsst.ip.isr.isrQa.IsrQaConfig`
2155  Configuration object containing parameters on which background
2156  statistics and subgrids to use.
2157  """
2158  if IsrQaConfig is not None:
2159  statsControl = afwMath.StatisticsControl(IsrQaConfig.flatness.clipSigma,
2160  IsrQaConfig.flatness.nIter)
2161  maskVal = exposure.getMaskedImage().getMask().getPlaneBitMask(["BAD", "SAT", "DETECTED"])
2162  statsControl.setAndMask(maskVal)
2163  maskedImage = exposure.getMaskedImage()
2164  stats = afwMath.makeStatistics(maskedImage, afwMath.MEDIAN | afwMath.STDEVCLIP, statsControl)
2165  skyLevel = stats.getValue(afwMath.MEDIAN)
2166  skySigma = stats.getValue(afwMath.STDEVCLIP)
2167  self.log.info("Flattened sky level: %f +/- %f" % (skyLevel, skySigma))
2168  metadata = exposure.getMetadata()
2169  metadata.set('SKYLEVEL', skyLevel)
2170  metadata.set('SKYSIGMA', skySigma)
2171 
2172  # calcluating flatlevel over the subgrids
2173  stat = afwMath.MEANCLIP if IsrQaConfig.flatness.doClip else afwMath.MEAN
2174  meshXHalf = int(IsrQaConfig.flatness.meshX/2.)
2175  meshYHalf = int(IsrQaConfig.flatness.meshY/2.)
2176  nX = int((exposure.getWidth() + meshXHalf) / IsrQaConfig.flatness.meshX)
2177  nY = int((exposure.getHeight() + meshYHalf) / IsrQaConfig.flatness.meshY)
2178  skyLevels = numpy.zeros((nX, nY))
2179 
2180  for j in range(nY):
2181  yc = meshYHalf + j * IsrQaConfig.flatness.meshY
2182  for i in range(nX):
2183  xc = meshXHalf + i * IsrQaConfig.flatness.meshX
2184 
2185  xLLC = xc - meshXHalf
2186  yLLC = yc - meshYHalf
2187  xURC = xc + meshXHalf - 1
2188  yURC = yc + meshYHalf - 1
2189 
2190  bbox = lsst.geom.Box2I(lsst.geom.Point2I(xLLC, yLLC), lsst.geom.Point2I(xURC, yURC))
2191  miMesh = maskedImage.Factory(exposure.getMaskedImage(), bbox, afwImage.LOCAL)
2192 
2193  skyLevels[i, j] = afwMath.makeStatistics(miMesh, stat, statsControl).getValue()
2194 
2195  good = numpy.where(numpy.isfinite(skyLevels))
2196  skyMedian = numpy.median(skyLevels[good])
2197  flatness = (skyLevels[good] - skyMedian) / skyMedian
2198  flatness_rms = numpy.std(flatness)
2199  flatness_pp = flatness.max() - flatness.min() if len(flatness) > 0 else numpy.nan
2200 
2201  self.log.info("Measuring sky levels in %dx%d grids: %f" % (nX, nY, skyMedian))
2202  self.log.info("Sky flatness in %dx%d grids - pp: %f rms: %f" %
2203  (nX, nY, flatness_pp, flatness_rms))
2204 
2205  metadata.set('FLATNESS_PP', float(flatness_pp))
2206  metadata.set('FLATNESS_RMS', float(flatness_rms))
2207  metadata.set('FLATNESS_NGRIDS', '%dx%d' % (nX, nY))
2208  metadata.set('FLATNESS_MESHX', IsrQaConfig.flatness.meshX)
2209  metadata.set('FLATNESS_MESHY', IsrQaConfig.flatness.meshY)
2210 
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<>
Definition: Statistics.h:520
Pass parameters to a Statistics object.
Definition: Statistics.h:93
An integer coordinate rectangle.
Definition: Box.h:54

◆ overscanCorrection()

def lsst.ip.isr.isrTask.IsrTask.overscanCorrection (   self,
  ccdExposure,
  amp 
)
Apply overscan correction in place.

This method does initial pixel rejection of the overscan
region.  The overscan can also be optionally segmented to
allow for discontinuous overscan responses to be fit
separately.  The actual overscan subtraction is performed by
the `lsst.ip.isr.isrFunctions.overscanCorrection` function,
which is called here after the amplifier is preprocessed.

Parameters
----------
ccdExposure : `lsst.afw.image.Exposure`
    Exposure to have overscan correction performed.
amp : `lsst.afw.table.AmpInfoCatalog`
    The amplifier to consider while correcting the overscan.

Returns
-------
overscanResults : `lsst.pipe.base.Struct`
    Result struct with components:
    - ``imageFit`` : scalar or `lsst.afw.image.Image`
Value or fit subtracted from the amplifier image data.
    - ``overscanFit`` : scalar or `lsst.afw.image.Image`
Value or fit subtracted from the overscan image data.
    - ``overscanImage`` : `lsst.afw.image.Image`
Image of the overscan region with the overscan
correction applied. This quantity is used to estimate
the amplifier read noise empirically.

Raises
------
RuntimeError
    Raised if the ``amp`` does not contain raw pixel information.

See Also
--------
lsst.ip.isr.isrFunctions.overscanCorrection

Definition at line 1691 of file isrTask.py.

1691  def overscanCorrection(self, ccdExposure, amp):
1692  """Apply overscan correction in place.
1693 
1694  This method does initial pixel rejection of the overscan
1695  region. The overscan can also be optionally segmented to
1696  allow for discontinuous overscan responses to be fit
1697  separately. The actual overscan subtraction is performed by
1698  the `lsst.ip.isr.isrFunctions.overscanCorrection` function,
1699  which is called here after the amplifier is preprocessed.
1700 
1701  Parameters
1702  ----------
1703  ccdExposure : `lsst.afw.image.Exposure`
1704  Exposure to have overscan correction performed.
1705  amp : `lsst.afw.table.AmpInfoCatalog`
1706  The amplifier to consider while correcting the overscan.
1707 
1708  Returns
1709  -------
1710  overscanResults : `lsst.pipe.base.Struct`
1711  Result struct with components:
1712  - ``imageFit`` : scalar or `lsst.afw.image.Image`
1713  Value or fit subtracted from the amplifier image data.
1714  - ``overscanFit`` : scalar or `lsst.afw.image.Image`
1715  Value or fit subtracted from the overscan image data.
1716  - ``overscanImage`` : `lsst.afw.image.Image`
1717  Image of the overscan region with the overscan
1718  correction applied. This quantity is used to estimate
1719  the amplifier read noise empirically.
1720 
1721  Raises
1722  ------
1723  RuntimeError
1724  Raised if the ``amp`` does not contain raw pixel information.
1725 
1726  See Also
1727  --------
1728  lsst.ip.isr.isrFunctions.overscanCorrection
1729  """
1730  if not amp.getHasRawInfo():
1731  raise RuntimeError("This method must be executed on an amp with raw information.")
1732 
1733  if amp.getRawHorizontalOverscanBBox().isEmpty():
1734  self.log.info("ISR_OSCAN: No overscan region. Not performing overscan correction.")
1735  return None
1736 
1737  statControl = afwMath.StatisticsControl()
1738  statControl.setAndMask(ccdExposure.mask.getPlaneBitMask("SAT"))
1739 
1740  # Determine the bounding boxes
1741  dataBBox = amp.getRawDataBBox()
1742  oscanBBox = amp.getRawHorizontalOverscanBBox()
1743  dx0 = 0
1744  dx1 = 0
1745 
1746  prescanBBox = amp.getRawPrescanBBox()
1747  if (oscanBBox.getBeginX() > prescanBBox.getBeginX()): # amp is at the right
1748  dx0 += self.config.overscanNumLeadingColumnsToSkip
1749  dx1 -= self.config.overscanNumTrailingColumnsToSkip
1750  else:
1751  dx0 += self.config.overscanNumTrailingColumnsToSkip
1752  dx1 -= self.config.overscanNumLeadingColumnsToSkip
1753 
1754  # Determine if we need to work on subregions of the amplifier and overscan.
1755  imageBBoxes = []
1756  overscanBBoxes = []
1757 
1758  if ((self.config.overscanBiasJump and
1759  self.config.overscanBiasJumpLocation) and
1760  (ccdExposure.getMetadata().exists(self.config.overscanBiasJumpKeyword) and
1761  ccdExposure.getMetadata().getScalar(self.config.overscanBiasJumpKeyword) in
1762  self.config.overscanBiasJumpDevices)):
1763  if amp.getReadoutCorner() in (afwTable.LL, afwTable.LR):
1764  yLower = self.config.overscanBiasJumpLocation
1765  yUpper = dataBBox.getHeight() - yLower
1766  else:
1767  yUpper = self.config.overscanBiasJumpLocation
1768  yLower = dataBBox.getHeight() - yUpper
1769 
1770  imageBBoxes.append(lsst.geom.Box2I(dataBBox.getBegin(),
1771  lsst.geom.Extent2I(dataBBox.getWidth(), yLower)))
1772  overscanBBoxes.append(lsst.geom.Box2I(oscanBBox.getBegin() +
1773  lsst.geom.Extent2I(dx0, 0),
1774  lsst.geom.Extent2I(oscanBBox.getWidth() - dx0 + dx1,
1775  yLower)))
1776 
1777  imageBBoxes.append(lsst.geom.Box2I(dataBBox.getBegin() + lsst.geom.Extent2I(0, yLower),
1778  lsst.geom.Extent2I(dataBBox.getWidth(), yUpper)))
1779  overscanBBoxes.append(lsst.geom.Box2I(oscanBBox.getBegin() + lsst.geom.Extent2I(dx0, yLower),
1780  lsst.geom.Extent2I(oscanBBox.getWidth() - dx0 + dx1,
1781  yUpper)))
1782  else:
1783  imageBBoxes.append(lsst.geom.Box2I(dataBBox.getBegin(),
1784  lsst.geom.Extent2I(dataBBox.getWidth(), dataBBox.getHeight())))
1785  overscanBBoxes.append(lsst.geom.Box2I(oscanBBox.getBegin() + lsst.geom.Extent2I(dx0, 0),
1786  lsst.geom.Extent2I(oscanBBox.getWidth() - dx0 + dx1,
1787  oscanBBox.getHeight())))
1788 
1789  # Perform overscan correction on subregions, ensuring saturated pixels are masked.
1790  for imageBBox, overscanBBox in zip(imageBBoxes, overscanBBoxes):
1791  ampImage = ccdExposure.maskedImage[imageBBox]
1792  overscanImage = ccdExposure.maskedImage[overscanBBox]
1793 
1794  overscanArray = overscanImage.image.array
1795  median = numpy.ma.median(numpy.ma.masked_where(overscanImage.mask.array, overscanArray))
1796  bad = numpy.where(numpy.abs(overscanArray - median) > self.config.overscanMaxDev)
1797  overscanImage.mask.array[bad] = overscanImage.mask.getPlaneBitMask("SAT")
1798 
1799  statControl = afwMath.StatisticsControl()
1800  statControl.setAndMask(ccdExposure.mask.getPlaneBitMask("SAT"))
1801 
1802  overscanResults = isrFunctions.overscanCorrection(ampMaskedImage=ampImage,
1803  overscanImage=overscanImage,
1804  fitType=self.config.overscanFitType,
1805  order=self.config.overscanOrder,
1806  collapseRej=self.config.overscanNumSigmaClip,
1807  statControl=statControl,
1808  overscanIsInt=self.config.overscanIsInt
1809  )
1810 
1811  # Measure average overscan levels and record them in the metadata
1812  levelStat = afwMath.MEDIAN
1813  sigmaStat = afwMath.STDEVCLIP
1814 
1815  sctrl = afwMath.StatisticsControl(self.config.qa.flatness.clipSigma,
1816  self.config.qa.flatness.nIter)
1817  metadata = ccdExposure.getMetadata()
1818  ampNum = amp.getName()
1819  if self.config.overscanFitType in ("MEDIAN", "MEAN", "MEANCLIP"):
1820  metadata.set("ISR_OSCAN_LEVEL%s" % ampNum, overscanResults.overscanFit)
1821  metadata.set("ISR_OSCAN_SIGMA%s" % ampNum, 0.0)
1822  else:
1823  stats = afwMath.makeStatistics(overscanResults.overscanFit, levelStat | sigmaStat, sctrl)
1824  metadata.set("ISR_OSCAN_LEVEL%s" % ampNum, stats.getValue(levelStat))
1825  metadata.set("ISR_OSCAN_SIGMA%s" % ampNum, stats.getValue(sigmaStat))
1826 
1827  return overscanResults
1828 
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<>
Definition: Statistics.h:520
Pass parameters to a Statistics object.
Definition: Statistics.h:93
An integer coordinate rectangle.
Definition: Box.h:54
def overscanCorrection(ampMaskedImage, overscanImage, fitType='MEDIAN', order=1, collapseRej=3.0, statControl=None, overscanIsInt=True)

◆ readIsrData()

def lsst.ip.isr.isrTask.IsrTask.readIsrData (   self,
  dataRef,
  rawExposure 
)

Retrieve necessary frames for instrument signature removal.

Pre-fetching all required ISR data products limits the IO required by the ISR. Any conflict between the calibration data available and that needed for ISR is also detected prior to doing processing, allowing it to fail quickly.

Parameters

dataRef : daf.persistence.butlerSubset.ButlerDataRef Butler reference of the detector data to be processed rawExposure : afw.image.Exposure The raw exposure that will later be corrected with the retrieved calibration data; should not be modified in this method.

Returns

result : lsst.pipe.base.Struct Result struct with components (which may be None):

  • bias: bias calibration frame (afw.image.Exposure)
  • linearizer: functor for linearization (ip.isr.linearize.LinearizeBase)
  • crosstalkSources: list of possible crosstalk sources (list)
  • dark: dark calibration frame (afw.image.Exposure)
  • flat: flat calibration frame (afw.image.Exposure)
  • bfKernel: Brighter-Fatter kernel (numpy.ndarray)
  • defects: list of defects (lsst.meas.algorithms.Defects)
  • fringes: lsst.pipe.base.Struct with components:

fringes: fringe calibration frame (afw.image.Exposure)

  • seed: random seed derived from the ccdExposureId for random number generator (uint32)
    • opticsTransmission: lsst.afw.image.TransmissionCurve A TransmissionCurve that represents the throughput of the optics, to be evaluated in focal-plane coordinates.
    • filterTransmission : lsst.afw.image.TransmissionCurve A TransmissionCurve that represents the throughput of the filter itself, to be evaluated in focal-plane coordinates.
    • sensorTransmission : lsst.afw.image.TransmissionCurve A TransmissionCurve that represents the throughput of the sensor itself, to be evaluated in post-assembly trimmed detector coordinates.
    • atmosphereTransmission : lsst.afw.image.TransmissionCurve A TransmissionCurve that represents the throughput of the atmosphere, assumed to be spatially constant.
    • strayLightData : object An opaque object containing calibration information for stray-light correction. If None, no correction will be performed.
    • illumMaskedImage : illumination correction image (lsst.afw.image.MaskedImage)

Raises

NotImplementedError : Raised if a per-amplifier brighter-fatter kernel is requested by the configuration.

Definition at line 878 of file isrTask.py.

878  def readIsrData(self, dataRef, rawExposure):
879  """!Retrieve necessary frames for instrument signature removal.
880 
881  Pre-fetching all required ISR data products limits the IO
882  required by the ISR. Any conflict between the calibration data
883  available and that needed for ISR is also detected prior to
884  doing processing, allowing it to fail quickly.
885 
886  Parameters
887  ----------
888  dataRef : `daf.persistence.butlerSubset.ButlerDataRef`
889  Butler reference of the detector data to be processed
890  rawExposure : `afw.image.Exposure`
891  The raw exposure that will later be corrected with the
892  retrieved calibration data; should not be modified in this
893  method.
894 
895  Returns
896  -------
897  result : `lsst.pipe.base.Struct`
898  Result struct with components (which may be `None`):
899  - ``bias``: bias calibration frame (`afw.image.Exposure`)
900  - ``linearizer``: functor for linearization (`ip.isr.linearize.LinearizeBase`)
901  - ``crosstalkSources``: list of possible crosstalk sources (`list`)
902  - ``dark``: dark calibration frame (`afw.image.Exposure`)
903  - ``flat``: flat calibration frame (`afw.image.Exposure`)
904  - ``bfKernel``: Brighter-Fatter kernel (`numpy.ndarray`)
905  - ``defects``: list of defects (`lsst.meas.algorithms.Defects`)
906  - ``fringes``: `lsst.pipe.base.Struct` with components:
907  - ``fringes``: fringe calibration frame (`afw.image.Exposure`)
908  - ``seed``: random seed derived from the ccdExposureId for random
909  number generator (`uint32`)
910  - ``opticsTransmission``: `lsst.afw.image.TransmissionCurve`
911  A ``TransmissionCurve`` that represents the throughput of the optics,
912  to be evaluated in focal-plane coordinates.
913  - ``filterTransmission`` : `lsst.afw.image.TransmissionCurve`
914  A ``TransmissionCurve`` that represents the throughput of the filter
915  itself, to be evaluated in focal-plane coordinates.
916  - ``sensorTransmission`` : `lsst.afw.image.TransmissionCurve`
917  A ``TransmissionCurve`` that represents the throughput of the sensor
918  itself, to be evaluated in post-assembly trimmed detector coordinates.
919  - ``atmosphereTransmission`` : `lsst.afw.image.TransmissionCurve`
920  A ``TransmissionCurve`` that represents the throughput of the
921  atmosphere, assumed to be spatially constant.
922  - ``strayLightData`` : `object`
923  An opaque object containing calibration information for
924  stray-light correction. If `None`, no correction will be
925  performed.
926  - ``illumMaskedImage`` : illumination correction image (`lsst.afw.image.MaskedImage`)
927 
928  Raises
929  ------
930  NotImplementedError :
931  Raised if a per-amplifier brighter-fatter kernel is requested by the configuration.
932  """
933  ccd = rawExposure.getDetector()
934  filterName = afwImage.Filter(rawExposure.getFilter().getId()).getName() # Canonical name for filter
935  rawExposure.mask.addMaskPlane("UNMASKEDNAN") # needed to match pre DM-15862 processing.
936  biasExposure = (self.getIsrExposure(dataRef, self.config.biasDataProductName)
937  if self.config.doBias else None)
938  # immediate=True required for functors and linearizers are functors; see ticket DM-6515
939  linearizer = (dataRef.get("linearizer", immediate=True)
940  if self.doLinearize(ccd) else None)
941  crosstalkSources = (self.crosstalk.prepCrosstalk(dataRef)
942  if self.config.doCrosstalk else None)
943  darkExposure = (self.getIsrExposure(dataRef, self.config.darkDataProductName)
944  if self.config.doDark else None)
945  flatExposure = (self.getIsrExposure(dataRef, self.config.flatDataProductName)
946  if self.config.doFlat else None)
947 
948  brighterFatterKernel = None
949  if self.config.doBrighterFatter is True:
950 
951  # Use the new-style cp_pipe version of the kernel is it exists.
952  try:
953  brighterFatterKernel = dataRef.get("brighterFatterKernel")
954  except NoResults:
955  # Fall back to the old-style numpy-ndarray style kernel if necessary.
956  try:
957  brighterFatterKernel = dataRef.get("bfKernel")
958  except NoResults:
959  brighterFatterKernel = None
960  if brighterFatterKernel is not None and not isinstance(brighterFatterKernel, numpy.ndarray):
961  # If the kernel is not an ndarray, it's the cp_pipe version, so extract the kernel for
962  # this detector, or raise an error.
963  if self.config.brighterFatterLevel == 'DETECTOR':
964  brighterFatterKernel = brighterFatterKernel.kernel[ccd.getId()]
965  else:
966  # TODO DM-15631 for implementing this
967  raise NotImplementedError("Per-amplifier brighter-fatter correction not implemented")
968 
969  defectList = (dataRef.get("defects")
970  if self.config.doDefect else None)
971  fringeStruct = (self.fringe.readFringes(dataRef, assembler=self.assembleCcd
972  if self.config.doAssembleIsrExposures else None)
973  if self.config.doFringe and self.fringe.checkFilter(rawExposure)
974  else pipeBase.Struct(fringes=None))
975 
976  if self.config.doAttachTransmissionCurve:
977  opticsTransmission = (dataRef.get("transmission_optics")
978  if self.config.doUseOpticsTransmission else None)
979  filterTransmission = (dataRef.get("transmission_filter")
980  if self.config.doUseFilterTransmission else None)
981  sensorTransmission = (dataRef.get("transmission_sensor")
982  if self.config.doUseSensorTransmission else None)
983  atmosphereTransmission = (dataRef.get("transmission_atmosphere")
984  if self.config.doUseAtmosphereTransmission else None)
985  else:
986  opticsTransmission = None
987  filterTransmission = None
988  sensorTransmission = None
989  atmosphereTransmission = None
990 
991  if self.config.doStrayLight:
992  strayLightData = self.strayLight.readIsrData(dataRef, rawExposure)
993  else:
994  strayLightData = None
995 
996  illumMaskedImage = (self.getIsrExposure(dataRef,
997  self.config.illuminationCorrectionDataProductName).getMaskedImage()
998  if (self.config.doIlluminationCorrection and
999  filterName in self.config.illumFilters)
1000  else None)
1001 
1002  # Struct should include only kwargs to run()
1003  return pipeBase.Struct(bias=biasExposure,
1004  linearizer=linearizer,
1005  crosstalkSources=crosstalkSources,
1006  dark=darkExposure,
1007  flat=flatExposure,
1008  bfKernel=brighterFatterKernel,
1009  defects=defectList,
1010  fringes=fringeStruct,
1011  opticsTransmission=opticsTransmission,
1012  filterTransmission=filterTransmission,
1013  sensorTransmission=sensorTransmission,
1014  atmosphereTransmission=atmosphereTransmission,
1015  strayLightData=strayLightData,
1016  illumMaskedImage=illumMaskedImage
1017  )
1018 
Holds an integer identifier for an LSST filter.
Definition: Filter.h:141

◆ roughZeroPoint()

def lsst.ip.isr.isrTask.IsrTask.roughZeroPoint (   self,
  exposure 
)
Set an approximate magnitude zero point for the exposure.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to process.

Definition at line 2211 of file isrTask.py.

2211  def roughZeroPoint(self, exposure):
2212  """Set an approximate magnitude zero point for the exposure.
2213 
2214  Parameters
2215  ----------
2216  exposure : `lsst.afw.image.Exposure`
2217  Exposure to process.
2218  """
2219  filterName = afwImage.Filter(exposure.getFilter().getId()).getName() # Canonical name for filter
2220  if filterName in self.config.fluxMag0T1:
2221  fluxMag0 = self.config.fluxMag0T1[filterName]
2222  else:
2223  self.log.warn("No rough magnitude zero point set for filter %s" % filterName)
2224  fluxMag0 = self.config.defaultFluxMag0T1
2225 
2226  expTime = exposure.getInfo().getVisitInfo().getExposureTime()
2227  if not expTime > 0: # handle NaN as well as <= 0
2228  self.log.warn("Non-positive exposure time; skipping rough zero point")
2229  return
2230 
2231  self.log.info("Setting rough magnitude zero point: %f" % (2.5*math.log10(fluxMag0*expTime),))
2232  exposure.setPhotoCalib(afwImage.makePhotoCalibFromCalibZeroPoint(fluxMag0*expTime, 0.0))
2233 
std::shared_ptr< PhotoCalib > makePhotoCalibFromCalibZeroPoint(double instFluxMag0, double instFluxMag0Err)
Construct a PhotoCalib from the deprecated Calib-style instFluxMag0/instFluxMag0Err values...
Definition: PhotoCalib.cc:644
Holds an integer identifier for an LSST filter.
Definition: Filter.h:141

◆ run()

def lsst.ip.isr.isrTask.IsrTask.run (   self,
  ccdExposure,
  camera = None,
  bias = None,
  linearizer = None,
  crosstalkSources = None,
  dark = None,
  flat = None,
  bfKernel = None,
  defects = None,
  fringes = None,
  opticsTransmission = None,
  filterTransmission = None,
  sensorTransmission = None,
  atmosphereTransmission = None,
  detectorNum = None,
  strayLightData = None,
  illumMaskedImage = None,
  isGen3 = False 
)

Perform instrument signature removal on an exposure.

Steps included in the ISR processing, in order performed, are:

  • saturation and suspect pixel masking
  • overscan subtraction
  • CCD assembly of individual amplifiers
  • bias subtraction
  • variance image construction
  • linearization of non-linear response
  • crosstalk masking
  • brighter-fatter correction
  • dark subtraction
  • fringe correction
  • stray light subtraction
  • flat correction
  • masking of known defects and camera specific features
  • vignette calculation
  • appending transmission curve and distortion model

Parameters

ccdExposure : lsst.afw.image.Exposure The raw exposure that is to be run through ISR. The exposure is modified by this method. camera : lsst.afw.cameraGeom.Camera, optional The camera geometry for this exposure. Used to select the distortion model appropriate for this data. bias : lsst.afw.image.Exposure, optional Bias calibration frame. linearizer : lsst.ip.isr.linearize.LinearizeBase, optional Functor for linearization. crosstalkSources : list, optional List of possible crosstalk sources. dark : lsst.afw.image.Exposure, optional Dark calibration frame. flat : lsst.afw.image.Exposure, optional Flat calibration frame. bfKernel : numpy.ndarray, optional Brighter-fatter kernel. defects : lsst.meas.algorithms.Defects, optional List of defects. fringes : lsst.pipe.base.Struct, optional Struct containing the fringe correction data, with elements:

  • fringes: fringe calibration frame (afw.image.Exposure)
  • seed: random seed derived from the ccdExposureId for random number generator (uint32) opticsTransmission: lsst.afw.image.TransmissionCurve, optional A TransmissionCurve that represents the throughput of the optics, to be evaluated in focal-plane coordinates. filterTransmission : lsst.afw.image.TransmissionCurve A TransmissionCurve that represents the throughput of the filter itself, to be evaluated in focal-plane coordinates. sensorTransmission : lsst.afw.image.TransmissionCurve A TransmissionCurve that represents the throughput of the sensor itself, to be evaluated in post-assembly trimmed detector coordinates. atmosphereTransmission : lsst.afw.image.TransmissionCurve A TransmissionCurve that represents the throughput of the atmosphere, assumed to be spatially constant. detectorNum : int, optional The integer number for the detector to process. isGen3 : bool, optional Flag this call to run() as using the Gen3 butler environment. strayLightData : object, optional Opaque object containing calibration information for stray-light correction. If None, no correction will be performed. illumMaskedImage : lsst.afw.image.MaskedImage, optional Illumination correction image.

Returns

result : lsst.pipe.base.Struct Result struct with component:

  • exposure : afw.image.Exposure The fully ISR corrected exposure.
  • outputExposure : afw.image.Exposure An alias for exposure
  • ossThumb : numpy.ndarray Thumbnail image of the exposure after overscan subtraction.
  • flattenedThumb : numpy.ndarray Thumbnail image of the exposure after flat-field correction.

Raises

RuntimeError Raised if a configuration option is set to True, but the required calibration data has not been specified.

Notes

The current processed exposure can be viewed by setting the appropriate lsstDebug entries in the debug.display dictionary. The names of these entries correspond to some of the IsrTaskConfig Boolean options, with the value denoting the frame to use. The exposure is shown inside the matching option check and after the processing of that step has finished. The steps with debug points are:

doAssembleCcd doBias doCrosstalk doBrighterFatter doDark doFringe doStrayLight doFlat

In addition, setting the "postISRCCD" entry displays the exposure after all ISR processing has finished.

Definition at line 1026 of file isrTask.py.

1026  ):
1027  """!Perform instrument signature removal on an exposure.
1028 
1029  Steps included in the ISR processing, in order performed, are:
1030  - saturation and suspect pixel masking
1031  - overscan subtraction
1032  - CCD assembly of individual amplifiers
1033  - bias subtraction
1034  - variance image construction
1035  - linearization of non-linear response
1036  - crosstalk masking
1037  - brighter-fatter correction
1038  - dark subtraction
1039  - fringe correction
1040  - stray light subtraction
1041  - flat correction
1042  - masking of known defects and camera specific features
1043  - vignette calculation
1044  - appending transmission curve and distortion model
1045 
1046  Parameters
1047  ----------
1048  ccdExposure : `lsst.afw.image.Exposure`
1049  The raw exposure that is to be run through ISR. The
1050  exposure is modified by this method.
1051  camera : `lsst.afw.cameraGeom.Camera`, optional
1052  The camera geometry for this exposure. Used to select the
1053  distortion model appropriate for this data.
1054  bias : `lsst.afw.image.Exposure`, optional
1055  Bias calibration frame.
1056  linearizer : `lsst.ip.isr.linearize.LinearizeBase`, optional
1057  Functor for linearization.
1058  crosstalkSources : `list`, optional
1059  List of possible crosstalk sources.
1060  dark : `lsst.afw.image.Exposure`, optional
1061  Dark calibration frame.
1062  flat : `lsst.afw.image.Exposure`, optional
1063  Flat calibration frame.
1064  bfKernel : `numpy.ndarray`, optional
1065  Brighter-fatter kernel.
1066  defects : `lsst.meas.algorithms.Defects`, optional
1067  List of defects.
1068  fringes : `lsst.pipe.base.Struct`, optional
1069  Struct containing the fringe correction data, with
1070  elements:
1071  - ``fringes``: fringe calibration frame (`afw.image.Exposure`)
1072  - ``seed``: random seed derived from the ccdExposureId for random
1073  number generator (`uint32`)
1074  opticsTransmission: `lsst.afw.image.TransmissionCurve`, optional
1075  A ``TransmissionCurve`` that represents the throughput of the optics,
1076  to be evaluated in focal-plane coordinates.
1077  filterTransmission : `lsst.afw.image.TransmissionCurve`
1078  A ``TransmissionCurve`` that represents the throughput of the filter
1079  itself, to be evaluated in focal-plane coordinates.
1080  sensorTransmission : `lsst.afw.image.TransmissionCurve`
1081  A ``TransmissionCurve`` that represents the throughput of the sensor
1082  itself, to be evaluated in post-assembly trimmed detector coordinates.
1083  atmosphereTransmission : `lsst.afw.image.TransmissionCurve`
1084  A ``TransmissionCurve`` that represents the throughput of the
1085  atmosphere, assumed to be spatially constant.
1086  detectorNum : `int`, optional
1087  The integer number for the detector to process.
1088  isGen3 : bool, optional
1089  Flag this call to run() as using the Gen3 butler environment.
1090  strayLightData : `object`, optional
1091  Opaque object containing calibration information for stray-light
1092  correction. If `None`, no correction will be performed.
1093  illumMaskedImage : `lsst.afw.image.MaskedImage`, optional
1094  Illumination correction image.
1095 
1096  Returns
1097  -------
1098  result : `lsst.pipe.base.Struct`
1099  Result struct with component:
1100  - ``exposure`` : `afw.image.Exposure`
1101  The fully ISR corrected exposure.
1102  - ``outputExposure`` : `afw.image.Exposure`
1103  An alias for `exposure`
1104  - ``ossThumb`` : `numpy.ndarray`
1105  Thumbnail image of the exposure after overscan subtraction.
1106  - ``flattenedThumb`` : `numpy.ndarray`
1107  Thumbnail image of the exposure after flat-field correction.
1108 
1109  Raises
1110  ------
1111  RuntimeError
1112  Raised if a configuration option is set to True, but the
1113  required calibration data has not been specified.
1114 
1115  Notes
1116  -----
1117  The current processed exposure can be viewed by setting the
1118  appropriate lsstDebug entries in the `debug.display`
1119  dictionary. The names of these entries correspond to some of
1120  the IsrTaskConfig Boolean options, with the value denoting the
1121  frame to use. The exposure is shown inside the matching
1122  option check and after the processing of that step has
1123  finished. The steps with debug points are:
1124 
1125  doAssembleCcd
1126  doBias
1127  doCrosstalk
1128  doBrighterFatter
1129  doDark
1130  doFringe
1131  doStrayLight
1132  doFlat
1133 
1134  In addition, setting the "postISRCCD" entry displays the
1135  exposure after all ISR processing has finished.
1136 
1137  """
1138 
1139  if isGen3 is True:
1140  # Gen3 currently cannot automatically do configuration overrides.
1141  # DM-15257 looks to discuss this issue.
1142 
1143  self.config.doFringe = False
1144 
1145  # Configure input exposures;
1146  if detectorNum is None:
1147  raise RuntimeError("Must supply the detectorNum if running as Gen3")
1148 
1149  ccdExposure = self.ensureExposure(ccdExposure, camera, detectorNum)
1150  bias = self.ensureExposure(bias, camera, detectorNum)
1151  dark = self.ensureExposure(dark, camera, detectorNum)
1152  flat = self.ensureExposure(flat, camera, detectorNum)
1153  else:
1154  if isinstance(ccdExposure, ButlerDataRef):
1155  return self.runDataRef(ccdExposure)
1156 
1157  ccd = ccdExposure.getDetector()
1158  filterName = afwImage.Filter(ccdExposure.getFilter().getId()).getName() # Canonical name for filter
1159 
1160  if not ccd:
1161  assert not self.config.doAssembleCcd, "You need a Detector to run assembleCcd"
1162  ccd = [FakeAmp(ccdExposure, self.config)]
1163 
1164  # Validate Input
1165  if self.config.doBias and bias is None:
1166  raise RuntimeError("Must supply a bias exposure if config.doBias=True.")
1167  if self.doLinearize(ccd) and linearizer is None:
1168  raise RuntimeError("Must supply a linearizer if config.doLinearize=True for this detector.")
1169  if self.config.doBrighterFatter and bfKernel is None:
1170  raise RuntimeError("Must supply a kernel if config.doBrighterFatter=True.")
1171  if self.config.doDark and dark is None:
1172  raise RuntimeError("Must supply a dark exposure if config.doDark=True.")
1173  if fringes is None:
1174  fringes = pipeBase.Struct(fringes=None)
1175  if self.config.doFringe and not isinstance(fringes, pipeBase.Struct):
1176  raise RuntimeError("Must supply fringe exposure as a pipeBase.Struct.")
1177  if self.config.doFlat and flat is None:
1178  raise RuntimeError("Must supply a flat exposure if config.doFlat=True.")
1179  if self.config.doDefect and defects is None:
1180  raise RuntimeError("Must supply defects if config.doDefect=True.")
1181  if self.config.doAddDistortionModel and camera is None:
1182  raise RuntimeError("Must supply camera if config.doAddDistortionModel=True.")
1183  if (self.config.doIlluminationCorrection and filterName in self.config.illumFilters and
1184  illumMaskedImage is None):
1185  raise RuntimeError("Must supply an illumcor if config.doIlluminationCorrection=True.")
1186 
1187  # Begin ISR processing.
1188  if self.config.doConvertIntToFloat:
1189  self.log.info("Converting exposure to floating point values")
1190  ccdExposure = self.convertIntToFloat(ccdExposure)
1191 
1192  # Amplifier level processing.
1193  overscans = []
1194  for amp in ccd:
1195  # if ccdExposure is one amp, check for coverage to prevent performing ops multiple times
1196  if ccdExposure.getBBox().contains(amp.getBBox()):
1197  # Check for fully masked bad amplifiers, and generate masks for SUSPECT and SATURATED values.
1198  badAmp = self.maskAmplifier(ccdExposure, amp, defects)
1199 
1200  if self.config.doOverscan and not badAmp:
1201  # Overscan correction on amp-by-amp basis.
1202  overscanResults = self.overscanCorrection(ccdExposure, amp)
1203  self.log.debug("Corrected overscan for amplifier %s" % (amp.getName()))
1204  if self.config.qa is not None and self.config.qa.saveStats is True:
1205  if isinstance(overscanResults.overscanFit, float):
1206  qaMedian = overscanResults.overscanFit
1207  qaStdev = float("NaN")
1208  else:
1209  qaStats = afwMath.makeStatistics(overscanResults.overscanFit,
1210  afwMath.MEDIAN | afwMath.STDEVCLIP)
1211  qaMedian = qaStats.getValue(afwMath.MEDIAN)
1212  qaStdev = qaStats.getValue(afwMath.STDEVCLIP)
1213 
1214  self.metadata.set("ISR OSCAN {} MEDIAN".format(amp.getName()), qaMedian)
1215  self.metadata.set("ISR OSCAN {} STDEV".format(amp.getName()), qaStdev)
1216  self.log.debug(" Overscan stats for amplifer %s: %f +/- %f" %
1217  (amp.getName(), qaMedian, qaStdev))
1218  ccdExposure.getMetadata().set('OVERSCAN', "Overscan corrected")
1219  else:
1220  if badAmp:
1221  self.log.warn("Amplifier %s is bad." % (amp.getName()))
1222  overscanResults = None
1223 
1224  overscans.append(overscanResults if overscanResults is not None else None)
1225  else:
1226  self.log.info("Skipped OSCAN")
1227 
1228  if self.config.doCrosstalk and self.config.doCrosstalkBeforeAssemble:
1229  self.log.info("Applying crosstalk correction.")
1230  self.crosstalk.run(ccdExposure, crosstalkSources=crosstalkSources)
1231  self.debugView(ccdExposure, "doCrosstalk")
1232 
1233  if self.config.doAssembleCcd:
1234  self.log.info("Assembling CCD from amplifiers")
1235  ccdExposure = self.assembleCcd.assembleCcd(ccdExposure)
1236 
1237  if self.config.expectWcs and not ccdExposure.getWcs():
1238  self.log.warn("No WCS found in input exposure")
1239  self.debugView(ccdExposure, "doAssembleCcd")
1240 
1241  ossThumb = None
1242  if self.config.qa.doThumbnailOss:
1243  ossThumb = isrQa.makeThumbnail(ccdExposure, isrQaConfig=self.config.qa)
1244 
1245  if self.config.doBias:
1246  self.log.info("Applying bias correction.")
1247  isrFunctions.biasCorrection(ccdExposure.getMaskedImage(), bias.getMaskedImage(),
1248  trimToFit=self.config.doTrimToMatchCalib)
1249  self.debugView(ccdExposure, "doBias")
1250 
1251  if self.config.doVariance:
1252  for amp, overscanResults in zip(ccd, overscans):
1253  if ccdExposure.getBBox().contains(amp.getBBox()):
1254  self.log.debug("Constructing variance map for amplifer %s" % (amp.getName()))
1255  ampExposure = ccdExposure.Factory(ccdExposure, amp.getBBox())
1256  if overscanResults is not None:
1257  self.updateVariance(ampExposure, amp,
1258  overscanImage=overscanResults.overscanImage)
1259  else:
1260  self.updateVariance(ampExposure, amp,
1261  overscanImage=None)
1262  if self.config.qa is not None and self.config.qa.saveStats is True:
1263  qaStats = afwMath.makeStatistics(ampExposure.getVariance(),
1264  afwMath.MEDIAN | afwMath.STDEVCLIP)
1265  self.metadata.set("ISR VARIANCE {} MEDIAN".format(amp.getName()),
1266  qaStats.getValue(afwMath.MEDIAN))
1267  self.metadata.set("ISR VARIANCE {} STDEV".format(amp.getName()),
1268  qaStats.getValue(afwMath.STDEVCLIP))
1269  self.log.debug(" Variance stats for amplifer %s: %f +/- %f" %
1270  (amp.getName(), qaStats.getValue(afwMath.MEDIAN),
1271  qaStats.getValue(afwMath.STDEVCLIP)))
1272 
1273  if self.doLinearize(ccd):
1274  self.log.info("Applying linearizer.")
1275  linearizer(image=ccdExposure.getMaskedImage().getImage(), detector=ccd, log=self.log)
1276 
1277  if self.config.doCrosstalk and not self.config.doCrosstalkBeforeAssemble:
1278  self.log.info("Applying crosstalk correction.")
1279  self.crosstalk.run(ccdExposure, crosstalkSources=crosstalkSources, isTrimmed=True)
1280  self.debugView(ccdExposure, "doCrosstalk")
1281 
1282  # Masking block. Optionally mask known defects, NAN pixels, widen trails, and do
1283  # anything else the camera needs. Saturated and suspect pixels have already been masked.
1284  if self.config.doDefect:
1285  self.log.info("Masking defects.")
1286  self.maskDefect(ccdExposure, defects)
1287 
1288  if self.config.doNanMasking:
1289  self.log.info("Masking NAN value pixels.")
1290  self.maskNan(ccdExposure)
1291 
1292  if self.config.doWidenSaturationTrails:
1293  self.log.info("Widening saturation trails.")
1294  isrFunctions.widenSaturationTrails(ccdExposure.getMaskedImage().getMask())
1295 
1296  if self.config.doCameraSpecificMasking:
1297  self.log.info("Masking regions for camera specific reasons.")
1298  self.masking.run(ccdExposure)
1299 
1300  if self.config.doBrighterFatter:
1301  # We need to apply flats and darks before we can interpolate, and we
1302  # need to interpolate before we do B-F, but we do B-F without the
1303  # flats and darks applied so we can work in units of electrons or holes.
1304  # This context manager applies and then removes the darks and flats.
1305  #
1306  # We also do not want to interpolate values here, so operate on temporary
1307  # images so we can apply only the BF-correction and roll back the
1308  # interpolation.
1309  interpExp = ccdExposure.clone()
1310  with self.flatContext(interpExp, flat, dark):
1311  isrFunctions.interpolateFromMask(
1312  maskedImage=ccdExposure.getMaskedImage(),
1313  fwhm=self.config.fwhm,
1314  growSaturatedFootprints=self.config.growSaturationFootprintSize,
1315  maskNameList=self.config.maskListToInterpolate
1316  )
1317  bfExp = interpExp.clone()
1318 
1319  self.log.info("Applying brighter fatter correction.")
1320  isrFunctions.brighterFatterCorrection(bfExp, bfKernel,
1321  self.config.brighterFatterMaxIter,
1322  self.config.brighterFatterThreshold,
1323  self.config.brighterFatterApplyGain,
1324  )
1325  image = ccdExposure.getMaskedImage().getImage()
1326  bfCorr = bfExp.getMaskedImage().getImage()
1327  bfCorr -= interpExp.getMaskedImage().getImage()
1328  image += bfCorr
1329 
1330  self.debugView(ccdExposure, "doBrighterFatter")
1331 
1332  if self.config.doDark:
1333  self.log.info("Applying dark correction.")
1334  self.darkCorrection(ccdExposure, dark)
1335  self.debugView(ccdExposure, "doDark")
1336 
1337  if self.config.doFringe and not self.config.fringeAfterFlat:
1338  self.log.info("Applying fringe correction before flat.")
1339  self.fringe.run(ccdExposure, **fringes.getDict())
1340  self.debugView(ccdExposure, "doFringe")
1341 
1342  if self.config.doStrayLight:
1343  if strayLightData is not None:
1344  self.log.info("Applying stray light correction.")
1345  self.strayLight.run(ccdExposure, strayLightData)
1346  self.debugView(ccdExposure, "doStrayLight")
1347  else:
1348  self.log.debug("Skipping stray light correction: no data found for this image.")
1349 
1350  if self.config.doFlat:
1351  self.log.info("Applying flat correction.")
1352  self.flatCorrection(ccdExposure, flat)
1353  self.debugView(ccdExposure, "doFlat")
1354 
1355  if self.config.doApplyGains:
1356  self.log.info("Applying gain correction instead of flat.")
1357  isrFunctions.applyGains(ccdExposure, self.config.normalizeGains)
1358 
1359  if self.config.doFringe and self.config.fringeAfterFlat:
1360  self.log.info("Applying fringe correction after flat.")
1361  self.fringe.run(ccdExposure, **fringes.getDict())
1362 
1363  if self.config.doVignette:
1364  self.log.info("Constructing Vignette polygon.")
1365  self.vignettePolygon = self.vignette.run(ccdExposure)
1366 
1367  if self.config.vignette.doWriteVignettePolygon:
1368  self.setValidPolygonIntersect(ccdExposure, self.vignettePolygon)
1369 
1370  if self.config.doAttachTransmissionCurve:
1371  self.log.info("Adding transmission curves.")
1372  isrFunctions.attachTransmissionCurve(ccdExposure, opticsTransmission=opticsTransmission,
1373  filterTransmission=filterTransmission,
1374  sensorTransmission=sensorTransmission,
1375  atmosphereTransmission=atmosphereTransmission)
1376 
1377  if self.config.doAddDistortionModel:
1378  self.log.info("Adding a distortion model to the WCS.")
1379  isrFunctions.addDistortionModel(exposure=ccdExposure, camera=camera)
1380 
1381  flattenedThumb = None
1382  if self.config.qa.doThumbnailFlattened:
1383  flattenedThumb = isrQa.makeThumbnail(ccdExposure, isrQaConfig=self.config.qa)
1384 
1385  if self.config.doIlluminationCorrection and filterName in self.config.illumFilters:
1386  self.log.info("Performing illumination correction.")
1387  isrFunctions.illuminationCorrection(ccdExposure.getMaskedImage(),
1388  illumMaskedImage, illumScale=self.config.illumScale,
1389  trimToFit=self.config.doTrimToMatchCalib)
1390 
1391  preInterpExp = None
1392  if self.config.doSaveInterpPixels:
1393  preInterpExp = ccdExposure.clone()
1394 
1395  if self.config.doInterpolate:
1396  self.log.info("Interpolating masked pixels.")
1397  isrFunctions.interpolateFromMask(
1398  maskedImage=ccdExposure.getMaskedImage(),
1399  fwhm=self.config.fwhm,
1400  growSaturatedFootprints=self.config.growSaturationFootprintSize,
1401  maskNameList=list(self.config.maskListToInterpolate)
1402  )
1403 
1404  if self.config.doSetBadRegions:
1405  # This is like an interpolation.
1406  badPixelCount, badPixelValue = isrFunctions.setBadRegions(ccdExposure)
1407  if badPixelCount > 0:
1408  self.log.info("Set %d BAD pixels to %f." % (badPixelCount, badPixelValue))
1409 
1410  self.roughZeroPoint(ccdExposure)
1411 
1412  if self.config.doMeasureBackground:
1413  self.log.info("Measuring background level:")
1414  self.measureBackground(ccdExposure, self.config.qa)
1415 
1416  if self.config.qa is not None and self.config.qa.saveStats is True:
1417  for amp in ccd:
1418  ampExposure = ccdExposure.Factory(ccdExposure, amp.getBBox())
1419  qaStats = afwMath.makeStatistics(ampExposure.getImage(),
1420  afwMath.MEDIAN | afwMath.STDEVCLIP)
1421  self.metadata.set("ISR BACKGROUND {} MEDIAN".format(amp.getName()),
1422  qaStats.getValue(afwMath.MEDIAN))
1423  self.metadata.set("ISR BACKGROUND {} STDEV".format(amp.getName()),
1424  qaStats.getValue(afwMath.STDEVCLIP))
1425  self.log.debug(" Background stats for amplifer %s: %f +/- %f" %
1426  (amp.getName(), qaStats.getValue(afwMath.MEDIAN),
1427  qaStats.getValue(afwMath.STDEVCLIP)))
1428 
1429  self.debugView(ccdExposure, "postISRCCD")
1430 
1431  return pipeBase.Struct(
1432  exposure=ccdExposure,
1433  ossThumb=ossThumb,
1434  flattenedThumb=flattenedThumb,
1435 
1436  preInterpolatedExposure=preInterpExp,
1437  outputExposure=ccdExposure,
1438  outputOssThumbnail=ossThumb,
1439  outputFlattenedThumbnail=flattenedThumb,
1440  )
1441 
bool contains(VertexIterator const begin, VertexIterator const end, UnitVector3d const &v)
daf::base::PropertySet * set
Definition: fits.cc:884
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<>
Definition: Statistics.h:520
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:168
Holds an integer identifier for an LSST filter.
Definition: Filter.h:141
daf::base::PropertyList * list
Definition: fits.cc:885

◆ runDataRef()

def lsst.ip.isr.isrTask.IsrTask.runDataRef (   self,
  sensorRef 
)
Perform instrument signature removal on a ButlerDataRef of a Sensor.

This method contains the `CmdLineTask` interface to the ISR
processing.  All IO is handled here, freeing the `run()` method
to manage only pixel-level calculations.  The steps performed
are:
- Read in necessary detrending/isr/calibration data.
- Process raw exposure in `run()`.
- Persist the ISR-corrected exposure as "postISRCCD" if
  config.doWrite=True.

Parameters
----------
sensorRef : `daf.persistence.butlerSubset.ButlerDataRef`
    DataRef of the detector data to be processed

Returns
-------
result : `lsst.pipe.base.Struct`
    Result struct with component:
    - ``exposure`` : `afw.image.Exposure`
The fully ISR corrected exposure.

Raises
------
RuntimeError
    Raised if a configuration option is set to True, but the
    required calibration data does not exist.

Definition at line 1443 of file isrTask.py.

1443  def runDataRef(self, sensorRef):
1444  """Perform instrument signature removal on a ButlerDataRef of a Sensor.
1445 
1446  This method contains the `CmdLineTask` interface to the ISR
1447  processing. All IO is handled here, freeing the `run()` method
1448  to manage only pixel-level calculations. The steps performed
1449  are:
1450  - Read in necessary detrending/isr/calibration data.
1451  - Process raw exposure in `run()`.
1452  - Persist the ISR-corrected exposure as "postISRCCD" if
1453  config.doWrite=True.
1454 
1455  Parameters
1456  ----------
1457  sensorRef : `daf.persistence.butlerSubset.ButlerDataRef`
1458  DataRef of the detector data to be processed
1459 
1460  Returns
1461  -------
1462  result : `lsst.pipe.base.Struct`
1463  Result struct with component:
1464  - ``exposure`` : `afw.image.Exposure`
1465  The fully ISR corrected exposure.
1466 
1467  Raises
1468  ------
1469  RuntimeError
1470  Raised if a configuration option is set to True, but the
1471  required calibration data does not exist.
1472 
1473  """
1474  self.log.info("Performing ISR on sensor %s" % (sensorRef.dataId))
1475 
1476  ccdExposure = sensorRef.get(self.config.datasetType)
1477 
1478  camera = sensorRef.get("camera")
1479  if camera is None and self.config.doAddDistortionModel:
1480  raise RuntimeError("config.doAddDistortionModel is True "
1481  "but could not get a camera from the butler")
1482  isrData = self.readIsrData(sensorRef, ccdExposure)
1483 
1484  result = self.run(ccdExposure, camera=camera, **isrData.getDict())
1485 
1486  if self.config.doWrite:
1487  sensorRef.put(result.exposure, "postISRCCD")
1488  if result.preInterpolatedExposure is not None:
1489  sensorRef.put(result.preInterpolatedExposure, "postISRCCD_uninterpolated")
1490  if result.ossThumb is not None:
1491  isrQa.writeThumbnail(sensorRef, result.ossThumb, "ossThumb")
1492  if result.flattenedThumb is not None:
1493  isrQa.writeThumbnail(sensorRef, result.flattenedThumb, "flattenedThumb")
1494 
1495  return result
1496 

◆ saturationDetection()

def lsst.ip.isr.isrTask.IsrTask.saturationDetection (   self,
  exposure,
  amp 
)

Detect saturated pixels and mask them using mask plane config.saturatedMaskName, in place.

Parameters

exposure : lsst.afw.image.Exposure Exposure to process. Only the amplifier DataSec is processed. amp : lsst.afw.table.AmpInfoCatalog Amplifier detector data.

See Also

lsst.ip.isr.isrFunctions.makeThresholdMask

Definition at line 1965 of file isrTask.py.

1965  def saturationDetection(self, exposure, amp):
1966  """!Detect saturated pixels and mask them using mask plane config.saturatedMaskName, in place.
1967 
1968  Parameters
1969  ----------
1970  exposure : `lsst.afw.image.Exposure`
1971  Exposure to process. Only the amplifier DataSec is processed.
1972  amp : `lsst.afw.table.AmpInfoCatalog`
1973  Amplifier detector data.
1974 
1975  See Also
1976  --------
1977  lsst.ip.isr.isrFunctions.makeThresholdMask
1978  """
1979  if not math.isnan(amp.getSaturation()):
1980  maskedImage = exposure.getMaskedImage()
1981  dataView = maskedImage.Factory(maskedImage, amp.getRawBBox())
1982  isrFunctions.makeThresholdMask(
1983  maskedImage=dataView,
1984  threshold=amp.getSaturation(),
1985  growFootprints=0,
1986  maskName=self.config.saturatedMaskName,
1987  )
1988 

◆ saturationInterpolation()

def lsst.ip.isr.isrTask.IsrTask.saturationInterpolation (   self,
  exposure 
)

Interpolate over saturated pixels, in place.

This method should be called after saturationDetection, to ensure that the saturated pixels have been identified in the SAT mask. It should also be called after assembleCcd, since saturated regions may cross amplifier boundaries.

Parameters

exposure : lsst.afw.image.Exposure Exposure to process.

See Also

lsst.ip.isr.isrTask.saturationDetection lsst.ip.isr.isrFunctions.interpolateFromMask

Definition at line 1989 of file isrTask.py.

1989  def saturationInterpolation(self, exposure):
1990  """!Interpolate over saturated pixels, in place.
1991 
1992  This method should be called after `saturationDetection`, to
1993  ensure that the saturated pixels have been identified in the
1994  SAT mask. It should also be called after `assembleCcd`, since
1995  saturated regions may cross amplifier boundaries.
1996 
1997  Parameters
1998  ----------
1999  exposure : `lsst.afw.image.Exposure`
2000  Exposure to process.
2001 
2002  See Also
2003  --------
2004  lsst.ip.isr.isrTask.saturationDetection
2005  lsst.ip.isr.isrFunctions.interpolateFromMask
2006  """
2007  isrFunctions.interpolateFromMask(
2008  maskedImage=exposure.getMaskedImage(),
2009  fwhm=self.config.fwhm,
2010  growSaturatedFootprints=self.config.growSaturationFootprintSize,
2011  maskNameList=list(self.config.saturatedMaskName),
2012  )
2013 
daf::base::PropertyList * list
Definition: fits.cc:885

◆ setValidPolygonIntersect()

def lsst.ip.isr.isrTask.IsrTask.setValidPolygonIntersect (   self,
  ccdExposure,
  fpPolygon 
)

Set the valid polygon as the intersection of fpPolygon and the ccd corners.

Parameters

ccdExposure : lsst.afw.image.Exposure Exposure to process. fpPolygon : lsst.afw.geom.Polygon Polygon in focal plane coordinates.

Definition at line 2234 of file isrTask.py.

2234  def setValidPolygonIntersect(self, ccdExposure, fpPolygon):
2235  """!Set the valid polygon as the intersection of fpPolygon and the ccd corners.
2236 
2237  Parameters
2238  ----------
2239  ccdExposure : `lsst.afw.image.Exposure`
2240  Exposure to process.
2241  fpPolygon : `lsst.afw.geom.Polygon`
2242  Polygon in focal plane coordinates.
2243  """
2244  # Get ccd corners in focal plane coordinates
2245  ccd = ccdExposure.getDetector()
2246  fpCorners = ccd.getCorners(FOCAL_PLANE)
2247  ccdPolygon = Polygon(fpCorners)
2248 
2249  # Get intersection of ccd corners with fpPolygon
2250  intersect = ccdPolygon.intersectionSingle(fpPolygon)
2251 
2252  # Transform back to pixel positions and build new polygon
2253  ccdPoints = ccd.transform(intersect, FOCAL_PLANE, PIXELS)
2254  validPolygon = Polygon(ccdPoints)
2255  ccdExposure.getInfo().setValidPolygon(validPolygon)
2256 

◆ suspectDetection()

def lsst.ip.isr.isrTask.IsrTask.suspectDetection (   self,
  exposure,
  amp 
)

Detect suspect pixels and mask them using mask plane config.suspectMaskName, in place.

Parameters

exposure : lsst.afw.image.Exposure Exposure to process. Only the amplifier DataSec is processed. amp : lsst.afw.table.AmpInfoCatalog Amplifier detector data.

See Also

lsst.ip.isr.isrFunctions.makeThresholdMask

Notes

Suspect pixels are pixels whose value is greater than amp.getSuspectLevel(). This is intended to indicate pixels that may be affected by unknown systematics; for example if non-linearity corrections above a certain level are unstable then that would be a useful value for suspectLevel. A value of nan indicates that no such level exists and no pixels are to be masked as suspicious.

Definition at line 2014 of file isrTask.py.

2014  def suspectDetection(self, exposure, amp):
2015  """!Detect suspect pixels and mask them using mask plane config.suspectMaskName, in place.
2016 
2017  Parameters
2018  ----------
2019  exposure : `lsst.afw.image.Exposure`
2020  Exposure to process. Only the amplifier DataSec is processed.
2021  amp : `lsst.afw.table.AmpInfoCatalog`
2022  Amplifier detector data.
2023 
2024  See Also
2025  --------
2026  lsst.ip.isr.isrFunctions.makeThresholdMask
2027 
2028  Notes
2029  -----
2030  Suspect pixels are pixels whose value is greater than amp.getSuspectLevel().
2031  This is intended to indicate pixels that may be affected by unknown systematics;
2032  for example if non-linearity corrections above a certain level are unstable
2033  then that would be a useful value for suspectLevel. A value of `nan` indicates
2034  that no such level exists and no pixels are to be masked as suspicious.
2035  """
2036  suspectLevel = amp.getSuspectLevel()
2037  if math.isnan(suspectLevel):
2038  return
2039 
2040  maskedImage = exposure.getMaskedImage()
2041  dataView = maskedImage.Factory(maskedImage, amp.getRawBBox())
2042  isrFunctions.makeThresholdMask(
2043  maskedImage=dataView,
2044  threshold=suspectLevel,
2045  growFootprints=0,
2046  maskName=self.config.suspectMaskName,
2047  )
2048 

◆ updateVariance()

def lsst.ip.isr.isrTask.IsrTask.updateVariance (   self,
  ampExposure,
  amp,
  overscanImage = None 
)
Set the variance plane using the amplifier gain and read noise

The read noise is calculated from the ``overscanImage`` if the
``doEmpiricalReadNoise`` option is set in the configuration; otherwise
the value from the amplifier data is used.

Parameters
----------
ampExposure : `lsst.afw.image.Exposure`
    Exposure to process.
amp : `lsst.afw.table.AmpInfoRecord` or `FakeAmp`
    Amplifier detector data.
overscanImage : `lsst.afw.image.MaskedImage`, optional.
    Image of overscan, required only for empirical read noise.

See also
--------
lsst.ip.isr.isrFunctions.updateVariance

Definition at line 1829 of file isrTask.py.

1829  def updateVariance(self, ampExposure, amp, overscanImage=None):
1830  """Set the variance plane using the amplifier gain and read noise
1831 
1832  The read noise is calculated from the ``overscanImage`` if the
1833  ``doEmpiricalReadNoise`` option is set in the configuration; otherwise
1834  the value from the amplifier data is used.
1835 
1836  Parameters
1837  ----------
1838  ampExposure : `lsst.afw.image.Exposure`
1839  Exposure to process.
1840  amp : `lsst.afw.table.AmpInfoRecord` or `FakeAmp`
1841  Amplifier detector data.
1842  overscanImage : `lsst.afw.image.MaskedImage`, optional.
1843  Image of overscan, required only for empirical read noise.
1844 
1845  See also
1846  --------
1847  lsst.ip.isr.isrFunctions.updateVariance
1848  """
1849  maskPlanes = [self.config.saturatedMaskName, self.config.suspectMaskName]
1850  gain = amp.getGain()
1851 
1852  if math.isnan(gain):
1853  gain = 1.0
1854  self.log.warn("Gain set to NAN! Updating to 1.0 to generate Poisson variance.")
1855  elif gain <= 0:
1856  patchedGain = 1.0
1857  self.log.warn("Gain for amp %s == %g <= 0; setting to %f" %
1858  (amp.getName(), gain, patchedGain))
1859  gain = patchedGain
1860 
1861  if self.config.doEmpiricalReadNoise and overscanImage is None:
1862  self.log.info("Overscan is none for EmpiricalReadNoise")
1863 
1864  if self.config.doEmpiricalReadNoise and overscanImage is not None:
1865  stats = afwMath.StatisticsControl()
1866  stats.setAndMask(overscanImage.mask.getPlaneBitMask(maskPlanes))
1867  readNoise = afwMath.makeStatistics(overscanImage, afwMath.STDEVCLIP, stats).getValue()
1868  self.log.info("Calculated empirical read noise for amp %s: %f", amp.getName(), readNoise)
1869  else:
1870  readNoise = amp.getReadNoise()
1871 
1872  isrFunctions.updateVariance(
1873  maskedImage=ampExposure.getMaskedImage(),
1874  gain=gain,
1875  readNoise=readNoise,
1876  )
1877 
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<>
Definition: Statistics.h:520
Pass parameters to a Statistics object.
Definition: Statistics.h:93
def updateVariance(maskedImage, gain, readNoise)

Member Data Documentation

◆ ConfigClass

lsst.ip.isr.isrTask.IsrTask.ConfigClass = IsrTaskConfig
static

Definition at line 756 of file isrTask.py.

◆ vignettePolygon

lsst.ip.isr.isrTask.IsrTask.vignettePolygon

Definition at line 1365 of file isrTask.py.


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