def get_flux_in_half_light_radius(self, fileName, hlr, detector, camera, obs, epoch=2000.0):
        """
        Read in a FITS image.  Return the total flux in that image as well as the flux contained
        within a specified radius of the maximum pixel of the image.

        @param [in] fileName is the name of the FITS file to be read in

        @param [in] hlr is the half light radius to be tested (in arc seconds)

        @param [in] detector is an instantiation of the afw.cameraGeom Detector
        class characterizing the detector corresponding to this image

        @param [in] camera is an instantiation of the afw.cameraGeom Camera class
        characterizing the camera to which detector belongs

        @param [in] obs is an instantiation of ObservationMetaData characterizing
        the telescope pointing

        @param [in] epoch is the epoch in Julian years of the equinox against which
        RA and Dec are measured.

        @param [out] totalFlux is the total number of counts in the images

        @param [out] measuredHalfFlux is the measured flux within hlr of the maximum pixel
        """

        im = afwImage.ImageF(fileName).getArray()
        totalFlux = im.sum()

        _maxPixel = numpy.array([im.argmax()/im.shape[1], im.argmax()%im.shape[1]])
        maxPixel = numpy.array([_maxPixel[1], _maxPixel[0]])

        raMax, decMax = _raDecFromPixelCoords(maxPixel[0:1],
                                              maxPixel[1:2],
                                              [detector.getName()],
                                              camera=camera,
                                              obs_metadata=obs,
                                              epoch=epoch)

        activePoints = numpy.where(im>1.0e-10)
        self.assertGreater(len(activePoints), 0)

        xPixList = activePoints[1] # this looks backwards, but remember: the way numpy handles
        yPixList = activePoints[0] # arrays, the first index indicates what row it is in (the y coordinate)
        chipNameList = [detector.getName()]*len(xPixList)


        raList, decList = _raDecFromPixelCoords(xPixList, yPixList, chipNameList,
                                                camera=camera, obs_metadata=obs,
                                                epoch=epoch)

        distanceList = arcsecFromRadians(haversine(raList, decList, raMax[0], decMax[0]))

        dexContained = [ix for ix, dd in enumerate(distanceList) if dd<=hlr]
        measuredHalfFlux = numpy.array([im[yPixList[dex]][xPixList[dex]] for dex in dexContained]).sum()
        return totalFlux, measuredHalfFlux
    def _radec(self, x, y):
        """
        This is a method required by the GalSim WCS API

        Convert pixel coordinates into ra, dec coordinates.
        x and y already have crpix1 and crpix2 subtracted from them.
        Return ra, dec in radians.
        """

        chipNameList = [self.afwDetector.getName()]

        if type(x) is np.ndarray:
            chipNameList = chipNameList * len(x)

        ra, dec = _raDecFromPixelCoords(x + self.afw_crpix1,
                                        y + self.afw_crpix2,
                                        chipNameList,
                                        camera=self.afwCamera,
                                        obs_metadata=self.obs_metadata,
                                        epoch=self.epoch)

        if type(x) is np.ndarray:
            return (ra, dec)
        else:
            return (ra[0], dec[0])
    def testTanSipWcs(self):
        """
        Test that tanSipWcsFromDetector works by fitting a TAN WCS and a TAN-SIP WCS to
        a detector with distortions and verifying that the TAN-SIP WCS better approximates
        the truth.
        """


        tanWcs = tanWcsFromDetector(self.detector, self.camera, self.obs, self.epoch)
        tanSipWcs = tanSipWcsFromDetector(self.detector, self.camera, self.obs, self.epoch)

        tanWcsRa = []
        tanWcsDec = []
        tanSipWcsRa = []
        tanSipWcsDec = []

        xPixList = []
        yPixList = []
        for xx in numpy.arange(0.0, 4001.0, 100.0):
            for yy in numpy.arange(0.0, 4001.0, 100.0):
                xPixList.append(xx)
                yPixList.append(yy)

                pt = afwGeom.Point2D(xx ,yy)
                skyPt = tanWcs.pixelToSky(pt).getPosition()
                tanWcsRa.append(skyPt.getX())
                tanWcsDec.append(skyPt.getY())

                skyPt = tanSipWcs.pixelToSky(pt).getPosition()
                tanSipWcsRa.append(skyPt.getX())
                tanSipWcsDec.append(skyPt.getY())

        tanWcsRa = numpy.radians(numpy.array(tanWcsRa))
        tanWcsDec = numpy.radians(numpy.array(tanWcsDec))

        tanSipWcsRa = numpy.radians(numpy.array(tanSipWcsRa))
        tanSipWcsDec = numpy.radians(numpy.array(tanSipWcsDec))

        xPixList = numpy.array(xPixList)
        yPixList = numpy.array(yPixList)

        raTest, decTest = _raDecFromPixelCoords(xPixList, yPixList,
                                                [self.detector.getName()]*len(xPixList),
                                                camera=self.camera, obs_metadata=self.obs,
                                                epoch=self.epoch)

        tanDistanceList = arcsecFromRadians(haversine(raTest, decTest, tanWcsRa, tanWcsDec))
        tanSipDistanceList = arcsecFromRadians(haversine(raTest, decTest, tanSipWcsRa, tanSipWcsDec))

        maxDistanceTan = tanDistanceList.max()
        maxDistanceTanSip = tanSipDistanceList.max()

        msg = 'max error in TAN WCS %e arcsec; in TAN-SIP %e arcsec' % (maxDistanceTan, maxDistanceTanSip)
        self.assertLess(maxDistanceTanSip, 0.01, msg=msg)
        self.assertGreater(maxDistanceTan-maxDistanceTanSip, 1.0e-10, msg=msg)
    def testTanSipWcs(self):
        """
        Test that tanSipWcsFromDetector works by fitting a TAN WCS and a TAN-SIP WCS to
        a detector with distortions and verifying that the TAN-SIP WCS better approximates
        the truth.
        """

        tanWcs = tanWcsFromDetector(self.detector, self.camera, self.obs, self.epoch)
        tanSipWcs = tanSipWcsFromDetector(self.detector, self.camera, self.obs, self.epoch)

        tanWcsRa = []
        tanWcsDec = []
        tanSipWcsRa = []
        tanSipWcsDec = []

        xPixList = []
        yPixList = []
        for xx in np.arange(0.0, 4001.0, 100.0):
            for yy in np.arange(0.0, 4001.0, 100.0):
                xPixList.append(xx)
                yPixList.append(yy)

                pt = afwGeom.Point2D(xx, yy)
                skyPt = tanWcs.pixelToSky(pt).getPosition()
                tanWcsRa.append(skyPt.getX())
                tanWcsDec.append(skyPt.getY())

                skyPt = tanSipWcs.pixelToSky(pt).getPosition()
                tanSipWcsRa.append(skyPt.getX())
                tanSipWcsDec.append(skyPt.getY())

        tanWcsRa = np.radians(np.array(tanWcsRa))
        tanWcsDec = np.radians(np.array(tanWcsDec))

        tanSipWcsRa = np.radians(np.array(tanSipWcsRa))
        tanSipWcsDec = np.radians(np.array(tanSipWcsDec))

        xPixList = np.array(xPixList)
        yPixList = np.array(yPixList)

        raTest, decTest = _raDecFromPixelCoords(xPixList, yPixList,
                                                [self.detector.getName()]*len(xPixList),
                                                camera=self.camera, obs_metadata=self.obs,
                                                epoch=self.epoch)

        tanDistanceList = arcsecFromRadians(haversine(raTest, decTest, tanWcsRa, tanWcsDec))
        tanSipDistanceList = arcsecFromRadians(haversine(raTest, decTest, tanSipWcsRa, tanSipWcsDec))

        maxDistanceTan = tanDistanceList.max()
        maxDistanceTanSip = tanSipDistanceList.max()

        msg = 'max error in TAN WCS %e arcsec; in TAN-SIP %e arcsec' % (maxDistanceTan, maxDistanceTanSip)
        self.assertLess(maxDistanceTanSip, 0.01, msg=msg)
        self.assertGreater(maxDistanceTan-maxDistanceTanSip, 1.0e-10, msg=msg)
