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)
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)
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)
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])
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
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))
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
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