def pixelCoordinatesFromPupilCoordinates(self, xPupil, yPupil):
        """
        Convert pupil coordinates into pixel coordinates on this detector

        @param [in] xPupil is a numpy array or a float indicating x pupil coordinates
        in radians

        @param [in] yPupil a numpy array or a float indicating y pupil coordinates
        in radians

        @param [out] xPix is a numpy array indicating the x pixel coordinate

        @param [out] yPix is a numpy array indicating the y pixel coordinate
        """

        nameList = [self._name]
        if type(xPupil) is numpy.ndarray:
            nameList = nameList*len(xPupil)
            xp = xPupil
            yp = yPupil
        else:
            xp = numpy.array([xPupil])
            yp = numpy.array([yPupil])

        xPix, yPix = pixelCoordsFromPupilCoords(xp, yp, chipNames=nameList,
                                                camera=self._afwCamera)

        return xPix, yPix
    def pixelCoordinatesFromPupilCoordinates(self, xPupil, yPupil):
        """
        Convert pupil coordinates into pixel coordinates on this detector

        @param [in] xPupil is a numpy array or a float indicating x pupil coordinates
        in radians

        @param [in] yPupil a numpy array or a float indicating y pupil coordinates
        in radians

        @param [out] xPix is a numpy array indicating the x pixel coordinate

        @param [out] yPix is a numpy array indicating the y pixel coordinate
        """

        nameList = [self._name]
        if type(xPupil) is np.ndarray:
            nameList = nameList * len(xPupil)
            xp = xPupil
            yp = yPupil
        else:
            xp = np.array([xPupil])
            yp = np.array([yPupil])

        xPix, yPix = pixelCoordsFromPupilCoords(xp,
                                                yp,
                                                chipName=nameList,
                                                camera=self._afwCamera)

        return xPix, yPix
    def test_pixel_coords(self):
        """
        Test that pixelCoordsFromRaDecLSST with non-zero proper motion etc.
        agrees with pixelCoordsFromPupilCoords when pupilCoords are
        calculated with the same proper motion, etc.
        """
        (obs, ra_list, dec_list, pm_ra_list, pm_dec_list, parallax_list,
         v_rad_list) = self.set_data(26)

        for is_none in ('pm_ra', 'pm_dec', 'parallax', 'v_rad'):
            pm_ra = pm_ra_list
            pm_dec = pm_dec_list
            parallax = parallax_list
            v_rad = v_rad_list

            if is_none == 'pm_ra':
                pm_ra = None
            elif is_none == 'pm_dec':
                pm_dec = None
            elif is_none == 'parallax':
                parallax = None
            elif is_none == 'v_rad':
                v_rad = None

            xp, yp = pupilCoordsFromRaDec(ra_list,
                                          dec_list,
                                          pm_ra=pm_ra,
                                          pm_dec=pm_dec,
                                          parallax=parallax,
                                          v_rad=v_rad,
                                          obs_metadata=obs)

            xpx_control, ypx_control = pixelCoordsFromPupilCoords(
                xp, yp, camera=self.camera)

            xpx_test, ypx_test = pixelCoordsFromRaDecLSST(ra_list,
                                                          dec_list,
                                                          pm_ra=pm_ra,
                                                          pm_dec=pm_dec,
                                                          parallax=parallax,
                                                          v_rad=v_rad,
                                                          obs_metadata=obs)

            xpx_radians, ypx_radians = _pixelCoordsFromRaDecLSST(
                np.radians(ra_list),
                np.radians(dec_list),
                pm_ra=radiansFromArcsec(pm_ra),
                pm_dec=radiansFromArcsec(pm_dec),
                parallax=radiansFromArcsec(parallax),
                v_rad=v_rad,
                obs_metadata=obs)

            np.testing.assert_array_equal(xpx_control, xpx_test)
            np.testing.assert_array_equal(ypx_control, ypx_test)
            np.testing.assert_array_equal(xpx_control, xpx_radians)
            np.testing.assert_array_equal(ypx_control, ypx_radians)
            self.assertLess(len(np.where(np.isnan(xpx_control))[0]),
                            len(xpx_test) / 4)
            self.assertLess(len(np.where(np.isnan(ypx_control))[0]),
                            len(ypx_test) / 4)
Example #4
0
    def pixelCoordsFromPupilCoords(self,
                                   xPupil,
                                   yPupil,
                                   chipName=None,
                                   includeDistortion=True):
        """
        Get the pixel positions (or nan if not on a chip) for objects based
        on their pupil coordinates.

        Paramters
        ---------
        xPupil is the x pupil coordinates in radians. Can be either a float
        or a numpy array.

        yPupil is the y pupil coordinates in radians. Can be either a float
        or a numpy array.

        chipName designates the names of the chips on which the pixel
        coordinates will be reckoned.  Can be either single value, an array, or None.
        If an array, there must be as many chipNames as there are (RA, Dec) pairs.
        If a single value, all of the pixel coordinates will be reckoned on the same
        chip.  If None, this method will calculate which chip each(RA, Dec) pair actually
        falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate
        chip.  Default is None.

        includeDistortion is a boolean.  If True (default), then this method will
        return the true pixel coordinates with optical distortion included.  If False, this
        method will return 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 x pixel coordinate
        and the second row is the y pixel coordinate.  These pixel coordinates
        are defined in the Camera team system, rather than the DM system.
        """
        dm_x_pix, dm_y_pix = coordUtils.pixelCoordsFromPupilCoords(
            xPupil,
            yPupil,
            chipName=chipName,
            camera=self._camera,
            includeDistortion=includeDistortion)

        cam_y_pix = dm_x_pix
        if isinstance(chipName, list) or isinstance(chipName, np.ndarray):
            center_pix_dict = {}
            cam_x_pix = np.zeros(len(dm_y_pix))
            for ix, (det_name, yy) in enumerate(zip(chipName, dm_y_pix)):
                if det_name not in center_pix_dict:
                    center_pix = self.getCenterPixel(det_name)
                    center_pix_dict[det_name] = center_pix
                else:
                    center_pix = center_pix_dict[det_name]
                cam_x_pix[ix] = 2.0 * center_pix[0] - yy
        else:
            center_pix = self.getCenterPixel(chipName)
            cam_x_pix = 2.0 * center_pix[0] - dm_y_pix

        return cam_x_pix, cam_y_pix
    def test_pixel_coords(self):
        """
        Test that pixelCoordsFromRaDecLSST with non-zero proper motion etc.
        agrees with pixelCoordsFromPupilCoords when pupilCoords are
        calculated with the same proper motion, etc.
        """
        (obs, ra_list, dec_list,
         pm_ra_list, pm_dec_list,
         parallax_list, v_rad_list) = self.set_data(26)

        for is_none in ('pm_ra', 'pm_dec', 'parallax', 'v_rad'):
            pm_ra = pm_ra_list
            pm_dec = pm_dec_list
            parallax = parallax_list
            v_rad = v_rad_list

            if is_none == 'pm_ra':
                pm_ra = None
            elif is_none == 'pm_dec':
                pm_dec = None
            elif is_none == 'parallax':
                parallax = None
            elif is_none == 'v_rad':
                v_rad = None

            xp, yp = pupilCoordsFromRaDec(ra_list, dec_list,
                                          pm_ra=pm_ra, pm_dec=pm_dec,
                                          parallax=parallax, v_rad=v_rad,
                                          obs_metadata=obs)

            xpx_control, ypx_control = pixelCoordsFromPupilCoords(xp, yp, camera=self.camera,
                                                                  includeDistortion=False)

            xpx_test, ypx_test = pixelCoordsFromRaDecLSST(ra_list, dec_list,
                                                          pm_ra=pm_ra, pm_dec=pm_dec,
                                                          parallax=parallax, v_rad=v_rad,
                                                          obs_metadata=obs,
                                                          includeDistortion=False)

            xpx_radians, ypx_radians = _pixelCoordsFromRaDecLSST(np.radians(ra_list), np.radians(dec_list),
                                                                 pm_ra=radiansFromArcsec(pm_ra),
                                                                 pm_dec=radiansFromArcsec(pm_dec),
                                                                 parallax=radiansFromArcsec(parallax),
                                                                 v_rad=v_rad, obs_metadata=obs,
                                                                 includeDistortion=False)

            np.testing.assert_array_equal(xpx_control, xpx_test)
            np.testing.assert_array_equal(ypx_control, ypx_test)
            np.testing.assert_array_equal(xpx_control, xpx_radians)
            np.testing.assert_array_equal(ypx_control, ypx_radians)
            self.assertLess(len(np.where(np.isnan(xpx_control))[0]), len(xpx_test)/4)
            self.assertLess(len(np.where(np.isnan(ypx_control))[0]), len(ypx_test)/4)
    def pixelCoordsFromPupilCoords(self,
                                   xPupil,
                                   yPupil,
                                   chipName,
                                   obs_metadata,
                                   includeDistortion=True):
        """
        Get the pixel positions (or nan if not on a chip) for objects based
        on their pupil coordinates.

        Parameters
        ---------
        xPupil is the x pupil coordinates in radians. Can be either a float
        or a numpy array.

        yPupil is the y pupil coordinates in radians. Can be either a float
        or a numpy array.

        chipName designates the names of the chips on which the pixel
        coordinates will be reckoned.  Can be either single value, an array, or None.
        If an array, there must be as many chipNames as there are (RA, Dec) pairs.
        If a single value, all of the pixel coordinates will be reckoned on the same
        chip.  If None, this method will calculate which chip each(RA, Dec) pair actually
        falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate
        chip.

        obs_metadata is an ObservationMetaData characterizing the telescope
        pointing.

        includeDistortion is a boolean.  If True (default), then this method will
        return the true pixel coordinates with optical distortion included.  If False, this
        method will return 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 x pixel coordinate
        and the second row is the y pixel coordinate
        """
        if obs_metadata is None:
            raise RuntimeError("Must pass obs_metdata to "
                               "cameraWrapper.pixelCoordsFromPupilCoords")

        return coordUtils.pixelCoordsFromPupilCoords(
            xPupil,
            yPupil,
            chipName=chipName,
            camera=self._camera,
            includeDistortion=includeDistortion)
