LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
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 1239 of file dcrAssembleCoadd.py.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Variable Documentation

◆ goodPix

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

Definition at line 796 of file dcrAssembleCoadd.py.

◆ weightsThreshold

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

Definition at line 795 of file dcrAssembleCoadd.py.