Example #5
0
    def _raDecFromPixelCoords(self,
                              xPix,
                              yPix,
                              chipName,
                              obs_metadata,
                              epoch=2000.0,
                              includeDistortion=True):
        """
        Convert pixel coordinates into RA, Dec

        Parameters
        ----------
        xPix is the x pixel coordinate.  It can be either
        a float or a numpy array.

        yPix is the y pixel coordinate.  It can be either
        a float or a numpy array.

        chipName is the name of the chip(s) on which the pixel coordinates
        are defined.  This can be a list (in which case there should be one chip name
        for each (xPix, yPix) coordinate pair), or a single value (in which case, all
        of the (xPix, yPix) points will be reckoned on that chip).

        obs_metadata is an ObservationMetaData defining the pointing

        epoch is the mean epoch in years of the celestial coordinate system.
        Default is 2000.

        includeDistortion is a boolean.  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.

        Returns
        -------
        a 2-D numpy array in which the first row is the RA coordinate
        and the second row is the Dec coordinate (both in radians; in the
        International Celestial Reference System)

        WARNING: This method does not account for apparent motion due to parallax.
        This method is only useful for mapping positions on a theoretical focal plane
        to positions on the celestial sphere.
        """

        return coordUtils._raDecFromPixelCoords(
            xPix,
            yPix,
            chipName,
            camera=self._camera,
            obs_metadata=obs_metadata,
            epoch=epoch,
            includeDistortion=includeDistortion)
    def testContainsRaDec(self):
        """
        Test whether or not the method containsRaDec correctly identifies
        RA and Dec that fall inside and outside the detector
        """

        photParams = PhotometricParameters()
        gsdet = GalSimDetector(self.camera[0].getName(),
                               GalSimCameraWrapper(self.camera),
                               self.obs,
                               self.epoch,
                               photParams=photParams)

        xxList = [gsdet.xMinPix, gsdet.xMaxPix]
        yyList = [gsdet.yMinPix, gsdet.yMaxPix]
        dxList = [-1.0, 1.0]
        dyList = [-1.0, 1.0]

        xPixList = []
        yPixList = []
        correctAnswer = []

        for xx, yy, dx, dy in zip(xxList, yyList, dxList, dyList):
            xPixList.append(xx)
            yPixList.append(yy)
            correctAnswer.append(True)

            xPixList.append(xx + dx)
            yPixList.append(yy)
            correctAnswer.append(False)

            xPixList.append(xx)
            yPixList.append(yy + dy)
            correctAnswer.append(False)

        nameList = [gsdet.name] * len(xPixList)
        xPixList = np.array(xPixList)
        yPixList = np.array(yPixList)

        raList, decList = _raDecFromPixelCoords(xPixList,
                                                yPixList,
                                                nameList,
                                                camera=self.camera,
                                                obs_metadata=self.obs,
                                                epoch=self.epoch)

        testAnswer = gsdet.containsRaDec(raList, decList)

        for c, t in zip(correctAnswer, testAnswer):
            self.assertIs(c, t)
    def testContainsRaDec(self):
        """
        Test whether or not the method containsRaDec correctly identifies
        RA and Dec that fall inside and outside the detector
        """

        photParams = PhotometricParameters()
        gsdet = GalSimDetector(self.camera[0], self.camera, \
                               self.obs, self.epoch,
                               photParams=photParams)

        xxList = [gsdet.xMinPix, gsdet.xMaxPix]
        yyList = [gsdet.yMinPix, gsdet.yMaxPix]
        dxList = [-1.0, 1.0]
        dyList = [-1.0, 1.0]

        xPixList = []
        yPixList = []
        correctAnswer = []

        for xx, yy, dx, dy in zip(xxList, yyList, dxList, dyList):
            xPixList.append(xx)
            yPixList.append(yy)
            correctAnswer.append(True)

            xPixList.append(xx+dx)
            yPixList.append(yy)
            correctAnswer.append(False)

            xPixList.append(xx)
            yPixList.append(yy+dy)
            correctAnswer.append(False)


        nameList = [gsdet.name]*len(xPixList)
        xPixList = numpy.array(xPixList)
        yPixList = numpy.array(yPixList)

        raList, decList = _raDecFromPixelCoords(xPixList, yPixList,
                                                nameList,
                                                camera=self.camera,
                                                obs_metadata=self.obs,
                                                epoch=self.epoch)

        testAnswer = gsdet.containsRaDec(raList, decList)

        for c, t in zip(correctAnswer, testAnswer):
            self.assertTrue(c is t)
    def testTanWcs(self):
        """
        Test method to return a Tan WCS by generating a bunch of pixel coordinates
        in the undistorted TAN-PIXELS coordinate system.  Then, use sims_coordUtils
        to convert those pixel coordinates into RA and Dec.  Compare these to the
        RA and Dec returned by the WCS.  Demand agreement to witin 0.001 arcseconds.

        Note: if you use a bigger camera, it is possible to have disagreements of
        order a few milliarcseconds.
        """

        detector = self.camera[0]

        xPixList = []
        yPixList = []

        tanWcs = tanWcsFromDetector(detector, self.camera, self.obs, self.epoch)
        wcsRa = []
        wcsDec = []
        for xx in numpy.arange(0.0, 4001.0, 1000.0):
            for yy in numpy.arange(0.0, 4001.0, 1000.0):
                xPixList.append(xx)
                yPixList.append(yy)

                pt = afwGeom.Point2D(xx ,yy)
                skyPt = tanWcs.pixelToSky(pt).getPosition()
                wcsRa.append(skyPt.getX())
                wcsDec.append(skyPt.getY())

        wcsRa = numpy.radians(numpy.array(wcsRa))
        wcsDec = numpy.radians(numpy.array(wcsDec))

        xPixList = numpy.array(xPixList)
        yPixList = numpy.array(yPixList)

        raTest, decTest = _raDecFromPixelCoords(xPixList, yPixList,
                                                [detector.getName()]*len(xPixList),
                                                camera=self.camera, obs_metadata=self.obs,
                                                epoch=self.epoch)

        distanceList = arcsecFromRadians(haversine(raTest, decTest, wcsRa, wcsDec))
        maxDistance = distanceList.max()

        msg = 'maxError in tanWcs was %e ' % maxDistance
        self.assertTrue(maxDistance<0.001, msg=msg)
    def _radec(self, x, y):
        """
        This is a method required by the GalSim WCS API

        Convert pixel coordinates into ra, dec coordinates.
        x and y already have crpix1 and crpix2 subtracted from them.
        Return ra, dec in radians.
        """

        chipNameList = [self.afwDetector.getName()]

        if type(x) is numpy.ndarray:
            chipNameList = chipNameList * len(x)

        ra, dec = _raDecFromPixelCoords(x + self.afw_crpix1, y + self.afw_crpix2, chipNameList,
                                        camera=self.afwCamera,
                                        obs_metadata=self.obs_metadata,
                                        epoch=self.epoch)

        if type(x) is numpy.ndarray:
            return (ra, dec)
        else:
            return (ra[0], dec[0])