Example #7
0
def _chip_downselect(mag_norm, x_pupil, y_pupil, logger, target_chips=None):
    """
    Down-select objects based on focalplane location relative to chip
    boundaries.  If target_chips is None, then the down-selection will
    be made for all of the science sensors in the focalplane.

    Returns
    -------
    dict: Dictionary of np.where indexes keyed by chip name
    """
    if target_chips is None:
        target_chips = [det.getName() for det in lsst_camera()]

    # how close to the edge of the detector a source has
    # to be before we will just simulate it anyway
    pix_tol = 50.0

    # any source brighter than this will be considered
    # so bright that it should be simulated for all
    # detectors, just in case light scatters onto them.
    max_mag = 16.0

    # Down-select by object location in focalplane relative to chip
    # boundaries.
    logger.debug('down-selecting by chip, %s GB', uss_mem())
    on_chip_dict = {}
    for chip_name in target_chips:
        pixel_corners = getCornerPixels(chip_name, lsst_camera())
        x_min = pixel_corners[0][0]
        x_max = pixel_corners[2][0]
        y_min = pixel_corners[0][1]
        y_max = pixel_corners[3][1]
        xpix, ypix = pixelCoordsFromPupilCoords(x_pupil,
                                                y_pupil,
                                                chipName=chip_name,
                                                camera=lsst_camera())

        on_chip = np.where(
            np.logical_or(
                mag_norm < max_mag,
                np.logical_and(
                    xpix > x_min - pix_tol,
                    np.logical_and(
                        xpix < x_max + pix_tol,
                        np.logical_and(ypix > y_min - pix_tol,
                                       ypix < y_max + pix_tol)))))

        on_chip_dict[chip_name] = on_chip
    return on_chip_dict
    def testPlacement(self):
        """
        Test that GalSimInterpreter puts objects on the right detectors.

        Do so by creating a catalog of 3 closely-packed stars.  Draw test FITS
        images of them using the GalSim Catalog infrastructure.  Draw control FITS
        images of the detectors in the camera, paranoidly including every star
        in every control image (GalSim contains code such that it will not
        actually add flux to an image in cases where we try to include a
        star that does not actually fall on a detector).  Compare that

        a) the fluxes of the test and control images agree within some tolerance

        b) the fluxes of control images that have no corresponding test image
        (i.e. detectors on which no star actually fell) are effectively zero
        """

        # generate the database
        np_rng = np.random.RandomState(32)
        gs_rng = galsim.UniformDeviate(112)
        catSize = 3
        dbName = "galSimPlacementTestDB.db"
        driver = "sqlite"
        if os.path.exists(dbName):
            os.unlink(dbName)

        deltaRA = (-40.0 + np_rng.random_sample(catSize) * (120.0)) / 3600.0
        deltaDec = (-20.0 + np_rng.random_sample(catSize) * (80.0)) / 3600.0
        obs_metadata = makePhoSimTestDB(
            filename=dbName,
            deltaRA=deltaRA,
            deltaDec=deltaDec,
            bandpass=self.bandpassNameList,
            m5=self.m5,
            seeing=self.seeing,
        )

        stars = testStarsDBObj(driver=driver, database=dbName)

        # create the catalog
        cat = testStarCatalog(stars, obs_metadata=obs_metadata)
        results = cat.iter_catalog()
        firstLine = True

        # iterate over the catalog, giving every star a chance to
        # illumine every detector
        controlImages = {}
        for i, line in enumerate(results):
            xPupil = line[5]
            yPupil = line[6]

            if firstLine:
                sedList = list(cat._calculateGalSimSeds())
                for detector in cat.galSimInterpreter.detectors:
                    for bandpass in cat.galSimInterpreter.bandpassDict:
                        controlImages[
                            "placementControl_"
                            + cat.galSimInterpreter._getFileName(detector=detector, bandpassName=bandpass)
                        ] = cat.galSimInterpreter.blankImage(detector=detector)

                firstLine = False

            for bp in cat.galSimInterpreter.bandpassDict:
                bandpass = cat.galSimInterpreter.bandpassDict[bp]
                adu = sedList[i].calcADU(bandpass, cat.photParams)
                for detector in cat.galSimInterpreter.detectors:
                    centeredObj = cat.galSimInterpreter.PSF.applyPSF(xPupil=xPupil, yPupil=yPupil)

                    xPix, yPix = pixelCoordsFromPupilCoords(
                        radiansFromArcsec(xPupil),
                        radiansFromArcsec(yPupil),
                        chipName=detector.name,
                        camera=detector.afwCamera,
                    )

                    dx = xPix - detector.xCenterPix
                    dy = yPix - detector.yCenterPix
                    obj = centeredObj.withFlux(adu * detector.photParams.gain)
                    localImage = cat.galSimInterpreter.blankImage(detector=detector)
                    localImage = obj.drawImage(
                        wcs=detector.wcs,
                        method="phot",
                        gain=detector.photParams.gain,
                        image=localImage,
                        offset=galsim.PositionD(dx, dy),
                        rng=gs_rng,
                    )

                    controlImages[
                        "placementControl_" + cat.galSimInterpreter._getFileName(detector=detector, bandpassName=bp)
                    ] += localImage

        self.assertGreater(len(controlImages), 0)

        for name in controlImages:
            controlImages[name].write(file_name=name)

        # write the test images using the catalog infrastructure
        testNames = cat.write_images(nameRoot="placementTest")

        # make sure that every test image has a corresponding control image
        for testName in testNames:
            controlName = testName.replace("Test", "Control")
            msg = "%s has no counterpart " % testName
            self.assertIn(controlName, controlImages, msg=msg)

        # make sure that the test and control images agree to some tolerance
        ignored = 0
        zeroFlux = 0
        valid = 0
        for controlName in controlImages:
            controlImage = afwImage.ImageF(controlName)
            controlFlux = controlImage.getArray().sum()

            testName = controlName.replace("Control", "Test")
            if testName in testNames:
                testImage = afwImage.ImageF(testName)
                testFlux = testImage.getArray().sum()
                if controlFlux > 1000.0:
                    countSigma = np.sqrt(controlFlux / cat.photParams.gain)
                    msg = "%s: controlFlux = %e, testFlux = %e, sigma %e" % (
                        controlName,
                        controlFlux,
                        testFlux,
                        countSigma,
                    )

                    # the randomness of photon shooting means that faint images won't agree
                    self.assertLess(np.abs(controlFlux - testFlux), 4.0 * countSigma, msg=msg)
                    valid += 1
                else:
                    ignored += 1
            else:
                # make sure that controlImages that have no corresponding test image really do
                # have zero flux (because no star fell on them)
                zeroFlux += 1
                msg = "%s has flux %e but was not written by catalog" % (controlName, controlFlux)
                self.assertLess(controlFlux, 1.0, msg=msg)

        self.assertGreater(valid, 0)
        self.assertLess(ignored, len(testNames) / 2)
        self.assertGreater(zeroFlux, 0)

        for testName in testNames:
            if os.path.exists(testName):
                os.unlink(testName)

        for controlName in controlImages:
            if os.path.exists(controlName):
                os.unlink(controlName)

        if os.path.exists(dbName):
            os.unlink(dbName)
