Skip to content

Commit

Permalink
Clean up issues in tests/warpExposure.py
Browse files Browse the repository at this point in the history
tests/warpExposure.py had a number of issues including:
- One null test was comparing an image to itself (bug)
- The EDGE mask was still being used
- One test that was supposed to compare good pixels
  was not comparing image or variance planes
- Use of numpy.alltrue is deprecated; use numpy.all instead
  • Loading branch information
r-owen committed Nov 10, 2015
1 parent 532f289 commit d75680e
Showing 1 changed file with 19 additions and 102 deletions.
121 changes: 19 additions & 102 deletions tests/warpExposure.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def testNullWarpExposure(self, interpLength=10):
"""Test that warpExposure maps an image onto itself.
Note:
- edge and off-CCD pixels must be ignored
- NO_DATA and off-CCD pixels must be ignored
- bad mask pixels get smeared out so we have to excluded all bad mask pixels
from the output image when comparing masks.
"""
Expand All @@ -138,29 +138,21 @@ def testNullWarpExposure(self, interpLength=10):

afwWarpedMaskedImage = afwWarpedExposure.getMaskedImage()
afwWarpedMask = afwWarpedMaskedImage.getMask()
edgeBitMask = afwWarpedMask.getPlaneBitMask("EDGE")
noDataBitMask = afwWarpedMask.getPlaneBitMask("NO_DATA")
if edgeBitMask == 0:
self.fail("warped mask has no EDGE bit")
if noDataBitMask == 0:
self.fail("warped mask has no NO_DATA bit")
# WARNING: there is probably no reason to use EDGE; just use NO_DATA
afwWarpedMaskedImageArrSet = afwWarpedMaskedImage.getArrays()
afwWarpedMaskArr = afwWarpedMaskedImageArrSet[1]

# compare all non-edge pixels of image and variance, but relax specs a bit
# compare all non-DATA pixels of image and variance, but relax specs a bit
# because of minor noise introduced by bad pixels
skipMaskArr = afwWarpedMaskArr & (edgeBitMask | noDataBitMask)
noDataMaskArr = afwWarpedMaskArr & noDataBitMask
msg = "afw null-warped MaskedImage (all pixels, relaxed tolerance)"
self.assertMaskedImagesNearlyEqual(afwWarpedMaskedImage, originalExposure.getMaskedImage(),
doMask=False, skipMask=skipMaskArr, atol=1e-5, msg=msg)
doMask=False, skipMask=noDataMaskArr, atol=1e-5, msg=msg)

# compare good pixels of image, mask and variance using full tolerance
# WARNING: this doesn't do what is claimed; it only compares the mask bits
# so it would be clearer to use assertMasksNearlyEqual
# compare good pixels (mask=0) of image, mask and variance using full tolerance
msg = "afw null-warped MaskedImage (good pixels, max tolerance)"
self.assertMaskedImagesNearlyEqual(afwWarpedMaskedImage, originalExposure.getMaskedImage(),
doImage=False, doVariance=False, skipMask=afwWarpedMaskArr, msg=msg)
skipMask=afwWarpedMask, msg=msg)

def testNullWarpImage(self, interpLength=10):
"""Test that warpImage maps an image onto itself.
Expand All @@ -176,13 +168,11 @@ def testNullWarpImage(self, interpLength=10):
if SAVE_FITS_FILES:
afwWarpedImage.writeFits("afwWarpedImageNull.fits")
afwWarpedImageArr = afwWarpedImage.getArray()
edgeMaskArr = numpy.isnan(afwWarpedImageArr)
noDataMaskArr = numpy.isnan(afwWarpedImageArr)
# relax specs a bit because of minor noise introduced by bad pixels
msg = "afw null-warped Image"
# WARNING: THIS IS A NULL TEST; FIX IT! Should compare against afwWarpedImage
# Also it would be safer to make the edge mask using NO_DATA
self.assertImagesNearlyEqual(originalImage, originalImage,
skipMask=edgeMaskArr, msg=msg)
self.assertImagesNearlyEqual(originalImage, afwWarpedImage, skipMask=noDataMaskArr,
atol=1e-5, msg=msg)

def testNullWcs(self, interpLength=10):
"""Cannot warp from or into an exposure without a Wcs.
Expand Down Expand Up @@ -438,11 +428,10 @@ def testSmallSrc(self):
numGoodPix = afwMath.warpExposure(toExp, fromExp, warpControl)
self.assertEqual(numGoodPix, 0)
imArr, maskArr, varArr = toExp.getMaskedImage().getArrays()
self.assertTrue(numpy.alltrue(numpy.isnan(imArr)))
self.assertTrue(numpy.alltrue(numpy.isinf(varArr)))
edgeMask = afwImage.MaskU.getPlaneBitMask("EDGE")
noDataMask = afwImage.MaskU.getPlaneBitMask("NO_DATA")
self.assertTrue(numpy.alltrue(maskArr == (noDataMask or edgeMask)))
self.assertTrue(numpy.all(numpy.isnan(imArr)))
self.assertTrue(numpy.all(numpy.isinf(varArr)))
noDataBitMask = afwImage.MaskU.getPlaneBitMask("NO_DATA")
self.assertTrue(numpy.all(maskArr == noDataBitMask))