Example #10
0
    def get_position_angle(self, imageName, afwCamera, afwDetector,
                           obs_metadata, epoch):
        """
        Read in a FITS image containing one extended object.

        Determine its north and east axes by examining how RA and Dec change
        with pixel position.

        Determine the semi-major axis of the object by treating the distribution
        of flux as a covariance matrix and finding its eigen vectors.

        Return the angle between the semi-major axis and the north axis of
        the image

        @param [in] imageName is the name of the FITS image to be read

        @param [in] afwCamera is an afw.cameraGeom.Camera

        @param [in] afwDetector is an afw.cameraGeom.Detector

        @param [in] obs_metadata is an ObservationMetaData describing the
        pointing of the telescope

        @param [in] epoch is the epoch in Julian years of the equinox against
        which RA and Dec are measured

        @param [out] the position angle of the object in the image in degrees
        """

        im = afwImage.ImageF(imageName).getArray()
        activePixels = np.where(im > 1.0e-10)
        self.assertGreater(len(activePixels), 0)
        xPixList = activePixels[1]
        yPixList = activePixels[0]

        xCenterPix = np.array([im.shape[1] / 2])
        yCenterPix = np.array([im.shape[0] / 2])

        raCenter, decCenter = _raDecFromPixelCoords(xCenterPix,
                                                    yCenterPix,
                                                    [afwDetector.getName()],
                                                    camera=afwCamera,
                                                    obs_metadata=obs_metadata,
                                                    epoch=epoch)

        xCenterP1 = xCenterPix + 1
        yCenterP1 = yCenterPix + 1
        raCenterP1, decCenterP1 = _raDecFromPixelCoords(
            xCenterP1,
            yCenterP1, [afwDetector.getName()],
            camera=afwCamera,
            obs_metadata=obs_metadata,
            epoch=epoch)

        # find the angle between the (1,1) vector in pixel space and the
        # north axis of the image
        theta = np.arctan2((raCenterP1[0] - raCenter[0]),
                           decCenterP1[0] - decCenter[0])

        # rotate the (1,1) vector in pixel space so that it is pointing
        # along the north axis
        north = np.array(
            [np.cos(theta) - np.sin(theta),
             np.cos(theta) + np.sin(theta)])
        north = north / np.sqrt(north[0] * north[0] + north[1] * north[1])

        # find the east axis of the image
        east = np.array([north[1], -1.0 * north[0]])

        # now find the covariance matrix of the x, y  pixel space distribution
        # of flux on the image
        maxPixel = np.array(
            [im.argmax() % im.shape[1],
             im.argmax() / im.shape[1]])

        xx = np.array([
            im[iy][ix] * np.power(ix - maxPixel[0], 2)
            for ix, iy in zip(xPixList, yPixList)
        ]).sum()

        xy = np.array([
            im[iy][ix] * (ix - maxPixel[0]) * (iy - maxPixel[1])
            for ix, iy in zip(xPixList, yPixList)
        ]).sum()

        yy = np.array([
            im[iy][ix] * (iy - maxPixel[1]) * (iy - maxPixel[1])
            for ix, iy in zip(xPixList, yPixList)
        ]).sum()

        covar = np.array([[xx, xy], [xy, yy]])

        # find the eigen vectors of this covarinace matrix;
        # treat the one with the largest eigen value as the
        # semi-major axis of the object
        eigenVals, eigenVecs = np.linalg.eig(covar)

        iMax = eigenVals.argmax()
        majorAxis = eigenVecs[:, iMax]

        majorAxis = majorAxis / np.sqrt(majorAxis[0] * majorAxis[0] +
                                        majorAxis[1] * majorAxis[1])

        # return the angle between the north axis of the image
        # and the semi-major axis of the object
        cosTheta = np.dot(majorAxis, north)
        sinTheta = np.dot(majorAxis, east)

        theta = np.arctan2(sinTheta, cosTheta)

        return np.degrees(theta)
    def get_position_angle(self, imageName, afwCamera, afwDetector, \
                           obs_metadata, epoch):
        """
        Read in a FITS image containing one extended object.

        Determine its north and east axes by examining how RA and Dec change
        with pixel position.

        Determin the semi-major axis of the object by treating the distribution
        of flux as a covariance matrix and finding its eigen vectors.

        Return the angle between the semi-major axis and the north axis of
        the image

        @param [in] imageName is the name of the FITS image to be read

        @param [in] afwCamera is an afw.cameraGeom.Camera

        @param [in] afwDetector is an afw.cameraGeom.Detector

        @param [in] obs_metadata is an ObservationMetaData describing the
        pointing of the telescope

        @param [in] epoch is the epoch in Julian years of the equinox against
        which RA and Dec are measured

        @param [out] the position angle of the object in the image in degrees
        """

        im = afwImage.ImageF(imageName).getArray()
        activePixels = numpy.where(im>1.0e-10)
        self.assertGreater(len(activePixels), 0)
        xPixList = activePixels[1]
        yPixList = activePixels[0]

        xCenterPix = numpy.array([im.shape[1]/2])
        yCenterPix = numpy.array([im.shape[0]/2])

        raCenter, decCenter = _raDecFromPixelCoords(xCenterPix, yCenterPix,
                                                    [afwDetector.getName()],
                                                    camera=afwCamera,
                                                    obs_metadata=obs_metadata,
                                                    epoch=epoch)

        xCenterP1 = xCenterPix+1
        yCenterP1 = yCenterPix+1
        raCenterP1,decCenterP1 = _raDecFromPixelCoords(xCenterP1, yCenterP1,
                                                       [afwDetector.getName()],
                                                       camera=afwCamera,
                                                       obs_metadata=obs_metadata,
                                                       epoch=epoch)

        # find the angle between the (1,1) vector in pixel space and the
        # north axis of the image
        theta = numpy.arctan2(-1.0*(raCenterP1[0]-raCenter[0]), decCenterP1[0]-decCenter[0])

        # rotate the (1,1) vector in pixel space so that it is pointing
        # along the north axis
        north = numpy.array([numpy.cos(theta)-numpy.sin(theta), numpy.cos(theta)+numpy.sin(theta)])
        north = north/numpy.sqrt(north[0]*north[0]+north[1]*north[1])

        # find the west axis of the image
        west = numpy.array([north[1], -1.0*north[0]])

        # now find the covariance matrix of the x, y  pixel space distribution
        # of flux on the image
        maxPixel = numpy.array([im.argmax()%im.shape[1], im.argmax()/im.shape[1]])

        xx = numpy.array([im[iy][ix]*numpy.power(ix-maxPixel[0],2) \
                         for ix, iy in zip(xPixList, yPixList)]).sum()

        xy = numpy.array([im[iy][ix]*(ix-maxPixel[0])*(iy-maxPixel[1]) \
                          for ix, iy in zip(xPixList, yPixList)]).sum()

        yy = numpy.array([im[iy][ix]*(iy-maxPixel[1])*(iy-maxPixel[1]) \
                          for ix, iy in zip(xPixList, yPixList)]).sum()

        covar = numpy.array([[xx, xy],[xy, yy]])

        # find the eigen vectors of this covarinace matrix;
        # treat the one with the largest eigen value as the
        # semi-major axis of the object
        eigenVals, eigenVecs = numpy.linalg.eig(covar)

        iMax = eigenVals.argmax()
        majorAxis = eigenVecs[:,iMax]

        majorAxis = majorAxis/numpy.sqrt(majorAxis[0]*majorAxis[0]+majorAxis[1]*majorAxis[1])


        # return the angle between the north axis of the image
        # and the semi-major axis of the object
        cosTheta = numpy.dot(majorAxis, north)
        sinTheta = numpy.dot(majorAxis, west)
        theta = numpy.arctan2(sinTheta, cosTheta)

        return numpy.degrees(theta)
