LSSTApplications  20.0.0
LSSTDataManagementBasePackage
Classes | Functions | Variables
lsst.pipe.tasks.dcrAssembleCoadd Namespace Reference

Classes

class  DcrAssembleCoaddConnections
 

Functions

def dcrAssembleSubregion (self, dcrModels, subExposures, bbox, dcrBBox, warpRefList, statsCtrl, convergenceMetric, gain, modelWeights, refImage, dcrWeights)
 
def dcrResiduals (self, residual, visitInfo, wcs, filterInfo)
 
def newModelFromResidual (self, dcrModels, residualGeneratorList, dcrBBox, statsCtrl, gain, modelWeights, refImage, dcrWeights)
 
def calculateConvergence (self, dcrModels, subExposures, bbox, warpRefList, weightList, statsCtrl)
 
def calculateSingleConvergence (self, dcrModels, exposure, significanceImage, statsCtrl)
 
def stackCoadd (self, dcrCoadds)
 
def fillCoadd (self, dcrModels, skyInfo, warpRefList, weightList, calibration=None, coaddInputs=None, mask=None, variance=None)
 
def calculateGain (self, convergenceList, gainList)
 
def calculateModelWeights (self, dcrModels, dcrBBox)
 
def applyModelWeights (self, modelImages, refImage, modelWeights)
 
def loadSubExposures (self, bbox, statsCtrl, warpRefList, imageScalerList, spanSetMaskList)
 
def selectCoaddPsf (self, templateCoadd, warpRefList)
 

Variables

 weightsThreshold
 
 goodPix
 

Function Documentation

◆ applyModelWeights()

def lsst.pipe.tasks.dcrAssembleCoadd.applyModelWeights (   self,
  modelImages,
  refImage,
  modelWeights 
)
Smoothly replace model pixel values with those from a
reference at locations away from detected sources.

Parameters
----------
modelImages : `list` of `lsst.afw.image.Image`
    The new DCR model images from the current iteration.
    The values will be modified in place.
refImage : `lsst.afw.image.MaskedImage`
    A reference image used to supply the default pixel values.
modelWeights : `numpy.ndarray` or `float`
    A 2D array of weight values that tapers smoothly to zero away from detected sources.
    Set to a placeholder value of 1.0 if ``self.config.useModelWeights`` is False.

Definition at line 1224 of file dcrAssembleCoadd.py.

1224  def applyModelWeights(self, modelImages, refImage, modelWeights):
1225  """Smoothly replace model pixel values with those from a
1226  reference at locations away from detected sources.
1227 
1228  Parameters
1229  ----------
1230  modelImages : `list` of `lsst.afw.image.Image`
1231  The new DCR model images from the current iteration.
1232  The values will be modified in place.
1233  refImage : `lsst.afw.image.MaskedImage`
1234  A reference image used to supply the default pixel values.
1235  modelWeights : `numpy.ndarray` or `float`
1236  A 2D array of weight values that tapers smoothly to zero away from detected sources.
1237  Set to a placeholder value of 1.0 if ``self.config.useModelWeights`` is False.
1238  """
1239  if self.config.useModelWeights:
1240  for model in modelImages:
1241  model.array *= modelWeights
1242  model.array += refImage.array*(1. - modelWeights)/self.config.dcrNumSubfilters
1243 

◆ calculateConvergence()

def lsst.pipe.tasks.dcrAssembleCoadd.calculateConvergence (   self,
  dcrModels,
  subExposures,
  bbox,
  warpRefList,
  weightList,
  statsCtrl 
)
Calculate a quality of fit metric for the matched templates.

Parameters
----------
dcrModels : `lsst.pipe.tasks.DcrModel`
    Best fit model of the true sky after correcting chromatic effects.
subExposures : `dict` of `lsst.afw.image.ExposureF`
    The pre-loaded exposures for the current subregion.
bbox : `lsst.geom.box.Box2I`
    Sub-region to coadd
warpRefList : `list` of `lsst.daf.butler.DeferredDatasetHandle` or
    `lsst.daf.persistence.ButlerDataRef`
    The data references to the input warped exposures.
weightList : `list` of `float`
    The weight to give each input exposure in the coadd
statsCtrl : `lsst.afw.math.StatisticsControl`
    Statistics control object for coadd

Returns
-------
convergenceMetric : `float`
    Quality of fit metric for all input exposures, within the sub-region

Definition at line 949 of file dcrAssembleCoadd.py.

949  def calculateConvergence(self, dcrModels, subExposures, bbox, warpRefList, weightList, statsCtrl):
950  """Calculate a quality of fit metric for the matched templates.
951 
952  Parameters
953  ----------
954  dcrModels : `lsst.pipe.tasks.DcrModel`
955  Best fit model of the true sky after correcting chromatic effects.
956  subExposures : `dict` of `lsst.afw.image.ExposureF`
957  The pre-loaded exposures for the current subregion.
958  bbox : `lsst.geom.box.Box2I`
959  Sub-region to coadd
960  warpRefList : `list` of `lsst.daf.butler.DeferredDatasetHandle` or
961  `lsst.daf.persistence.ButlerDataRef`
962  The data references to the input warped exposures.
963  weightList : `list` of `float`
964  The weight to give each input exposure in the coadd
965  statsCtrl : `lsst.afw.math.StatisticsControl`
966  Statistics control object for coadd
967 
968  Returns
969  -------
970  convergenceMetric : `float`
971  Quality of fit metric for all input exposures, within the sub-region
972  """
973  significanceImage = np.abs(dcrModels.getReferenceImage(bbox))
974  nSigma = 3.
975  significanceImage += nSigma*dcrModels.calculateNoiseCutoff(dcrModels[1], statsCtrl,
976  bufferSize=self.bufferSize)
977  if np.max(significanceImage) == 0:
978  significanceImage += 1.
979  weight = 0
980  metric = 0.
981  metricList = {}
982  for warpExpRef, expWeight in zip(warpRefList, weightList):
983  visit = warpExpRef.dataId["visit"]
984  exposure = subExposures[visit][bbox]
985  singleMetric = self.calculateSingleConvergence(dcrModels, exposure, significanceImage, statsCtrl)
986  metric += singleMetric
987  metricList[visit] = singleMetric
988  weight += 1.
989  self.log.info("Individual metrics:\n%s", metricList)
990  return 1.0 if weight == 0.0 else metric/weight
991 

