class TestAlgorithm(unittest.TestCase): """Test the Algorithm class.""" def setUp(self): # Get the path of module self.modulePath = getModulePath() # Define the image folder and image names # Image data -- Don't know the final image format. # It is noted that image.readFile inuts is based on the txt file imageFolderPath = os.path.join(self.modulePath, "tests", "testData", "testImages", "LSST_NE_SN25") intra_image_name = "z11_0.25_intra.txt" extra_image_name = "z11_0.25_extra.txt" # Define fieldXY: [1.185, 1.185] or [0, 0] # This is the position of donut on the focal plane in degree fieldXY = [1.185, 1.185] # Define the optical model: "paraxial", "onAxis", "offAxis" self.opticalModel = "offAxis" # Image files Path intra_image_file = os.path.join(imageFolderPath, intra_image_name) extra_image_file = os.path.join(imageFolderPath, extra_image_name) # Theree is the difference between intra and extra images # I1: intra_focal images, I2: extra_focal Images self.I1 = CompensableImage() self.I2 = CompensableImage() self.I1.setImg(fieldXY, DefocalType.Intra, imageFile=intra_image_file) self.I2.setImg(fieldXY, DefocalType.Extra, imageFile=extra_image_file) # Set up the instrument cwfsConfigDir = os.path.join(getConfigDir(), "cwfs") instDir = os.path.join(cwfsConfigDir, "instData") self.inst = Instrument(instDir) self.inst.config(CamType.LsstCam, self.I1.getImgSizeInPix(), announcedDefocalDisInMm=1.0) # Set up the algorithm algoDir = os.path.join(cwfsConfigDir, "algo") self.algoExp = Algorithm(algoDir) self.algoExp.config("exp", self.inst) self.algoFft = Algorithm(algoDir) self.algoFft.config("fft", self.inst) def testGetDebugLevel(self): self.assertEqual(self.algoExp.getDebugLevel(), 0) def testSetDebugLevel(self): self.algoExp.config("exp", self.inst, debugLevel=3) self.assertEqual(self.algoExp.getDebugLevel(), 3) self.algoExp.setDebugLevel(0) self.assertEqual(self.algoExp.getDebugLevel(), 0) def testGetZer4UpInNm(self): zer4UpNm = self.algoExp.getZer4UpInNm() self.assertTrue(isinstance(zer4UpNm, np.ndarray)) def testGetPoissonSolverName(self): self.assertEqual(self.algoExp.getPoissonSolverName(), "exp") self.assertEqual(self.algoFft.getPoissonSolverName(), "fft") def testGetNumOfZernikes(self): self.assertEqual(self.algoExp.getNumOfZernikes(), 22) self.assertEqual(self.algoFft.getNumOfZernikes(), 22) def testGetZernikeTerms(self): zTerms = self.algoExp.getZernikeTerms() self.assertTrue(type(zTerms[0]), int) self.assertEqual(len(zTerms), self.algoExp.getNumOfZernikes()) self.assertEqual(zTerms[1], 1) self.assertEqual(zTerms[-1], self.algoExp.getNumOfZernikes() - 1) zTerms = self.algoFft.getZernikeTerms() self.assertTrue(type(zTerms[0]), int) self.assertEqual(len(zTerms), self.algoExp.getNumOfZernikes()) def testGetObsOfZernikes(self): self.assertEqual(self.algoExp.getObsOfZernikes(), self.inst.getObscuration()) self.assertEqual(self.algoFft.getObsOfZernikes(), self.inst.getObscuration()) def testGetNumOfOuterItr(self): self.assertEqual(self.algoExp.getNumOfOuterItr(), 14) self.assertEqual(self.algoFft.getNumOfOuterItr(), 14) def testGetNumOfInnerItr(self): self.assertEqual(self.algoFft.getNumOfInnerItr(), 6) def testGetFeedbackGain(self): self.assertEqual(self.algoExp.getFeedbackGain(), 0.6) self.assertEqual(self.algoFft.getFeedbackGain(), 0.6) def testGetOffAxisPolyOrder(self): self.assertEqual(self.algoExp.getOffAxisPolyOrder(), 10) self.assertEqual(self.algoFft.getOffAxisPolyOrder(), 10) def testGetCompensatorMode(self): self.assertEqual(self.algoExp.getCompensatorMode(), "zer") self.assertEqual(self.algoFft.getCompensatorMode(), "zer") def testGetCompSequence(self): compSequence = self.algoExp.getCompSequence() self.assertTrue(isinstance(compSequence, np.ndarray)) self.assertEqual(compSequence.dtype, int) self.assertEqual(len(compSequence), self.algoExp.getNumOfOuterItr()) self.assertEqual(compSequence[0], 4) self.assertEqual(compSequence[-1], 22) compSequence = self.algoFft.getCompSequence() self.assertEqual(len(compSequence), self.algoFft.getNumOfOuterItr()) def testGetBoundaryThickness(self): self.assertEqual(self.algoExp.getBoundaryThickness(), 8) self.assertEqual(self.algoFft.getBoundaryThickness(), 1) def testGetFftDimension(self): self.assertEqual(self.algoFft.getFftDimension(), 128) def testGetSignalClipSequence(self): sumclipSequence = self.algoFft.getSignalClipSequence() self.assertTrue(isinstance(sumclipSequence, np.ndarray)) self.assertEqual(len(sumclipSequence), self.algoExp.getNumOfOuterItr() + 1) self.assertEqual(sumclipSequence[0], 0.33) self.assertEqual(sumclipSequence[-1], 0.51) def testGetMaskScalingFactor(self): self.assertAlmostEqual(self.algoExp.getMaskScalingFactor(), 1.0939, places=4) self.assertAlmostEqual(self.algoFft.getMaskScalingFactor(), 1.0939, places=4) def testGetWavefrontMapEstiInIter0(self): self.assertRaises(RuntimeError, self.algoExp.getWavefrontMapEsti) def testGetWavefrontMapEstiAndResidual(self): self.algoExp.runIt(self.I1, self.I2, self.opticalModel, tol=1e-3) wavefrontMapEsti = self.algoExp.getWavefrontMapEsti() wavefrontMapEsti[np.isnan(wavefrontMapEsti)] = 0 self.assertGreater(np.sum(np.abs(wavefrontMapEsti)), 4.8e-4) wavefrontMapResidual = self.algoExp.getWavefrontMapResidual() wavefrontMapResidual[np.isnan(wavefrontMapResidual)] = 0 self.assertLess(np.sum(np.abs(wavefrontMapResidual)), 2.5e-6) def testItr0(self): self.algoExp.itr0(self.I1, self.I2, self.opticalModel) zer4UpNm = self.algoExp.getZer4UpInNm() self.assertEqual( np.sum(np.abs(np.rint(zer4UpNm) - self._getAnsItr0())), 0) def _getAnsItr0(self): return [ 31, -69, -21, 84, 44, -53, 48, -146, 6, 10, 13, -5, 1, -12, -8, 7, 0, -6, 11, ] def testNextItrWithOneIter(self): self.algoExp.nextItr(self.I1, self.I2, self.opticalModel, nItr=1) zer4UpNm = self.algoExp.getZer4UpInNm() self.assertEqual( np.sum(np.abs(np.rint(zer4UpNm) - self._getAnsItr0())), 0) def testNextItrWithTwoIter(self): self.algoExp.nextItr(self.I1, self.I2, self.opticalModel, nItr=2) zer4UpNm = self.algoExp.getZer4UpInNm() ansRint = [ 40, -80, -18, 92, 44.0, -52, 54, -146, 5, 10, 15, -3, -0, -12, -8, 7, 1, -3, 12, ] self.assertEqual(np.sum(np.abs(np.rint(zer4UpNm) - ansRint)), 0) def testIter0AndNextIterToCheckReset(self): self.algoExp.itr0(self.I1, self.I2, self.opticalModel) tmp1 = self.algoExp.getZer4UpInNm() self.algoExp.nextItr(self.I1, self.I2, self.opticalModel, nItr=2) # itr0() should reset the images and ignore the effect from nextItr() self.algoExp.itr0(self.I1, self.I2, self.opticalModel) tmp2 = self.algoExp.getZer4UpInNm() difference = np.sum(np.abs(tmp1 - tmp2)) self.assertEqual(difference, 0) def testRunItOfExp(self): self.algoExp.runIt(self.I1, self.I2, self.opticalModel, tol=1e-3) # Check the value zk = self.algoExp.getZer4UpInNm() self.assertEqual(int(zk[7]), -192) def testResetAfterFullCalc(self): self.algoExp.runIt(self.I1, self.I2, self.opticalModel, tol=1e-3) # Reset and check the calculation again fieldXY = [self.I1.fieldX, self.I1.fieldY] self.I1.setImg(fieldXY, self.I1.getDefocalType(), image=self.I1.getImgInit()) self.I2.setImg(fieldXY, self.I2.getDefocalType(), image=self.I2.getImgInit()) self.algoExp.reset() self.algoExp.runIt(self.I1, self.I2, self.opticalModel, tol=1e-3) zk = self.algoExp.getZer4UpInNm() self.assertEqual(int(zk[7]), -192) def testRunItOfFft(self): self.algoFft.runIt(self.I1, self.I2, self.opticalModel, tol=1e-3) zk = self.algoFft.getZer4UpInNm() self.assertEqual(int(zk[7]), -192)
class TestCompensableImage(unittest.TestCase): """Test the CompensableImage class.""" def setUp(self): # Get the path of module modulePath = getModulePath() # Define the instrument folder instDir = os.path.join(getConfigDir(), "cwfs", "instData") # Define the instrument name dimOfDonutOnSensor = 120 self.inst = Instrument(instDir) self.inst.config(CamType.LsstCam, dimOfDonutOnSensor, announcedDefocalDisInMm=1.0) # Define the image folder and image names # Image data -- Don't know the final image format. # It is noted that image.readFile inuts is based on the txt file imageFolderPath = os.path.join(modulePath, "tests", "testData", "testImages", "LSST_NE_SN25") intra_image_name = "z11_0.25_intra.txt" extra_image_name = "z11_0.25_extra.txt" self.imgFilePathIntra = os.path.join(imageFolderPath, intra_image_name) self.imgFilePathExtra = os.path.join(imageFolderPath, extra_image_name) # This is the position of donut on the focal plane in degree self.fieldXY = (1.185, 1.185) # Define the optical model: "paraxial", "onAxis", "offAxis" self.opticalModel = "offAxis" # Get the true Zk zcAnsFilePath = os.path.join( modulePath, "tests", "testData", "testImages", "validation", "simulation", "LSST_NE_SN25_z11_0.25_exp.txt", ) self.zcCol = np.loadtxt(zcAnsFilePath) self.wfsImg = CompensableImage() def testGetDefocalType(self): defocalType = self.wfsImg.getDefocalType() self.assertEqual(defocalType, DefocalType.Intra) def testGetImgObj(self): imgObj = self.wfsImg.getImgObj() self.assertTrue(isinstance(imgObj, Image)) def testGetImg(self): img = self.wfsImg.getImg() self.assertTrue(isinstance(img, np.ndarray)) self.assertEqual(len(img), 0) def testGetImgSizeInPix(self): imgSizeInPix = self.wfsImg.getImgSizeInPix() self.assertEqual(imgSizeInPix, 0) def testGetOffAxisCoeff(self): offAxisCoeff, offAxisOffset = self.wfsImg.getOffAxisCoeff() self.assertTrue(isinstance(offAxisCoeff, np.ndarray)) self.assertEqual(len(offAxisCoeff), 0) self.assertEqual(offAxisOffset, 0.0) def testGetImgInit(self): imgInit = self.wfsImg.getImgInit() self.assertEqual(imgInit, None) def testIsCaustic(self): self.assertFalse(self.wfsImg.isCaustic()) def testGetPaddedMask(self): pMask = self.wfsImg.getPaddedMask() self.assertEqual(len(pMask), 0) self.assertEqual(pMask.dtype, int) def testGetNonPaddedMask(self): cMask = self.wfsImg.getNonPaddedMask() self.assertEqual(len(cMask), 0) self.assertEqual(cMask.dtype, int) def testGetFieldXY(self): fieldX, fieldY = self.wfsImg.getFieldXY() self.assertEqual(fieldX, 0) self.assertEqual(fieldY, 0) def testSetImg(self): self._setIntraImg() self.assertEqual(self.wfsImg.getImg().shape, (120, 120)) def _setIntraImg(self): self.wfsImg.setImg(self.fieldXY, DefocalType.Intra, imageFile=self.imgFilePathIntra) def testUpdateImage(self): self._setIntraImg() newImg = np.random.rand(5, 5) self.wfsImg.updateImage(newImg) self.assertTrue(np.all(self.wfsImg.getImg() == newImg)) def testUpdateImgInit(self): self._setIntraImg() self.wfsImg.updateImgInit() delta = np.sum(np.abs(self.wfsImg.getImgInit() - self.wfsImg.getImg())) self.assertEqual(delta, 0) def testImageCoCenter(self): self._setIntraImg() self.wfsImg.imageCoCenter(self.inst) xc, yc = self.wfsImg.getImgObj().getCenterAndR()[0:2] self.assertEqual(int(xc), 63) self.assertEqual(int(yc), 63) def testCompensate(self): # Generate a fake algorithm class algo = TempAlgo() # Test the function of image compensation boundaryT = 8 offAxisCorrOrder = 10 zcCol = np.zeros(22) zcCol[3:] = self.zcCol * 1e-9 wfsImgIntra = CompensableImage() wfsImgExtra = CompensableImage() wfsImgIntra.setImg( self.fieldXY, DefocalType.Intra, imageFile=self.imgFilePathIntra, ) wfsImgExtra.setImg(self.fieldXY, DefocalType.Extra, imageFile=self.imgFilePathExtra) for wfsImg in [wfsImgIntra, wfsImgExtra]: wfsImg.makeMask(self.inst, self.opticalModel, boundaryT, 1) wfsImg.setOffAxisCorr(self.inst, offAxisCorrOrder) wfsImg.imageCoCenter(self.inst) wfsImg.compensate(self.inst, algo, zcCol, self.opticalModel) # Get the common region intraImg = wfsImgIntra.getImg() extraImg = wfsImgExtra.getImg() centroid = CentroidRandomWalk() binaryImgIntra = centroid.getImgBinary(intraImg) binaryImgExtra = centroid.getImgBinary(extraImg) binaryImg = binaryImgIntra + binaryImgExtra binaryImg[binaryImg < 2] = 0 binaryImg = binaryImg / 2 # Calculate the difference res = np.sum(np.abs(intraImg - extraImg) * binaryImg) self.assertLess(res, 500) def testCenterOnProjection(self): template = self._prepareGaussian2D(100, 1) dx = 2 dy = 8 img = np.roll(np.roll(template, dx, axis=1), dy, axis=0) np.roll(np.roll(img, dx, axis=1), dy, axis=0) self.assertGreater(np.sum(np.abs(img - template)), 29) imgRecenter = self.wfsImg.centerOnProjection(img, template, window=20) self.assertLess(np.sum(np.abs(imgRecenter - template)), 1e-7) def _prepareGaussian2D(self, imgSize, sigma): x = np.linspace(-10, 10, imgSize) y = np.linspace(-10, 10, imgSize) xx, yy = np.meshgrid(x, y) return (1 / (2 * np.pi * sigma**2) * np.exp(-(xx**2 / (2 * sigma**2) + yy**2 / (2 * sigma**2)))) def testSetOffAxisCorr(self): self._setIntraImg() offAxisCorrOrder = 10 self.wfsImg.setOffAxisCorr(self.inst, offAxisCorrOrder) offAxisCoeff, offAxisOffset = self.wfsImg.getOffAxisCoeff() self.assertEqual(offAxisCoeff.shape, (4, 66)) self.assertAlmostEqual(offAxisCoeff[0, 0], -2.6362089 * 1e-3) self.assertEqual(offAxisOffset, 0.001) def testMakeMaskListOfParaxial(self): self._setIntraImg() model = "paraxial" masklist = self.wfsImg.makeMaskList(self.inst, model) masklistAns = np.array([[0, 0, 1, 1], [0, 0, 0.61, 0]]) self.assertEqual(np.sum(np.abs(masklist - masklistAns)), 0) def testMakeMaskListOfOffAxis(self): self._setIntraImg() model = "offAxis" masklist = self.wfsImg.makeMaskList(self.inst, model) masklistAns = np.array([ [0, 0, 1, 1], [0, 0, 0.61, 0], [-0.21240585, -0.21240585, 1.2300922, 1], [-0.08784336, -0.08784336, 0.55802573, 0], ]) self.assertAlmostEqual(np.sum(np.abs(masklist - masklistAns)), 0) def testMakeMask(self): self._setIntraImg() boundaryT = 8 maskScalingFactorLocal = 1 model = "offAxis" self.wfsImg.makeMask(self.inst, model, boundaryT, maskScalingFactorLocal) image = self.wfsImg.getImg() pMask = self.wfsImg.getPaddedMask() cMask = self.wfsImg.getNonPaddedMask() self.assertEqual(pMask.shape, image.shape) self.assertEqual(cMask.shape, image.shape) self.assertEqual(np.sum(np.abs(cMask - pMask)), 3001)
class TestAlgorithm(unittest.TestCase): """Test the Algorithm class.""" def setUp(self): # Get the path of module self.modulePath = getModulePath() # Define the image folder and image names # Image data -- Don't know the final image format. # It is noted that image.readFile inuts is based on the txt file imageFolderPath = os.path.join(self.modulePath, "tests", "testData", "testImages", "LSST_NE_SN25") intra_image_name = "z11_0.25_intra.txt" extra_image_name = "z11_0.25_extra.txt" # Define fieldXY: [1.185, 1.185] or [0, 0] # This is the position of donut on the focal plane in degree fieldXY = [1.185, 1.185] # Define the optical model: "paraxial", "onAxis", "offAxis" self.opticalModel = "offAxis" # Image files Path intra_image_file = os.path.join(imageFolderPath, intra_image_name) extra_image_file = os.path.join(imageFolderPath, extra_image_name) # Theree is the difference between intra and extra images # I1: intra_focal images, I2: extra_focal Images self.I1 = CompensableImage() self.I2 = CompensableImage() self.I1.setImg(fieldXY, DefocalType.Intra, imageFile=intra_image_file) self.I2.setImg(fieldXY, DefocalType.Extra, imageFile=extra_image_file) # Set up the instrument cwfsConfigDir = os.path.join(getConfigDir(), "cwfs") instDir = os.path.join(cwfsConfigDir, "instData") self.inst = Instrument(instDir) self.inst.config(CamType.LsstCam, self.I1.getImgSizeInPix(), announcedDefocalDisInMm=1.0) # Set up the algorithm algoDir = os.path.join(cwfsConfigDir, "algo") self.algoExp = Algorithm(algoDir) self.algoExp.config("exp", self.inst) self.algoFft = Algorithm(algoDir) self.algoFft.config("fft", self.inst) def testGetDebugLevel(self): self.assertEqual(self.algoExp.getDebugLevel(), 0) def testSetDebugLevel(self): self.algoExp.config("exp", self.inst, debugLevel=3) self.assertEqual(self.algoExp.getDebugLevel(), 3) self.algoExp.setDebugLevel(0) self.assertEqual(self.algoExp.getDebugLevel(), 0) def testGetZer4UpInNm(self): zer4UpNm = self.algoExp.getZer4UpInNm() self.assertTrue(isinstance(zer4UpNm, np.ndarray)) def testGetPoissonSolverName(self): self.assertEqual(self.algoExp.getPoissonSolverName(), "exp") self.assertEqual(self.algoFft.getPoissonSolverName(), "fft") def testGetNumOfZernikes(self): self.assertEqual(self.algoExp.getNumOfZernikes(), 22) self.assertEqual(self.algoFft.getNumOfZernikes(), 22) def testGetZernikeTerms(self): zTerms = self.algoExp.getZernikeTerms() self.assertTrue(zTerms.dtype, int) self.assertEqual(len(zTerms), self.algoExp.getNumOfZernikes()) self.assertEqual(zTerms[0], 1) self.assertEqual(zTerms[-1], self.algoExp.getNumOfZernikes()) zTerms = self.algoFft.getZernikeTerms() self.assertTrue(zTerms.dtype, int) self.assertEqual(len(zTerms), self.algoExp.getNumOfZernikes()) def testGetObsOfZernikes(self): self.assertEqual(self.algoExp.getObsOfZernikes(), self.inst.getObscuration()) self.assertEqual(self.algoFft.getObsOfZernikes(), self.inst.getObscuration()) def testGetNumOfOuterItr(self): self.assertEqual(self.algoExp.getNumOfOuterItr(), 14) self.assertEqual(self.algoFft.getNumOfOuterItr(), 14) def testGetNumOfInnerItr(self): self.assertEqual(self.algoFft.getNumOfInnerItr(), 6) def testGetFeedbackGain(self): self.assertEqual(self.algoExp.getFeedbackGain(), 0.6) self.assertEqual(self.algoFft.getFeedbackGain(), 0.6) def testGetOffAxisPolyOrder(self): self.assertEqual(self.algoExp.getOffAxisPolyOrder(), 10) self.assertEqual(self.algoFft.getOffAxisPolyOrder(), 10) def testGetCompensatorMode(self): self.assertEqual(self.algoExp.getCompensatorMode(), "zer") self.assertEqual(self.algoFft.getCompensatorMode(), "zer") def testGetCompSequence(self): compSequence = self.algoExp.getCompSequence() self.assertTrue(isinstance(compSequence, np.ndarray)) self.assertEqual(compSequence.dtype, int) self.assertEqual(len(compSequence), self.algoExp.getNumOfOuterItr()) self.assertEqual(compSequence[0], 4) self.assertEqual(compSequence[-1], 22) compSequence = self.algoFft.getCompSequence() self.assertEqual(len(compSequence), self.algoFft.getNumOfOuterItr()) def testGetBoundaryThickness(self): self.assertEqual(self.algoExp.getBoundaryThickness(), 8) self.assertEqual(self.algoFft.getBoundaryThickness(), 1) def testGetFftDimension(self): self.assertEqual(self.algoFft.getFftDimension(), 128) def testGetSignalClipSequence(self): sumclipSequence = self.algoFft.getSignalClipSequence() self.assertTrue(isinstance(sumclipSequence, np.ndarray)) self.assertEqual(len(sumclipSequence), self.algoExp.getNumOfOuterItr()+1) self.assertEqual(sumclipSequence[0], 0.33) self.assertEqual(sumclipSequence[-1], 0.51) def testGetMaskScalingFactor(self): self.assertAlmostEqual(self.algoExp.getMaskScalingFactor(), 1.0939, places=4) self.assertAlmostEqual(self.algoFft.getMaskScalingFactor(), 1.0939, places=4) def testRunItOfExp(self): # Test functions: itr0() and nextItr() self.algoExp.itr0(self.I1, self.I2, self.opticalModel) tmp1 = self.algoExp.getZer4UpInNm() self.algoExp.nextItr(self.I1, self.I2, self.opticalModel, nItr=2) self.algoExp.itr0(self.I1, self.I2, self.opticalModel) tmp2 = self.algoExp.getZer4UpInNm() difference = np.sum(np.abs(tmp1-tmp2)) self.assertEqual(difference, 0) # Run it self.algoExp.runIt(self.I1, self.I2, self.opticalModel, tol=1e-3) # Check the value Zk = self.algoExp.getZer4UpInNm() self.assertEqual(int(Zk[7]), -192) # Reset and check the calculation again fieldXY = [self.I1.fieldX, self.I1.fieldY] self.I1.setImg(fieldXY, self.I1.getDefocalType(), image=self.I1.getImgInit()) self.I2.setImg(fieldXY, self.I2.getDefocalType(), image=self.I2.getImgInit()) self.algoExp.reset() self.algoExp.runIt(self.I1, self.I2, self.opticalModel, tol=1e-3) Zk = self.algoExp.getZer4UpInNm() self.assertEqual(int(Zk[7]), -192) def testRunItOfFft(self): self.algoFft.runIt(self.I1, self.I2, self.opticalModel, tol=1e-3) zk = self.algoFft.getZer4UpInNm() self.assertEqual(int(zk[7]), -192)