Example #9
0
def pixelCoordsFromPupilCoordsLSST(xPupil,
                                   yPupil,
                                   chipName=None,
                                   band="r",
                                   includeDistortion=True):
    """
    Convert radians on the pupil into pixel coordinates.

    Parameters
    ----------
    xPupil -- is the x coordinate on the pupil in radians

    yPupil -- is the y coordinate on the pupil in radians

    chipName -- designates the names of the chips on which the pixel
    coordinates will be reckoned.  Can be either single value, an array, or None.
    If an array, there must be as many chipNames as there are (xPupil, yPupil) pairs.
    If a single value, all of the pixel coordinates will be reckoned on the same
    chip.  If None, this method will calculate which chip each(xPupil, yPupil) pair
    actually falls on, and return pixel coordinates for each (xPupil, yPupil) pair on
    the appropriate chip.  Default is None.

    band -- the filter we are simulating (default=r)

    includeDistortion -- a boolean which turns on and off optical distortions
    (default=True)

    Returns
    -------
    a 2-D numpy array in which the first row is the x pixel coordinate
    and the second row is the y pixel coordinate
    """

    if not includeDistortion:
        return pixelCoordsFromPupilCoords(xPupil,
                                          yPupil,
                                          chipName=chipName,
                                          camera=lsst_camera(),
                                          includeDistortion=includeDistortion)

    are_arrays, \
    chipNameList = _validate_inputs_and_chipname([xPupil, yPupil],
                                                 ['xPupil', 'yPupil'],
                                                 'pixelCoordsFromPupilCoordsLSST',
                                                 chipName)

    if chipNameList is None:
        chipNameList = chipNameFromPupilCoordsLSST(xPupil, yPupil)
        if not isinstance(chipNameList, np.ndarray):
            chipNameList = np.array([chipNameList])
    else:
        if not isinstance(chipNameList, list) and not isinstance(
                chipNameList, np.ndarray):
            chipNameList = np.array([chipNameList])
        elif isinstance(chipNameList, list):
            chipNameList = np.array(chipNameList)

    x_f, y_f = focalPlaneCoordsFromPupilCoordsLSST(xPupil, yPupil, band=band)

    if are_arrays:

        has_transform = set()
        focal_to_pixel_dict = {}
        chip_name_int = np.zeros(len(x_f), dtype=int)
        name_to_int = {}
        name_to_int[None] = 0
        name_to_int['None'] = 0
        ii = 1
        for i_obj, chip_name in enumerate(chipNameList):
            if chip_name not in has_transform and chip_name is not None and chip_name != 'None':
                has_transform.add(chip_name)
                focal_to_pixel_dict[chip_name] = lsst_camera(
                )[chip_name].getTransform(FOCAL_PLANE, PIXELS)
                name_to_int[chip_name] = ii
                ii += 1

            chip_name_int[i_obj] = name_to_int[chip_name]

        x_pix = np.NaN * np.ones(len(x_f), dtype=float)
        y_pix = np.NaN * np.ones(len(x_f), dtype=float)

        for chip_name in has_transform:
            if chip_name == 'None' or chip_name is None:
                continue

            local_int = name_to_int[chip_name]
            local_valid = np.where(chip_name_int == local_int)
            if len(local_valid[0]) == 0:
                continue
            focal_pt_arr = [
                geom.Point2D(x_f[ii], y_f[ii]) for ii in local_valid[0]
            ]
            pixel_pt_arr = focal_to_pixel_dict[chip_name].applyForward(
                focal_pt_arr)
            pixel_coord_arr = np.array([[pp.getX(), pp.getY()]
                                        for pp in pixel_pt_arr]).transpose()

            x_pix[local_valid] = pixel_coord_arr[0]
            y_pix[local_valid] = pixel_coord_arr[1]
    else:
        chip_name = chipNameList[0]
        if chip_name is None:
            x_pix = np.NaN
            y_pix = np.NaN
        else:
            det = lsst_camera()[chip_name]
            focal_to_pixels = det.getTransform(FOCAL_PLANE, PIXELS)
            focal_pt = geom.Point2D(x_f, y_f)
            pixel_pt = focal_to_pixels.applyForward(focal_pt)
            x_pix = pixel_pt.getX()
            y_pix = pixel_pt.getY()

    return np.array([x_pix, y_pix])