◆ calculateGain()

def lsst.pipe.tasks.dcrAssembleCoadd.calculateGain (   self,
  convergenceList,
  gainList 
)
Calculate the gain to use for the current iteration.

After calculating a new DcrModel, each value is averaged with the
value in the corresponding pixel from the previous iteration. This
reduces oscillating solutions that iterative techniques are plagued by,
and speeds convergence. By far the biggest changes to the model
happen in the first couple iterations, so we can also use a more
aggressive gain later when the model is changing slowly.

Parameters
----------
convergenceList : `list` of `float`
    The quality of fit metric from each previous iteration.
gainList : `list` of `float`
    The gains used in each previous iteration: appended with the new
    gain value.
    Gains are numbers between ``self.config.baseGain`` and 1.

Returns
-------
gain : `float`
    Relative weight to give the new solution when updating the model.
    A value of 1.0 gives equal weight to both solutions.

Raises
------
ValueError
    If ``len(convergenceList) != len(gainList)+1``.

Definition at line 1110 of file dcrAssembleCoadd.py.

1110  def calculateGain(self, convergenceList, gainList):
1111  """Calculate the gain to use for the current iteration.
1112 
1113  After calculating a new DcrModel, each value is averaged with the
1114  value in the corresponding pixel from the previous iteration. This
1115  reduces oscillating solutions that iterative techniques are plagued by,
1116  and speeds convergence. By far the biggest changes to the model
1117  happen in the first couple iterations, so we can also use a more
1118  aggressive gain later when the model is changing slowly.
1119 
1120  Parameters
1121  ----------
1122  convergenceList : `list` of `float`
1123  The quality of fit metric from each previous iteration.
1124  gainList : `list` of `float`
1125  The gains used in each previous iteration: appended with the new
1126  gain value.
1127  Gains are numbers between ``self.config.baseGain`` and 1.
1128 
1129  Returns
1130  -------
1131  gain : `float`
1132  Relative weight to give the new solution when updating the model.
1133  A value of 1.0 gives equal weight to both solutions.
1134 
1135  Raises
1136  ------
1137  ValueError
1138  If ``len(convergenceList) != len(gainList)+1``.
1139  """
1140  nIter = len(convergenceList)
1141  if nIter != len(gainList) + 1:
1142  raise ValueError("convergenceList (%d) must be one element longer than gainList (%d)."
1143  % (len(convergenceList), len(gainList)))
1144 
1145  if self.config.baseGain is None:
1146  # If ``baseGain`` is not set, calculate it from the number of DCR subfilters
1147  # The more subfilters being modeled, the lower the gain should be.
1148  baseGain = 1./(self.config.dcrNumSubfilters - 1)
1149  else:
1150  baseGain = self.config.baseGain
1151 
1152  if self.config.useProgressiveGain and nIter > 2:
1153  # To calculate the best gain to use, compare the past gains that have been used
1154  # with the resulting convergences to estimate the best gain to use.
1155  # Algorithmically, this is a Kalman filter.
1156  # If forward modeling proceeds perfectly, the convergence metric should
1157  # asymptotically approach a final value.
1158  # We can estimate that value from the measured changes in convergence
1159  # weighted by the gains used in each previous iteration.
1160  estFinalConv = [((1 + gainList[i])*convergenceList[i + 1] - convergenceList[i])/gainList[i]
1161  for i in range(nIter - 1)]
1162  # The convergence metric is strictly positive, so if the estimated final convergence is
1163  # less than zero, force it to zero.
1164  estFinalConv = np.array(estFinalConv)
1165  estFinalConv[estFinalConv < 0] = 0
1166  # Because the estimate may slowly change over time, only use the most recent measurements.
1167  estFinalConv = np.median(estFinalConv[max(nIter - 5, 0):])
1168  lastGain = gainList[-1]
1169  lastConv = convergenceList[-2]
1170  newConv = convergenceList[-1]
1171  # The predicted convergence is the value we would get if the new model calculated
1172  # in the previous iteration was perfect. Recall that the updated model that is
1173  # actually used is the gain-weighted average of the new and old model,
1174  # so the convergence would be similarly weighted.
1175  predictedConv = (estFinalConv*lastGain + lastConv)/(1. + lastGain)
1176  # If the measured and predicted convergence are very close, that indicates
1177  # that our forward model is accurate and we can use a more aggressive gain
1178  # If the measured convergence is significantly worse (or better!) than predicted,
1179  # that indicates that the model is not converging as expected and
1180  # we should use a more conservative gain.
1181  delta = (predictedConv - newConv)/((lastConv - estFinalConv)/(1 + lastGain))
1182  newGain = 1 - abs(delta)
1183  # Average the gains to prevent oscillating solutions.
1184  newGain = (newGain + lastGain)/2.
1185  gain = max(baseGain, newGain)
1186  else:
1187  gain = baseGain
1188  gainList.append(gain)
1189  return gain
1190 

◆ calculateModelWeights()

def lsst.pipe.tasks.dcrAssembleCoadd.calculateModelWeights (   self,
  dcrModels,
  dcrBBox 
)
Build an array that smoothly tapers to 0 away from detected sources.

Parameters
----------
dcrModels : `lsst.pipe.tasks.DcrModel`
    Best fit model of the true sky after correcting chromatic effects.