Example #12
0
    def testOutputWcsOfImage(self):
        """
        Test that, when GalSim generates an image, in encodes the WCS in a
        way afw can read.  This is done by creating an image,then reading
        it back in, getting its WCS, and comparing the pixel-to-sky conversion
        both for the read WCS and the original afw.cameraGeom.detector.
        Raise an exception if the median difference between the two is
        greater than 0.01 arcseconds.
        """
        scratchDir = os.path.join(getPackageDir('sims_GalSimInterface'),
                                  'tests', 'scratchSpace')
        catName = os.path.join(scratchDir, 'outputWcs_test_Catalog.dat')
        imageRoot = os.path.join(scratchDir, 'outputWcs_test_Image')
        dbFileName = os.path.join(scratchDir,
                                  'outputWcs_test_InputCatalog.dat')

        baseDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests',
                               'cameraData')
        camera = ReturnCamera(baseDir)

        detector = camera[0]
        detName = detector.getName()
        imageName = '%s_%s_u.fits' % (imageRoot, detName)

        nSamples = 3
        rng = np.random.RandomState(42)
        pointingRaList = rng.random_sample(nSamples) * 360.0
        pointingDecList = rng.random_sample(nSamples) * 180.0 - 90.0
        rotSkyPosList = rng.random_sample(nSamples) * 360.0

        for raPointing, decPointing, rotSkyPos in \
            zip(pointingRaList, pointingDecList, rotSkyPosList):

            obs = ObservationMetaData(pointingRA=raPointing,
                                      pointingDec=decPointing,
                                      boundType='circle',
                                      boundLength=4.0,
                                      rotSkyPos=rotSkyPos,
                                      mjd=49250.0)

            fwhm = 0.7
            create_text_catalog(obs, dbFileName, np.array([3.0]),
                                np.array([1.0]))

            db = outputWcsFileDBObj(dbFileName, runtable='test')

            cat = outputWcsCat(db, obs_metadata=obs)
            cat.camera = camera

            psf = SNRdocumentPSF(fwhm=fwhm)
            cat.setPSF(psf)

            cat.write_catalog(catName)
            cat.write_images(nameRoot=imageRoot)

            # 20 March 2017
            # the 'try' block is how it worked in SWIG;
            # the 'except' block is how it works in pybind11
            try:
                exposure = afwImage.ExposureD_readFits(imageName)
            except AttributeError:
                exposure = afwImage.ExposureD.readFits(imageName)

            wcs = exposure.getWcs()

            xxTestList = []
            yyTestList = []

            raImage = []
            decImage = []

            for xx in np.arange(0.0, 4001.0, 100.0):
                for yy in np.arange(0.0, 4001.0, 100.0):
                    xxTestList.append(xx)
                    yyTestList.append(yy)

                    pt = afwGeom.Point2D(xx, yy)
                    skyPt = wcs.pixelToSky(pt).getPosition()
                    raImage.append(skyPt.getX())
                    decImage.append(skyPt.getY())

            xxTestList = np.array(xxTestList)
            yyTestList = np.array(yyTestList)

            raImage = np.radians(np.array(raImage))
            decImage = np.radians(np.array(decImage))

            raControl, \
            decControl = _raDecFromPixelCoords(xxTestList, yyTestList,
                                               [detector.getName()]*len(xxTestList),
                                               camera=camera, obs_metadata=obs,
                                               epoch=2000.0)

            errorList = arcsecFromRadians(
                haversine(raControl, decControl, raImage, decImage))

            medianError = np.median(errorList)
            msg = 'medianError was %e' % medianError
            self.assertLess(medianError, 0.01, msg=msg)

            if os.path.exists(catName):
                os.unlink(catName)
            if os.path.exists(dbFileName):
                os.unlink(dbFileName)
            if os.path.exists(imageName):
                os.unlink(imageName)
Example #13
0
    def check_placement(self, imageName, raList, decList, fwhmList,
                        countList, gain,
                        detector, camera, obs, epoch=2000.0):
        """
        Read in a FITS image and a list of objects meant to be on that
        image.  Verify that the objects were placed at the correct pixel
        by counting up all of the flux within 2 fwhm of each object's
        expected location and verifying it with the counts expected for
        that object.

        @param [in] imageName is the name of the FITS file to be read in

        @param [in] raList is a numpy array of the RA coordinates of the objects
        in the image (in radians)

        @param [in] decList is a numpy array of the Dec coordinates of the objects
        in the image (in radians)

        @param [in] fwhmList is a list of the Full Width at Half Maximum of
        each object in arcseconds

        @param [in] countList is a list of the counts expected for each object

        @param [in] gain is the gain of the detector (electrons per ADU)

        @param [in] detector is an instantiation of the afw.cameraGeom Detector
        class characterizing the detector corresponding to this image

        @param [in] camera is an instantiation of the afw.cameraGeom Camera class
        characterizing the camera to which detector belongs

        @param [in] obs is an instantiation of ObservationMetaData characterizing
        the telescope pointing

        @param [in] epoch is the epoch in Julian years of the equinox against which
        RA and Dec are measured.

        Raises an exception of the counts detected for each object differs from
        the expected amount by more than 3 sigma.
        """

        im = afwImage.ImageF(imageName).getArray()
        activePixels = np.where(im > 1.0e-10)

        # I know this seems backwards, but the way numpy handles arrays,
        # the first index is the row (i.e. the y coordinate)
        imXList = activePixels[1]
        imYList = activePixels[0]

        nameList = [detector.getName()]*len(raList)
        xPixList, yPixList = _pixelCoordsFromRaDec(raList, decList,
                                                   chipName=nameList,
                                                   camera=camera,
                                                   obs_metadata=obs,
                                                   epoch=epoch)

        for rr, dd, xx, yy, fwhm, cc in \
        zip(raList, decList, xPixList, yPixList, fwhmList, countList):

            countSigma = np.sqrt(cc/gain)

            imNameList = [detector.getName()]*len(imXList)
            raImList, decImList = _raDecFromPixelCoords(imXList, imYList,
                                                        imNameList,
                                                        camera=camera,
                                                        obs_metadata=obs,
                                                        epoch=epoch)

            distanceList = arcsecFromRadians(haversine(raImList, decImList, rr, dd))

            fluxArray = np.array([im[imYList[ix]][imXList[ix]]
                                  for ix in range(len(distanceList))
                                  if distanceList[ix] < 2.0*fwhm])

            totalFlux = fluxArray.sum()
            msg = 'totalFlux %e should be %e diff/sigma %e' \
                  % (totalFlux, cc, np.abs(totalFlux-cc)/countSigma)

            self.assertLess(np.abs(totalFlux-cc), 3.0*countSigma, msg=msg)