Example #10
0
    def testUtilityMethods(self):
        """
        Generate a catalog using the methods from AstrometryUtils.py and CameraUtils.py.
        Read that data in, and then recalculate the values 'by hand' to make sure
        that they are consistent.
        """

        catName = os.path.join(getPackageDir('sims_catUtils'), 'tests', 'scratchSpace',
                               'AstrometryUtilityCatalog.txt')

        if os.path.exists(catName):
            os.unlink(catName)

        self.cat.write_catalog(catName)

        dtype = [('id', int),
                 ('raICRS', float), ('decICRS', float),
                 ('parallax', float), ('radial_velocity', float),
                 ('x_pupil', float), ('y_pupil', float), ('chipName', str, 11),
                 ('xPix', float), ('yPix', float),
                 ('xFocalPlane', float), ('yFocalPlane', float)]

        baselineData = np.genfromtxt(catName, dtype=dtype, delimiter=';')

        self.assertGreater(len(baselineData), 0)

        pupilTest = _pupilCoordsFromRaDec(baselineData['raICRS'],
                                          baselineData['decICRS'],
                                          parallax=baselineData['parallax'],
                                          v_rad=baselineData['radial_velocity'],
                                          obs_metadata=self.obs_metadata,
                                          epoch=2000.0)

        for (xxtest, yytest, xx, yy) in \
                zip(pupilTest[0], pupilTest[1], baselineData['x_pupil'], baselineData['y_pupil']):
            self.assertAlmostEqual(xxtest, xx, 6)
            self.assertAlmostEqual(yytest, yy, 6)

        focalTest = focalPlaneCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera)

        focalRa = _focalPlaneCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'],
                                             parallax=baselineData['parallax'],
                                             v_rad=baselineData['radial_velocity'],
                                             epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata,
                                             camera=self.cat.camera)

        for (xxtest, yytest, xxra, yyra, xx, yy) in \
                zip(focalTest[0], focalTest[1], focalRa[0], focalRa[1],
                    baselineData['xFocalPlane'], baselineData['yFocalPlane']):

            self.assertAlmostEqual(xxtest, xx, 6)
            self.assertAlmostEqual(yytest, yy, 6)
            self.assertAlmostEqual(xxra, xx, 6)
            self.assertAlmostEqual(yyra, yy, 6)

        pixTest = pixelCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera)

        pixTestRaDec = _pixelCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'],
                                             parallax=baselineData['parallax'],
                                             v_rad=baselineData['radial_velocity'],
                                             epoch=self.cat.db_obj.epoch,
                                             obs_metadata=self.cat.obs_metadata,
                                             camera=self.cat.camera)

        for (xxtest, yytest, xxra, yyra, xx, yy) in \
                zip(pixTest[0], pixTest[1], pixTestRaDec[0], pixTestRaDec[1],
                    baselineData['xPix'], baselineData['yPix']):

            if not np.isnan(xx) and not np.isnan(yy):
                self.assertAlmostEqual(xxtest, xx, 5)
                self.assertAlmostEqual(yytest, yy, 5)
                self.assertAlmostEqual(xxra, xx, 5)
                self.assertAlmostEqual(yyra, yy, 5)
            else:
                np.testing.assert_equal(xx, np.NaN)
                np.testing.assert_equal(yy, np.NaN)
                np.testing.assert_equal(xxra, np.NaN)
                np.testing.assert_equal(yyra, np.NaN)
                np.testing.assert_equal(xxtest, np.NaN)
                np.testing.assert_equal(yytest, np.NaN)

        nameTest = chipNameFromPupilCoords(pupilTest[0], pupilTest[1],
                                           camera=self.cat.camera)

        nameRA = _chipNameFromRaDec(baselineData['raICRS'], baselineData['decICRS'],
                                    epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata,
                                    camera=self.cat.camera)

        is_none = 0
        for (ntest, nra, ncontrol) in zip(nameTest, nameRA, baselineData['chipName']):
            if ncontrol != 'None':
                self.assertEqual(ntest, ncontrol)
                self.assertEqual(nra, ncontrol)
            else:
                is_none += 1
                self.assertIsNone(ntest)
                self.assertIsNone(nra)

        self.assertGreater(is_none, 0)
        self.assertLess(is_none, len(baselineData))

        if os.path.exists(catName):
            os.unlink(catName)
    def testPlacement(self):
        """
        Test that GalSimInterpreter puts objects on the right detectors.

        Do so by creating a catalog of 10 closely-packed stars.  Draw test FITS
        images of them using the GalSim Catalog infrastructure.  Draw control FITS
        images of the detectors in the camera, paranoidly including every star
        in every control image (GalSim contains code such that it will not
        actually add flux to an image in cases where we try to include a
        star that does not actually fall on a detector).  Compare that

        a) the fluxes of the test and control images agree within some tolerance

        b) the fluxes of control images that have no corresponding test image
        (i.e. detectors on which no star actually fell) are effectively zero
        """

        #generate the database
        numpy.random.seed(32)
        catSize = 10
        dbName = 'galSimPlacementTestDB.db'
        driver = 'sqlite'
        if os.path.exists(dbName):
            os.unlink(dbName)

        displacedRA = (-40.0 + numpy.random.sample(catSize)*(120.0))/3600.0
        displacedDec = (-20.0 + numpy.random.sample(catSize)*(80.0))/3600.0
        obs_metadata = makePhoSimTestDB(filename=dbName, displacedRA=displacedRA, displacedDec=displacedDec,
                                        bandpass=self.bandpassNameList,
                                        m5=self.m5, seeing=self.seeing)

        catName = 'testPlacementCat.sav'
        stars = testStarsDBObj(driver=driver, database=dbName)

        #create the catalog
        cat = testStarCatalog(stars, obs_metadata = obs_metadata)
        results = cat.iter_catalog()
        firstLine = True

        #iterate over the catalog, giving every star a chance to
        #illumine every detector
        controlImages = {}
        for i, line in enumerate(results):
            galSimType = line[0]
            xPupil = line[5]
            yPupil = line[6]


            majorAxis = line[8]
            minorAxis = line[9]
            sindex = line[10]
            halfLightRadius = line[11]
            positionAngle = line[12]
            if firstLine:
                sedList = cat._calculateGalSimSeds()
                for detector in cat.galSimInterpreter.detectors:
                    for bandpass in cat.galSimInterpreter.bandpasses:
                        controlImages['placementControl_' + \
                                      cat.galSimInterpreter._getFileName(detector=detector, bandpassName=bandpass)] = \
                                      cat.galSimInterpreter.blankImage(detector=detector)
                firstLine = False

            spectrum = galsim.SED(spec=lambda ll: numpy.interp(ll, sedList[i].wavelen, sedList[i].flambda), flux_type='flambda')
            for bp in cat.galSimInterpreter.bandpasses:
                bandpass = cat.galSimInterpreter.bandpasses[bp]
                for detector in cat.galSimInterpreter.detectors:
                    centeredObj = cat.galSimInterpreter.PSF.applyPSF(xPupil=xPupil, yPupil=yPupil, bandpass=bandpass)

                    xPix, yPix = pixelCoordsFromPupilCoords(numpy.array([radiansFromArcsec(xPupil)]),
                                                            numpy.array([radiansFromArcsec(yPupil)]),
                                                            chipNames = [detector.name],
                                                            camera = detector.afwCamera)

                    dx = xPix[0] - detector.xCenterPix
                    dy = yPix[0] - detector.yCenterPix
                    obj = centeredObj*spectrum
                    localImage = cat.galSimInterpreter.blankImage(detector=detector)
                    localImage = obj.drawImage(bandpass=bandpass, wcs=detector.wcs, method='phot',
                                               gain=detector.photParams.gain, image=localImage,
                                               offset=galsim.PositionD(dx, dy))

                    controlImages['placementControl_' + \
                                  cat.galSimInterpreter._getFileName(detector=detector, bandpassName=bp)] += \
                                  localImage

        for name in controlImages:
            controlImages[name].write(file_name=name)

        #write the test images using the catalog infrastructure
        testNames = cat.write_images(nameRoot='placementTest')

        #make sure that every test image has a corresponding control image
        for testName in testNames:
            controlName = testName.replace('Test', 'Control')
            msg = '%s has no counterpart ' % testName
            self.assertTrue(controlName in controlImages, msg=msg)

        #make sure that the test and control images agree to some tolerance
        ignored = 0
        zeroFlux = 0
        for controlName in controlImages:
            controlImage = afwImage.ImageF(controlName)
            controlFlux = controlImage.getArray().sum()

            testName = controlName.replace('Control', 'Test')
            if testName in testNames:
                testImage = afwImage.ImageF(testName)
                testFlux = testImage.getArray().sum()
                msg = '%s: controlFlux = %e, testFlux = %e' % (controlName, controlFlux, testFlux)
                if controlFlux>1000.0:
                    #the randomness of photon shooting means that faint images won't agree
                    self.assertTrue(numpy.abs(controlFlux/testFlux - 1.0)<0.1, msg=msg)
                else:
                    ignored += 1
            else:
                #make sure that controlImages that have no corresponding test image really do
                #have zero flux (because no star fell on them)
                zeroFlux += 1
                msg = '%s has flux %e but was not written by catalog' % (controlName, controlFlux)
                self.assertTrue(controlFlux<1.0, msg=msg)

        self.assertTrue(ignored<len(testNames)/2)
        self.assertTrue(zeroFlux>0)

        for testName in testNames:
            if os.path.exists(testName):
                os.unlink(testName)

        for controlName in controlImages:
            if os.path.exists(controlName):
                os.unlink(controlName)

        if os.path.exists(dbName):
            os.unlink(dbName)