dcrBBox : `lsst.geom.box.Box2I`
    Sub-region of the coadd which includes a buffer to allow for DCR.

Returns
-------
weights : `numpy.ndarray` or `float`
    A 2D array of weight values that tapers smoothly to zero away from detected sources.
    Set to a placeholder value of 1.0 if ``self.config.useModelWeights`` is False.

Raises
------
ValueError
    If ``useModelWeights`` is set and ``modelWeightsWidth`` is negative.

Definition at line 1191 of file dcrAssembleCoadd.py.

1191  def calculateModelWeights(self, dcrModels, dcrBBox):
1192  """Build an array that smoothly tapers to 0 away from detected sources.
1193 
1194  Parameters
1195  ----------
1196  dcrModels : `lsst.pipe.tasks.DcrModel`
1197  Best fit model of the true sky after correcting chromatic effects.
1198  dcrBBox : `lsst.geom.box.Box2I`
1199  Sub-region of the coadd which includes a buffer to allow for DCR.
1200 
1201  Returns
1202  -------
1203  weights : `numpy.ndarray` or `float`
1204  A 2D array of weight values that tapers smoothly to zero away from detected sources.
1205  Set to a placeholder value of 1.0 if ``self.config.useModelWeights`` is False.
1206 
1207  Raises
1208  ------
1209  ValueError
1210  If ``useModelWeights`` is set and ``modelWeightsWidth`` is negative.
1211  """
1212  if not self.config.useModelWeights:
1213  return 1.0
1214  if self.config.modelWeightsWidth < 0:
1215  raise ValueError("modelWeightsWidth must not be negative if useModelWeights is set")
1216  convergeMask = dcrModels.mask.getPlaneBitMask(self.config.convergenceMaskPlanes)
1217  convergeMaskPixels = dcrModels.mask[dcrBBox].array & convergeMask > 0
1218  weights = np.zeros_like(dcrModels[0][dcrBBox].array)
1219  weights[convergeMaskPixels] = 1.
1220  weights = ndimage.filters.gaussian_filter(weights, self.config.modelWeightsWidth)
1221  weights /= np.max(weights)
1222  return weights
1223 

◆ calculateSingleConvergence()

def lsst.pipe.tasks.dcrAssembleCoadd.calculateSingleConvergence (   self,
  dcrModels,
  exposure,
  significanceImage,
  statsCtrl 
)
Calculate a quality of fit metric for a single matched template.

Parameters
----------
dcrModels : `lsst.pipe.tasks.DcrModel`
    Best fit model of the true sky after correcting chromatic effects.
exposure : `lsst.afw.image.ExposureF`
    The input warped exposure to evaluate.
significanceImage : `numpy.ndarray`
    Array of weights for each pixel corresponding to its significance
    for the convergence calculation.
statsCtrl : `lsst.afw.math.StatisticsControl`
    Statistics control object for coadd

Returns
-------
convergenceMetric : `float`
    Quality of fit metric for one exposure, within the sub-region.

Definition at line 992 of file dcrAssembleCoadd.py.

992  def calculateSingleConvergence(self, dcrModels, exposure, significanceImage, statsCtrl):
993  """Calculate a quality of fit metric for a single matched template.
994 
995  Parameters
996  ----------
997  dcrModels : `lsst.pipe.tasks.DcrModel`
998  Best fit model of the true sky after correcting chromatic effects.
999  exposure : `lsst.afw.image.ExposureF`
1000  The input warped exposure to evaluate.
1001  significanceImage : `numpy.ndarray`
1002  Array of weights for each pixel corresponding to its significance
1003  for the convergence calculation.
1004  statsCtrl : `lsst.afw.math.StatisticsControl`
1005  Statistics control object for coadd
1006 
1007  Returns
1008  -------
1009  convergenceMetric : `float`
1010  Quality of fit metric for one exposure, within the sub-region.
1011  """
1012  convergeMask = exposure.mask.getPlaneBitMask(self.config.convergenceMaskPlanes)
1013  templateImage = dcrModels.buildMatchedTemplate(exposure=exposure,
1014  order=self.config.imageInterpOrder,
1015  splitSubfilters=self.config.splitSubfilters,
1016  splitThreshold=self.config.splitThreshold,
1017  amplifyModel=self.config.accelerateModel)
1018  diffVals = np.abs(exposure.image.array - templateImage.array)*significanceImage
1019  refVals = np.abs(exposure.image.array + templateImage.array)*significanceImage/2.
1020 
1021  finitePixels = np.isfinite(diffVals)
1022  goodMaskPixels = (exposure.mask.array & statsCtrl.getAndMask()) == 0
1023  convergeMaskPixels = exposure.mask.array & convergeMask > 0
1024  usePixels = finitePixels & goodMaskPixels & convergeMaskPixels
1025  if np.sum(usePixels) == 0:
1026  metric = 0.
1027  else:
1028  diffUse = diffVals[usePixels]
1029  refUse = refVals[usePixels]
1030  metric = np.sum(diffUse/np.median(diffUse))/np.sum(refUse/np.median(diffUse))
1031  return metric
1032 

◆ dcrAssembleSubregion()

def lsst.pipe.tasks.dcrAssembleCoadd.dcrAssembleSubregion (   self,
  dcrModels,
  subExposures,
  bbox,
  dcrBBox,
  warpRefList,
  statsCtrl,
  convergenceMetric,
  gain,
  modelWeights,
  refImage,
  dcrWeights 
)
Assemble the DCR coadd for a sub-region.

Build a DCR-matched template for each input exposure, then shift the
residuals according to the DCR in each subfilter.
Stack the shifted residuals and apply them as a correction to the
solution from the previous iteration.
Restrict the new model solutions from varying by more than a factor of
`modelClampFactor` from the last solution, and additionally restrict the
individual subfilter models from varying by more than a factor of
`frequencyClampFactor` from their average.
Finally, mitigate potentially oscillating solutions by averaging the new
solution with the solution from the previous iteration, weighted by
their convergence metric.