Example #14
0
    def get_flux_in_half_light_radius(self,
                                      fileName,
                                      hlr,
                                      detector,
                                      camera,
                                      obs,
                                      epoch=2000.0):
        """
        Read in a FITS image.  Return the total flux in that image as well as the flux contained
        within a specified radius of the maximum pixel of the image.

        @param [in] fileName is the name of the FITS file to be read in

        @param [in] hlr is the half light radius to be tested (in arc seconds)

        @param [in] detector is an instantiation of the afw.cameraGeom Detector
        class characterizing the detector corresponding to this image

        @param [in] camera is an instantiation of the afw.cameraGeom Camera class
        characterizing the camera to which detector belongs

        @param [in] obs is an instantiation of ObservationMetaData characterizing
        the telescope pointing

        @param [in] epoch is the epoch in Julian years of the equinox against which
        RA and Dec are measured.

        @param [out] totalFlux is the total number of counts in the images

        @param [out] measuredHalfFlux is the measured flux within hlr of the maximum pixel
        """

        im = afwImage.ImageF(fileName).getArray()
        totalFlux = im.sum()

        _maxPixel = np.array(
            [im.argmax() / im.shape[1],
             im.argmax() % im.shape[1]])
        maxPixel = np.array([_maxPixel[1], _maxPixel[0]])

        raMax, decMax = _raDecFromPixelCoords(maxPixel[0:1],
                                              maxPixel[1:2],
                                              [detector.getName()],
                                              camera=camera,
                                              obs_metadata=obs,
                                              epoch=epoch)

        activePoints = np.where(im > 1.0e-10)
        self.assertGreater(len(activePoints), 0)

        xPixList = activePoints[
            1]  # this looks backwards, but remember: the way numpy handles
        yPixList = activePoints[
            0]  # arrays, the first index indicates what row it is in (the y coordinate)
        chipNameList = [detector.getName()] * len(xPixList)

        raList, decList = _raDecFromPixelCoords(xPixList,
                                                yPixList,
                                                chipNameList,
                                                camera=camera,
                                                obs_metadata=obs,
                                                epoch=epoch)

        distanceList = arcsecFromRadians(
            haversine(raList, decList, raMax[0], decMax[0]))

        dexContained = [ix for ix, dd in enumerate(distanceList) if dd <= hlr]
        measuredHalfFlux = np.array(
            [im[yPixList[dex]][xPixList[dex]] for dex in dexContained]).sum()
        return totalFlux, measuredHalfFlux
    def verify_fwhm(self, fileName, fwhm, detector, camera, obs, epoch=2000.0):
        """
        Read in a FITS image with one object on it and verify that that object
        has the expected Full Width at Half Maximum.  This is done by finding
        the brightest pixel in the image, and then drawing 1-dimensional profiles
        of the object centered on that pixel (but at different angles relative to
        the axes of the image).  The code then walks along those profiles and keeps
        track of the distance between the two points at which the flux is half of
        the maximum.

        @param [in] fileName is the name of the FITS image

        @param [in] fwhm is the expected Full Width at Half Maximum in arcseconds

        @param [in] detector is an instantiation of the afw.cameraGeom Detector
        class characterizing the detector corresponding to this image

        @param [in] camera is an instantiation of the afw.cameraGeom Camera class
        characterizing the camera to which detector belongs

        @param [in] obs is an instantiation of ObservationMetaData characterizing
        the telescope pointing

        @param [in] epoch is the epoch in Julian years of the equinox against which
        RA and Dec are measured.

        This method will raise an exception if the measured Full Width at Half Maximum
        deviates from the expected value by more than ten percent.
        """
        im = afwImage.ImageF(fileName).getArray()
        maxFlux = im.max()

        # this looks backwards, but remember: the way numpy handles
        # arrays, the first index indicates what row it is in (the y coordinate)
        _maxPixel = numpy.array([im.argmax() / im.shape[1], im.argmax() % im.shape[1]])
        maxPixel = numpy.array([_maxPixel[1], _maxPixel[0]])

        raMax, decMax = _raDecFromPixelCoords(
            maxPixel[:1], maxPixel[1:2], [detector.getName()], camera=camera, obs_metadata=obs, epoch=epoch
        )

        half_flux = 0.5 * maxFlux

        for theta in numpy.arange(0.0, 2.0 * numpy.pi, 0.21 * numpy.pi):

            slope = numpy.tan(theta)

            if numpy.abs(slope < 1.0):
                xPixList = numpy.array(
                    [
                        ix
                        for ix in range(0, im.shape[1])
                        if int(slope * (ix - maxPixel[0]) + maxPixel[1]) >= 0
                        and int(slope * (ix - maxPixel[0]) + maxPixel[1]) < im.shape[0]
                    ]
                )

                yPixList = numpy.array([int(slope * (ix - maxPixel[0]) + maxPixel[1]) for ix in xPixList])
            else:
                yPixList = numpy.array(
                    [
                        iy
                        for iy in range(0, im.shape[0])
                        if int((iy - maxPixel[1]) / slope + maxPixel[0]) >= 0
                        and int((iy - maxPixel[1]) / slope + maxPixel[0]) < im.shape[1]
                    ]
                )

                xPixList = numpy.array([int((iy - maxPixel[1]) / slope + maxPixel[0]) for iy in yPixList])

            chipNameList = [detector.getName()] * len(xPixList)
            raList, decList = _raDecFromPixelCoords(
                xPixList, yPixList, chipNameList, camera=camera, obs_metadata=obs, epoch=epoch
            )

            distanceList = arcsecFromRadians(haversine(raList, decList, raMax[0], decMax[0]))

            fluxList = numpy.array([im[iy][ix] for ix, iy in zip(xPixList, yPixList)])

            distanceToLeft = None
            distanceToRight = None

            for ix in range(1, len(xPixList)):
                if fluxList[ix] < half_flux and fluxList[ix + 1] >= half_flux:
                    break

            newOrigin = ix + 1

            mm = (distanceList[ix] - distanceList[ix + 1]) / (fluxList[ix] - fluxList[ix + 1])
            bb = distanceList[ix] - mm * fluxList[ix]
            distanceToLeft = mm * half_flux + bb

            for ix in range(newOrigin, len(xPixList) - 1):
                if fluxList[ix] >= half_flux and fluxList[ix + 1] < half_flux:
                    break

            mm = (distanceList[ix] - distanceList[ix + 1]) / (fluxList[ix] - fluxList[ix + 1])
            bb = distanceList[ix] - mm * fluxList[ix]
            distanceToRight = mm * half_flux + bb

            self.assertTrue(numpy.abs(distanceToLeft + distanceToRight - fwhm) < 0.1 * fwhm)
    def test_generic_camera_wrapper(self):
        """
        Test that GalSimCameraWrapper wraps its methods as expected.
        This is mostly to catch changes in afw API.
        """
        camera = camTestUtils.CameraWrapper().camera
        camera_wrapper = GalSimCameraWrapper(camera)

        obs_mjd = ObservationMetaData(mjd=60000.0)
        ra, dec = raDecFromAltAz(35.0, 112.0, obs_mjd)
        obs = ObservationMetaData(pointingRA=ra,
                                  pointingDec=dec,
                                  mjd=obs_mjd.mjd,
                                  rotSkyPos=22.4)

        rng = np.random.RandomState(8124)

        for detector in camera:
            name = detector.getName()
            bbox = camera[name].getBBox()
            bbox_wrapper = camera_wrapper.getBBox(name)
            self.assertEqual(bbox.getMinX(), bbox_wrapper.getMinX())
            self.assertEqual(bbox.getMaxX(), bbox_wrapper.getMaxX())
            self.assertEqual(bbox.getMinY(), bbox_wrapper.getMinY())
            self.assertEqual(bbox.getMaxY(), bbox_wrapper.getMaxY())

            center_point = camera[name].getCenter(FOCAL_PLANE)
            pixel_system = camera[name].makeCameraSys(PIXELS)
            center_pix = camera.transform(center_point, FOCAL_PLANE,
                                          pixel_system)
            center_pix_wrapper = camera_wrapper.getCenterPixel(name)
            self.assertEqual(center_pix.getX(), center_pix_wrapper.getX())
            self.assertEqual(center_pix.getY(), center_pix_wrapper.getY())

            pupil_system = camera[name].makeCameraSys(FIELD_ANGLE)
            center_pupil = camera.transform(center_point, FOCAL_PLANE,
                                            pupil_system)
            center_pupil_wrapper = camera_wrapper.getCenterPupil(name)
            self.assertEqual(center_pupil.getX(), center_pupil_wrapper.getX())
            self.assertEqual(center_pupil.getY(), center_pupil_wrapper.getY())

            corner_pupil_wrapper = camera_wrapper.getCornerPupilList(name)
            corner_point_list = camera[name].getCorners(FOCAL_PLANE)
            for point in corner_point_list:
                point_pupil = camera.transform(point, FOCAL_PLANE,
                                               pupil_system)
                dd_min = 1.0e10
                for wrapper_point in corner_pupil_wrapper:
                    dd = np.sqrt(
                        (point_pupil.getX() - wrapper_point.getX())**2 +
                        (point_pupil.getY() - wrapper_point.getY())**2)

                    if dd < dd_min:
                        dd_min = dd
                self.assertLess(dd_min, 1.0e-20)

            xpix_min = None
            xpix_max = None
            ypix_min = None
            ypix_max = None
            focal_to_tan_pix = camera[name].getTransform(
                FOCAL_PLANE, TAN_PIXELS)
            for point in corner_point_list:
                pixel_point = focal_to_tan_pix.applyForward(point)
                xx = pixel_point.getX()
                yy = pixel_point.getY()
                if xpix_min is None or xx < xpix_min:
                    xpix_min = xx
                if ypix_min is None or yy < ypix_min:
                    ypix_min = yy
                if xpix_max is None or xx > xpix_max:
                    xpix_max = xx
                if ypix_max is None or yy > ypix_max:
                    ypix_max = yy

            pix_bounds_wrapper = camera_wrapper.getTanPixelBounds(name)
            self.assertEqual(pix_bounds_wrapper[0], xpix_min)
            self.assertEqual(pix_bounds_wrapper[1], xpix_max)
            self.assertEqual(pix_bounds_wrapper[2], ypix_min)
            self.assertEqual(pix_bounds_wrapper[3], ypix_max)

            x_pup = rng.random_sample(10) * 0.005 - 0.01
            y_pup = rng.random_sample(10) * 0.005 - 0.01
            x_pix, y_pix = pixelCoordsFromPupilCoords(x_pup,
                                                      y_pup,
                                                      chipName=name,
                                                      camera=camera)

            (x_pix_wrapper,
             y_pix_wrapper) = camera_wrapper.pixelCoordsFromPupilCoords(
                 x_pup, y_pup, name, obs)

            nan_x = np.where(np.isnan(x_pix))
            self.assertEqual(len(nan_x[0]), 0)
            np.testing.assert_array_equal(x_pix, x_pix_wrapper)
            np.testing.assert_array_equal(y_pix, y_pix_wrapper)

            x_pix = rng.random_sample(10) * 100.0 - 200.0
            y_pix = rng.random_sample(10) * 100.0 - 200.0
            x_pup, y_pup = pupilCoordsFromPixelCoords(x_pix,
                                                      y_pix,
                                                      chipName=name,
                                                      camera=camera)

            (x_pup_wrapper,
             y_pup_wrapper) = camera_wrapper.pupilCoordsFromPixelCoords(
                 x_pix, y_pix, name, obs)

            nan_x = np.where(np.isnan(x_pup))
            self.assertEqual(len(nan_x[0]), 0)
            np.testing.assert_array_equal(x_pup, x_pup_wrapper)
            np.testing.assert_array_equal(y_pup, y_pup_wrapper)

            ra, dec = raDecFromPixelCoords(x_pix,
                                           y_pix,
                                           name,
                                           camera=camera,
                                           obs_metadata=obs)

            (ra_wrapper, dec_wrapper) = camera_wrapper.raDecFromPixelCoords(
                x_pix, y_pix, name, obs)

            nan_ra = np.where(np.isnan(ra))
            self.assertEqual(len(nan_ra[0]), 0)
            np.testing.assert_array_equal(ra, ra_wrapper)
            np.testing.assert_array_equal(dec, dec_wrapper)

            ra, dec = _raDecFromPixelCoords(x_pix,
                                            y_pix,
                                            name,
                                            camera=camera,
                                            obs_metadata=obs)

            (ra_wrapper, dec_wrapper) = camera_wrapper._raDecFromPixelCoords(
                x_pix, y_pix, name, obs)

            nan_ra = np.where(np.isnan(ra))
            self.assertEqual(len(nan_ra[0]), 0)
            np.testing.assert_array_equal(ra, ra_wrapper)
            np.testing.assert_array_equal(dec, dec_wrapper)

            ra = obs.pointingRA + (rng.random_sample(10) * 150.0 -
                                   100.0) / 160.0
            dec = obs.pointingDec + (rng.random_sample(10) * 150.0 -
                                     100.0) / 160.0

            x_pix, y_pix = pixelCoordsFromRaDec(ra,
                                                dec,
                                                chipName=name,
                                                camera=camera,
                                                obs_metadata=obs)

            (x_pix_wrapper,
             y_pix_wrapper) = camera_wrapper.pixelCoordsFromRaDec(
                 ra, dec, chipName=name, obs_metadata=obs)

            nan_x = np.where(np.isnan(x_pix))
            self.assertEqual(len(nan_x[0]), 0)
            np.testing.assert_array_equal(x_pix, x_pix_wrapper)
            np.testing.assert_array_equal(y_pix, y_pix_wrapper)

            ra = np.radians(ra)
            dec = np.radians(dec)

            x_pix, y_pix = _pixelCoordsFromRaDec(ra,
                                                 dec,
                                                 chipName=name,
                                                 camera=camera,
                                                 obs_metadata=obs)

            (x_pix_wrapper,
             y_pix_wrapper) = camera_wrapper._pixelCoordsFromRaDec(
                 ra, dec, chipName=name, obs_metadata=obs)

            nan_x = np.where(np.isnan(x_pix))
            self.assertEqual(len(nan_x[0]), 0)
            np.testing.assert_array_equal(x_pix, x_pix_wrapper)
            np.testing.assert_array_equal(y_pix, y_pix_wrapper)

        del camera
    def check_placement(self, imageName, raList, decList, fwhmList,
                        countList, gain,
                        detector, camera, obs, epoch=2000.0):
        """
        Read in a FITS image and a list of objects meant to be on that
        image.  Verify that the objects were placed at the correct pixel
        by counting up all of the flux within 2 fwhm of each object's
        expected location and verifying it with the counts expected for
        that object.

        @param [in] imageName is the name of the FITS file to be read in

        @param [in] raList is a numpy array of the RA coordinates of the objects
        in the image (in radians)

        @param [in] decList is a numpy array of the Dec coordinates of the objects
        in the image (in radians)

        @param [in] fwhmList is a list of the Full Width at Half Maximum of
        each object in arcseconds

        @param [in] countList is a list of the counts expected for each object

        @param [in] gain is the gain of the detector (electrons per ADU)

        @param [in] detector is an instantiation of the afw.cameraGeom Detector
        class characterizing the detector corresponding to this image

        @param [in] camera is an instantiation of the afw.cameraGeom Camera class
        characterizing the camera to which detector belongs

        @param [in] obs is an instantiation of ObservationMetaData characterizing
        the telescope pointing

        @param [in] epoch is the epoch in Julian years of the equinox against which
        RA and Dec are measured.

        Raises an exception of the counts detected for each object differs from
        the expected amount by more than 3 sigma.
        """


        im = afwImage.ImageF(imageName).getArray()
        activePixels = numpy.where(im>1.0e-10)

        # I know this seems backwards, but the way numpy handles arrays,
        # the first index is the row (i.e. the y coordinate)
        imXList = activePixels[1]
        imYList = activePixels[0]

        nameList = [detector.getName()]*len(raList)
        xPixList, yPixList = _pixelCoordsFromRaDec(raList, decList,
                                                   chipNames=nameList,
                                                   camera=camera,
                                                   obs_metadata=obs,
                                                   epoch=epoch)

        for rr, dd, xx, yy, fwhm, cc in \
        zip(raList, decList, xPixList, yPixList, fwhmList, countList):
            countSigma = numpy.sqrt(cc/gain)

            imNameList = [detector.getName()]*len(imXList)
            raImList, decImList = _raDecFromPixelCoords(imXList, imYList,
                                                        imNameList,
                                                        camera=camera,
                                                        obs_metadata=obs,
                                                        epoch=epoch)

            distanceList = arcsecFromRadians(haversine(raImList, decImList, rr, dd))

            fluxArray = numpy.array(
                                  [im[imYList[ix]][imXList[ix]] \
                                   for ix in range(len(distanceList)) \
                                   if distanceList[ix]<2.0*fwhm]
                                  )

            totalFlux = fluxArray.sum()
            self.assertTrue(numpy.abs(totalFlux-cc)<3.0*countSigma)
