LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
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, effectiveWavelength, bandwidth)
 
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

int weightsThreshold = 1.
 
int goodPix = dcrWeights[0].array > weightsThreshold
 

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 1234 of file dcrAssembleCoadd.py.

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

◆ 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 959 of file dcrAssembleCoadd.py.

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

◆ 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 1120 of file dcrAssembleCoadd.py.

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

◆ 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 1201 of file dcrAssembleCoadd.py.

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

◆ 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 1002 of file dcrAssembleCoadd.py.

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

◆ 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 800 of file dcrAssembleCoadd.py.

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

◆ dcrResiduals()

def lsst.pipe.tasks.dcrAssembleCoadd.dcrResiduals (   self,
  residual,
  visitInfo,
  wcs,
  effectiveWavelength,
  bandwidth 
)
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.

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

Definition at line 874 of file dcrAssembleCoadd.py.

874  def dcrResiduals(self, residual, visitInfo, wcs, effectiveWavelength, bandwidth):
875  """Prepare a residual image for stacking in each subfilter by applying the reverse DCR shifts.
876 
877  Parameters
878  ----------
879  residual : `numpy.ndarray`
880  The residual masked image for one exposure,
881  after subtracting the matched template
882  visitInfo : `lsst.afw.image.VisitInfo`
883  Metadata for the exposure.
884  wcs : `lsst.afw.geom.SkyWcs`
885  Coordinate system definition (wcs) for the exposure.
886 
887  Yields
888  ------
889  residualImage : `numpy.ndarray`
890  The residual image for the next subfilter, shifted for DCR.
891  """
892  # Pre-calculate the spline-filtered residual image, so that step can be
893  # skipped in the shift calculation in `applyDcr`.
894  filteredResidual = ndimage.spline_filter(residual, order=self.config.imageInterpOrder)
895  # Note that `splitSubfilters` is always turned off in the reverse direction.
896  # This option introduces additional blurring if applied to the residuals.
897  dcrShift = calculateDcr(visitInfo, wcs, effectiveWavelength, bandwidth, self.config.dcrNumSubfilters,
898  splitSubfilters=False)
899  for dcr in dcrShift:
900  yield applyDcr(filteredResidual, dcr, useInverse=True, splitSubfilters=False,
901  doPrefilter=False, order=self.config.imageInterpOrder)
902 
def applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0., doPrefilter=True, order=3)
Definition: dcrModel.py:694
def calculateDcr(visitInfo, wcs, effectiveWavelength, bandwidth, dcrNumSubfilters, splitSubfilters=False)
Definition: dcrModel.py:759
def dcrResiduals(self, residual, visitInfo, wcs, effectiveWavelength, bandwidth)

◆ 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 1062 of file dcrAssembleCoadd.py.

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

◆ 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 1254 of file dcrAssembleCoadd.py.

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

◆ 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 903 of file dcrAssembleCoadd.py.

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

◆ 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 1301 of file dcrAssembleCoadd.py.

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

◆ 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 1043 of file dcrAssembleCoadd.py.

1043  def stackCoadd(self, dcrCoadds):
1044  """Add a list of sub-band coadds together.
1045 
1046  Parameters
1047  ----------
1048  dcrCoadds : `list` of `lsst.afw.image.ExposureF`
1049  A list of coadd exposures, each exposure containing
1050  the model for one subfilter.
1051 
1052  Returns
1053  -------
1054  coaddExposure : `lsst.afw.image.ExposureF`
1055  A single coadd exposure that is the sum of the sub-bands.
1056  """
1057  coaddExposure = dcrCoadds[0].clone()
1058  for coadd in dcrCoadds[1:]:
1059  coaddExposure.maskedImage += coadd.maskedImage
1060  return coaddExposure
1061 

Variable Documentation

◆ goodPix

tuple lsst.pipe.tasks.dcrAssembleCoadd.goodPix = dcrWeights[0].array > weightsThreshold

Definition at line 791 of file dcrAssembleCoadd.py.

◆ weightsThreshold

int lsst.pipe.tasks.dcrAssembleCoadd.weightsThreshold = 1.

Definition at line 790 of file dcrAssembleCoadd.py.