Parameters
----------
dcrModels : `lsst.pipe.tasks.DcrModel`
    Best fit model of the true sky after correcting chromatic effects.
subExposures : `dict` of `lsst.afw.image.ExposureF`
    The pre-loaded exposures for the current subregion.
bbox : `lsst.geom.box.Box2I`
    Bounding box of the subregion to coadd.
dcrBBox : `lsst.geom.box.Box2I`
    Sub-region of the coadd which includes a buffer to allow for DCR.
warpRefList : `list` of `lsst.daf.butler.DeferredDatasetHandle` or
    `lsst.daf.persistence.ButlerDataRef`
    The data references to the input warped exposures.
statsCtrl : `lsst.afw.math.StatisticsControl`
    Statistics control object for coadd
convergenceMetric : `float`
    Quality of fit metric for the matched templates of the input images.
gain : `float`, optional
    Relative weight to give the new solution when updating the model.
modelWeights : `numpy.ndarray` or `float`
    A 2D array of weight values that tapers smoothly to zero away from detected sources.
    Set to a placeholder value of 1.0 if ``self.config.useModelWeights`` is False.
refImage : `lsst.afw.image.Image`
    A reference image used to supply the default pixel values.
dcrWeights : `list` of `lsst.afw.image.Image`
    Per-pixel weights for each subfilter.
    Equal to 1/(number of unmasked images contributing to each pixel).

Definition at line 790 of file dcrAssembleCoadd.py.

790  def dcrAssembleSubregion(self, dcrModels, subExposures, bbox, dcrBBox, warpRefList,
791  statsCtrl, convergenceMetric,
792  gain, modelWeights, refImage, dcrWeights):
793  """Assemble the DCR coadd for a sub-region.
794 
795  Build a DCR-matched template for each input exposure, then shift the
796  residuals according to the DCR in each subfilter.
797  Stack the shifted residuals and apply them as a correction to the
798  solution from the previous iteration.
799  Restrict the new model solutions from varying by more than a factor of
800  `modelClampFactor` from the last solution, and additionally restrict the
801  individual subfilter models from varying by more than a factor of
802  `frequencyClampFactor` from their average.
803  Finally, mitigate potentially oscillating solutions by averaging the new
804  solution with the solution from the previous iteration, weighted by
805  their convergence metric.
806 
807  Parameters
808  ----------
809  dcrModels : `lsst.pipe.tasks.DcrModel`
810  Best fit model of the true sky after correcting chromatic effects.
811  subExposures : `dict` of `lsst.afw.image.ExposureF`
812  The pre-loaded exposures for the current subregion.
813  bbox : `lsst.geom.box.Box2I`
814  Bounding box of the subregion to coadd.
815  dcrBBox : `lsst.geom.box.Box2I`
816  Sub-region of the coadd which includes a buffer to allow for DCR.
817  warpRefList : `list` of `lsst.daf.butler.DeferredDatasetHandle` or
818  `lsst.daf.persistence.ButlerDataRef`
819  The data references to the input warped exposures.
820  statsCtrl : `lsst.afw.math.StatisticsControl`
821  Statistics control object for coadd
822  convergenceMetric : `float`
823  Quality of fit metric for the matched templates of the input images.
824  gain : `float`, optional
825  Relative weight to give the new solution when updating the model.
826  modelWeights : `numpy.ndarray` or `float`
827  A 2D array of weight values that tapers smoothly to zero away from detected sources.
828  Set to a placeholder value of 1.0 if ``self.config.useModelWeights`` is False.
829  refImage : `lsst.afw.image.Image`
830  A reference image used to supply the default pixel values.
831  dcrWeights : `list` of `lsst.afw.image.Image`
832  Per-pixel weights for each subfilter.
833  Equal to 1/(number of unmasked images contributing to each pixel).
834  """
835  residualGeneratorList = []
836 
837  for warpExpRef in warpRefList:
838  visit = warpExpRef.dataId["visit"]
839  exposure = subExposures[visit]
840  visitInfo = exposure.getInfo().getVisitInfo()
841  wcs = exposure.getInfo().getWcs()
842  templateImage = dcrModels.buildMatchedTemplate(exposure=exposure,
843  order=self.config.imageInterpOrder,
844  splitSubfilters=self.config.splitSubfilters,
845  splitThreshold=self.config.splitThreshold,
846  amplifyModel=self.config.accelerateModel)
847  residual = exposure.image.array - templateImage.array
848  # Note that the variance plane here is used to store weights, not the actual variance
849  residual *= exposure.variance.array
850  # The residuals are stored as a list of generators.
851  # This allows the residual for a given subfilter and exposure to be created
852  # on the fly, instead of needing to store them all in memory.
853  residualGeneratorList.append(self.dcrResiduals(residual, visitInfo, wcs, dcrModels.filter))
854 
855  dcrSubModelOut = self.newModelFromResidual(dcrModels, residualGeneratorList, dcrBBox, statsCtrl,
856  gain=gain,
857  modelWeights=modelWeights,
858  refImage=refImage,
859  dcrWeights=dcrWeights)
860  dcrModels.assign(dcrSubModelOut, bbox)
861 

◆ dcrResiduals()

def lsst.pipe.tasks.dcrAssembleCoadd.dcrResiduals (   self,
  residual,
  visitInfo,
  wcs,
  filterInfo 
)
Prepare a residual image for stacking in each subfilter by applying the reverse DCR shifts.

Parameters
----------
residual : `numpy.ndarray`
    The residual masked image for one exposure,
    after subtracting the matched template
visitInfo : `lsst.afw.image.VisitInfo`
    Metadata for the exposure.
wcs : `lsst.afw.geom.SkyWcs`
    Coordinate system definition (wcs) for the exposure.