def tanWcsFromDetector(afwDetector, afwCamera, obs_metadata, epoch):
    """
    Take an afw.cameraGeom detector and return a WCS which approximates
    the focal plane as perfectly flat (i.e. it ignores optical distortions
    that the telescope may impose on the image)

    @param [in] afwDetector is an instantiation of afw.cameraGeom's Detector
    class which characterizes the detector for which you wish to return th
    WCS

    @param [in] afwCamera is an instantiation of afw.cameraGeom's Camera
    class which characterizes the camera containing afwDetector

    @param [in] obs_metadata is an instantiation of ObservationMetaData
    characterizing the telescope's current pointing

    @param [in] epoch is the epoch in Julian years of the equinox against
    which RA and Dec are measured

    @param [out] tanWcs is an instantiation of afw.image's TanWcs class
    representing the WCS of the detector as if there were no optical
    distortions imposed by the telescope.
    """

    xTanPixMin, xTanPixMax, \
    yTanPixMin, yTanPixMax = _getTanPixelBounds(afwDetector, afwCamera)

    xPixList = []
    yPixList = []
    nameList = []

    # dx and dy are set somewhat heuristically
    # setting them eqal to 0.1(max-min) lead to errors
    # on the order of 0.7 arcsec in the WCS

    dx = 0.5 * (xTanPixMax - xTanPixMin)
    dy = 0.5 * (yTanPixMax - yTanPixMin)

    for xx in np.arange(xTanPixMin, xTanPixMax + 0.5 * dx, dx):
        for yy in np.arange(yTanPixMin, yTanPixMax + 0.5 * dy, dy):
            xPixList.append(xx)
            yPixList.append(yy)
            nameList.append(afwDetector.getName())

    raList, decList = _raDecFromPixelCoords(np.array(xPixList),
                                            np.array(yPixList),
                                            nameList,
                                            camera=afwCamera,
                                            obs_metadata=obs_metadata,
                                            epoch=epoch,
                                            includeDistortion=False)

    crPix1, crPix2 = _pixelCoordsFromRaDec(obs_metadata._pointingRA,
                                           obs_metadata._pointingDec,
                                           chipName=afwDetector.getName(),
                                           camera=afwCamera,
                                           obs_metadata=obs_metadata,
                                           epoch=epoch,
                                           includeDistortion=False)

    lonList, latList = _nativeLonLatFromPointing(raList, decList,
                                                 obs_metadata._pointingRA,
                                                 obs_metadata._pointingDec)

    # convert from native longitude and latitude to intermediate world coordinates
    # according to equations (12), (13), (54) and (55) of
    #
    # Calabretta and Greisen (2002), A&A 395, p. 1077
    #
    radiusList = 180.0 / (np.tan(latList) * np.pi)
    uList = radiusList * np.sin(lonList)
    vList = -radiusList * np.cos(lonList)

    delta_xList = xPixList - crPix1
    delta_yList = yPixList - crPix2

    bVector = np.array([
        (delta_xList * uList).sum(), (delta_yList * uList).sum(),
        (delta_xList * vList).sum(), (delta_yList * vList).sum()
    ])

    offDiag = (delta_yList * delta_xList).sum()
    xsq = np.power(delta_xList, 2).sum()
    ysq = np.power(delta_yList, 2).sum()

    aMatrix = np.array([[xsq, offDiag, 0.0, 0.0], [offDiag, ysq, 0.0, 0.0],
                        [0.0, 0.0, xsq, offDiag], [0.0, 0.0, offDiag, ysq]])

    coeffs = np.linalg.solve(aMatrix, bVector)

    fitsHeader = dafBase.PropertyList()
    fitsHeader.set("RADESYS", "ICRS")
    fitsHeader.set("EQUINOX", epoch)
    fitsHeader.set("CRVAL1", obs_metadata.pointingRA)
    fitsHeader.set("CRVAL2", obs_metadata.pointingDec)
    fitsHeader.set("CRPIX1",
                   crPix1 + 1)  # the +1 is because LSST uses 0-indexed images
    fitsHeader.set("CRPIX2", crPix2 + 1)  # FITS files use 1-indexed images
    fitsHeader.set("CTYPE1", "RA---TAN")
    fitsHeader.set("CTYPE2", "DEC--TAN")
    fitsHeader.setDouble("CD1_1", coeffs[0])
    fitsHeader.setDouble("CD1_2", coeffs[1])
    fitsHeader.setDouble("CD2_1", coeffs[2])
    fitsHeader.setDouble("CD2_2", coeffs[3])

    # 20 March 2017
    # the 'try' block is required by the SWIG stack;
    # the 'except' block is required by the pybind11 stack.
    try:
        tanWcs = afwImage.cast_TanWcs(afwImage.makeWcs(fitsHeader))
    except AttributeError:
        tanWcs = afwImage.makeWcs(fitsHeader)

    return tanWcs
