Skip to content

Commit 6a6037f

Browse files
committed
Refactor and update TODO comments, AEW
1 parent c652ce0 commit 6a6037f

File tree

2 files changed

+139
-291
lines changed

2 files changed

+139
-291
lines changed

python/lsst/pipe/tasks/background.py

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
"SkyMeasurementConfig",
2929
"SkyMeasurementTask",
3030
"SkyStatsConfig",
31+
"TractBackground",
32+
"TractBackgroundConfig",
3133
]
3234

3335
import importlib
@@ -368,16 +370,10 @@ def solveScales(self, scales):
368370
skySamples = numpy.array(skySamples)
369371

370372
def solve(mask):
371-
<<<<<<< HEAD
372373
# Make sure we return a float, not an array.
373374
return afwMath.LeastSquares.fromDesignMatrix(skySamples[mask].reshape(mask.sum(), 1),
374375
imageSamples[mask],
375376
afwMath.LeastSquares.DIRECT_SVD).getSolution()[0]
376-
=======
377-
return afwMath.LeastSquares.fromDesignMatrix(
378-
skySamples[mask].reshape(mask.sum(), 1), imageSamples[mask], afwMath.LeastSquares.DIRECT_SVD
379-
).getSolution()
380-
>>>>>>> 8cf1e691 (Add full tract background functionality.)
381377

382378
mask = numpy.isfinite(imageSamples) & numpy.isfinite(skySamples)
383379
for ii in range(self.config.skyIter):
@@ -860,14 +856,13 @@ class TractBackgroundConfig(Config):
860856
)
861857
doSmooth = Field(dtype=bool, default=False, doc="Do smoothing?")
862858
smoothScale = Field(dtype=float, default=2.0, doc="Smoothing scale, as a multiple of the bin size")
863-
binning = Field(dtype=int, default=200, doc="Binning to use for warp background model (pixels)")
859+
binning = Field(dtype=int, default=64, doc="Binning to use for warp background model (pixels)")
864860

865861

866862
class TractBackground:
867863
"""
868864
As FocalPlaneBackground, but works in warped tract coordinates
869865
"""
870-
871866
@classmethod
872867
def fromSimilar(cls, other):
873868
"""Construct from an object that has the same interface.
@@ -883,9 +878,9 @@ def fromSimilar(cls, other):
883878
background : `TractBackground`
884879
Something guaranteed to be a `TractBackground`.
885880
"""
886-
return cls(other.config, other.dims, other.transform, other._values, other._numbers)
881+
return cls(other.config, other.tract, other.dims, other.transform, other._values, other._numbers)
887882

888-
def __init__(self, config, values=None, numbers=None):
883+
def __init__(self, config, skymap, tract, values=None, numbers=None):
889884
"""Constructor
890885
891886
Developers should note that changes to the signature of this method
@@ -895,14 +890,24 @@ def __init__(self, config, values=None, numbers=None):
895890
----------
896891
config : `TractBackgroundConfig`
897892
Configuration for measuring tract backgrounds.
893+
skymap : `lsst.skymap.ringsSkyMap.RingsSkyMap`
894+
Skymap object
895+
tract : `int`
896+
Placeholder Tract ID
897+
transform : `lsst.afw.geom.TransformPoint2ToPoint2`
898+
Transformation from tract coordinates to warp coordinates.
898899
values : `lsst.afw.image.ImageF`
899900
Measured background values.
900901
numbers : `lsst.afw.image.ImageF`
901902
Number of pixels in each background measurement.
902903
"""
903904
self.config = config
904-
# TODO: dynamic tract dimensions?
905-
self.dims = geom.Extent2I(36000 / self.config.xBin, 36000 / self.config.yBin)
905+
self.skymap = skymap
906+
self.tract = tract
907+
self.tractInfo = self.skymap.generateTract(tract)
908+
tractDimX, tractDimY = self.tractInfo.getBBox().getDimensions()
909+
self.dims = geom.Extent2I(tractDimX / self.config.xBin,
910+
tractDimY / self.config.yBin)
906911

907912
if values is None:
908913
values = afwImage.ImageF(self.dims)
@@ -920,10 +925,10 @@ def __init__(self, config, values=None, numbers=None):
920925
self._numbers = numbers
921926