def _pixelCoordsFromRaDecLSST(ra, dec, pm_ra=None, pm_dec=None, parallax=None, v_rad=None,
                              obs_metadata=None,
                              chipName=None, camera=None,
                              epoch=2000.0, includeDistortion=True):
    """
    Get the pixel positions on the LSST camera (or nan if not on a chip) for objects based
    on their RA, and Dec (in radians)

    @param [in] ra is in radians in the International Celestial Reference System.
    Can be either a float or a numpy array.

    @param [in] dec is in radians in the International Celestial Reference System.
    Can be either a float or a numpy array.

    @param [in] pm_ra is proper motion in RA multiplied by cos(Dec) (radians/yr)
    Can be a numpy array or a number or None (default=None).

    @param [in] pm_dec is proper motion in dec (radians/yr)
    Can be a numpy array or a number or None (default=None).

    @param [in] parallax is parallax in radians
    Can be a numpy array or a number or None (default=None).

    @param [in] v_rad is radial velocity (km/s)
    Can be a numpy array or a number or None (default=None).

    @param [in] obs_metadata is an ObservationMetaData characterizing the telescope
    pointing.

    @param [in] epoch is the epoch in Julian years of the equinox against which
    RA is measured.  Default is 2000.

    @param [in] chipName designates the names of the chips on which the pixel
    coordinates will be reckoned.  Can be either single value, an array, or None.
    If an array, there must be as many chipNames as there are (RA, Dec) pairs.
    If a single value, all of the pixel coordinates will be reckoned on the same
    chip.  If None, this method will calculate which chip each(RA, Dec) pair actually
    falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate
    chip.  Default is None.

    @param [in] camera is an afwCameraGeom object specifying the attributes of the camera.
    This is an optional argument to be passed to chipName.

    @param [in] includeDistortion is a boolean.  If True (default), then this method will
    return the true pixel coordinates with optical distortion included.  If False, this
    method will return TAN_PIXEL coordinates, which are the pixel coordinates with
    estimated optical distortion removed.  See the documentation in afw.cameraGeom for more
    details.

    @param [out] a 2-D numpy array in which the first row is the x pixel coordinate
    and the second row is the y pixel coordinate
    """

    are_arrays, \
    chipNameList = _validate_inputs_and_chipname([ra, dec], ['ra', 'dec'],
                                                 'pixelCoordsFromRaDecLSST',
                                                 chipName)

    if epoch is None:
        raise RuntimeError("You need to pass an epoch into pixelCoordsFromRaDec")

    if obs_metadata is None:
        raise RuntimeError("You need to pass an ObservationMetaData into pixelCoordsFromRaDec")

    if obs_metadata.mjd is None:
        raise RuntimeError("You need to pass an ObservationMetaData with an mjd into "
                           "pixelCoordsFromRaDec")

    if obs_metadata.rotSkyPos is None:
        raise RuntimeError("You need to pass an ObservationMetaData with a rotSkyPos into "
                           "pixelCoordsFromRaDec")

    xPupil, yPupil = _pupilCoordsFromRaDec(ra, dec,
                                           pm_ra=pm_ra, pm_dec=pm_dec,
                                           parallax=parallax, v_rad=v_rad,
                                           obs_metadata=obs_metadata, epoch=epoch)

    if chipNameList is None:
        chipNameList = chipNameFromPupilCoordsLSST(xPupil, yPupil)

    return pixelCoordsFromPupilCoords(xPupil, yPupil, chipName=chipNameList, camera=lsst_camera(),
                                      includeDistortion=includeDistortion)
    def testUtilityMethods(self):
        """
        Generate a catalog using the methods from AstrometryUtils.py and CameraUtils.py.
        Read that data in, and then recalculate the values 'by hand' to make sure
        that they are consistent.
        """

        self.cat.write_catalog("AstrometryTestCatalog.txt")

        dtype = [('id',int),
                 ('raPhoSim',float), ('decPhoSim',float),
                 ('raObserved',float), ('decObserved',float),
                 ('x_pupil',float), ('y_pupil',float), ('chipName',str,11),
                 ('xPix',float), ('yPix',float),
                 ('xFocalPlane',float), ('yFocalPlane',float)]

        baselineData = numpy.loadtxt('AstrometryTestCatalog.txt', dtype=dtype, delimiter=';')

        pupilTest = _pupilCoordsFromRaDec(baselineData['raObserved'],
                                              baselineData['decObserved'],
                                              obs_metadata=self.obs_metadata,
                                              epoch=2000.0)

        for (xxtest, yytest, xx, yy) in \
                zip(pupilTest[0], pupilTest[1], baselineData['x_pupil'], baselineData['y_pupil']):
            self.assertAlmostEqual(xxtest,xx,6)
            self.assertAlmostEqual(yytest,yy,6)

        focalTest = focalPlaneCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera)

        focalRa = _focalPlaneCoordsFromRaDec(baselineData['raObserved'], baselineData['decObserved'],
                                             epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata,
                                             camera=self.cat.camera)

        for (xxtest, yytest, xxra, yyra, xx, yy) in \
                zip(focalTest[0], focalTest[1], focalRa[0], focalRa[1],
                        baselineData['xFocalPlane'], baselineData['yFocalPlane']):

            self.assertAlmostEqual(xxtest,xx,6)
            self.assertAlmostEqual(yytest,yy,6)
            self.assertAlmostEqual(xxra,xx,6)
            self.assertAlmostEqual(yyra,yy,6)

        pixTest = pixelCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera)

        pixTestRaDec = _pixelCoordsFromRaDec(baselineData['raObserved'], baselineData['decObserved'],
                                             epoch=self.cat.db_obj.epoch,
                                             obs_metadata=self.cat.obs_metadata,
                                             camera=self.cat.camera)

        for (xxtest, yytest, xxra, yyra, xx, yy) in \
                zip(pixTest[0], pixTest[1], pixTestRaDec[0], pixTestRaDec[1],
                           baselineData['xPix'], baselineData['yPix']):

            if not numpy.isnan(xx) and not numpy.isnan(yy):
                self.assertAlmostEqual(xxtest,xx,5)
                self.assertAlmostEqual(yytest,yy,5)
                self.assertAlmostEqual(xxra,xx,5)
                self.assertAlmostEqual(yyra,yy,5)
            else:
                self.assertTrue(numpy.isnan(xx))
                self.assertTrue(numpy.isnan(yy))
                self.assertTrue(numpy.isnan(xxra))
                self.assertTrue(numpy.isnan(yyra))
                self.assertTrue(numpy.isnan(xxtest))
                self.assertTrue(numpy.isnan(yytest))


        nameTest = chipNameFromPupilCoords(pupilTest[0], pupilTest[1],
                                           camera=self.cat.camera)

        nameRA = _chipNameFromRaDec(baselineData['raObserved'], baselineData['decObserved'],
                                    epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata,
                                    camera=self.cat.camera)

        for (ntest, nra, ncontrol) in zip(nameTest, nameRA, baselineData['chipName']):
            if ncontrol != 'None':
                self.assertEqual(ntest,ncontrol)
                self.assertEqual(nra,ncontrol)
            else:
                self.assertTrue(ntest is None)
                self.assertTrue(nra is None)

        if os.path.exists("AstrometryTestCatalog.txt"):
            os.unlink("AstrometryTestCatalog.txt")
    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