filterInfo : `lsst.afw.image.Filter`
    The filter definition, set in the current instruments' obs package.
    Required for any calculation of DCR, including making matched templates.

Yields
------
residualImage : `numpy.ndarray`
    The residual image for the next subfilter, shifted for DCR.

Definition at line 862 of file dcrAssembleCoadd.py.

862  def dcrResiduals(self, residual, visitInfo, wcs, filterInfo):
863  """Prepare a residual image for stacking in each subfilter by applying the reverse DCR shifts.
864 
865  Parameters
866  ----------
867  residual : `numpy.ndarray`
868  The residual masked image for one exposure,
869  after subtracting the matched template
870  visitInfo : `lsst.afw.image.VisitInfo`
871  Metadata for the exposure.
872  wcs : `lsst.afw.geom.SkyWcs`
873  Coordinate system definition (wcs) for the exposure.
874  filterInfo : `lsst.afw.image.Filter`
875  The filter definition, set in the current instruments' obs package.
876  Required for any calculation of DCR, including making matched templates.
877 
878  Yields
879  ------
880  residualImage : `numpy.ndarray`
881  The residual image for the next subfilter, shifted for DCR.
882  """
883  # Pre-calculate the spline-filtered residual image, so that step can be
884  # skipped in the shift calculation in `applyDcr`.
885  filteredResidual = ndimage.spline_filter(residual, order=self.config.imageInterpOrder)
886  # Note that `splitSubfilters` is always turned off in the reverse direction.
887  # This option introduces additional blurring if applied to the residuals.
888  dcrShift = calculateDcr(visitInfo, wcs, filterInfo, self.config.dcrNumSubfilters,
889  splitSubfilters=False)
890  for dcr in dcrShift:
891  yield applyDcr(filteredResidual, dcr, useInverse=True, splitSubfilters=False,
892  doPrefilter=False, order=self.config.imageInterpOrder)
893 

◆ fillCoadd()

def lsst.pipe.tasks.dcrAssembleCoadd.fillCoadd (   self,
  dcrModels,
  skyInfo,
  warpRefList,
  weightList,
  calibration = None,
  coaddInputs = None,
  mask = None,
  variance = None 
)
Create a list of coadd exposures from a list of masked images.

Parameters
----------
dcrModels : `lsst.pipe.tasks.DcrModel`
    Best fit model of the true sky after correcting chromatic effects.
skyInfo : `lsst.pipe.base.Struct`
    Patch geometry information, from getSkyInfo
warpRefList : `list` of `lsst.daf.butler.DeferredDatasetHandle` or
    `lsst.daf.persistence.ButlerDataRef`
    The data references to the input warped exposures.
weightList : `list` of `float`
    The weight to give each input exposure in the coadd
calibration : `lsst.afw.Image.PhotoCalib`, optional
    Scale factor to set the photometric calibration of an exposure.
coaddInputs : `lsst.afw.Image.CoaddInputs`, optional
    A record of the observations that are included in the coadd.
mask : `lsst.afw.image.Mask`, optional
    Optional mask to override the values in the final coadd.
variance : `lsst.afw.image.Image`, optional
    Optional variance plane to override the values in the final coadd.

Returns
-------
dcrCoadds : `list` of `lsst.afw.image.ExposureF`
    A list of coadd exposures, each exposure containing
    the model for one subfilter.

Definition at line 1052 of file dcrAssembleCoadd.py.

1052  def fillCoadd(self, dcrModels, skyInfo, warpRefList, weightList, calibration=None, coaddInputs=None,
1053  mask=None, variance=None):
1054  """Create a list of coadd exposures from a list of masked images.
1055 
1056  Parameters
1057  ----------
1058  dcrModels : `lsst.pipe.tasks.DcrModel`
1059  Best fit model of the true sky after correcting chromatic effects.
1060  skyInfo : `lsst.pipe.base.Struct`
1061  Patch geometry information, from getSkyInfo
1062  warpRefList : `list` of `lsst.daf.butler.DeferredDatasetHandle` or
1063  `lsst.daf.persistence.ButlerDataRef`
1064  The data references to the input warped exposures.
1065  weightList : `list` of `float`
1066  The weight to give each input exposure in the coadd
1067  calibration : `lsst.afw.Image.PhotoCalib`, optional
1068  Scale factor to set the photometric calibration of an exposure.
1069  coaddInputs : `lsst.afw.Image.CoaddInputs`, optional
1070  A record of the observations that are included in the coadd.
1071  mask : `lsst.afw.image.Mask`, optional
1072  Optional mask to override the values in the final coadd.
1073  variance : `lsst.afw.image.Image`, optional
1074  Optional variance plane to override the values in the final coadd.
1075 
1076  Returns
1077  -------
1078  dcrCoadds : `list` of `lsst.afw.image.ExposureF`
1079  A list of coadd exposures, each exposure containing
1080  the model for one subfilter.
1081  """
1082  dcrCoadds = []
1083  refModel = dcrModels.getReferenceImage()
1084  for model in dcrModels:
1085  if self.config.accelerateModel > 1:
1086  model.array = (model.array - refModel)*self.config.accelerateModel + refModel
1087  coaddExposure = afwImage.ExposureF(skyInfo.bbox, skyInfo.wcs)
1088  if calibration is not None:
1089  coaddExposure.setPhotoCalib(calibration)
1090  if coaddInputs is not None:
1091  coaddExposure.getInfo().setCoaddInputs(coaddInputs)
1092  # Set the metadata for the coadd, including PSF and aperture corrections.
1093  self.assembleMetadata(coaddExposure, warpRefList, weightList)
1094  # Overwrite the PSF
1095  coaddExposure.setPsf(dcrModels.psf)
1096  coaddUtils.setCoaddEdgeBits(dcrModels.mask[skyInfo.bbox], dcrModels.variance[skyInfo.bbox])
1097  maskedImage = afwImage.MaskedImageF(dcrModels.bbox)
1098  maskedImage.image = model
1099  maskedImage.mask = dcrModels.mask
1100  maskedImage.variance = dcrModels.variance
1101  coaddExposure.setMaskedImage(maskedImage[skyInfo.bbox])
1102  coaddExposure.setPhotoCalib(self.scaleZeroPoint.getPhotoCalib())
1103  if mask is not None:
1104  coaddExposure.setMask(mask)
1105  if variance is not None:
1106  coaddExposure.setVariance(variance)
1107  dcrCoadds.append(coaddExposure)
1108  return dcrCoadds
1109 

