2828 "SkyMeasurementConfig" ,
2929 "SkyMeasurementTask" ,
3030 "SkyStatsConfig" ,
31+ "TractBackground" ,
32+ "TractBackgroundConfig" ,
3133]
3234
3335import 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- >> >> >> > 8 cf1e691 (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
866862class 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