Example #15
0
    def testPlacement(self):
        """
        Test that GalSimInterpreter puts objects on the right detectors.

        Do so by creating a catalog of 3 closely-packed stars.  Draw test FITS
        images of them using the GalSim Catalog infrastructure.  Draw control FITS
        images of the detectors in the camera, paranoidly including every star
        in every control image (GalSim contains code such that it will not
        actually add flux to an image in cases where we try to include a
        star that does not actually fall on a detector).  Compare that

        a) the fluxes of the test and control images agree within some tolerance

        b) the fluxes of control images that have no corresponding test image
        (i.e. detectors on which no star actually fell) are effectively zero
        """

        # generate the database
        np_rng = np.random.RandomState(32)
        gs_rng = galsim.UniformDeviate(112)
        catSize = 3
        dbName = 'galSimPlacementTestDB.db'
        driver = 'sqlite'
        if os.path.exists(dbName):
            os.unlink(dbName)

        deltaRA = (-40.0 + np_rng.random_sample(catSize) * (120.0)) / 3600.0
        deltaDec = (-20.0 + np_rng.random_sample(catSize) * (80.0)) / 3600.0
        obs_metadata = makePhoSimTestDB(filename=dbName,
                                        deltaRA=deltaRA,
                                        deltaDec=deltaDec,
                                        bandpass=self.bandpassNameList,
                                        m5=self.m5,
                                        seeing=self.seeing)

        stars = testStarsDBObj(driver=driver, database=dbName)

        # create the catalog
        cat = testStarCatalog(stars, obs_metadata=obs_metadata)
        results = cat.iter_catalog()
        firstLine = True

        # iterate over the catalog, giving every star a chance to
        # illumine every detector
        controlImages = {}
        for i, line in enumerate(results):
            xPupil = line[5]
            yPupil = line[6]

            if firstLine:
                sedList = list(cat._calculateGalSimSeds())
                for detector in cat.galSimInterpreter.detectors:
                    for bandpass in cat.galSimInterpreter.bandpassDict:
                        controlImages['placementControl_' +
                                      cat.galSimInterpreter._getFileName(detector=detector,
                                                                         bandpassName=bandpass)] = \
                            cat.galSimInterpreter.blankImage(detector=detector)

                firstLine = False

            for bp in cat.galSimInterpreter.bandpassDict:
                bandpass = cat.galSimInterpreter.bandpassDict[bp]
                adu = sedList[i].calcADU(bandpass, cat.photParams)
                for detector in cat.galSimInterpreter.detectors:
                    centeredObj = cat.galSimInterpreter.PSF.applyPSF(
                        xPupil=xPupil, yPupil=yPupil)

                    xPix, yPix = pixelCoordsFromPupilCoords(
                        radiansFromArcsec(xPupil),
                        radiansFromArcsec(yPupil),
                        chipName=detector.name,
                        camera=detector.afwCamera)

                    dx = xPix - detector.xCenterPix
                    dy = yPix - detector.yCenterPix
                    obj = centeredObj.withFlux(adu * detector.photParams.gain)
                    localImage = cat.galSimInterpreter.blankImage(
                        detector=detector)
                    localImage = obj.drawImage(wcs=detector.wcs,
                                               method='phot',
                                               gain=detector.photParams.gain,
                                               image=localImage,
                                               offset=galsim.PositionD(dx, dy),
                                               rng=gs_rng)

                    controlImages[
                        'placementControl_' +
                        cat.galSimInterpreter._getFileName(
                            detector=detector, bandpassName=bp)] += localImage

        self.assertGreater(len(controlImages), 0)

        for name in controlImages:
            controlImages[name].write(file_name=name)

        # write the test images using the catalog infrastructure
        testNames = cat.write_images(nameRoot='placementTest')

        # make sure that every test image has a corresponding control image
        for testName in testNames:
            controlName = testName.replace('Test', 'Control')
            msg = '%s has no counterpart ' % testName
            self.assertIn(controlName, controlImages, msg=msg)

        # make sure that the test and control images agree to some tolerance
        ignored = 0
        zeroFlux = 0
        valid = 0
        for controlName in controlImages:
            controlImage = afwImage.ImageF(controlName)
            controlFlux = controlImage.getArray().sum()

            testName = controlName.replace('Control', 'Test')
            if testName in testNames:
                testImage = afwImage.ImageF(testName)
                testFlux = testImage.getArray().sum()
                if controlFlux > 1000.0:
                    countSigma = np.sqrt(controlFlux / cat.photParams.gain)
                    msg = '%s: controlFlux = %e, testFlux = %e, sigma %e' \
                          % (controlName, controlFlux, testFlux, countSigma)

                    # the randomness of photon shooting means that faint images won't agree
                    self.assertLess(np.abs(controlFlux - testFlux),
                                    4.0 * countSigma,
                                    msg=msg)
                    valid += 1
                else:
                    ignored += 1
            else:
                # make sure that controlImages that have no corresponding test image really do
                # have zero flux (because no star fell on them)
                zeroFlux += 1
                msg = '%s has flux %e but was not written by catalog' % (
                    controlName, controlFlux)
                self.assertLess(controlFlux, 1.0, msg=msg)

        self.assertGreater(valid, 0)
        self.assertLess(ignored, len(testNames) / 2)
        self.assertGreater(zeroFlux, 0)

        for testName in testNames:
            if os.path.exists(testName):
                os.unlink(testName)

        for controlName in controlImages:
            if os.path.exists(controlName):
                os.unlink(controlName)

        if os.path.exists(dbName):
            os.unlink(dbName)
    def testUtilityMethods(self):
        """
        Generate a catalog using the methods from AstrometryUtils.py and CameraUtils.py.
        Read that data in, and then recalculate the values 'by hand' to make sure
        that they are consistent.
        """

        with lsst.utils.tests.getTempFilePath('.txt') as catName:
            self.cat.write_catalog(catName)

            dtype = [('id', int),
                     ('raICRS', float), ('decICRS', float),
                     ('parallax', float), ('radial_velocity', float),
                     ('x_pupil', float), ('y_pupil', float), ('chipName', str, 11),
                     ('xPix', float), ('yPix', float),
                     ('xFocalPlane', float), ('yFocalPlane', float)]

            baselineData = np.genfromtxt(catName, dtype=dtype, delimiter=';')

        self.assertGreater(len(baselineData), 0)

        pupilTest = _pupilCoordsFromRaDec(baselineData['raICRS'],
                                          baselineData['decICRS'],
                                          parallax=baselineData['parallax'],
                                          v_rad=baselineData['radial_velocity'],
                                          obs_metadata=self.obs_metadata,
                                          epoch=2000.0)

        for (xxtest, yytest, xx, yy) in \
                zip(pupilTest[0], pupilTest[1], baselineData['x_pupil'], baselineData['y_pupil']):
            self.assertAlmostEqual(xxtest, xx, 6)
            self.assertAlmostEqual(yytest, yy, 6)

        focalTest = focalPlaneCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera)

        focalRa = _focalPlaneCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'],
                                             parallax=baselineData['parallax'],
                                             v_rad=baselineData['radial_velocity'],
                                             epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata,
                                             camera=self.cat.camera)

        for (xxtest, yytest, xxra, yyra, xx, yy) in \
                zip(focalTest[0], focalTest[1], focalRa[0], focalRa[1],
                    baselineData['xFocalPlane'], baselineData['yFocalPlane']):

            self.assertAlmostEqual(xxtest, xx, 6)
            self.assertAlmostEqual(yytest, yy, 6)
            self.assertAlmostEqual(xxra, xx, 6)
            self.assertAlmostEqual(yyra, yy, 6)

        pixTest = pixelCoordsFromPupilCoords(pupilTest[0], pupilTest[1], camera=self.cat.camera)

        pixTestRaDec = _pixelCoordsFromRaDec(baselineData['raICRS'], baselineData['decICRS'],
                                             parallax=baselineData['parallax'],
                                             v_rad=baselineData['radial_velocity'],
                                             epoch=self.cat.db_obj.epoch,
                                             obs_metadata=self.cat.obs_metadata,
                                             camera=self.cat.camera)

        for (xxtest, yytest, xxra, yyra, xx, yy) in \
                zip(pixTest[0], pixTest[1], pixTestRaDec[0], pixTestRaDec[1],
                    baselineData['xPix'], baselineData['yPix']):

            if not np.isnan(xx) and not np.isnan(yy):
                self.assertAlmostEqual(xxtest, xx, 5)
                self.assertAlmostEqual(yytest, yy, 5)
                self.assertAlmostEqual(xxra, xx, 5)
                self.assertAlmostEqual(yyra, yy, 5)
            else:
                np.testing.assert_equal(xx, np.NaN)
                np.testing.assert_equal(yy, np.NaN)
                np.testing.assert_equal(xxra, np.NaN)
                np.testing.assert_equal(yyra, np.NaN)
                np.testing.assert_equal(xxtest, np.NaN)
                np.testing.assert_equal(yytest, np.NaN)

        nameTest = chipNameFromPupilCoords(pupilTest[0], pupilTest[1],
                                           camera=self.cat.camera)

        nameRA = _chipNameFromRaDec(baselineData['raICRS'], baselineData['decICRS'],
                                    epoch=self.cat.db_obj.epoch, obs_metadata=self.cat.obs_metadata,
                                    camera=self.cat.camera)

        is_none = 0
        for (ntest, nra, ncontrol) in zip(nameTest, nameRA, baselineData['chipName']):
            if ncontrol != 'None':
                self.assertEqual(ntest, ncontrol)
                self.assertEqual(nra, ncontrol)
            else:
                is_none += 1
                self.assertIsNone(ntest)
                self.assertIsNone(nra)

        self.assertGreater(is_none, 0)
        self.assertLess(is_none, len(baselineData))