Example #19
0
def tanWcsFromDetector(afwDetector, afwCamera, obs_metadata, epoch):
    """
    Take an afw.cameraGeom detector and return a WCS which approximates
    the focal plane as perfectly flat (i.e. it ignores optical distortions
    that the telescope may impose on the image)

    @param [in] afwDetector is an instantiation of afw.cameraGeom's Detector
    class which characterizes the detector for which you wish to return th
    WCS

    @param [in] afwCamera is an instantiation of afw.cameraGeom's Camera
    class which characterizes the camera containing afwDetector

    @param [in] obs_metadata is an instantiation of ObservationMetaData
    characterizing the telescope's current pointing

    @param [in] epoch is the epoch in Julian years of the equinox against
    which RA and Dec are measured

    @param [out] tanWcs is an instantiation of afw.image's TanWcs class
    representing the WCS of the detector as if there were no optical
    distortions imposed by the telescope.
    """

    xTanPixMin, xTanPixMax, \
    yTanPixMin, yTanPixMax = _getTanPixelBounds(afwDetector, afwCamera)

    xPixList = []
    yPixList = []
    nameList = []

    # dx and dy are set somewhat heuristically
    # setting them eqal to 0.1(max-min) lead to errors
    # on the order of 0.7 arcsec in the WCS

    dx = 0.5*(xTanPixMax-xTanPixMin)
    dy = 0.5*(yTanPixMax-yTanPixMin)

    for xx in np.arange(xTanPixMin, xTanPixMax+0.5*dx, dx):
        for yy in np.arange(yTanPixMin, yTanPixMax+0.5*dy, dy):
            xPixList.append(xx)
            yPixList.append(yy)
            nameList.append(afwDetector.getName())

    raList, decList = _raDecFromPixelCoords(np.array(xPixList),
                                            np.array(yPixList),
                                            nameList,
                                            camera=afwCamera,
                                            obs_metadata=obs_metadata,
                                            epoch=epoch,
                                            includeDistortion=False)

    crPix1, crPix2 = _pixelCoordsFromRaDec(obs_metadata._pointingRA,
                                           obs_metadata._pointingDec,
                                           chipName=afwDetector.getName(), camera=afwCamera,
                                           obs_metadata=obs_metadata, epoch=epoch,
                                           includeDistortion=False)

    lonList, latList = _nativeLonLatFromPointing(raList, decList,
                                                 obs_metadata._pointingRA,
                                                 obs_metadata._pointingDec)

    # convert from native longitude and latitude to intermediate world coordinates
    # according to equations (12), (13), (54) and (55) of
    #
    # Calabretta and Greisen (2002), A&A 395, p. 1077
    #
    radiusList = 180.0/(np.tan(latList)*np.pi)
    uList = radiusList*np.sin(lonList)
    vList = -radiusList*np.cos(lonList)

    delta_xList = xPixList - crPix1
    delta_yList = yPixList - crPix2

    bVector = np.array([
                       (delta_xList*uList).sum(),
                       (delta_yList*uList).sum(),
                       (delta_xList*vList).sum(),
                       (delta_yList*vList).sum()
                       ])

    offDiag = (delta_yList*delta_xList).sum()
    xsq = np.power(delta_xList, 2).sum()
    ysq = np.power(delta_yList, 2).sum()

    aMatrix = np.array([
                       [xsq, offDiag, 0.0, 0.0],
                       [offDiag, ysq, 0.0, 0.0],
                       [0.0, 0.0, xsq, offDiag],
                       [0.0, 0.0, offDiag, ysq]
                       ])

    coeffs = np.linalg.solve(aMatrix, bVector)

    fitsHeader = dafBase.PropertyList()
    fitsHeader.set("RADESYS", "ICRS")
    fitsHeader.set("EQUINOX", epoch)
    fitsHeader.set("CRVAL1", obs_metadata.pointingRA)
    fitsHeader.set("CRVAL2", obs_metadata.pointingDec)
    fitsHeader.set("CRPIX1", crPix1+1)  # the +1 is because LSST uses 0-indexed images
    fitsHeader.set("CRPIX2", crPix2+1)  # FITS files use 1-indexed images
    fitsHeader.set("CTYPE1", "RA---TAN")
    fitsHeader.set("CTYPE2", "DEC--TAN")
    fitsHeader.setDouble("CD1_1", coeffs[0])
    fitsHeader.setDouble("CD1_2", coeffs[1])
    fitsHeader.setDouble("CD2_1", coeffs[2])
    fitsHeader.setDouble("CD2_2", coeffs[3])
    tanWcs = afwImage.cast_TanWcs(afwImage.makeWcs(fitsHeader))

    return tanWcs
    def testOutputWcsOfImage(self):
        """
        Test that, when GalSim generates an image, in encodes the WCS in a
        way afw can read.  This is done by creating an image,then reading
        it back in, getting its WCS, and comparing the pixel-to-sky conversion
        both for the read WCS and the original afw.cameraGeom.detector.
        Raise an exception if the median difference between the two is
        greater than 0.01 arcseconds.
        """
        scratchDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'scratchSpace')
        catName = os.path.join(scratchDir, 'outputWcs_test_Catalog.dat')
        imageRoot = os.path.join(scratchDir, 'outputWcs_test_Image')
        dbFileName = os.path.join(scratchDir, 'outputWcs_test_InputCatalog.dat')

        baseDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'cameraData')
        camera = ReturnCamera(baseDir)

        detector = camera[0]
        detName = detector.getName()
        imageName = '%s_%s_u.fits' % (imageRoot, detName)

        nSamples = 3
        rng = np.random.RandomState(42)
        pointingRaList = rng.random_sample(nSamples)*360.0
        pointingDecList = rng.random_sample(nSamples)*180.0 - 90.0
        rotSkyPosList = rng.random_sample(nSamples)*360.0

        for raPointing, decPointing, rotSkyPos in \
            zip(pointingRaList, pointingDecList, rotSkyPosList):

            obs = ObservationMetaData(pointingRA = raPointing,
                                      pointingDec = decPointing,
                                      boundType = 'circle',
                                      boundLength = 4.0,
                                      rotSkyPos = rotSkyPos,
                                      mjd = 49250.0)

            fwhm = 0.7
            create_text_catalog(obs, dbFileName, np.array([3.0]),
                                np.array([1.0]))

            db = outputWcsFileDBObj(dbFileName, runtable='test')

            cat = outputWcsCat(db, obs_metadata=obs)
            cat.camera = camera

            psf = SNRdocumentPSF(fwhm=fwhm)
            cat.setPSF(psf)

            cat.write_catalog(catName)
            cat.write_images(nameRoot=imageRoot)

            exposure = afwImage.ExposureD_readFits(imageName)
            wcs = exposure.getWcs()

            xxTestList = []
            yyTestList = []

            raImage = []
            decImage = []

            for xx in np.arange(0.0, 4001.0, 100.0):
                for yy in np.arange(0.0, 4001.0, 100.0):
                    xxTestList.append(xx)
                    yyTestList.append(yy)

                    pt = afwGeom.Point2D(xx, yy)
                    skyPt = wcs.pixelToSky(pt).getPosition()
                    raImage.append(skyPt.getX())
                    decImage.append(skyPt.getY())

            xxTestList = np.array(xxTestList)
            yyTestList = np.array(yyTestList)

            raImage = np.radians(np.array(raImage))
            decImage = np.radians(np.array(decImage))

            raControl, \
            decControl = _raDecFromPixelCoords(xxTestList, yyTestList,
                                               [detector.getName()]*len(xxTestList),
                                               camera=camera, obs_metadata=obs,
                                               epoch=2000.0)

            errorList = arcsecFromRadians(haversine(raControl, decControl,
                                                    raImage, decImage))

            medianError = np.median(errorList)
            msg = 'medianError was %e' % medianError
            self.assertLess(medianError, 0.01, msg=msg)

            if os.path.exists(catName):
                os.unlink(catName)
            if os.path.exists(dbFileName):
                os.unlink(dbFileName)
            if os.path.exists(imageName):
                os.unlink(imageName)