def verifyMaskWarp(self, kernelName, maskKernelName, growFullMask, interpLength=10, cacheSize=100000,
rtol=4e-05, atol=1e-2):
Expand Down Expand Up @@ -574,16 +563,12 @@ def compareToSwarp(self, kernelName,
afwWarpedMaskedImage = afwImage.MaskedImageF(swarpedImage.getDimensions())
afwWarpedExposure = afwImage.ExposureF(afwWarpedMaskedImage, warpedWcs)
afwMath.warpExposure(afwWarpedExposure, originalExposure, warpingControl)
afwWarpedMask = afwWarpedMaskedImage.getMask()
if SAVE_FITS_FILES:
afwWarpedExposure.writeFits(afwWarpedImagePath)
if display:
ds9.mtv(afwWarpedExposure, frame=1, title="Warped")

afwWarpedMask = afwWarpedMaskedImage.getMask()
edgeBitMask = afwWarpedMask.getPlaneBitMask("EDGE")
if edgeBitMask == 0:
self.fail("warped mask has no EDGE bit")


swarpedMaskedImage = afwImage.MaskedImageF(swarpedImage)

if display:
Expand All @@ -592,8 +577,8 @@ def compareToSwarp(self, kernelName,
msg = "afw and swarp %s-warped differ (ignoring bad pixels)" % (kernelName,)
try:
self.assertMaskedImagesNearlyEqual(afwWarpedMaskedImage, swarpedMaskedImage,
doImage=True, doMask=False, doVariance=False, skipMask=afwWarpedMaskedImage.getMask(),
rtol=rtol, atol=atol)
doImage=True, doMask=False, doVariance=False, skipMask=afwWarpedMask,
rtol=rtol, atol=atol, msg=msg)
except Exception:
if SAVE_FAILED_FITS_FILES:
afwWarpedExposure.writeFits(afwWarpedImagePath)
Expand All @@ -618,86 +603,18 @@ def compareToSwarp(self, kernelName,
afwWarpedImage.writeFits(afwWarpedImagePath)

afwWarpedImageArr = afwWarpedImage.getArray()
edgeMaskArr = numpy.isnan(afwWarpedImageArr)
edgeMask = afwImage.makeMaskFromArray(numpy.array(edgeMaskArr, dtype=numpy.uint16))
noDataMaskArr = numpy.isnan(afwWarpedImageArr)
msg = "afw and swarp %s-warped images do not match (ignoring NaN pixels)" % \
(kernelName,)
try:
self.assertImagesNearlyEqual(afwWarpedImage, swarpedImage,
skipMask=edgeMask, rtol=rtol, atol=atol, msg=msg)
skipMask=noDataMaskArr, rtol=rtol, atol=atol, msg=msg)
except Exception:
if SAVE_FAILED_FITS_FILES:
# save the image anyway
afwWarpedImage.writeFits(afwWarpedImagePath)
print "Saved failed afw-warped image as: %s" % (afwWarpedImagePath,)
raise

def compareMaskedImages(self, maskedImage1, maskedImage2, descr="",
doImage=True, doMask=True, doVariance=True, skipMaskArr=None, rtol=1.0e-05, atol=1e-08):
"""Compare pixels from two masked images
WARNING: OBSOLETE; REMOVE ME
Inputs:
- maskedImage1: first masked image to compare
- maskedImage2: second masked image to compare
- descr: a short description of the inputs
- doImage: compare image planes if True
- doMask: compare mask planes if True
- doVariance: compare variance planes if True
- skipMaskArr: pixels to ingore on the image, mask and variance arrays; nonzero values are skipped
Returns None if all is well, or an error string if any plane did not match.
The error string is one of:
<plane> plane does not match
(<plane1>, <plane2>,...) planes do not match
"""
badPlanes = []
for (doPlane, planeName) in ((doImage, "image"), (doMask, "mask"), (doVariance, "variance")):
if not doPlane:
continue
funcName = "get%s" % (planeName.title(),)
imageDescr = "%s: %s plane" % (descr, planeName)
image1 = getattr(maskedImage1, funcName)()
image2 = getattr(maskedImage2, funcName)()
imageOK = self.compareImages(image1, image2, descr=imageDescr, skipMaskArr=skipMaskArr,
rtol=rtol, atol=atol)
if not imageOK:
badPlanes.append(planeName)
if not badPlanes:
return None
if len(badPlanes) > 1:
return "%s planes do not match" % (badPlanes,)
return "%s plane does not match" % (badPlanes[0],)

def compareImages(self, image1, image2, descr="", skipMaskArr=None, rtol=1.0e-05, atol=1e-08):
"""Return True if two images are nearly equal, False otherwise
WARNING: OBSOLETE; REMOVE ME
"""
arr1 = image1.getArray()
arr2 = image2.getArray()

if skipMaskArr != None:
skipMaskArr = numpy.array(skipMaskArr != 0, dtype=bool)
maskedArr1 = numpy.ma.array(arr1, copy=False, mask = skipMaskArr)
maskedArr2 = numpy.ma.array(arr2, copy=False, mask = skipMaskArr)
filledArr1 = maskedArr1.filled(0.0)
filledArr2 = maskedArr2.filled(0.0)
else:
filledArr1 = arr1
filledArr2 = arr2

if not numpy.allclose(filledArr1, filledArr2, rtol=rtol, atol=atol):
errArr = numpy.abs(filledArr1 - filledArr2) - (filledArr2 * rtol) + atol
maxErr = errArr.max()
maxPosInd = numpy.where(errArr==maxErr)
maxPosTuple = (maxPosInd[0][0], maxPosInd[1][0])
relErr = numpy.abs(filledArr1 - filledArr2) / (filledArr1 + filledArr2)
print "%s: maxErr=%s at position %s; value=%s vs. %s; relErr=%s" % \
(descr, maxErr, maxPosTuple, filledArr1[maxPosInd][0], filledArr2[maxPosInd][0], relErr)
return False
return True


#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Expand Down

0 comments on commit d75680e

Please sign in to comment.