Example #17
0
def sources_from_file(file_name, obs_md, phot_params, numRows=None):
    """
    Read in an InstanceCatalog and extract all of the astrophysical
    sources from it

    Parameters
    ----------
    file_name: str
        The name of the InstanceCatalog

    obs_md: ObservationMetaData
        The ObservationMetaData characterizing the pointing

    phot_params: PhotometricParameters
        The PhotometricParameters characterizing this telescope

    numRows: int (optional)
        The number of rows of the InstanceCatalog to read in (including the
        header)

    Returns
    -------
    gs_obj_arr: numpy array
        Contains the GalSimCelestialObjects for all of the
        astrophysical sources in this InstanceCatalog

    out_obj_dict: dict
        Keyed on the names of the detectors in the LSST camera.
        The values are numpy arrays of GalSimCelestialObjects
        that should be simulated for that detector, including
        objects that are near the edge of the chip or
        just bright (in which case, they might still illuminate
        the detector).
    """

    camera = get_obs_lsstSim_camera()

    num_objects = 0
    ct_rows = 0
    with fopen(file_name, mode='rt') as input_file:
        for line in input_file:
            ct_rows += 1
            params = line.strip().split()
            if params[0] == 'object':
                num_objects += 1
            if numRows is not None and ct_rows >= numRows:
                break

    # RA, Dec in the coordinate system expected by PhoSim
    ra_phosim = np.zeros(num_objects, dtype=float)
    dec_phosim = np.zeros(num_objects, dtype=float)

    sed_name = [None] * num_objects
    mag_norm = 55.0 * np.ones(num_objects, dtype=float)
    gamma1 = np.zeros(num_objects, dtype=float)
    gamma2 = np.zeros(num_objects, dtype=float)
    kappa = np.zeros(num_objects, dtype=float)

    internal_av = np.zeros(num_objects, dtype=float)
    internal_rv = np.zeros(num_objects, dtype=float)
    galactic_av = np.zeros(num_objects, dtype=float)
    galactic_rv = np.zeros(num_objects, dtype=float)
    semi_major_arcsec = np.zeros(num_objects, dtype=float)
    semi_minor_arcsec = np.zeros(num_objects, dtype=float)
    position_angle_degrees = np.zeros(num_objects, dtype=float)
    sersic_index = np.zeros(num_objects, dtype=float)
    npoints = np.zeros(num_objects, dtype=int)
    redshift = np.zeros(num_objects, dtype=float)

    unique_id = np.zeros(num_objects, dtype=int)
    object_type = np.zeros(num_objects, dtype=int)

    i_obj = -1
    with fopen(file_name, mode='rt') as input_file:
        for line in input_file:
            params = line.strip().split()
            if params[0] != 'object':
                continue
            i_obj += 1
            if numRows is not None and i_obj >= num_objects:
                break
            unique_id[i_obj] = int(params[1])
            ra_phosim[i_obj] = float(params[2])
            dec_phosim[i_obj] = float(params[3])
            mag_norm[i_obj] = float(params[4])
            sed_name[i_obj] = params[5]
            redshift[i_obj] = float(params[6])
            gamma1[i_obj] = float(params[7])
            gamma2[i_obj] = float(params[8])
            kappa[i_obj] = float(params[9])
            if params[12].lower() == 'point':
                object_type[i_obj] = _POINT_SOURCE
                i_gal_dust_model = 14
                if params[13].lower() != 'none':
                    i_gal_dust_model = 16
                    internal_av[i_obj] = float(params[14])
                    internal_rv[i_obj] = float(params[15])
                if params[i_gal_dust_model].lower() != 'none':
                    galactic_av[i_obj] = float(params[i_gal_dust_model + 1])
                    galactic_rv[i_obj] = float(params[i_gal_dust_model + 2])
            elif params[12].lower() == 'sersic2d':
                object_type[i_obj] = _SERSIC_2D
                semi_major_arcsec[i_obj] = float(params[13])
                semi_minor_arcsec[i_obj] = float(params[14])
                position_angle_degrees[i_obj] = float(params[15])
                sersic_index[i_obj] = float(params[16])
                i_gal_dust_model = 18
                if params[17].lower() != 'none':
                    i_gal_dust_model = 20
                    internal_av[i_obj] = float(params[18])
                    internal_rv[i_obj] = float(params[19])
                if params[i_gal_dust_model].lower() != 'none':
                    galactic_av[i_obj] = float(params[i_gal_dust_model + 1])
                    galactic_rv[i_obj] = float(params[i_gal_dust_model + 2])
            elif params[12].lower() == 'knots':
                object_type[i_obj] = _RANDOM_WALK
                semi_major_arcsec[i_obj] = float(params[13])
                semi_minor_arcsec[i_obj] = float(params[14])
                position_angle_degrees[i_obj] = float(params[15])
                npoints[i_obj] = int(params[16])
                i_gal_dust_model = 18
                if params[17].lower() != 'none':
                    i_gal_dust_model = 20
                    internal_av[i_obj] = float(params[18])
                    internal_rv[i_obj] = float(params[19])
                if params[i_gal_dust_model].lower() != 'none':
                    galactic_av[i_obj] = float(params[i_gal_dust_model + 1])
                    galactic_rv[i_obj] = float(params[i_gal_dust_model + 2])
            else:
                raise RuntimeError("Do not know how to handle "
                                   "object type: %s" % params[12])

    ra_appGeo, dec_appGeo = PhoSimAstrometryBase._appGeoFromPhoSim(
        np.radians(ra_phosim), np.radians(dec_phosim), obs_md)

    (ra_obs_rad, dec_obs_rad) = _observedFromAppGeo(ra_appGeo,
                                                    dec_appGeo,
                                                    obs_metadata=obs_md,
                                                    includeRefraction=True)

    semi_major_radians = radiansFromArcsec(semi_major_arcsec)
    semi_minor_radians = radiansFromArcsec(semi_minor_arcsec)
    position_angle_radians = np.radians(position_angle_degrees)

    x_pupil, y_pupil = _pupilCoordsFromObserved(ra_obs_rad, dec_obs_rad,
                                                obs_md)

    bp_dict = BandpassDict.loadTotalBandpassesFromFiles()

    sed_dir = lsstUtils.getPackageDir('sims_sed_library')

    object_is_valid = np.array([True] * num_objects)

    invalid_objects = np.where(
        np.logical_or(
            np.logical_or(
                mag_norm > 50.0,
                np.logical_and(galactic_av == 0.0, galactic_rv == 0.0)),
            np.logical_or(
                np.logical_and(object_type == _SERSIC_2D,
                               semi_major_arcsec < semi_minor_arcsec),
                np.logical_and(object_type == _RANDOM_WALK, npoints <= 0))))

    object_is_valid[invalid_objects] = False

    if len(invalid_objects[0]) > 0:
        message = "\nOmitted %d suspicious objects from " % len(
            invalid_objects[0])
        message += "the instance catalog:\n"
        n_bad_mag_norm = len(np.where(mag_norm > 50.0)[0])
        message += "    %d had mag_norm > 50.0\n" % n_bad_mag_norm
        n_bad_av = len(
            np.where(np.logical_and(galactic_av == 0.0,
                                    galactic_rv == 0.0))[0])
        message += "    %d had galactic_Av == galactic_Rv == 0\n" % n_bad_av
        n_bad_axes = len(
            np.where(
                np.logical_and(object_type == _SERSIC_2D,
                               semi_major_arcsec < semi_minor_arcsec))[0])
        message += "    %d had semi_major_axis < semi_minor_axis\n" % n_bad_axes
        n_bad_knots = len(
            np.where(np.logical_and(object_type == _RANDOM_WALK,
                                    npoints <= 0))[0])
        message += "    %d had n_points <= 0 \n" % n_bad_knots
        warnings.warn(message)

    wav_int = None
    wav_gal = None

    gs_object_arr = []
    for i_obj in range(num_objects):
        if not object_is_valid[i_obj]:
            continue

        if object_type[i_obj] == _POINT_SOURCE:
            gs_type = 'pointSource'
        elif object_type[i_obj] == _SERSIC_2D:
            gs_type = 'sersic'
        elif object_type[i_obj] == _RANDOM_WALK:
            gs_type = 'RandomWalk'

        # load the SED
        sed_obj = Sed()
        sed_obj.readSED_flambda(os.path.join(sed_dir, sed_name[i_obj]))
        fnorm = getImsimFluxNorm(sed_obj, mag_norm[i_obj])
        sed_obj.multiplyFluxNorm(fnorm)
        if internal_av[i_obj] != 0.0:
            if wav_int is None or not np.array_equal(sed_obj.wavelen, wav_int):
                a_int, b_int = sed_obj.setupCCMab()
                wav_int = copy.deepcopy(sed_obj.wavelen)

            sed_obj.addCCMDust(a_int,
                               b_int,
                               A_v=internal_av[i_obj],
                               R_v=internal_rv[i_obj])

        if redshift[i_obj] != 0.0:
            sed_obj.redshiftSED(redshift[i_obj], dimming=True)

        sed_obj.resampleSED(wavelen_match=bp_dict.wavelenMatch)

        if galactic_av[i_obj] != 0.0:
            if wav_gal is None or not np.array_equal(sed_obj.wavelen, wav_gal):
                a_g, b_g = sed_obj.setupCCMab()
                wav_gal = copy.deepcopy(sed_obj.wavelen)

            sed_obj.addCCMDust(a_g,
                               b_g,
                               A_v=galactic_av[i_obj],
                               R_v=galactic_rv[i_obj])

        gs_object = GalSimCelestialObject(gs_type,
                                          x_pupil[i_obj],
                                          y_pupil[i_obj],
                                          semi_major_radians[i_obj],
                                          semi_minor_radians[i_obj],
                                          semi_major_radians[i_obj],
                                          position_angle_radians[i_obj],
                                          sersic_index[i_obj],
                                          sed_obj,
                                          bp_dict,
                                          phot_params,
                                          npoints[i_obj],
                                          gamma1=gamma1[i_obj],
                                          gamma2=gamma2[i_obj],
                                          kappa=kappa[i_obj],
                                          uniqueId=unique_id[i_obj])

        gs_object_arr.append(gs_object)

    gs_object_arr = np.array(gs_object_arr)

    # how close to the edge of the detector a source has
    # to be before we will just simulate it anyway
    pix_tol = 50.0

    # any source brighter than this will be considered
    # so bright that it should be simulated for all
    # detectors, just in case light scatters onto them.
    max_mag = 16.0

    # down-select mag_norm, x_pupil, and y_pupil
    # to only contain those objects that were
    # deemed to be valid above
    valid = np.where(object_is_valid)
    mag_norm = mag_norm[valid]
    x_pupil = x_pupil[valid]
    y_pupil = y_pupil[valid]

    assert len(mag_norm) == len(gs_object_arr)
    assert len(x_pupil) == len(gs_object_arr)
    assert len(y_pupil) == len(gs_object_arr)

    out_obj_dict = {}
    for det in lsst_camera():
        chip_name = det.getName()
        pixel_corners = getCornerPixels(chip_name, lsst_camera())
        x_min = pixel_corners[0][0]
        x_max = pixel_corners[2][0]
        y_min = pixel_corners[0][1]
        y_max = pixel_corners[3][1]
        xpix, ypix = pixelCoordsFromPupilCoords(x_pupil,
                                                y_pupil,
                                                chipName=chip_name,
                                                camera=lsst_camera())

        on_chip = np.where(
            np.logical_or(
                mag_norm < max_mag,
                np.logical_and(
                    xpix > x_min - pix_tol,
                    np.logical_and(
                        xpix < x_max + pix_tol,
                        np.logical_and(ypix > y_min - pix_tol,
                                       ypix < y_max + pix_tol)))))

        out_obj_dict[chip_name] = gs_object_arr[on_chip]

    return gs_object_arr, out_obj_dict