Example #21
0
    def verify_fwhm(self, fileName, fwhm, detector, camera, obs, epoch=2000.0):
        """
        Read in a FITS image with one object on it and verify that that object
        has the expected Full Width at Half Maximum.  This is done by finding
        the brightest pixel in the image, and then drawing 1-dimensional profiles
        of the object centered on that pixel (but at different angles relative to
        the axes of the image).  The code then walks along those profiles and keeps
        track of the distance between the two points at which the flux is half of
        the maximum.

        @param [in] fileName is the name of the FITS image

        @param [in] fwhm is the expected Full Width at Half Maximum in arcseconds

        @param [in] detector is an instantiation of the afw.cameraGeom Detector
        class characterizing the detector corresponding to this image

        @param [in] camera is an instantiation of the afw.cameraGeom Camera class
        characterizing the camera to which detector belongs

        @param [in] obs is an instantiation of ObservationMetaData characterizing
        the telescope pointing

        @param [in] epoch is the epoch in Julian years of the equinox against which
        RA and Dec are measured.

        This method will raise an exception if the measured Full Width at Half Maximum
        deviates from the expected value by more than ten percent.
        """
        im = afwImage.ImageF(fileName).getArray()
        maxFlux = im.max()
        self.assertGreater(maxFlux, 100.0)  # make sure the image is not blank
        valid = np.where(im > 0.25*maxFlux)
        x_center = np.median(valid[1])
        y_center = np.median(valid[0])

        raMax, decMax = _raDecFromPixelCoords(x_center,
                                              y_center,
                                              [detector.getName()],
                                              camera=camera,
                                              obs_metadata=obs,
                                              epoch=epoch)

        half_flux = 0.5*maxFlux

        # only need to consider orientations between 0 and pi because the objects
        # will be circularly symmetric (and FWHM is a circularly symmetric measure, anyway)
        for theta in np.arange(0.0, np.pi, 0.3*np.pi):

            slope = np.tan(theta)

            if np.abs(slope < 1.0):
                xPixList = np.array([ix for ix in range(0, im.shape[1])
                                     if int(slope*(ix-x_center) + y_center) >= 0 and
                                     int(slope*(ix-x_center)+y_center) < im.shape[0]])

                yPixList = np.array([int(slope*(ix-x_center)+y_center) for ix in xPixList])
            else:
                yPixList = np.array([iy for iy in range(0, im.shape[0])
                                     if int((iy-y_center)/slope + x_center) >= 0 and
                                     int((iy-y_center)/slope + x_center) < im.shape[1]])

                xPixList = np.array([int((iy-y_center)/slope + x_center) for iy in yPixList])

            chipNameList = [detector.getName()]*len(xPixList)
            raList, decList = _raDecFromPixelCoords(xPixList, yPixList, chipNameList,
                                                    camera=camera, obs_metadata=obs, epoch=epoch)

            distanceList = arcsecFromRadians(haversine(raList, decList, raMax, decMax))

            fluxList = np.array([im[iy][ix] for ix, iy in zip(xPixList, yPixList)])

            distanceToLeft = None
            distanceToRight = None

            for ix in range(1, len(xPixList)):
                if fluxList[ix] < half_flux and fluxList[ix+1] >= half_flux:
                    break

            newOrigin = ix+1

            mm = (distanceList[ix]-distanceList[ix+1])/(fluxList[ix]-fluxList[ix+1])
            bb = distanceList[ix] - mm * fluxList[ix]
            distanceToLeft = mm*half_flux + bb

            for ix in range(newOrigin, len(xPixList)-1):
                if fluxList[ix] >= half_flux and fluxList[ix+1] < half_flux:
                    break

            mm = (distanceList[ix]-distanceList[ix+1])/(fluxList[ix]-fluxList[ix+1])
            bb = distanceList[ix] - mm * fluxList[ix]
            distanceToRight = mm*half_flux + bb

            msg = "measured fwhm %e; expected fwhm %e; maxFlux %e; orientation %e pi\n" % \
                  (distanceToLeft+distanceToRight, fwhm, maxFlux, theta/np.pi)

            self.assertLess(np.abs(distanceToLeft+distanceToRight-fwhm), 0.1*fwhm, msg=msg)