LSSTApplications  19.0.0-14-gb0260a2+72efe9b372,20.0.0+7927753e06,20.0.0+8829bf0056,20.0.0+995114c5d2,20.0.0+b6f4b2abd1,20.0.0+bddc4f4cbe,20.0.0-1-g253301a+8829bf0056,20.0.0-1-g2b7511a+0d71a2d77f,20.0.0-1-g5b95a8c+7461dd0434,20.0.0-12-g321c96ea+23efe4bbff,20.0.0-16-gfab17e72e+fdf35455f6,20.0.0-2-g0070d88+ba3ffc8f0b,20.0.0-2-g4dae9ad+ee58a624b3,20.0.0-2-g61b8584+5d3db074ba,20.0.0-2-gb780d76+d529cf1a41,20.0.0-2-ged6426c+226a441f5f,20.0.0-2-gf072044+8829bf0056,20.0.0-2-gf1f7952+ee58a624b3,20.0.0-20-geae50cf+e37fec0aee,20.0.0-25-g3dcad98+544a109665,20.0.0-25-g5eafb0f+ee58a624b3,20.0.0-27-g64178ef+f1f297b00a,20.0.0-3-g4cc78c6+e0676b0dc8,20.0.0-3-g8f21e14+4fd2c12c9a,20.0.0-3-gbd60e8c+187b78b4b8,20.0.0-3-gbecbe05+48431fa087,20.0.0-38-ge4adf513+a12e1f8e37,20.0.0-4-g97dc21a+544a109665,20.0.0-4-gb4befbc+087873070b,20.0.0-4-gf910f65+5d3db074ba,20.0.0-5-gdfe0fee+199202a608,20.0.0-5-gfbfe500+d529cf1a41,20.0.0-6-g64f541c+d529cf1a41,20.0.0-6-g9a5b7a1+a1cd37312e,20.0.0-68-ga3f3dda+5fca18c6a4,20.0.0-9-g4aef684+e18322736b,w.2020.45
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, 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

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

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

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

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

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

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

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

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

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

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

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

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

◆ 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.
filterInfo : `lsst.afw.image.Filter`
    The filter definition, set in the current instruments' obs package.
    Note: this object will be changed in DM-21333.

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

Definition at line 878 of file dcrAssembleCoadd.py.

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

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

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

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

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

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

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

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

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

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

Variable Documentation

◆ goodPix

lsst.pipe.tasks.dcrAssembleCoadd.goodPix

Definition at line 795 of file dcrAssembleCoadd.py.

◆ weightsThreshold

lsst.pipe.tasks.dcrAssembleCoadd.weightsThreshold

Definition at line 794 of file dcrAssembleCoadd.py.

lsst.pipe.tasks.dcrAssembleCoadd.selectCoaddPsf
def selectCoaddPsf(self, templateCoadd, warpRefList)
Definition: dcrAssembleCoadd.py:1308
astshim.fitsChanContinued.next
def next(self)
Definition: fitsChanContinued.py:105
lsst::log.log.logContinued.info
def info(fmt, *args)
Definition: logContinued.py:201
lsst.pipe.tasks.dcrAssembleCoadd.fillCoadd
def fillCoadd(self, dcrModels, skyInfo, warpRefList, weightList, calibration=None, coaddInputs=None, mask=None, variance=None)
Definition: dcrAssembleCoadd.py:1069
lsst.pipe.tasks.dcrAssembleCoadd.dcrAssembleSubregion
def dcrAssembleSubregion(self, dcrModels, subExposures, bbox, dcrBBox, warpRefList, statsCtrl, convergenceMetric, gain, modelWeights, refImage, dcrWeights)
Definition: dcrAssembleCoadd.py:804
lsst.pipe.tasks.dcrAssembleCoadd.calculateGain
def calculateGain(self, convergenceList, gainList)
Definition: dcrAssembleCoadd.py:1127
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:696
lsst.pipe.tasks.dcrAssembleCoadd.calculateSingleConvergence
def calculateSingleConvergence(self, dcrModels, exposure, significanceImage, statsCtrl)
Definition: dcrAssembleCoadd.py:1009
lsst.pipe.tasks.dcrAssembleCoadd.calculateModelWeights
def calculateModelWeights(self, dcrModels, dcrBBox)
Definition: dcrAssembleCoadd.py:1208
lsst.pipe.tasks.dcrAssembleCoadd.calculateConvergence
def calculateConvergence(self, dcrModels, subExposures, bbox, warpRefList, weightList, statsCtrl)
Definition: dcrAssembleCoadd.py:966
lsst.pipe.tasks.dcrAssembleCoadd.dcrResiduals
def dcrResiduals(self, residual, visitInfo, wcs, effectiveWavelength, bandwidth)
Definition: dcrAssembleCoadd.py:878
lsst.pipe.tasks.dcrAssembleCoadd.applyModelWeights
def applyModelWeights(self, modelImages, refImage, modelWeights)
Definition: dcrAssembleCoadd.py:1241
lsst.pipe.tasks.dcrAssembleCoadd.newModelFromResidual
def newModelFromResidual(self, dcrModels, residualGeneratorList, dcrBBox, statsCtrl, gain, modelWeights, refImage, dcrWeights)
Definition: dcrAssembleCoadd.py:910
max
int max
Definition: BoundedField.cc:104
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::ip::diffim.dcrModel.calculateDcr
def calculateDcr(visitInfo, wcs, effectiveWavelength, bandwidth, dcrNumSubfilters, splitSubfilters=False)
Definition: dcrModel.py:762
lsst.pipe.tasks.dcrAssembleCoadd.stackCoadd
def stackCoadd(self, dcrCoadds)
Definition: dcrAssembleCoadd.py:1050
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:1261