Example #18
0
    def test_LSST_camera_wrapper(self):
        """
        Test that LSSTCameraWrapper wraps its methods as expected.

        Recall that the LSSTCameraWrapper applies the 90 degree rotation
        to go from DM pixel coordinates to Camera team pixel coordinates.
        Namely,

        Camera +y = DM +x
        Camera +x = DM -y
        """
        camera = lsst_camera()
        camera_wrapper = LSSTCameraWrapper()

        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.getMinY())
            self.assertEqual(bbox.getMaxX(), bbox_wrapper.getMaxY())
            self.assertEqual(bbox.getMinY(), bbox_wrapper.getMinX())
            self.assertEqual(bbox.getMaxY(), bbox_wrapper.getMaxX())
            self.assertGreater(bbox_wrapper.getMaxY()-bbox_wrapper.getMinY(),
                               bbox_wrapper.getMaxX()-bbox_wrapper.getMinX())

            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.getY())
            self.assertEqual(center_pix.getY(), center_pix_wrapper.getX())

            # Note that DM and the Camera team agree on the orientation
            # of the pupil coordinate/field angle axes
            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], ypix_min)
            self.assertEqual(pix_bounds_wrapper[1], ypix_max)
            self.assertEqual(pix_bounds_wrapper[2], xpix_min)
            self.assertEqual(pix_bounds_wrapper[3], xpix_max)

            # generate some random pupil coordinates;
            # verify that the relationship between the DM and Camera team
            # pixel coordinates corresponding to those pupil coordinates
            # is as expected
            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,
                                                                        chipName=name)

            nan_x = np.where(np.isnan(x_pix))
            self.assertEqual(len(nan_x[0]), 0)
            np.testing.assert_allclose(x_pix-center_pix.getX(),
                                       y_pix_wrapper-center_pix_wrapper.getY(),
                                       atol=1.0e-10, rtol=0.0)
            np.testing.assert_allclose(y_pix-center_pix.getY(),
                                       center_pix_wrapper.getX()-x_pix_wrapper,
                                       atol=1.0e-10, rtol=0.0)

            # use camera_wrapper.pupilCoordsFromPixelCoords to go back to pupil
            # coordinates from x_pix_wrapper, y_pix_wrapper; make sure you get
            # the original pupil coordinates back out
            (x_pup_wrapper,
             y_pup_wrapper) = camera_wrapper.pupilCoordsFromPixelCoords(x_pix_wrapper,
                                                                        y_pix_wrapper,
                                                                        chipName=name)
            msg = 'worst error %e' % np.abs(x_pup-x_pup_wrapper).max()
            np.testing.assert_allclose(x_pup, x_pup_wrapper, atol=1.0e-10, rtol=0.0, err_msg=msg)
            msg = 'worst error %e' % np.abs(y_pup-y_pup_wrapper).max()
            np.testing.assert_allclose(y_pup, y_pup_wrapper, atol=1.0e-10, rtol=0.0, err_msg=msg)

            # generate some random sky coordinates; verify that the methods that
            # convert between (RA, Dec) and pixel coordinates behave as expected.
            # NOTE: x_pix, y_pix will be in DM pixel coordinate convention
            x_pix = bbox.getMinX() + rng.random_sample(10)*(bbox.getMaxX()-bbox.getMinX())
            y_pix = bbox.getMinY() + rng.random_sample(10)*(bbox.getMaxY()-bbox.getMinY())

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

            (ra_wrapper,
             dec_wrapper) = camera_wrapper.raDecFromPixelCoords(2.0*center_pix.getY()-y_pix,
                                                                x_pix, name, obs)

            nan_ra = np.where(np.isnan(ra))
            self.assertEqual(len(nan_ra[0]), 0)
            np.testing.assert_allclose(ra, ra_wrapper, atol=1.0e-10, rtol=0.0)
            np.testing.assert_allclose(dec, dec_wrapper, atol=1.0e-10, rtol=0.0)

            # make sure that the method that returns RA, Dec in radians agrees with
            # the method that returns RA, Dec in degrees
            (ra_rad,
             dec_rad) = camera_wrapper._raDecFromPixelCoords(2.0*center_pix.getY()-y_pix,
                                                             x_pix, name, obs)

            np.testing.assert_allclose(np.radians(ra_wrapper), ra_rad, atol=1.0e-10, rtol=0.0)
            np.testing.assert_allclose(np.radians(dec_wrapper), dec_rad, atol=1.0e-10, rtol=0.0)

            # Go back to pixel coordinates with pixelCoordsFromRaDec; verify that
            # the result relates to the original DM pixel coordinates as expected
            # (x_pix_inv, y_pix_inv will be in Camera pixel coordinates)
            (x_pix_inv,
             y_pix_inv) = camera_wrapper.pixelCoordsFromRaDec(ra_wrapper, dec_wrapper,
                                                              chipName=name,
                                                              obs_metadata=obs)

            np.testing.assert_allclose(y_pix_inv, x_pix, atol=1.0e-5, rtol=0.0)
            np.testing.assert_allclose(x_pix_inv, 2.0*center_pix.getY()-y_pix, atol=1.0e-5, rtol=0.0)

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

            # check that the the method that accepts RA, Dec in radians agrees with the
            # method that accepts RA, Dec in degrees
            (x_pix_wrapper,
             y_pix_wrapper) = camera_wrapper._pixelCoordsFromRaDec(ra, dec, chipName=name,
                                                                   obs_metadata=obs)

            np.testing.assert_allclose(x_pix_inv, x_pix_wrapper, atol=1.0e-10, rtol=0.0)
            np.testing.assert_allclose(y_pix_inv, y_pix_wrapper, atol=1.0e-10, rtol=0.0)

        del camera
        del camera_wrapper
        del lsst_camera._lsst_camera
    def drawObject(self, gsObject):
        """
        Draw an astronomical object on all of the relevant FITS files.

        @param [in] gsObject is an instantiation of the GalSimCelestialObject
        class carrying all of the information for the object whose image
        is to be drawn

        @param [out] outputString is a string denoting which detectors the astronomical
        object illumines, suitable for output in the GalSim InstanceCatalog
        """

        # find the detectors which the astronomical object illumines
        outputString, \
        detectorList, \
        centeredObj = self.findAllDetectors(gsObject)

        if gsObject.sed is None or len(detectorList) == 0:
            # there is nothing to draw
            return outputString

        # go through the list of detector/bandpass combinations and initialize
        # all of the FITS files we will need (if they have not already been initialized)
        for detector in detectorList:
            for bandpassName in self.bandpassDict:
                name = self._getFileName(detector=detector, bandpassName=bandpassName)
                if name not in self.detectorImages:
                    self.detectorImages[name] = self.blankImage(detector=detector)
                    if self.noiseWrapper is not None:
                        # Add sky background and noise to the image
                        self.detectorImages[name] = \
                            self.noiseWrapper.addNoiseAndBackground(self.detectorImages[name],
                                                                    bandpass=self.bandpassDict[bandpassName],
                                                                    m5=self.obs_metadata.m5[bandpassName],
                                                                    FWHMeff=
                                                                    self.obs_metadata.seeing[bandpassName],
                                                                    photParams=detector.photParams)

        for bandpassName in self.bandpassDict:

            # create a new object if one has not already been created or if the PSF is wavelength
            # dependent (in which case, each filter is going to need its own initialized object)
            if centeredObj is None:
                return outputString

            for detector in detectorList:

                name = self._getFileName(detector=detector, bandpassName=bandpassName)

                xPix, yPix = pixelCoordsFromPupilCoords(gsObject.xPupilRadians,
                                                        gsObject.yPupilRadians,
                                                        chipName=detector.name,
                                                        camera=detector.afwCamera)

                obj = centeredObj.copy()

                # convolve the object's shape profile with the spectrum
                obj = obj.withFlux(gsObject.flux(bandpassName))

                self.detectorImages[name] = obj.drawImage(method='phot',
                                                          gain=detector.photParams.gain,
                                                          offset=galsim.PositionD(xPix-detector.xCenterPix,
                                                                                  yPix-detector.yCenterPix),
                                                          rng=self._rng,
                                                          image=self.detectorImages[name],
                                                          add_to_image=True)

        return outputString