◆ loadSubExposures()

def lsst.pipe.tasks.dcrAssembleCoadd.loadSubExposures (   self,
  bbox,
  statsCtrl,
  warpRefList,
  imageScalerList,
  spanSetMaskList 
)
Pre-load sub-regions of a list of exposures.

Parameters
----------
bbox : `lsst.geom.box.Box2I`
    Sub-region to coadd
statsCtrl : `lsst.afw.math.StatisticsControl`
    Statistics control object for coadd
warpRefList : `list` of `lsst.daf.butler.DeferredDatasetHandle` or
    `lsst.daf.persistence.ButlerDataRef`
    The data references to the input warped exposures.
imageScalerList : `list` of `lsst.pipe.task.ImageScaler`
    The image scalars correct for the zero point of the exposures.
spanSetMaskList : `list` of `dict` containing spanSet lists, or None
    Each element is dict with keys = mask plane name to add the spans to

Returns
-------
subExposures : `dict`
    The `dict` keys are the visit IDs,
    and the values are `lsst.afw.image.ExposureF`
    The pre-loaded exposures for the current subregion.
    The variance plane contains weights, and not the variance

Definition at line 1244 of file dcrAssembleCoadd.py.

1244  def loadSubExposures(self, bbox, statsCtrl, warpRefList, imageScalerList, spanSetMaskList):
1245  """Pre-load sub-regions of a list of exposures.
1246 
1247  Parameters
1248  ----------
1249  bbox : `lsst.geom.box.Box2I`
1250  Sub-region to coadd
1251  statsCtrl : `lsst.afw.math.StatisticsControl`
1252  Statistics control object for coadd
1253  warpRefList : `list` of `lsst.daf.butler.DeferredDatasetHandle` or
1254  `lsst.daf.persistence.ButlerDataRef`
1255  The data references to the input warped exposures.
1256  imageScalerList : `list` of `lsst.pipe.task.ImageScaler`
1257  The image scalars correct for the zero point of the exposures.
1258  spanSetMaskList : `list` of `dict` containing spanSet lists, or None
1259  Each element is dict with keys = mask plane name to add the spans to
1260 
1261  Returns
1262  -------
1263  subExposures : `dict`
1264  The `dict` keys are the visit IDs,
1265  and the values are `lsst.afw.image.ExposureF`
1266  The pre-loaded exposures for the current subregion.
1267  The variance plane contains weights, and not the variance
1268  """
1269  tempExpName = self.getTempExpDatasetName(self.warpType)
1270  zipIterables = zip(warpRefList, imageScalerList, spanSetMaskList)
1271  subExposures = {}
1272  for warpExpRef, imageScaler, altMaskSpans in zipIterables:
1273  if isinstance(warpExpRef, DeferredDatasetHandle):
1274  exposure = warpExpRef.get(parameters={'bbox': bbox})
1275  else:
1276  exposure = warpExpRef.get(tempExpName + "_sub", bbox=bbox)
1277  visit = warpExpRef.dataId["visit"]
1278  if altMaskSpans is not None:
1279  self.applyAltMaskPlanes(exposure.mask, altMaskSpans)
1280  imageScaler.scaleMaskedImage(exposure.maskedImage)
1281  # Note that the variance plane here is used to store weights, not the actual variance
1282  exposure.variance.array[:, :] = 0.
1283  # Set the weight of unmasked pixels to 1.
1284  exposure.variance.array[(exposure.mask.array & statsCtrl.getAndMask()) == 0] = 1.
1285  # Set the image value of masked pixels to zero.
1286  # This eliminates needing the mask plane when stacking images in ``newModelFromResidual``
1287  exposure.image.array[(exposure.mask.array & statsCtrl.getAndMask()) > 0] = 0.
1288  subExposures[visit] = exposure
1289  return subExposures
1290 

◆ newModelFromResidual()

def lsst.pipe.tasks.dcrAssembleCoadd.newModelFromResidual (   self,
  dcrModels,
  residualGeneratorList,
  dcrBBox,
  statsCtrl,
  gain,
  modelWeights,
  refImage,
  dcrWeights 
)
Calculate a new DcrModel from a set of image residuals.

Parameters
----------
dcrModels : `lsst.pipe.tasks.DcrModel`
    Current model of the true sky after correcting chromatic effects.
residualGeneratorList : `generator` of `numpy.ndarray`
    The residual image for the next subfilter, shifted for DCR.
dcrBBox : `lsst.geom.box.Box2I`
    Sub-region of the coadd which includes a buffer to allow for DCR.
statsCtrl : `lsst.afw.math.StatisticsControl`
    Statistics control object for coadd
gain : `float`
    Relative weight to give the new solution when updating the model.
modelWeights : `numpy.ndarray` or `float`
    A 2D array of weight values that tapers smoothly to zero away from detected sources.
    Set to a placeholder value of 1.0 if ``self.config.useModelWeights`` is False.
refImage : `lsst.afw.image.Image`
    A reference image used to supply the default pixel values.
dcrWeights : `list` of `lsst.afw.image.Image`
    Per-pixel weights for each subfilter.
    Equal to 1/(number of unmasked images contributing to each pixel).

Returns
-------
dcrModel : `lsst.pipe.tasks.DcrModel`
    New model of the true sky after correcting chromatic effects.

