Example #1
0
    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)
Example #2
0
    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")
Example #3
0
    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()
Example #4
0
    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
Example #6
0
    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
Example #9
0
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
Example #11
0
    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")
Example #12
0
    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
Example #13
0
    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)
Example #15
0
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)
Example #16
0
# 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
Example #17
0
    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()
Example #18
0
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
Example #19
0
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]