def _runWep(self, imgIntraName, imgExtraName, offset, model): # Cut the donut image from input files centroidFindType = CentroidFindType.Otsu imgIntra = Image(centroidFindType=centroidFindType) imgExtra = Image(centroidFindType=centroidFindType) imgIntraPath = os.path.join(self.testImgDir, imgIntraName) imgExtraPath = os.path.join(self.testImgDir, imgExtraName) imgIntra.setImg(imageFile=imgIntraPath) imgExtra.setImg(imageFile=imgExtraPath) xIntra, yIntra, _ = imgIntra.getCenterAndR() imgIntraArray = imgIntra.getImg()[int(yIntra) - offset:int(yIntra) + offset, int(xIntra) - offset:int(xIntra) + offset, ] xExtra, yExtra, _ = imgExtra.getCenterAndR() imgExtraArray = imgExtra.getImg()[int(yExtra) - offset:int(yExtra) + offset, int(xExtra) - offset:int(xExtra) + offset, ] # Set the images fieldXY = (0, 0) imgCompIntra = CompensableImage(centroidFindType=centroidFindType) imgCompIntra.setImg(fieldXY, DefocalType.Intra, image=imgIntraArray) imgCompExtra = CompensableImage(centroidFindType=centroidFindType) imgCompExtra.setImg(fieldXY, DefocalType.Extra, image=imgExtraArray) # Calculate the wavefront error # Set the instrument instDir = os.path.join(getConfigDir(), "cwfs", "instData") instAuxTel = Instrument(instDir) instAuxTel.config(CamType.AuxTel, imgCompIntra.getImgSizeInPix(), announcedDefocalDisInMm=0.8) # Set the algorithm algoFolderPath = os.path.join(getConfigDir(), "cwfs", "algo") algoAuxTel = Algorithm(algoFolderPath) algoAuxTel.config("exp", instAuxTel) algoAuxTel.runIt(imgCompIntra, imgCompExtra, model) return algoAuxTel.getZer4UpInNm()
def _configWfEstimator(self, camType): """Configure the wavefront estimator. Returns ------- WfEstimator Configured wavefront estimator. """ configDir = getConfigDir() instDir = os.path.join(configDir, "cwfs", "instData") algoDir = os.path.join(configDir, "cwfs", "algo") wfsEsti = WfEstimator(instDir, algoDir) solver = self.settingFile.getSetting("poissonSolver") opticalModel = self.settingFile.getSetting("opticalModel") defocalDistInMm = self.settingFile.getSetting("defocalDistInMm") donutImgSizeInPixel = self.settingFile.getSetting("donutImgSizeInPixel") centroidFind = self.settingFile.getSetting("centroidFindAlgo") centroidFindType = getCentroidFindType(centroidFind) wfsEsti.config( solver=solver, camType=camType, opticalModel=opticalModel, defocalDisInMm=defocalDistInMm, sizeInPix=donutImgSizeInPixel, centroidFindType=centroidFindType, ) return wfsEsti
def __init__(self, settingFileName="default.yaml", focalPlaneFileName="focalplanelayout.txt"): """Initialize the SourceProcessor class. Parameters ---------- settingFileName : str, optional Setting file name. (the default is "default.yaml".) focalPlaneFileName : str, optional Focal plane file name used in the PhoSim instrument directory. (the default is "focalplanelayout.txt".) """ self.sensorName = "" self.blendedImageDecorator = BlendedImageDecorator() configDir = getConfigDir() settingFilePath = os.path.join(configDir, settingFileName) self.settingFile = ParamReader(filePath=settingFilePath) self.sensorFocaPlaneInDeg = dict() self.sensorFocaPlaneInUm = dict() self.sensorDimList = dict() self.sensorEulerRot = dict() self._readFocalPlane(configDir, focalPlaneFileName)
def __init__(self, settingFileName="default.yaml", focalPlaneFileName="focalplanelayout.txt"): """Initialize the SourceProcessor class. Parameters ---------- settingFileName : str, optional Setting file name. (the default is "default.yaml".) focalPlaneFileName : str, optional Focal plane file name used in the PhoSim instrument directory. (the default is "focalplanelayout.txt".) """ self.sensorName = "" configDir = getConfigDir() settingFilePath = os.path.join(configDir, settingFileName) self.settingFile = ParamReader(filePath=settingFilePath) self.sensorFocaPlaneInDeg = dict() self.sensorFocaPlaneInUm = dict() self.sensorDimList = dict() self.sensorEulerRot = dict() self._readFocalPlane(configDir, focalPlaneFileName) # Deblending donut algorithm to use deblendDonutType = self._getDeblendDonutTypeInSetting() self.deblend = DeblendDonutFactory.createDeblendDonut(deblendDonutType)
def __init__(self, camType, bscDbType, settingFileName="default.yaml"): """Initialize the source selector class. Parameters ---------- camType : enum 'CamType' Camera type. bscDbType : enum 'BscDbType' Bright star catalog (BSC) database type. settingFileName : str, optional Setting file name (the default is "default.yaml".) """ self.camera = CamFactory.createCam(camType) self.db = DatabaseFactory.createDb(bscDbType) self.filter = Filter() self.maxDistance = 0.0 self.maxNeighboringStar = 0 settingFilePath = os.path.join(getConfigDir(), settingFileName) self.settingFile = ParamReader(filePath=settingFilePath) # Configurate the criteria of neighboring stars starRadiusInPixel = self.settingFile.getSetting("starRadiusInPixel") spacingCoefficient = self.settingFile.getSetting("spacingCoef") maxNeighboringStar = self.settingFile.getSetting("maxNumOfNbrStar") self.configNbrCriteria(starRadiusInPixel, spacingCoefficient, maxNeighboringStar=maxNeighboringStar)
def __init__(self, camType, bscDbType, settingFileName="default.yaml"): """Initialize the source selector class. Parameters ---------- camType : enum 'CamType' Camera type. bscDbType : enum 'BscDbType' Bright star catalog (BSC) database type. settingFileName : str, optional Setting file name (the default is "default.yaml".) """ self.camera = CamFactory.createCam(camType) self.db = DatabaseFactory.createDb(bscDbType) self.filter = Filter() self.maxDistance = 0.0 self.maxNeighboringStar = 0 settingFilePath = os.path.join(getConfigDir(), settingFileName) self.settingFile = ParamReader(filePath=settingFilePath) # Configurate the criteria of neighboring stars starRadiusInPixel = self.settingFile.getSetting("starRadiusInPixel") spacingCoefficient = self.settingFile.getSetting("spacingCoef") maxNeighboringStar = self.settingFile.getSetting("maxNumOfNbrStar") self.configNbrCriteria(starRadiusInPixel, spacingCoefficient, maxNeighboringStar=maxNeighboringStar)
def setUp(self): self.instDir = os.path.join(getConfigDir(), "cwfs", "instData") self.inst = Instrument(self.instDir) self.dimOfDonutOnSensor = 120 self.inst.config(CamType.LsstCam, self.dimOfDonutOnSensor, announcedDefocalDisInMm=1.5)
def __init__(self): """Initialize the filter class.""" # Configuration file of the limit of star's magnitude pathMagLimitStar = os.path.join(getConfigDir(), "bsc", "magLimitStar.yaml") self._fileMagLimitStar = ParamReader(filePath=pathMagLimitStar) # Filter type in use self.filter = FilterType.U
def setUp(self): self.instDir = os.path.join(getConfigDir(), "cwfs", "instData") self.inst = Instrument(self.instDir) self.dimOfDonutOnSensor = 120 self.inst.config(CamType.LsstCam, self.dimOfDonutOnSensor, announcedDefocalDisInMm=1.5)
def __init__(self, sensorNameToIdFileName="sensorNameToId.yaml"): """Construct a MapSensorNameAndId object. Parameters ---------- sensorNameToIdFileName : str, optional Configuration file name to map sensor name and Id. (the default is "sensorNameToId.yaml".) """ sensorNameToIdFilePath = os.path.join(getConfigDir(), sensorNameToIdFileName) self._sensorNameToIdFile = ParamReader(filePath=sensorNameToIdFilePath)
def __init__(self, sensorNameToIdFileName="sensorNameToId.yaml"): """Construct a MapSensorNameAndId object. Parameters ---------- sensorNameToIdFileName : str, optional Configuration file name to map sensor name and Id. (the default is "sensorNameToId.yaml".) """ sensorNameToIdFilePath = os.path.join(getConfigDir(), sensorNameToIdFileName) self._sensorNameToIdFile = ParamReader(filePath=sensorNameToIdFilePath)
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 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 __init__(self, astWcsSol, camType, isrDir, settingFileName="default.yaml"): """Construct an WEP calculation object. Parameters ---------- astWcsSol : AstWcsSol AST world coordinate system (WCS) solution. camType : enum 'CamType' Camera type. isrDir : str Instrument signature remocal (ISR) directory. This directory will have the input and output that the data butler needs. settingFileName : str, optional Setting file name. (the default is "default.yaml".) """ super().__init__() # This attribute is just a stakeholder here since there is no detail of # AST WCS solution yet self.astWcsSol = astWcsSol # ISR directory that the data butler uses self.isrDir = isrDir # Number of processors for WEP to use # This is just a stakeholder at this moment self.numOfProc = 1 # Boresight infomation self.raInDeg = 0.0 self.decInDeg = 0.0 # Sky rotation angle self.rotSkyPos = 0.0 # Sky information file for the temporary use self.skyFile = "" # Default setting file settingFilePath = os.path.join(getConfigDir(), settingFileName) self.settingFile = ParamReader(filePath=settingFilePath) # Configure the WEP controller self.wepCntlr = self._configWepController(camType, settingFileName)
def testMakeMasks(self): donutStamp = DonutStamp( self.testStamps[0], lsst.geom.SpherePoint(0.0, 0.0, lsst.geom.degrees), lsst.geom.Point2D(2047.5, 2001.5), DefocalType.Extra.value, "R22_S11", "LSSTCam", ) # Set up instrument instDataPath = os.path.join(getConfigDir(), "cwfs", "instData") inst = Instrument(instDataPath) donutWidth = 126 inst.config(CamType.LsstCam, donutWidth) # Check that masks are empty at start np.testing.assert_array_equal(np.empty(shape=(0, 0)), donutStamp.mask_comp.getArray()) np.testing.assert_array_equal(np.empty(shape=(0, 0)), donutStamp.mask_pupil.getArray()) # Check masks after creation donutStamp.makeMasks(inst, "offAxis", 0, 1) self.assertEqual(afwImage.MaskX, type(donutStamp.mask_comp)) self.assertEqual(afwImage.MaskX, type(donutStamp.mask_pupil)) self.assertDictEqual({ "BKGRD": 0, "DONUT": 1 }, donutStamp.mask_comp.getMaskPlaneDict()) self.assertDictEqual({ "BKGRD": 0, "DONUT": 1 }, donutStamp.mask_pupil.getMaskPlaneDict()) maskC = donutStamp.mask_comp.getArray() maskP = donutStamp.mask_pupil.getArray() # Donut should match self.assertEqual(np.shape(maskC), (126, 126)) self.assertEqual(np.shape(maskP), (126, 126)) # Make sure not just an empty array self.assertTrue(np.sum(maskC) > 0.0) self.assertTrue(np.sum(maskP) > 0.0) # Donut at center of focal plane should be symmetric np.testing.assert_array_equal(maskC[:63], maskC[-63:][::-1]) np.testing.assert_array_equal(maskP[:63], maskP[-63:][::-1])
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 _configWfEstimator(self): cwfsConfigDir = os.path.join(getConfigDir(), "cwfs") instDir = os.path.join(cwfsConfigDir, "instData") algoDir = os.path.join(cwfsConfigDir, "algo") wfEsti = WfEstimator(instDir, algoDir) # Use the comcam to calculate the LSST central raft image # with 1.5 mm defocal distance wfEsti.config( solver="exp", camType=CamType.ComCam, opticalModel="offAxis", defocalDisInMm=1.5, sizeInPix=160, debugLevel=0, ) return wfEsti
def setUp(self): # Set the path of module and the setting directories modulePath = getModulePath() cwfsConfigDir = os.path.join(getConfigDir(), "cwfs") self.instFolder = os.path.join(cwfsConfigDir, "instData") self.algoFolderPath = os.path.join(cwfsConfigDir, "algo") self.imageFolderPath = os.path.join(modulePath, "tests", "testData", "testImages") # Set the tolerance self.tor = 3 # Restart time self.startTime = time.time() self.difference = 0 self.validationDir = os.path.join(modulePath, "tests", "testData", "testImages", "validation")
def setUp(self): # Set the path of module and the setting directories modulePath = getModulePath() cwfsConfigDir = os.path.join(getConfigDir(), "cwfs") self.instFolder = os.path.join(cwfsConfigDir, "instData") self.algoFolderPath = os.path.join(cwfsConfigDir, "algo") self.imageFolderPath = os.path.join(modulePath, "tests", "testData", "testImages") # Set the tolerance self.tor = 4 # Restart time self.startTime = time.time() self.difference = 0 self.validationDir = os.path.join(modulePath, "tests", "testData", "testImages", "validation", "simulation")
def __init__(self, astWcsSol, camType, isrDir, settingFileName="default.yaml"): """Construct an WEP calculation object. Parameters ---------- astWcsSol : AstWcsSol AST world coordinate system (WCS) solution. camType : enum 'CamType' Camera type. isrDir : str Instrument signature remocal (ISR) directory. This directory will have the input and output that the data butler needs. settingFileName : str, optional Setting file name. (the default is "default.yaml".) """ super().__init__() # This attribute is just a stakeholder here since there is no detail of # AST WCS solution yet self.astWcsSol = astWcsSol # ISR directory that the data butler uses self.isrDir = isrDir # Boresight infomation self.raInDeg = 0.0 self.decInDeg = 0.0 # Sky rotation angle self.rotSkyPos = 0.0 # Sky information file for the temporary use self.skyFile = "" # Default setting file settingFilePath = os.path.join(getConfigDir(), settingFileName) self.settingFile = ParamReader(filePath=settingFilePath) # Configure the WEP controller self.wepCntlr = self._configWepController(camType, settingFileName)
def setUp(self): cwfsConfigDir = os.path.join(getConfigDir(), "cwfs") instDir = os.path.join(cwfsConfigDir, "instData") algoDir = os.path.join(cwfsConfigDir, "algo") self.wfsEst = WfEstimator(instDir, algoDir) # Define the image folder and image names # It is noted that image.readFile inuts is based on the txt file. self.modulePath = getModulePath() 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" # Path to image files self.intraImgFile = os.path.join(imageFolderPath, intra_image_name) self.extraImgFile = os.path.join(imageFolderPath, extra_image_name) # Field XY position self.fieldXY = (1.185, 1.185)
def setUp(self): cwfsConfigDir = os.path.join(getConfigDir(), "cwfs") instDir = os.path.join(cwfsConfigDir, "instData") algoDir = os.path.join(cwfsConfigDir, "algo") self.wfsEst = WfEstimator(instDir, algoDir) # Define the image folder and image names # It is noted that image.readFile inuts is based on the txt file. self.modulePath = getModulePath() 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" # Path to image files self.intraImgFile = os.path.join(imageFolderPath, intra_image_name) self.extraImgFile = os.path.join(imageFolderPath, extra_image_name) # Field XY position self.fieldXY = (1.185, 1.185)
def _configWfEstimator(self, camType): """Configure the wavefront estimator. Returns ------- WfEstimator Configured wavefront estimator. """ configDir = getConfigDir() instDir = os.path.join(configDir, "cwfs", "instData") algoDir = os.path.join(configDir, "cwfs", "algo") wfsEsti = WfEstimator(instDir, algoDir) solver = self.settingFile.getSetting("poissonSolver") opticalModel = self.settingFile.getSetting("opticalModel") defocalDisInMm = self.settingFile.getSetting("dofocalDistInMm") donutImgSizeInPixel = self.settingFile.getSetting("donutImgSizeInPixel") wfsEsti.config(solver=solver, camType=camType, opticalModel=opticalModel, defocalDisInMm=defocalDisInMm, sizeInPix=donutImgSizeInPixel) return wfsEsti
def makeTemplate(self, sensorName, defocalType, imageSize): """ Make the donut template image from phosim templates. The templates should have been created using code located in the `ts_phosim` repository under `bin.src/runCreatePhosimDonutTemplates.py`. The template files should then be stored here in `ts_wep` in `policy/cwfs/donutTemplateData/phosimTemplates`. See the `ts_wep` docs for more information or see `ts_phosim` docs for instructions on creating templates. Parameters ---------- sensorName : str The camera detector for which we want to make a template. Should be in "Rxx_Sxx" format. defocalType : enum 'DefocalType' The defocal state of the sensor. imageSize : int Size of template in pixels. The template will be a square. Returns ------- numpy.ndarray [int] The donut template as a binary image. """ configDir = getConfigDir() phosimTemplateDir = os.path.join(configDir, "cwfs", "donutTemplateData", "phosimTemplates") if defocalType == DefocalType.Extra: templateFilename = os.path.join( phosimTemplateDir, "extra_template-%s.txt" % sensorName) else: templateFilename = os.path.join( phosimTemplateDir, "intra_template-%s.txt" % sensorName) templateArray = np.genfromtxt(templateFilename, dtype=int) # Make the template the desired square shape by trimming edges of # template # Phosim templates from file are already a square templateSize = np.shape(templateArray)[0] if templateSize >= imageSize: # Find the excess number of pixels in x and y direction templateTrim = templateSize - imageSize # Find the left and right edges by trimming half pixels from # left and right. # Do the same for the top and bottom. leftEdge = topEdge = int(templateTrim / 2) rightEdge = bottomEdge = int(templateSize - (templateTrim - leftEdge)) templateFinal = templateArray[leftEdge:rightEdge, topEdge:bottomEdge] else: # If requesting a larger template than the phosim template # add padding of zeros to edges of template returned templatePad = imageSize - templateSize # Pad each side by equal amount of pixels padLeft = padTop = int(templatePad / 2) padRight = padBottom = int(imageSize - (templatePad - padLeft)) templateFinal = np.zeros((imageSize, imageSize)) templateFinal[padLeft:padRight, padTop:padBottom] = templateArray return templateFinal
def estimateZernikes(self, donutStampsExtra, donutStampsIntra): """ Take the donut postage stamps and estimate the Zernike coefficients. Parameters ---------- donutStampsExtra: DonutStamps Extra-focal donut postage stamps. donutStampsIntra: DonutStamps Intra-focal donut postage stamps. Returns ------- numpy.ndarray Zernike coefficients for the exposure. Will return one set of coefficients per set of stamps, not one set of coefficients per detector so this will be a 2-D numpy array with the number of rows equal to the number of donut stamps and the number of columns equal to the number of Zernike coefficients. """ zerArray = [] configDir = getConfigDir() instDir = os.path.join(configDir, "cwfs", "instData") algoDir = os.path.join(configDir, "cwfs", "algo") wfEsti = WfEstimator(instDir, algoDir) camType = getCamType(self.instName) defocalDisInMm = getDefocalDisInMm(self.instName) wfEsti.config( sizeInPix=self.donutStampSize, camType=camType, opticalModel=self.opticalModel, defocalDisInMm=defocalDisInMm, ) for donutExtra, donutIntra in zip(donutStampsExtra, donutStampsIntra): # Transpose field XY because CompensableImages below are transposed # so this gets the correct mask orientation in Algorithm.py fieldXYExtra = donutExtra.calcFieldXY()[::-1] fieldXYIntra = donutIntra.calcFieldXY()[::-1] camera = donutExtra.getCamera() detectorExtra = camera.get(donutExtra.detector_name) detectorIntra = camera.get(donutIntra.detector_name) # Rotate any sensors that are not lined up with the focal plane. # Mostly just for the corner wavefront sensors. The negative sign # creates the correct rotation based upon closed loop tests # with R04 and R40 corner sensors. eulerZExtra = -detectorExtra.getOrientation().getYaw().asDegrees() eulerZIntra = -detectorIntra.getOrientation().getYaw().asDegrees() # NOTE: TS_WEP expects these images to be transposed # TODO: Look into this wfEsti.setImg( fieldXYExtra, DefocalType.Extra, image=rotate(donutExtra.stamp_im.getImage().getArray(), eulerZExtra).T, ) wfEsti.setImg( fieldXYIntra, DefocalType.Intra, image=rotate(donutIntra.stamp_im.getImage().getArray(), eulerZIntra).T, ) wfEsti.reset() zer4UpNm = wfEsti.calWfsErr() zer4UpMicrons = zer4UpNm * 1e-3 zerArray.append(zer4UpMicrons) return np.array(zerArray)
def makeTemplate( self, sensorName, defocalType, imageSize, camType=CamType.LsstCam, opticalModel="offAxis", pixelScale=0.2, ): """Make the donut template image. Parameters ---------- sensorName : str The camera detector for which we want to make a template. Should be in "Rxx_Sxx" format. defocalType : enum 'DefocalType' The defocal state of the sensor. imageSize : int Size of template in pixels. The template will be a square. camType : enum 'CamType', optional Camera type. (Default is CamType.LsstCam) model : str, optional Optical model. It can be "paraxial", "onAxis", or "offAxis". (The default is "offAxis") pixelScale : float, optional The pixels to arcseconds conversion factor. (The default is 0.2) Returns ------- numpy.ndarray [int] The donut template as a binary image. """ configDir = getConfigDir() focalPlaneLayout = readPhoSimSettingData(configDir, "focalplanelayout.txt", "fieldCenter") pixelSizeInUm = float(focalPlaneLayout[sensorName][2]) sizeXinPixel = int(focalPlaneLayout[sensorName][3]) sensorXMicron, sensorYMicron = np.array( focalPlaneLayout[sensorName][:2], dtype=float) # Correction for wavefront sensors if sensorName in ("R44_S00_C0", "R00_S22_C1"): # Shift center to +x direction sensorXMicron = sensorXMicron + sizeXinPixel / 2 * pixelSizeInUm elif sensorName in ("R44_S00_C1", "R00_S22_C0"): # Shift center to -x direction sensorXMicron = sensorXMicron - sizeXinPixel / 2 * pixelSizeInUm elif sensorName in ("R04_S20_C1", "R40_S02_C0"): # Shift center to -y direction sensorYMicron = sensorYMicron - sizeXinPixel / 2 * pixelSizeInUm elif sensorName in ("R04_S20_C0", "R40_S02_C1"): # Shift center to +y direction sensorYMicron = sensorYMicron + sizeXinPixel / 2 * pixelSizeInUm # Load Instrument parameters instDir = os.path.join(configDir, "cwfs", "instData") inst = Instrument(instDir) inst.config(camType, imageSize) # Create image for mask img = CompensableImage() # Convert pixel locations to degrees sensorXPixel = float(sensorXMicron) / pixelSizeInUm sensorYPixel = float(sensorYMicron) / pixelSizeInUm # Multiply by pixelScale then divide by 3600 for arcsec -> deg conversion sensorXDeg = sensorXPixel * pixelScale / 3600 sensorYDeg = sensorYPixel * pixelScale / 3600 fieldXY = [sensorXDeg, sensorYDeg] # Define position of donut at center of current sensor in degrees boundaryT = 0 maskScalingFactorLocal = 1 img.setImg(fieldXY, defocalType, image=np.zeros((imageSize, imageSize))) img.makeMask(inst, opticalModel, boundaryT, maskScalingFactorLocal) return img.getNonPaddedMask()
def calcWfErr( self, centroidFindType, fieldXY, camType, algoName, announcedDefocalDisInMm, opticalModel, imageIntra=None, imageExtra=None, imageFileIntra=None, imageFileExtra=None, ): """Calculate the wavefront error. Parameters ---------- centroidFindType : enum 'CentroidFindType' Algorithm to find the centroid of donut. fieldXY : tuple or list Position of donut on the focal plane in degree (field x, field y). camType : enum 'CamType' Camera type. algoName : str Algorithm configuration file to solve the Poisson's equation in the transport of intensity equation (TIE). It can be "fft" or "exp" here. announcedDefocalDisInMm : float Announced defocal distance in mm. It is noted that the defocal distance offset used in calculation might be different from this value. opticalModel : str Optical model. It can be "paraxial", "onAxis", or "offAxis". imageIntra : numpy.ndarray, optional Array of intra-focal image. (the default is None.) imageExtra : numpy.ndarray, optional Array of extra-focal image. (the default is None.) imageFileIntra : str, optional Path of intra-focal image file. (the default is None.) imageFileExtra : str, optional Path of extra-focal image file. (the default is None.) Returns ------- numpy.ndarray Zernike polynomials of z4-zn in nm. """ # Set the defocal images imgIntra = CompensableImage(centroidFindType=centroidFindType) imgExtra = CompensableImage(centroidFindType=centroidFindType) imgIntra.setImg( fieldXY, DefocalType.Intra, image=imageIntra, imageFile=imageFileIntra ) imgExtra.setImg( fieldXY, DefocalType.Extra, image=imageExtra, imageFile=imageFileExtra ) # Set the instrument instDir = os.path.join(getConfigDir(), "cwfs", "instData") inst = Instrument(instDir) inst.config( camType, imgIntra.getImgSizeInPix(), announcedDefocalDisInMm=announcedDefocalDisInMm, ) # Define the algorithm to be used. algoFolderPath = os.path.join(getConfigDir(), "cwfs", "algo") algo = Algorithm(algoFolderPath) algo.config(algoName, inst, debugLevel=0) # Run it algo.runIt(imgIntra, imgExtra, opticalModel, tol=1e-3) # Return the Zernikes Zn (n>=4) return algo.getZer4UpInNm()
def testGetConfigDir(self): ansConfigDir = os.path.join(getModulePath(), "policy") self.assertEqual(getConfigDir(), ansConfigDir)
def testGetConfigDir(self): ansConfigDir = os.path.join(getModulePath(), "policy") self.assertEqual(getConfigDir(), ansConfigDir)
def makeTemplate( self, sensorName, defocalType, imageSize, camType=CamType.LsstCam, opticalModel="offAxis", pixelScale=0.2, ): """Make the donut template image. Parameters ---------- sensorName : str The camera detector for which we want to make a template. Should be in "Rxx_Sxx" format. defocalType : enum 'DefocalType' The defocal state of the sensor. imageSize : int Size of template in pixels. The template will be a square. camType : enum 'CamType', optional Camera type. (The default is CamType.LsstCam) opticalModel : str, optional Optical model. It can be "paraxial", "onAxis", or "offAxis". (The default is "offAxis") pixelScale : float, optional The pixels to arcseconds conversion factor. (The default is 0.2) Returns ------- numpy.ndarray [int] The donut template as a binary image. Raises ------ ValueError Camera type is not supported. """ configDir = getConfigDir() # Load Instrument parameters instDir = os.path.join(configDir, "cwfs", "instData") inst = Instrument(instDir) if camType in (CamType.LsstCam, CamType.LsstFamCam, CamType.ComCam): inst.config(camType, imageSize) focalPlaneLayout = readPhoSimSettingData(configDir, "focalplanelayout.txt", "fieldCenter") pixelSizeInUm = float(focalPlaneLayout[sensorName][2]) sensorXMicron, sensorYMicron = np.array( focalPlaneLayout[sensorName][:2], dtype=float) elif camType == CamType.AuxTel: # AuxTel only works with onAxis sources if opticalModel != "onAxis": raise ValueError( str(f"Optical Model {opticalModel} not supported with AuxTel. " + "Must use 'onAxis'.")) # Defocal distance for Latiss in mm # for LsstCam can use the default # hence only need to set here announcedDefocalDisInMm = getDefocalDisInMm("auxTel") inst.config(camType, imageSize, announcedDefocalDisInMm) # load the info for auxTel pixelSizeInMeters = inst.getCamPixelSize() # pixel size in meters. pixelSizeInUm = pixelSizeInMeters * 1e6 camera = obs_lsst.Latiss.getCamera() sensorName = list( camera.getNameIter())[0] # only one detector in latiss detector = camera.get(sensorName) xp, yp = detector.getCenter( cameraGeom.FOCAL_PLANE) # center of CCD in mm # multiply by 1000 to for mm --> microns conversion sensorXMicron = yp * 1000 sensorYMicron = xp * 1000 else: raise ValueError("Camera type (%s) is not supported." % camType) # Create image for mask img = CompensableImage() # Convert pixel locations to degrees sensorXPixel = float(sensorXMicron) / pixelSizeInUm sensorYPixel = float(sensorYMicron) / pixelSizeInUm # Multiply by pixelScale then divide by 3600 for arcsec->deg conversion sensorXDeg = sensorXPixel * pixelScale / 3600 sensorYDeg = sensorYPixel * pixelScale / 3600 fieldXY = [sensorXDeg, sensorYDeg] # Define position of donut at center of current sensor in degrees boundaryT = 0 maskScalingFactorLocal = 1 img.setImg(fieldXY, defocalType, image=np.zeros((imageSize, imageSize))) img.makeMask(inst, opticalModel, boundaryT, maskScalingFactorLocal) return img.getNonPaddedMask()