def addFieldXYbyCamPos(self, sensorName, xInpixel, yInPixel, folderPath2FocalPlane): """Add the new field X, Y in degree by the camera pixel positions. Parameters ---------- sensorName : str Canera sensor name (e.g. "R22_S11", "R40_S02_C0"). xInpixel : float Pixel x on camera coordinate. yInPixel : float Pixel y on camera coordinate. folderPath2FocalPlane : str Path to the directory of focal plane data ("focalplanelayout.txt"). """ # Get the focal plane data and set the sensor name sourProc = SourceProcessor() sourProc.config(sensorName=sensorName) # Do the coordinate transformation fieldXInDegree, fieldYInDegree = sourProc.camXYtoFieldXY(xInpixel, yInPixel) # Add to listed field x, y self.addFieldXYbyDeg(fieldXInDegree, fieldYInDegree)
def setUp(self): # Get the path of module self.modulePath = getModulePath() # Set the source processor self.sourProc = SourceProcessor() # Set the configuration self.sourProc.config(sensorName="R00_S22_C0")
def __init__(self): """Initialization of sky simulator class.""" self.starId = np.array([], dtype=int) self.ra = np.array([]) self.decl = np.array([]) self.mag = np.array([]) self._camera = LsstSimMapper().camera self._obs = ObservationMetaData() self._sourProc = SourceProcessor()
def setUp(self): # Get the path of module self.modulePath = getModulePath() # CCD focal plane file focalPlaneFolder = os.path.join(self.modulePath, "tests", "testData") # Set the source processor self.sourProc = SourceProcessor() # Set the configuration self.sourProc.config(sensorName="R00_S22_C0", folderPath2FocalPlane=focalPlaneFolder)
def _configSourceProcessor(self): folderPath2FocalPlane = os.path.join(self.modulePath, "tests", "testData") sourProc = SourceProcessor(folderPath2FocalPlane=folderPath2FocalPlane) return sourProc
def _configWepController(self, camType, settingFileName): """Configure the WEP controller. WEP: wavefront estimation pipeline. Parameters ---------- camType : enum 'CamType' Camera type. settingFileName : str Setting file name. Returns ------- WepController Configured WEP controller. """ dataCollector = CamDataCollector(self.isrDir) isrWrapper = CamIsrWrapper(self.isrDir) bscDbType = self._getBscDbType() sourSelc = self._configSourceSelector(camType, bscDbType, settingFileName) sourProc = SourceProcessor(settingFileName=settingFileName) wfsEsti = self._configWfEstimator(camType) wepCntlr = WepController(dataCollector, isrWrapper, sourSelc, sourProc, wfsEsti) return wepCntlr
def setUp(self): self.modulePath = getModulePath() testDir = os.path.join(self.modulePath, "tests") self.dataDir = tempfile.TemporaryDirectory(dir=testDir) self.butlerInput = tempfile.TemporaryDirectory(dir=self.dataDir.name) self.opdDir = os.path.join( self.modulePath, "tests", "testData", "opdOutput", "9005000" ) # Configurate the WEP components dataCollector = CamDataCollector(self.butlerInput.name) sourSelc = self._configSourceSelector() sourProc = SourceProcessor() wfEsti = self._configWfEstimator() # Instantiate the WEP controller self.wepCntlr = WepController(dataCollector, None, sourSelc, sourProc, wfEsti) # Intemediate data used in the test self.filter = FilterType.REF self.neighborStarMap = dict() self.starMap = dict() self.wavefrontSensors = dict() self.wfsImgMap = dict() self.donutMap = dict() self.masterDonutMap = dict()
def getCornOfChipOnSky(self, camera, obs, sensorName, folderPath2FocalPlane, epoch=2000.0, includeDistortion=True): """ Get the corner points of chip on sky position in (ra, dec). The direction is counter clockwise from the origin. Arguments: camera {[Camera]} -- Camera object (e.g. LsstSimMapper().camera). obs {[ObservationMetaData]} -- Observation metadata object. sensorName {[str]} -- Abbreviated sensor name (e.g. "R22_S11"). folderPath2FocalPlane {[str]} -- Path to the directory of focal plane data ("focalplanelayout.txt"). Keyword Arguments: epoch {float} -- Epoch is the mean epoch in years of the celestial coordinate system. (default: {2000.0}) includeDistortion {bool} -- If True (default), then this method will expect the true pixel coordinates with optical distortion included. If False, this method will expect TAN_PIXEL coordinates, which are the pixel coordinates with estimated optical distortion removed. See the documentation in afw.cameraGeom for more details. (default: {True}) Returns: [list] -- List of corner points in tuple. The unit is in (ra, dec). """ # Get the sensor dimension sourProc = SourceProcessor() sourProc.config(folderPath2FocalPlane=folderPath2FocalPlane) dimX, dimY = sourProc.sensorDimList[sensorName] # Corner in Pixel xInPixel = [0, dimX, dimX, 0] yInPixel = [0, 0, dimY, dimY] # Corner in (Ra, Dec) cornerInRaDecList = [] for ii in range(4): raInDeg, declInDeg = self.__getSkyPosByChipPos(camera, obs, sensorName, xInPixel[ii], yInPixel[ii], folderPath2FocalPlane, epoch=epoch, includeDistortion=includeDistortion) cornerInRaDecList.append((raInDeg, declInDeg)) return cornerInRaDecList
def showFieldMap(fieldX=None, fieldY=None, saveToFilePath=None, dpi=None): """Show the field map in degree. Parameters ---------- fieldX : numpy.ndarray, optional Field x in degree. (the default is None.) fieldY : numpy.ndarray, optional Field y in degree. (the default is None.) saveToFilePath : str, optional File path to save the figure. (the default is None.) dpi : int, optional The resolution in dots per inch. (the default is None.) """ # Declare the figure plt.figure() # Get the focal plane information sourProc = SourceProcessor() # Plot the CCD boundary for sensorName in sourProc.sensorDimList.keys(): # Get the CCD corner field points in degree pointXinDeg, pointYinDeg = _getCCDBoundInDeg(sourProc, sensorName) # Plot the boundary pointXinDeg.append(pointXinDeg[0]) pointYinDeg.append(pointYinDeg[0]) plt.plot(pointXinDeg, pointYinDeg, "b") # Plot the field X, Y position if (fieldX is not None) and (fieldY is not None): plt.plot(fieldX, fieldY, "ro") # Plot the 3.5 degree circle circle = plt.Circle((0, 0), 1.75, color="g", fill=False) plt.gcf().gca().add_artist(circle) # Do the labeling plt.xlabel("Field X (deg)") plt.ylabel("Field Y (deg)") # Label four corner rafts for the identification plt.text(-1.5, -1.5, "R00") plt.text(1.5, -1.5, "R40") plt.text(1.5, 1.5, "R44") plt.text(-1.5, 1.5, "R04") # Set the axis limit plt.xlim(-2, 2) plt.ylim(-2, 2) # Set the same scale plt.axis("equal") _saveFig(plt, saveToFilePath=saveToFilePath, dpi=dpi)
def __getSkyPosByChipPos(self, camera, obs, sensorName, xInpixelInCam, yInPixelInCam, folderPath2FocalPlane, epoch=2000.0, includeDistortion=True): """ Get the sky position in (ra, dec) based on the chip pixel positions. Arguments: camera {[Camera]} -- Camera object (e.g. LsstSimMapper().camera). obs {[ObservationMetaData]} -- Observation metadata object. sensorName {[str]} -- Abbreviated sensor name (e.g. "R22_S11"). xInpixelInCam {[float]} -- Pixel position x on camera coordinate. yInPixelInCam {[float]} -- Pixel position y on camera coordinate. folderPath2FocalPlane {[str]} -- Path to the directory of focal plane data ("focalplanelayout.txt"). Keyword Arguments: epoch {float} -- Epoch is the mean epoch in years of the celestial coordinate system. (default: {2000.0}) includeDistortion {bool} -- If True (default), then this method will expect the true pixel coordinates with optical distortion included. If False, this method will expect TAN_PIXEL coordinates, which are the pixel coordinates with estimated optical distortion removed. See the documentation in afw.cameraGeom for more details. (default: {True}) Returns: [float] -- Ra in degree. [float] -- Decl in degree. """ # Get the pixel positions in DM team sourProc = SourceProcessor() sourProc.config(sensorName=sensorName, folderPath2FocalPlane=folderPath2FocalPlane) pixelDmX, pixelDmY = sourProc.camXY2DmXY(xInpixelInCam, yInPixelInCam) # Expend the sensor name expendedSensorName = expandDetectorName(sensorName) # Get the sky position in (ra, decl) raInDeg, declInDeg = raDecFromPixelCoords(pixelDmX, pixelDmY, expendedSensorName, camera=camera, obs_metadata=obs, epoch=epoch, includeDistortion=includeDistortion) return raInDeg, declInDeg
def _configSourceProcessor(self): """Configure the source processor. Returns ------- SourceProcessor Configured source processor. """ folderPath2FocalPlane = os.path.join(getModulePath(), "tests", "testData") sourProc = SourceProcessor(folderPath2FocalPlane=folderPath2FocalPlane) return sourProc
def __init__(self): """Initialization of sky simulator class.""" # Star ID self.starId = np.array([], dtype=int) # Star RA self.ra = np.array([]) # Star Decl self.decl = np.array([]) # Star magnitude self.mag = np.array([]) # DM camera object contains the information to do the coordinate # transformation self._camera = LsstSimMapper().camera # SIMS observation metadata object self._obs = ObservationMetaData() # Source processor in ts_wep self._sourProc = SourceProcessor()
# (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. import os import numpy as np from lsst.ts.wep.Utility import getModulePath from lsst.ts.wep.SourceProcessor import SourceProcessor if __name__ == "__main__": # Set the 189 field points fieldPosFilePath = os.path.join(getModulePath(), "examples", "fieldPosLsst.txt") fieldXY = np.loadtxt(fieldPosFilePath) # Do the mapping sourPro = SourceProcessor() mapping = sourPro.mapSensorAndFieldIdx(fieldXY) # Print the mapping for sensorName, idxField in mapping.items(): print(sensorName, idxField)
class TestSourceProcessor(unittest.TestCase): """Test the source processor class.""" def setUp(self): # Get the path of module self.modulePath = getModulePath() # Set the source processor self.sourProc = SourceProcessor() # Set the configuration self.sourProc.config(sensorName="R00_S22_C0") def testInit(self): self.assertEqual(self.sourProc.sensorName, "R00_S22_C0") self.assertEqual(len(self.sourProc.sensorDimList), 205) self.assertEqual(len(self.sourProc.sensorEulerRot), 205) self.assertEqual(len(self.sourProc.sensorFocaPlaneInDeg), 205) self.assertEqual(len(self.sourProc.sensorFocaPlaneInUm), 205) self.assertEqual(self.sourProc.sensorDimList["R00_S22_C0"], (2000, 4072)) self.assertEqual(self.sourProc.sensorDimList["R22_S11"], (4000, 4072)) self.assertEqual(self.sourProc.sensorFocaPlaneInDeg["R22_S11"], (0, 0)) self.assertNotEqual(self.sourProc.sensorFocaPlaneInDeg["R00_S22_C0"], self.sourProc.sensorFocaPlaneInDeg["R00_S22_C1"]) def testConfig(self): sensorName = "sensorName" self.sourProc.config(sensorName=sensorName) self.assertEqual(self.sourProc.sensorName, sensorName) def testGetEulerZinDeg(self): wfsSensorName = "R40_S02_C1" eulerZ = self.sourProc.getEulerZinDeg(wfsSensorName) self.assertEqual(eulerZ, 90.004585) def testCamXYtoFieldXY(self): pixelX = 1000 pixelY = 2036 fieldX, fieldY = self.sourProc.camXYtoFieldXY(pixelX, pixelY) ansFieldX, ansFieldY = \ self.sourProc.sensorFocaPlaneInDeg[self.sourProc.sensorName] self.assertEqual(fieldX, ansFieldX) self.assertEqual(fieldY, ansFieldY) def testCamXYtoFieldXYforWfs(self): oxR00S22C0, oyR00S22C0 = self._camXYtoFieldXY("R00_S22_C0", 0, 0) oxR00S22C1, oyR00S22C1 = self._camXYtoFieldXY("R00_S22_C1", 0, 0) oxR40S02C0, oyR40S02C0 = self._camXYtoFieldXY("R40_S02_C0", 0, 0) oxR40S02C1, oyR40S02C1 = self._camXYtoFieldXY("R40_S02_C1", 0, 0) oxR44S00C0, oyR44S00C0 = self._camXYtoFieldXY("R44_S00_C0", 0, 0) oxR44S00C1, oyR44S00C1 = self._camXYtoFieldXY("R44_S00_C1", 0, 0) oxR04S20C0, oyR04S20C0 = self._camXYtoFieldXY("R04_S20_C0", 0, 0) oxR04S20C1, oyR04S20C1 = self._camXYtoFieldXY("R04_S20_C1", 0, 0) # Compare with the same RXX_SYY self.assertEqual(oyR00S22C0, oyR00S22C1) self.assertEqual(oxR40S02C0, oxR40S02C1) self.assertEqual(oyR44S00C0, oyR44S00C1) self.assertEqual(oxR04S20C0, oxR04S20C1) # Campare with different RXX_SYY self.assertEqual((oxR00S22C0 + oxR44S00C0, oyR00S22C0 + oyR44S00C0), (0, 0)) self.assertEqual((oxR40S02C1 + oxR04S20C1, oyR40S02C1 + oyR04S20C1), (0, 0)) def _camXYtoFieldXY(self, sensorName, pixelX, pixelY): self.sourProc.config(sensorName=sensorName) fieldX, fieldY = self.sourProc.camXYtoFieldXY(pixelX, pixelY) return fieldX, fieldY def testDmXY2CamXY(self): self.sourProc.config(sensorName="R22_S11") self.assertEqual(self.sourProc.dmXY2CamXY(4070, 1000), (3000, 4070)) def testCamXY2DmXY(self): self.sourProc.config(sensorName="R22_S11") self.assertEqual(self.sourProc.camXY2DmXY(3000, 4070), (4070, 1000)) def testIsVignette(self): isVignette = self.sourProc.isVignette(1.76, 0) self.assertTrue(isVignette) noVignette = self.sourProc.isVignette(0.2, 0.2) self.assertFalse(noVignette) def testSimulateImg(self): ccdImgIntra, ccdImgExtra = self._simulateImg() self.assertEqual(ccdImgIntra.shape, (4072, 2000)) self.assertNotEqual(np.sum(np.abs(ccdImgIntra)), 0) def _simulateImg(self): imageFolderPath = os.path.join(self.modulePath, "tests", "testData", "testImages", "LSST_C_SN26") defocalDis = 0.25 nbrStar = self._generateNbrStar() ccdImgIntra, ccdImgExtra = self.sourProc.simulateImg( imageFolderPath, defocalDis, nbrStar, FilterType.REF, noiseRatio=0) return ccdImgIntra, ccdImgExtra def _generateNbrStar(self): nbrStar = NbrStar() nbrStar.starId = {523572575: [], 523572679: [523572671]} nbrStar.lsstMagG = {523572575: 14.66652, 523572671: 16.00000, 523572679: 13.25217} nbrStar.raDeclInPixel = {523572679: (3966.44, 1022.91), 523572671: (3968.77, 1081.02), 523572575: (3475.48, 479.33)} return nbrStar def testGetSingleTargetImage(self): sglSciNeiImg, allStarPosX, allStarPosY, magRatio, offsetX, offsetY = \ self._getSingleTargetImage() self.assertEqual(sglSciNeiImg.shape, (310, 310)) self.assertAlmostEqual(allStarPosX[0], 126.98) self.assertAlmostEqual(allStarPosX[1], 185.09) self.assertAlmostEqual(allStarPosY[0], 206.77) self.assertAlmostEqual(allStarPosY[1], 204.44) self.assertAlmostEqual(magRatio[0], 0.07959174) self.assertEqual(magRatio[1], 1) self.assertEqual(offsetX, 792.0) self.assertEqual(offsetY, 3762.0) def _getSingleTargetImage(self): nbrStar = self._generateNbrStar() ccdImgIntra, ccdImgExtra = self._simulateImg() starIndex = list(nbrStar.getId()).index(523572679) sglSciNeiImg, allStarPosX, allStarPosY, magRatio, offsetX, offsetY = \ self.sourProc.getSingleTargetImage(ccdImgIntra, nbrStar, starIndex, FilterType.REF) return sglSciNeiImg, allStarPosX, allStarPosY, magRatio, offsetX, offsetY def testDoDeblending(self): sglSciNeiImg, allStarPosX, allStarPosY, magRatio, offsetX, offsetY = \ self._getSingleTargetImage() imgDeblend, realcx, realcy = self.sourProc.doDeblending( sglSciNeiImg, allStarPosX, allStarPosY, magRatio) self.assertEqual(imgDeblend.shape, (310, 310)) self.assertLess(np.abs(realcx-184.49), 3) self.assertLess(np.abs(realcy-205.00), 3) # Get the real camera position x, y after the deblending realCameraX = realcx + offsetX realCameraY = realcy + offsetY # Compared with DM prediction nbrStar = self._generateNbrStar() raDeclInPixel = nbrStar.getRaDeclInPixel() camX, camY = self.sourProc.dmXY2CamXY(raDeclInPixel[523572679][0], raDeclInPixel[523572679][1]) delta = np.sqrt((realCameraX-camX)**2 + (realCameraY-camY)**2) self.assertLess(delta, 10)
# but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. import numpy as np from lsst.ts.wep.SourceProcessor import SourceProcessor if __name__ == "__main__": # Configurate the source processor sourPro = SourceProcessor() # Get the list of sensor name and coordinate sensorFocaPlaneInDeg = sourPro.sensorFocaPlaneInDeg nameList = [] xList = [] yList = [] for aKey, aItem in sensorFocaPlaneInDeg.items(): nameList.append(aKey) xList.append(aItem[0]) yList.append(aItem[1]) xySensor = np.array([xList, yList]).T # Set the 35 field points
def showFieldMap(self, folderPath2FocalPlane=None, saveToFilePath=None, dpi=None, pixel2Arcsec=0.2): """ Show the field map in degree. Keyword Arguments: folderPath2FocalPlane {[str]} -- Folder directory to focal plane file. (default: {None}) saveToFilePath {str} -- File path to save the figure. (default: {None}) dpi {int} -- The resolution in dots per inch. (default: {None}) pixel2Arcsec {float} -- Pixel to arcsec. (default: {0.2}) """ # Declare the figure plt.figure() # Get the focal plane information if (folderPath2FocalPlane is not None): sourProc = SourceProcessor() sourProc.config(folderPath2FocalPlane=folderPath2FocalPlane) # Plot the CCD boundary for sensorName in sourProc.sensorDimList.keys(): # Get the CCD corner field points in degree pointXinDeg, pointYinDeg = self.__getCCDBoundInDeg( sourProc, sensorName, pixel2Arcsec=pixel2Arcsec) # Plot the boundary pointXinDeg.append(pointXinDeg[0]) pointYinDeg.append(pointYinDeg[0]) plt.plot(pointXinDeg, pointYinDeg, "b") # Plot the field X, Y position plt.plot(self.fieldX, self.fieldY, "ro") # Plot the 3.5 degree circle circle = plt.Circle((0, 0), 1.75, color="g", fill=False) plt.gcf().gca().add_artist(circle) # Do the labeling plt.xlabel("Field X (deg)") plt.ylabel("Field Y (deg)") # Label four corner rafts for the identification plt.text(-1.5, -1.5, "R00") plt.text(1.5, -1.5, "R40") plt.text(1.5, 1.5, "R44") plt.text(-1.5, 1.5, "R04") # Set the axis limit plt.xlim(-2, 2) plt.ylim(-2, 2) # Set the same scale plt.axis("equal") # Save the figure or not if (saveToFilePath is not None): plt.savefig(saveToFilePath, dpi=dpi) plt.close() else: plt.show()
class SkySim(object): def __init__(self): """Initialization of sky simulator class.""" self.starId = np.array([], dtype=int) self.ra = np.array([]) self.decl = np.array([]) self.mag = np.array([]) self._camera = LsstSimMapper().camera self._obs = ObservationMetaData() self._sourProc = SourceProcessor() def setCamera(self, camera): """Set the camera object. Parameters ---------- camera : Camera A collection of Detectors that also supports coordinate transformation """ self._camera = camera def setObservationMetaData(self, ra, decl, rotSkyPos, mjd): """Set the observation meta data. Parameters ---------- ra : float Pointing ra in degree. decl : float Pointing decl in degree. rotSkyPos : float The orientation of the telescope in degrees. mjd : float Camera MJD. """ self._obs = ObservationMetaData(pointingRA=ra, pointingDec=decl, rotSkyPos=rotSkyPos, mjd=mjd) def setFolderPath2FocalPlane(self, folderPath2FocalPlane): """Set the folder path to focal plane data. Parameters ---------- folderPath2FocalPlane : str Folder path to focal plane data. """ self._sourProc.config(folderPath2FocalPlane=folderPath2FocalPlane) def addStarByRaDecInDeg(self, starId, raInDeg, declInDeg, mag): """Add the star information by (ra, dec) in degrees. Parameters ---------- starId : int, list[int], or numpy.ndarray[int] Star Id. raInDeg : float, list, or numpy.ndarray Star ra in degree. declInDeg : float, list, or numpy.ndarray Star decl in degree. mag : float, list, or numpy.ndarray Star magnitude. """ # Check the inputs are list or not, and change the type if necessary starIdList = self._changeToListIfNecessary(starId) raInDegList = self._changeToListIfNecessary(raInDeg) declInDegList = self._changeToListIfNecessary(declInDeg) magList = self._changeToListIfNecessary(mag) # Add the stars for ii in range(len(starIdList)): intStarId = int(starIdList[ii]) if (self._isUniqStarId(intStarId)): self.starId = np.append(self.starId, intStarId) self.ra = np.append(self.ra, raInDegList[ii]) self.decl = np.append(self.decl, declInDegList[ii]) self.mag = np.append(self.mag, magList[ii]) def _changeToListIfNecessary(self, variable): """Change the data type to list. Parameters ---------- variable : int, float, list, or numpy.ndarray Variable. Returns ------- list Variable as the list. """ if isinstance(variable, (int, float)): return [variable] else: return variable def _isUniqStarId(self, starId): """Check the star ID is unique or not. Parameters ---------- starId : int Star Id. Returns ------- bool True if the unique Id. """ if starId in self.starId: isUnique = False print("StarId=%d is not unique." % starId) else: isUnique = True return isUnique def resetSky(self): """Reset the sky information and delete all existed stars.""" self.__init__() def setStarRaDecInDeg(self, starId, raInDeg, declInDeg, mag): """Set the star information by (ra, dec) in degrees. Parameters ---------- starId : int, list[int], or numpy.ndarray[int] Star Id. raInDeg : float, list, or numpy.ndarray Star ra in degree. declInDeg : float, list, or numpy.ndarray Star decl in degree. mag : float, list, or numpy.ndarray Star magnitude. """ self.resetSky() self.addStarByRaDecInDeg(starId, raInDeg, declInDeg, mag) def addStarByFile(self, readFilePath, skiprows=0): """Add the star data by reading the file. Parameters ---------- readFilePath : str Star data file path. skiprows : int, optional Skip the first "skiprows" lines. (the default is 0.) """ data = np.loadtxt(readFilePath, skiprows=skiprows) for star in data: self.addStarByRaDecInDeg(star[0], star[1], star[2], star[3]) def exportSkyToFile(self, outputFilePath): """Export the star information into the file. Parameters ---------- outputFilePath : str Output file path. """ # Add the header (star ID, ra, decl, magnitude) content = "# Id\t Ra\t\t Decl\t\t Mag\n" # Add the star information for ii in range(len(self.starId)): content += "%d\t %3.6f\t %3.6f\t %3.6f\n" % ( self.starId[ii], self.ra[ii], self.decl[ii], self.mag[ii]) # Write into file fid = open(outputFilePath, "w") fid.write(content) fid.close() def addStarByChipPos(self, sensorName, starId, xInpixelInCam, yInPixelInCam, starMag, epoch=2000.0, includeDistortion=True): """Add the star based on the chip position. Parameters ---------- sensorName : str Abbreviated sensor name (e.g. "R22_S11"). starId : int Star Id. xInpixelInCam : float Pixel position x on camera coordinate. yInPixelInCam : float Pixel position y on camera coordinate. starMag : float Star magnitude. epoch : float, optional Epoch is the mean epoch in years of the celestial coordinate system. (the default is 2000.0.) includeDistortion : bool, optional If True (default), then this method will expect the true pixel coordinates with optical distortion included. If False, this method will expect TAN_PIXEL coordinates, which are the pixel coordinates with estimated optical distortion removed. See the documentation in afw.cameraGeom for more details. (the default is True.) """ # Get the sky position in (ra, decl) raInDeg, declInDeg = self._getSkyPosByChipPos( sensorName, xInpixelInCam, yInPixelInCam, epoch=epoch, includeDistortion=includeDistortion) # Add the star self.addStarByRaDecInDeg(starId, raInDeg, declInDeg, starMag) def _getSkyPosByChipPos(self, sensorName, xInpixelInCam, yInPixelInCam, epoch=2000.0, includeDistortion=True): """Get the sky position in (ra, dec) based on the chip pixel positions. Parameters ---------- sensorName : str Abbreviated sensor name (e.g. "R22_S11"). xInpixelInCam : float Pixel position x on camera coordinate. yInPixelInCam : float Pixel position y on camera coordinate. epoch : float, optional Epoch is the mean epoch in years of the celestial coordinate system. (the default is 2000.0.) includeDistortion : bool, optional If True (default), then this method will expect the true pixel coordinates with optical distortion included. If False, this method will expect TAN_PIXEL coordinates, which are the pixel coordinates with estimated optical distortion removed. See the documentation in afw.cameraGeom for more details. (the default is True.) Returns ------- float Ra in degree. float Decl in degree. """ # Get the pixel positions in DM team self._sourProc.config(sensorName=sensorName) pixelDmX, pixelDmY = self._sourProc.camXY2DmXY(xInpixelInCam, yInPixelInCam) # Expend the sensor name expendedSensorName = expandDetectorName(sensorName) # Get the sky position in (ra, decl) raInDeg, declInDeg = raDecFromPixelCoords( pixelDmX, pixelDmY, expendedSensorName, camera=self._camera, obs_metadata=self._obs, epoch=epoch, includeDistortion=includeDistortion) return raInDeg, declInDeg
class TestSourceProcessor(unittest.TestCase): """Test the source processor class.""" def setUp(self): # Get the path of module self.modulePath = getModulePath() # Set the source processor self.sourProc = SourceProcessor() # Set the configuration self.sourProc.config(sensorName="R00_S22_C0") def testInit(self): self.assertEqual(self.sourProc.sensorName, "R00_S22_C0") self.assertEqual(len(self.sourProc.sensorDimList), 205) self.assertEqual(len(self.sourProc.sensorEulerRot), 205) self.assertEqual(len(self.sourProc.sensorFocaPlaneInDeg), 205) self.assertEqual(len(self.sourProc.sensorFocaPlaneInUm), 205) self.assertEqual(self.sourProc.sensorDimList["R00_S22_C0"], (2000, 4072)) self.assertEqual(self.sourProc.sensorDimList["R22_S11"], (4000, 4072)) self.assertEqual(self.sourProc.sensorFocaPlaneInDeg["R22_S11"], (0, 0)) self.assertNotEqual( self.sourProc.sensorFocaPlaneInDeg["R00_S22_C0"], self.sourProc.sensorFocaPlaneInDeg["R00_S22_C1"], ) def testConfig(self): sensorName = "sensorName" self.sourProc.config(sensorName=sensorName) self.assertEqual(self.sourProc.sensorName, sensorName) def testGetEulerZinDeg(self): wfsSensorName = "R40_S02_C1" eulerZ = self.sourProc.getEulerZinDeg(wfsSensorName) self.assertEqual(eulerZ, 90.004585) def testCamXYtoFieldXY(self): pixelX = 1000 pixelY = 2036 fieldX, fieldY = self.sourProc.camXYtoFieldXY(pixelX, pixelY) ansFieldX, ansFieldY = self.sourProc.sensorFocaPlaneInDeg[ self.sourProc.sensorName] self.assertEqual(fieldX, ansFieldX) self.assertEqual(fieldY, ansFieldY) def testCamXYtoFieldXYforWfs(self): oxR00S22C0, oyR00S22C0 = self._camXYtoFieldXY("R00_S22_C0", 0, 0) oxR00S22C1, oyR00S22C1 = self._camXYtoFieldXY("R00_S22_C1", 0, 0) oxR40S02C0, oyR40S02C0 = self._camXYtoFieldXY("R40_S02_C0", 0, 0) oxR40S02C1, oyR40S02C1 = self._camXYtoFieldXY("R40_S02_C1", 0, 0) oxR44S00C0, oyR44S00C0 = self._camXYtoFieldXY("R44_S00_C0", 0, 0) oxR44S00C1, oyR44S00C1 = self._camXYtoFieldXY("R44_S00_C1", 0, 0) oxR04S20C0, oyR04S20C0 = self._camXYtoFieldXY("R04_S20_C0", 0, 0) oxR04S20C1, oyR04S20C1 = self._camXYtoFieldXY("R04_S20_C1", 0, 0) # Compare with the same RXX_SYY self.assertEqual(oyR00S22C0, oyR00S22C1) self.assertEqual(oxR40S02C0, oxR40S02C1) self.assertEqual(oyR44S00C0, oyR44S00C1) self.assertEqual(oxR04S20C0, oxR04S20C1) # Campare with different RXX_SYY self.assertEqual((oxR00S22C0 + oxR44S00C0, oyR00S22C0 + oyR44S00C0), (0, 0)) self.assertEqual((oxR40S02C1 + oxR04S20C1, oyR40S02C1 + oyR04S20C1), (0, 0)) def _camXYtoFieldXY(self, sensorName, pixelX, pixelY): self.sourProc.config(sensorName=sensorName) fieldX, fieldY = self.sourProc.camXYtoFieldXY(pixelX, pixelY) return fieldX, fieldY def testDmXY2CamXY(self): self.sourProc.config(sensorName="R22_S11") self.assertEqual(self.sourProc.dmXY2CamXY(4070, 1000), (3000, 4070)) def testCamXY2DmXY(self): self.sourProc.config(sensorName="R22_S11") self.assertEqual(self.sourProc.camXY2DmXY(3000, 4070), (4070, 1000)) def testIsVignette(self): isVignette = self.sourProc.isVignette(1.76, 0) self.assertTrue(isVignette) noVignette = self.sourProc.isVignette(0.2, 0.2) self.assertFalse(noVignette) def testSimulateImg(self): ccdImgIntra, ccdImgExtra = self._simulateImg() self.assertEqual(ccdImgIntra.shape, (4072, 2000)) self.assertNotEqual(np.sum(np.abs(ccdImgIntra)), 0) def _simulateImg(self): imageFolderPath = os.path.join(self.modulePath, "tests", "testData", "testImages", "LSST_C_SN26") defocalDis = 0.25 nbrStar = self._generateNbrStar() ccdImgIntra, ccdImgExtra = self.sourProc.simulateImg(imageFolderPath, defocalDis, nbrStar, FilterType.REF, noiseRatio=0) return ccdImgIntra, ccdImgExtra def _generateNbrStar(self): nbrStar = NbrStar() nbrStar.starId = {523572575: [], 523572679: [523572671]} nbrStar.lsstMagG = { 523572575: 14.66652, 523572671: 16.00000, 523572679: 13.25217, } nbrStar.raDeclInPixel = { 523572679: (3966.44, 1022.91), 523572671: (3968.77, 1081.02), 523572575: (3475.48, 479.33), } return nbrStar def testGetSingleTargetImage(self): ( sglSciNeiImg, allStarPosX, allStarPosY, magRatio, offsetX, offsetY, ) = self._getSingleTargetImage() self.assertEqual(sglSciNeiImg.shape, (310, 310)) self.assertAlmostEqual(allStarPosX[0], 126.98) self.assertAlmostEqual(allStarPosX[1], 185.09) self.assertAlmostEqual(allStarPosY[0], 206.77) self.assertAlmostEqual(allStarPosY[1], 204.44) self.assertAlmostEqual(magRatio[0], 0.07959174) self.assertEqual(magRatio[1], 1) self.assertEqual(offsetX, 792.0) self.assertEqual(offsetY, 3762.0) def _getSingleTargetImage(self): nbrStar = self._generateNbrStar() ccdImgIntra, ccdImgExtra = self._simulateImg() starIndex = list(nbrStar.getId()).index(523572679) ( sglSciNeiImg, allStarPosX, allStarPosY, magRatio, offsetX, offsetY, ) = self.sourProc.getSingleTargetImage(ccdImgIntra, nbrStar, starIndex, FilterType.REF) return sglSciNeiImg, allStarPosX, allStarPosY, magRatio, offsetX, offsetY def testDoDeblending(self): ( sglSciNeiImg, allStarPosX, allStarPosY, magRatio, offsetX, offsetY, ) = self._getSingleTargetImage() imgDeblend, realcx, realcy = self.sourProc.doDeblending( sglSciNeiImg, allStarPosX, allStarPosY, magRatio) self.assertEqual(imgDeblend.shape, (310, 310)) self.assertLess(np.abs(realcx - 184.49), 3) self.assertLess(np.abs(realcy - 205.00), 3) # Get the real camera position x, y after the deblending realCameraX = realcx + offsetX realCameraY = realcy + offsetY # Compared with DM prediction nbrStar = self._generateNbrStar() raDeclInPixel = nbrStar.getRaDeclInPixel() camX, camY = self.sourProc.dmXY2CamXY(raDeclInPixel[523572679][0], raDeclInPixel[523572679][1]) delta = np.sqrt((realCameraX - camX)**2 + (realCameraY - camY)**2) self.assertLess(delta, 10)
import os import numpy as np from lsst.ts.wep.SourceProcessor import SourceProcessor from lsst.ts.wep.Utility import getModulePath if __name__ == "__main__": # Folder path of focal plane txt file folderPath2FocalPlane = os.path.join(getModulePath(), "tests", "testData") # Configurate the source processor sourPro = SourceProcessor(folderPath2FocalPlane=folderPath2FocalPlane) # Get the list of sensor name and coordinate sensorFocaPlaneInDeg = sourPro.sensorFocaPlaneInDeg nameList = [] xList = [] yList = [] for aKey, aItem in sensorFocaPlaneInDeg.items(): nameList.append(aKey) xList.append(aItem[0]) yList.append(aItem[1]) xySensor = np.array([xList, yList]).T # Set the 35 field points nArm = 6 armLen = [0.379, 0.841, 1.237, 1.535, 1.708]