Definition at line 894 of file dcrAssembleCoadd.py.

894  def newModelFromResidual(self, dcrModels, residualGeneratorList, dcrBBox, statsCtrl,
895  gain, modelWeights, refImage, dcrWeights):
896  """Calculate a new DcrModel from a set of image residuals.
897 
898  Parameters
899  ----------
900  dcrModels : `lsst.pipe.tasks.DcrModel`
901  Current model of the true sky after correcting chromatic effects.
902  residualGeneratorList : `generator` of `numpy.ndarray`
903  The residual image for the next subfilter, shifted for DCR.
904  dcrBBox : `lsst.geom.box.Box2I`
905  Sub-region of the coadd which includes a buffer to allow for DCR.
906  statsCtrl : `lsst.afw.math.StatisticsControl`
907  Statistics control object for coadd
908  gain : `float`
909  Relative weight to give the new solution when updating the model.
910  modelWeights : `numpy.ndarray` or `float`
911  A 2D array of weight values that tapers smoothly to zero away from detected sources.
912  Set to a placeholder value of 1.0 if ``self.config.useModelWeights`` is False.
913  refImage : `lsst.afw.image.Image`
914  A reference image used to supply the default pixel values.
915  dcrWeights : `list` of `lsst.afw.image.Image`
916  Per-pixel weights for each subfilter.
917  Equal to 1/(number of unmasked images contributing to each pixel).
918 
919  Returns
920  -------
921  dcrModel : `lsst.pipe.tasks.DcrModel`
922  New model of the true sky after correcting chromatic effects.
923  """
924  newModelImages = []
925  for subfilter, model in enumerate(dcrModels):
926  residualsList = [next(residualGenerator) for residualGenerator in residualGeneratorList]
927  residual = np.sum(residualsList, axis=0)
928  residual *= dcrWeights[subfilter][dcrBBox].array
929  # `MaskedImage`s only support in-place addition, so rename for readability
930  newModel = model[dcrBBox].clone()
931  newModel.array += residual
932  # Catch any invalid values
933  badPixels = ~np.isfinite(newModel.array)
934  newModel.array[badPixels] = model[dcrBBox].array[badPixels]
935  if self.config.regularizeModelIterations > 0:
936  dcrModels.regularizeModelIter(subfilter, newModel, dcrBBox,
937  self.config.regularizeModelIterations,
938  self.config.regularizationWidth)
939  newModelImages.append(newModel)
940  if self.config.regularizeModelFrequency > 0:
941  dcrModels.regularizeModelFreq(newModelImages, dcrBBox, statsCtrl,
942  self.config.regularizeModelFrequency,
943  self.config.regularizationWidth)
944  dcrModels.conditionDcrModel(newModelImages, dcrBBox, gain=gain)
945  self.applyModelWeights(newModelImages, refImage[dcrBBox], modelWeights)
946  return DcrModel(newModelImages, dcrModels.filter, dcrModels.psf,
947  dcrModels.mask, dcrModels.variance)
948 

◆ selectCoaddPsf()

def lsst.pipe.tasks.dcrAssembleCoadd.selectCoaddPsf (   self,
  templateCoadd,
  warpRefList 
)
Compute the PSF of the coadd from the exposures with the best seeing.

Parameters
----------
templateCoadd : `lsst.afw.image.ExposureF`
    The initial coadd exposure before accounting for DCR.
warpRefList : `list` of `lsst.daf.butler.DeferredDatasetHandle` or
    `lsst.daf.persistence.ButlerDataRef`
    The data references to the input warped exposures.

Returns
-------
psf : `lsst.meas.algorithms.CoaddPsf`
    The average PSF of the input exposures with the best seeing.

Definition at line 1291 of file dcrAssembleCoadd.py.

1291  def selectCoaddPsf(self, templateCoadd, warpRefList):
1292  """Compute the PSF of the coadd from the exposures with the best seeing.
1293 
1294  Parameters
1295  ----------
1296  templateCoadd : `lsst.afw.image.ExposureF`
1297  The initial coadd exposure before accounting for DCR.
1298  warpRefList : `list` of `lsst.daf.butler.DeferredDatasetHandle` or
1299  `lsst.daf.persistence.ButlerDataRef`
1300  The data references to the input warped exposures.
1301 
1302  Returns
1303  -------
1304  psf : `lsst.meas.algorithms.CoaddPsf`
1305  The average PSF of the input exposures with the best seeing.
1306  """
1307  sigma2fwhm = 2.*np.sqrt(2.*np.log(2.))
1308  tempExpName = self.getTempExpDatasetName(self.warpType)
1309  # Note: ``ccds`` is a `lsst.afw.table.ExposureCatalog` with one entry per ccd and per visit
1310  # If there are multiple ccds, it will have that many times more elements than ``warpExpRef``
1311  ccds = templateCoadd.getInfo().getCoaddInputs().ccds
1312  psfRefSize = templateCoadd.getPsf().computeShape().getDeterminantRadius()*sigma2fwhm
1313  psfSizes = np.zeros(len(ccds))
1314  ccdVisits = np.array(ccds["visit"])
1315  for warpExpRef in warpRefList:
1316  if isinstance(warpExpRef, DeferredDatasetHandle):
1317  # Gen 3 API
1318  psf = warpExpRef.get(component="psf")
1319  else:
1320  # Gen 2 API. Delete this when Gen 2 retired
1321  psf = warpExpRef.get(tempExpName).getPsf()
1322  visit = warpExpRef.dataId["visit"]
1323  psfSize = psf.computeShape().getDeterminantRadius()*sigma2fwhm
1324  psfSizes[ccdVisits == visit] = psfSize
1325  # Note that the input PSFs include DCR, which should be absent from the DcrCoadd
1326  # The selected PSFs are those that have a FWHM less than or equal to the smaller
1327  # of the mean or median FWHM of the input exposures.
1328  sizeThreshold = min(np.median(psfSizes), psfRefSize)
1329  goodPsfs = psfSizes <= sizeThreshold
1330  psf = measAlg.CoaddPsf(ccds[goodPsfs], templateCoadd.getWcs(),
1331  self.config.coaddPsf.makeControl())
1332  return psf