922927
def __reduce__(self):
923-
return self.__class__, (self.config, self._values, self._numbers)
928+
return self.__class__, (self.config, self.skymap, self.tract, self._values, self._numbers)
924929

925930
def clone(self):
926-
return self.__class__(self.config, self._values, self._numbers)
931+
return self.__class__(self.config, self.skymap, self.tract, self._values, self._numbers)
927932

928933
def addWarp(self, warp):
929934
"""
@@ -1039,10 +1044,21 @@ def toWarpBackground(self, warp):
10391044

10401045
# Transform from binned tract plane to tract plane
10411046
# Start at the patch corner, not the warp corner overlap region
1047+
wcs = self.tractInfo.getWcs()
1048+
coo = wcs.pixelToSky(1, 1)
1049+
ptch = self.tractInfo.findPatch(coo)
1050+
ptchDimX, ptchDimY = ptch.getInnerBBox().getDimensions()
1051+
if ptchDimX != ptchDimY:
1052+
raise ValueError(
1053+
"Patch dimensions %d,%d are unequal: cannot proceed as written."
1054+
% (ptchDimX, ptchDimY)
1055+
)
1056+
ptchOutDimX, _ = ptch.getOuterBBox().getDimensions()
1057+
overlap = ptchDimX - ptchOutDimX
10421058
corner = warp.getBBox().getMin()
1043-
if corner[0] % 4000 != 0: # TODO: hard-coded patch dimensions are bad
1044-
corner[0] += 100
1045-
corner[1] += 100
1059+
if corner[0] % ptchDimX != 0:
1060+
corner[0] += overlap
1061+
corner[1] += overlap
10461062
offset = geom.Extent2D(corner[0], corner[1])
10471063
tractTransform = (
10481064
geom.AffineTransform.makeTranslation(geom.Extent2D(-0.5, -0.5))
@@ -1064,13 +1080,15 @@ def toWarpBackground(self, warp):
10641080
image = afwImage.ImageF(bbox.getDimensions() // self.config.binning)
10651081
norm = afwImage.ImageF(image.getBBox())
10661082

1083+
# Warps full tract model to warp image scale
10671084
ctrl = afwMath.WarpingControl("bilinear")
10681085
afwMath.warpImage(image, tractPlane, toSample.inverted(), ctrl)
10691086
afwMath.warpImage(norm, tpNorm, toSample.inverted(), ctrl)
10701087
image /= norm
10711088
# Convert back to counts so the model can be subtracted w/o conversion
10721089
image /= warp.getPhotoCalib().instFluxToNanojansky(1)
10731090

1091+
# Only sky background model, so include only null values in mask plane
10741092
mask = afwImage.Mask(image.getBBox())
10751093
isBad = numpy.isnan(image.getArray())
10761094
mask.getArray()[isBad] = mask.getPlaneBitMask("BAD")
@@ -1095,18 +1113,12 @@ def getStatsImage(self):
10951113
"""
10961114
values = self._values.clone()
10971115
values /= self._numbers
1098-
# TODO: this logic smoothes over bad parts of the image, including NaN
1099-
# values. But it doesn't work here because NaN pixels are always found
1100-
# at the image edges. Could ignore it, or devise an alternative.
1101-
# tract have no overlap with the visit?
1102-
# thresh = self.config.minFrac * (self.config.xBin) * (self.config.yBin)
1103-
# isBad = self._numbers.getArray() < thresh
1104-
# if self.config.doSmooth:
1105-
# array = values.getArray()
1106-
# array[:] = smoothArray(array, isBad, self.config.smoothScale)
1107-
# isBad = numpy.isnan(values.array)
1108-
# if numpy.any(isBad):
1109-
# interpolateBadPixels(values.getArray(), isBad, self.config.interpolation)
1116+
# TODO: filling in bad pixels. Currently BAD mask plane includes both
1117+
# chip gaps and regions outside FP, so interpolating across chip gaps
1118+
# also includes extrapolating flux outside the FP, which is
1119+
# undesirable. But interpolation and extrapolation aren't currently
1120+
# separable, so for now this step is just not done.
1121+
11101122
return values
11111123

11121124

0 commit comments

Comments
 (0)