◆ stackCoadd()

def lsst.pipe.tasks.dcrAssembleCoadd.stackCoadd (   self,
  dcrCoadds 
)
Add a list of sub-band coadds together.

Parameters
----------
dcrCoadds : `list` of `lsst.afw.image.ExposureF`
    A list of coadd exposures, each exposure containing
    the model for one subfilter.

Returns
-------
coaddExposure : `lsst.afw.image.ExposureF`
    A single coadd exposure that is the sum of the sub-bands.

Definition at line 1033 of file dcrAssembleCoadd.py.

1033  def stackCoadd(self, dcrCoadds):
1034  """Add a list of sub-band coadds together.
1035 
1036  Parameters
1037  ----------
1038  dcrCoadds : `list` of `lsst.afw.image.ExposureF`
1039  A list of coadd exposures, each exposure containing
1040  the model for one subfilter.
1041 
1042  Returns
1043  -------
1044  coaddExposure : `lsst.afw.image.ExposureF`
1045  A single coadd exposure that is the sum of the sub-bands.
1046  """
1047  coaddExposure = dcrCoadds[0].clone()
1048  for coadd in dcrCoadds[1:]:
1049  coaddExposure.maskedImage += coadd.maskedImage
1050  return coaddExposure
1051 

Variable Documentation

◆ goodPix

lsst.pipe.tasks.dcrAssembleCoadd.goodPix

Definition at line 781 of file dcrAssembleCoadd.py.

◆ weightsThreshold

lsst.pipe.tasks.dcrAssembleCoadd.weightsThreshold

Definition at line 780 of file dcrAssembleCoadd.py.

lsst.pipe.tasks.dcrAssembleCoadd.selectCoaddPsf
def selectCoaddPsf(self, templateCoadd, warpRefList)
Definition: dcrAssembleCoadd.py:1291
astshim.fitsChanContinued.next
def next(self)
Definition: fitsChanContinued.py:105
lsst::log.log.logContinued.info
def info(fmt, *args)
Definition: logContinued.py:198
lsst.pipe.tasks.dcrAssembleCoadd.dcrResiduals
def dcrResiduals(self, residual, visitInfo, wcs, filterInfo)
Definition: dcrAssembleCoadd.py:862
lsst.pipe.tasks.dcrAssembleCoadd.fillCoadd
def fillCoadd(self, dcrModels, skyInfo, warpRefList, weightList, calibration=None, coaddInputs=None, mask=None, variance=None)
Definition: dcrAssembleCoadd.py:1052
lsst.pipe.tasks.dcrAssembleCoadd.dcrAssembleSubregion
def dcrAssembleSubregion(self, dcrModels, subExposures, bbox, dcrBBox, warpRefList, statsCtrl, convergenceMetric, gain, modelWeights, refImage, dcrWeights)
Definition: dcrAssembleCoadd.py:790
lsst.pipe.tasks.dcrAssembleCoadd.calculateGain
def calculateGain(self, convergenceList, gainList)
Definition: dcrAssembleCoadd.py:1110
lsst::sphgeom::abs
Angle abs(Angle const &a)
Definition: Angle.h:106
lsst::ip::diffim.dcrModel.applyDcr
def applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0., doPrefilter=True, order=3)
Definition: dcrModel.py:637
lsst.pipe.tasks.dcrAssembleCoadd.calculateSingleConvergence
def calculateSingleConvergence(self, dcrModels, exposure, significanceImage, statsCtrl)
Definition: dcrAssembleCoadd.py:992
lsst.pipe.tasks.dcrAssembleCoadd.calculateModelWeights
def calculateModelWeights(self, dcrModels, dcrBBox)
Definition: dcrAssembleCoadd.py:1191
lsst.pipe.tasks.dcrAssembleCoadd.calculateConvergence
def calculateConvergence(self, dcrModels, subExposures, bbox, warpRefList, weightList, statsCtrl)
Definition: dcrAssembleCoadd.py:949
lsst.pipe.tasks.dcrAssembleCoadd.applyModelWeights
def applyModelWeights(self, modelImages, refImage, modelWeights)
Definition: dcrAssembleCoadd.py:1224
lsst.pipe.tasks.dcrAssembleCoadd.newModelFromResidual
def newModelFromResidual(self, dcrModels, residualGeneratorList, dcrBBox, statsCtrl, gain, modelWeights, refImage, dcrWeights)
Definition: dcrAssembleCoadd.py:894
max
int max
Definition: BoundedField.cc:104
lsst::ip::diffim.dcrModel.calculateDcr
def calculateDcr(visitInfo, wcs, filterInfo, dcrNumSubfilters, splitSubfilters=False)
Definition: dcrModel.py:702
min
int min
Definition: BoundedField.cc:103
lsst::coadd::utils::setCoaddEdgeBits
void setCoaddEdgeBits(lsst::afw::image::Mask< lsst::afw::image::MaskPixel > &coaddMask, lsst::afw::image::Image< WeightPixelT > const &weightMap)
set edge bits of coadd mask based on weight map
Definition: setCoaddEdgeBits.cc:42
lsst.pipe.tasks.dcrAssembleCoadd.stackCoadd
def stackCoadd(self, dcrCoadds)
Definition: dcrAssembleCoadd.py:1033
lsst::afw::image.slicing.clone
clone
Definition: slicing.py:257
lsst.pipe.tasks.dcrAssembleCoadd.loadSubExposures
def loadSubExposures(self, bbox, statsCtrl, warpRefList, imageScalerList, spanSetMaskList)
Definition: dcrAssembleCoadd.py:1244