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 test_camPixFromDMpix(self): """ test that trasformation between Camera Team and DM pixels works """ camera_wrapper = DMtoCameraPixelTransformer() rng = np.random.RandomState() camera = lsst_camera() npts = 200 for det in camera: det_name = det.getName() cam_x_in = rng.random_sample(npts)*4000.0 cam_y_in = rng.random_sample(npts)*4000.0 dm_x, dm_y = camera_wrapper.dmPixFromCameraPix(cam_x_in, cam_y_in, det_name) cam_x, cam_y = camera_wrapper.cameraPixFromDMPix(dm_x, dm_y, det_name) np.testing.assert_array_almost_equal(cam_x_in, cam_x, decimal=10) np.testing.assert_array_almost_equal(cam_y_in, cam_y, decimal=10) center_point = camera[det_name].getCenter(FOCAL_PLANE) pixel_system = camera[det_name].makeCameraSys(PIXELS) center_pix = camera.transform(center_point, FOCAL_PLANE, pixel_system) # test that DM and Camera Team pixels are correctly rotated # with respect to each other np.testing.assert_allclose(dm_x-center_pix.getX(), cam_y-center_pix.getX(), atol=1.0e-10, rtol=0.0) np.testing.assert_allclose(dm_y-center_pix.getY(), center_pix.getY()-cam_x, atol=1.0e-10, rtol=0.0) del camera_wrapper del lsst_camera._lsst_camera
def __init__(self): self._camera = lsst_camera() self._pixel_transformer = DMtoCameraPixelTransformer() self._z_gen = ZernikePolynomialGenerator() self._rr = 500.0 # radius in mm of circle containing LSST focal plane; # make it a little bigger to accommodate any slop in # the conversion from focal plane coordinates back to # pupil coordinates (in case the optical distortions # cause points to cross over the actual boundary of # the focal plane) self._band_to_int = {} self._band_to_int['u'] = 0 self._band_to_int['g'] = 1 self._band_to_int['r'] = 2 self._band_to_int['i'] = 3 self._band_to_int['z'] = 4 self._band_to_int['y'] = 5 self._int_to_band = 'ugrizy' self._n_grid = [] self._m_grid = [] # 2018 May 8 # During development, I found that there was negligible # improvement in the fit when allowing n>4, so I am # hard-coding the limit of n=4 here. for n in range(4): for m in range(-n, n + 1, 2): self._n_grid.append(n) self._m_grid.append(m) self._build_transformations()
def __init__(self): self._camera = lsst_camera() self._pixel_transformer = DMtoCameraPixelTransformer() self._z_gen = ZernikePolynomialGenerator() self._rr = 500.0 # radius in mm of circle containing LSST focal plane; # make it a little bigger to accommodate any slop in # the conversion from focal plane coordinates back to # pupil coordinates (in case the optical distortions # cause points to cross over the actual boundary of # the focal plane) self._band_to_int = {} self._band_to_int['u'] = 0 self._band_to_int['g'] = 1 self._band_to_int['r'] = 2 self._band_to_int['i'] = 3 self._band_to_int['z'] = 4 self._band_to_int['y'] = 5 self._int_to_band = 'ugrizy' self._n_grid = [] self._m_grid = [] # 2018 May 8 # During development, I found that there was negligible # improvement in the fit when allowing n>4, so I am # hard-coding the limit of n=4 here. for n in range(4): for m in range(-n, n+1, 2): self._n_grid.append(n) self._m_grid.append(m) self._build_transformations()
def _setupCamera(self): self.camera = lsst_camera() self.ccd_type_dict = { SCIENCE: 'science', WAVEFRONT: 'wavefront', GUIDER: 'guider', FOCUS: 'focus' }
def get_obs_lsstSim_camera(log_level=lsstLog.WARN): """ Get the obs_lsstSim CameraMapper object, setting the default log-level at WARN in order to silence the INFO message about "Loading Posix exposure registry from .". Note that this only affects the 'CameraMapper' logging level. The logging level set by any calling code (e.g., imsim.py) will still apply to other log messages made by imSim code. """ lsstLog.setLevel('CameraMapper', log_level) return lsst_camera()
def pupilCoordsFromPixelCoords(self, xPix, yPix, chipName, includeDistortion=True): """ Convert pixel coordinates into pupil coordinates Parameters ---------- xPix is the x pixel coordinate of the point. Can be either a float or a numpy array. Defined in the Camera team system (not the DM system). yPix is the y pixel coordinate of the point. Can be either a float or a numpy array. Defined in the Camera team system (not the DM system). chipName is the name of the chip(s) on which the pixel coordinates are defined. This can be a list (in which case there should be one chip name for each (xPix, yPix) coordinate pair), or a single value (in which case, all of the (xPix, yPix) points will be reckoned on that chip). includeDistortion is a boolean. If True (default), then this method will expect the true pixel coordinates with optical distortion included. If False, this method will expect TAN_PIXEL coordinates, which are the pixel coordinates with estimated optical distortion removed. See the documentation in afw.cameraGeom for more details. Returns ------- a 2-D numpy array in which the first row is the x pupil coordinate and the second row is the y pupil coordinate (both in radians) """ dm_xPix = yPix if isinstance(chipName, list) or isinstance(chipName, np.ndarray): dm_yPix = np.zeros(len(xPix)) for ix, (det_name, xx) in enumerate(zip(chipName, xPix)): came_center_pix = self.getCenterPixel(det_name) dm_yPix[ix] = 2.0 * cam_center_pix.getX() - xPix[ix] else: cam_center_pix = self.getCenterPixel(chipName) dm_yPix = 2.0 * cam_center_pix.getX() - xPix return coordUtils.pupilCoordsFromPixelCoords( dm_xPix, dm_yPix, chipName, camera=coordUtils.lsst_camera(), includeDistortion=includeDistortion)
def sources_from_list(lines, obs_md, phot_params, file_name): """Return a two-item tuple containing * a list of GalSimCelestialObjects for each object entry in `lines` * a dictionary of these objects disaggregated by chip_name. """ target_chips = [det.getName() for det in lsst_camera()] gs_object_dict = dict() out_obj_dict = dict() for chip_name in target_chips: out_obj_dict[chip_name] \ = [_ for _ in desc.imsim.GsObjectList(lines, obs_md, phot_params, file_name, chip_name)] for gsobj in out_obj_dict[chip_name]: gs_object_dict[gsobj.uniqueId] = gsobj return list(gs_object_dict.values()), out_obj_dict
def setUpClass(cls): cls.camera = lsst_camera() cls.data_dir = os.path.join(getPackageDir('sims_coordUtils'), 'tests', 'lsstCameraData') pix_dtype = np.dtype([('ra', float), ('dec', float), ('name', str, 15), ('focal_x', float), ('focal_y', float), ('pixel_x', float), ('pixel_y', float)]) cls.pix_data = np.genfromtxt(os.path.join(cls.data_dir, 'lsst_pixel_data.txt'), delimiter=';', dtype=pix_dtype) ra = 25.0 dec = -62.0 cls.obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, rotSkyPos=57.2, mjd=59586.2)
def setUpClass(cls): cls.camera = lsst_camera() cls.data_dir = os.path.join(getPackageDir('sims_coordUtils'), 'tests', 'lsstCameraData') pix_dtype = np.dtype([('ra', float), ('dec', float), ('name', str, 15), ('focal_x', float), ('focal_y', float), ('pixel_x', float), ('pixel_y', float)]) cls.pix_data = np.genfromtxt(os.path.join(cls.data_dir, 'lsst_pixel_data.txt'), delimiter=';', dtype=pix_dtype) ra = 25.0 dec = -62.0 cls.obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, rotSkyPos=57.2, mjd=59586.2)
def pupilCoordsFromFocalPlaneCoordsLSST(xmm, ymm, band='r'): """ Convert mm on the focal plane to radians on the pupil. Note: round-tripping through focalPlaneCoordsFromPupilCoordsLSST and pupilCoordsFromFocalPlaneCoordsLSST introduces a residual of up to 2.18e-6 mm that accumulates with each round trip. Parameters ---------- xmm -- x coordinate in millimeters on the focal plane ymm -- y coordinate in millimeters on the focal plane band -- the filter we are simulating (default='r') Returns ------- a 2-D numpy array in which the first row is the x pupil coordinate and the second row is the y pupil coordinate (both in radians) """ if not hasattr(pupilCoordsFromFocalPlaneCoordsLSST, '_z_fitter'): pupilCoordsFromFocalPlaneCoordsLSST._z_fitter = LsstZernikeFitter() if isinstance(xmm, numbers.Number): if np.isnan(xmm) or np.isnan(ymm): return np.array([np.NaN, np.NaN]) z_fitter = pupilCoordsFromFocalPlaneCoordsLSST._z_fitter dx, dy = z_fitter.dxdy_inverse(xmm, ymm, band) x_f1 = xmm + dx y_f1 = ymm + dy xp, yp = pupilCoordsFromFocalPlaneCoords(x_f1, y_f1, camera=lsst_camera()) if not isinstance(xmm, numbers.Number): nan_dex = np.where(np.logical_or(np.isnan(xmm), np.isnan(ymm))) xp[nan_dex] = np.NaN yp[nan_dex] = np.NaN return np.array([xp, yp])
def focalPlaneCoordsFromPupilCoordsLSST(xPupil, yPupil, band='r'): """ Get the focal plane coordinates for all objects in the catalog. Parameters ---------- xPupil -- the x pupil coordinates in radians. Can be a float or a numpy array. yPupil -- the y pupil coordinates in radians. Can be a float or a numpy array. band -- the filter being simulated (default='r') Returns -------- a 2-D numpy array in which the first row is the x focal plane coordinate and the second row is the y focal plane coordinate (both in millimeters) """ if not hasattr(focalPlaneCoordsFromPupilCoordsLSST, '_z_fitter'): focalPlaneCoordsFromPupilCoordsLSST._z_fitter = LsstZernikeFitter() if isinstance(xPupil, numbers.Number): if np.isnan(xPupil) or np.isnan(yPupil): return np.array([np.NaN, np.NaN]) z_fitter = focalPlaneCoordsFromPupilCoordsLSST._z_fitter x_f0, y_f0 = focalPlaneCoordsFromPupilCoords(xPupil, yPupil, camera=lsst_camera()) dx, dy = z_fitter.dxdy(x_f0, y_f0, band) if not isinstance(xPupil, numbers.Number): nan_dex = np.where(np.logical_or(np.isnan(xPupil), np.isnan(yPupil))) x_f0[nan_dex] = np.NaN y_f0[nan_dex] = np.NaN return np.array([x_f0 + dx, y_f0 + dy])
def test_camPixFromDMpix(self): """ test that trasformation between Camera Team and DM pixels works """ camera_wrapper = DMtoCameraPixelTransformer() rng = np.random.RandomState() camera = lsst_camera() npts = 200 for det in camera: det_name = det.getName() cam_x_in = rng.random_sample(npts) * 4000.0 cam_y_in = rng.random_sample(npts) * 4000.0 dm_x, dm_y = camera_wrapper.dmPixFromCameraPix( cam_x_in, cam_y_in, det_name) cam_x, cam_y = camera_wrapper.cameraPixFromDMPix( dm_x, dm_y, det_name) np.testing.assert_array_almost_equal(cam_x_in, cam_x, decimal=10) np.testing.assert_array_almost_equal(cam_y_in, cam_y, decimal=10) center_point = camera[det_name].getCenter(FOCAL_PLANE) pixel_system = camera[det_name].makeCameraSys(PIXELS) center_pix = camera.transform(center_point, FOCAL_PLANE, pixel_system) # test that DM and Camera Team pixels are correctly rotated # with respect to each other np.testing.assert_allclose(dm_x - center_pix.getX(), cam_y - center_pix.getX(), atol=1.0e-10, rtol=0.0) np.testing.assert_allclose(dm_y - center_pix.getY(), center_pix.getY() - cam_x, atol=1.0e-10, rtol=0.0) del camera_wrapper del lsst_camera._lsst_camera
def _findDetectorsListLSST(focalPointList, detectorList, possible_points, allow_multiple_chips=False): """!Find the detectors that cover a list of points specified by x and y coordinates in any system This is based one afw.camerGeom.camera.findDetectorsList. It has been optimized for the LSST camera in the following way: - it accepts a limited list of detectors to check in advance (this list should be constructed by comparing the pupil coordinates in question and comparing to the pupil coordinates of the center of each detector) - it will stop looping through detectors one it has found one that is correct (the LSST camera does not allow an object to fall on more than one detector) @param[in] focalPointList a list of points in FOCAL_PLANE coordinates @param[in] detectorList is a list of the afwCameraGeom detector objects being considered @param[in] possible_points is a list of lists. possible_points[ii] is a list of integers corresponding to the indices in focalPointList of the pupilPoints that may be on detectorList[ii]. @param [in] allow_multiple_chips is a boolean (default False) indicating whether or not this method will allow objects to be visible on more than one chip. If it is 'False' and an object appears on more than one chip, only the first chip will appear in the list of chipNames but NO WARNING WILL BE EMITTED. If it is 'True' and an object falls on more than one chip, a list of chipNames will appear for that object. @return outputNameList is a numpy array of the names of the detectors """ # transform the points to the native coordinate system # # The conversion to a numpy array looks a little clunky. # The problem, if you do the naive thing (nativePointList = np.array(lsst_camera().....), # the conversion to a numpy array gets passed down to the contents of nativePointList # and they end up in a form that the afwCameraGeom code does not know how to handle nativePointList = np.zeros(len(focalPointList), dtype=object) for ii in range(len(focalPointList)): nativePointList[ii] = focalPointList[ii] # initialize output and some caching lists outputNameList = [None] * len(focalPointList) chip_has_found = np.array([-1] * len(focalPointList)) unfound_pts = len(chip_has_found) # Figure out if any of these (RA, Dec) pairs could be # on more than one chip. This is possible on the # wavefront sensors, since adjoining wavefront sensors # are kept one in focus, one out of focus. # See figure 2 of arXiv:1506.04839v2 # (This might actually be a bug in obs_lsstSim # I opened DM-8075 on 25 October 2016 to investigate) could_be_multiple = [False] * len(focalPointList) if allow_multiple_chips: for ipt in range(len(focalPointList)): for det in detectorList[ipt]: if det.getType() == WAVEFRONT: could_be_multiple[ipt] = True # t_assemble_list = 0.0 # loop over detectors for i_detector, detector in enumerate(detectorList): if len(possible_points[i_detector]) == 0: continue if unfound_pts <= 0: if unfound_pts < 0: raise RuntimeError( "Somehow, unfound_pts = %d in _findDetectorsListLSST" % unfound_pts) # we have already found all of the (RA, Dec) pairs for ix, name in enumerate(outputNameList): if isinstance(name, list): outputNameList[ix] = str(name) return np.array(outputNameList) # find all of the pupil points that could be on this detector valid_pt_dexes = possible_points[i_detector][np.where( chip_has_found[possible_points[i_detector]] < 0)] if len(valid_pt_dexes) > 0: valid_pt_list = nativePointList[valid_pt_dexes] transform = detector.getTransform(lsst_camera()._nativeCameraSys, PIXELS) detectorPointList = transform.applyForward(valid_pt_list) box = geom.Box2D(detector.getBBox()) for ix, pt in zip(valid_pt_dexes, detectorPointList): if box.contains(pt): if not could_be_multiple[ix]: # because this (RA, Dec) pair is not marked as could_be_multiple, # the fact that this (RA, Dec) pair is on the current chip # means this (RA, Dec) pair no longer needs to be considered. # You can set chip_has_found[ix] to unity. outputNameList[ix] = detector.getName() chip_has_found[ix] = 1 unfound_pts -= 1 else: # Since this (RA, Dec) pair has been makred could_be_multiple, # finding this (RA, Dec) pair on the chip does not remove the # (RA, Dec) pair from contention. if outputNameList[ix] is None: outputNameList[ix] = detector.getName() elif isinstance(outputNameList[ix], list): outputNameList[ix].append(detector.getName()) else: outputNameList[ix] = [ outputNameList[ix], detector.getName() ] # convert entries corresponding to multiple chips into strings # (i.e. [R:2,2 S:0,0, R:2,2 S:0,1] becomes `[R:2,2 S:0,0, R:2,2 S:0,1]`) for ix, name in enumerate(outputNameList): if isinstance(name, list): outputNameList[ix] = str(name) # print('t_assemble %.2e' % t_assemble_list) return np.array(outputNameList)
def _build_lsst_focal_coord_map(): """ Build a map of focal plane coordinates on the LSST focal plane. Returns _lsst_focal_coord_map, which is a dict. _lsst_focal_coord_map['name'] contains a list of the names of each chip in the lsst camera _lsst_focal_coord_map['xx'] contains the x focal plane coordinate of the center of each chip (mm) _lsst_focal_coord_map['yy'] contains the y focal plane coordinate of the center of each chip (mm) _lsst_focal_coord_map['dp'] contains the radius (in mm) of the circle containing each chip """ camera = lsst_camera() name_list = [] x_pix_list = [] y_pix_list = [] x_mm_list = [] y_mm_list = [] n_chips = 0 for chip in camera: chip_name = chip.getName() pixels_to_focal = chip.getTransform(PIXELS, FOCAL_PLANE) n_chips += 1 corner_list = getCornerPixels(chip_name, lsst_camera()) for corner in corner_list: x_pix_list.append(corner[0]) y_pix_list.append(corner[1]) pixel_pt = geom.Point2D(corner[0], corner[1]) focal_pt = pixels_to_focal.applyForward(pixel_pt) x_mm_list.append(focal_pt.getX()) y_mm_list.append(focal_pt.getY()) name_list.append(chip_name) x_pix_list = np.array(x_pix_list) y_pix_list = np.array(y_pix_list) x_mm_list = np.array(x_mm_list) y_mm_list = np.array(y_mm_list) center_x = np.zeros(n_chips, dtype=float) center_y = np.zeros(n_chips, dtype=float) extent = np.zeros(n_chips, dtype=float) final_name = [] for ix_ct in range(n_chips): ix = ix_ct * 4 chip_name = name_list[ix] xx = 0.25 * (x_mm_list[ix] + x_mm_list[ix + 1] + x_mm_list[ix + 2] + x_mm_list[ix + 3]) yy = 0.25 * (y_mm_list[ix] + y_mm_list[ix + 1] + y_mm_list[ix + 2] + y_mm_list[ix + 3]) dx = 0.25 * np.array([ np.sqrt( np.power(xx - x_mm_list[ix + ii], 2) + np.power(yy - y_mm_list[ix + ii], 2)) for ii in range(4) ]).sum() center_x[ix_ct] = xx center_y[ix_ct] = yy extent[ix_ct] = dx final_name.append(chip_name) final_name = np.array(final_name) lsst_focal_coord_map = {} lsst_focal_coord_map['name'] = final_name lsst_focal_coord_map['xx'] = center_x lsst_focal_coord_map['yy'] = center_y lsst_focal_coord_map['dp'] = extent return lsst_focal_coord_map
def test_naive_focal_plane_position(self): """ Test deprecession of PhoSim coordinates by comparing the focal plane position predicted by CatSim from ICRS with the focal plane position predicted by CatSim from deprecessed coordinates. """ phosim_mixin = PhoSimAstrometryBase() mjd = 59587.2 # create site with no atmosphere so that we can avoid # refraction site = Site(name="LSST", pressure=0.0, humidity=0.0) obs = ObservationMetaData(mjd=mjd, site=site) ra, dec = raDecFromAltAz(31.0, 112.0, obs) d_sun = distanceToSun(ra, dec, obs.mjd) self.assertGreater(d_sun, 45.0) obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, rotSkyPos=27.3, mjd=mjd, site=site) ra_icrs = np.arange(obs.pointingRA - 2.0, obs.pointingRA + 2.0, 0.05) dec_icrs = np.arange(obs.pointingDec - 2.0, obs.pointingDec + 2.0, 0.05) coord_grid = np.meshgrid(ra_icrs, dec_icrs) ra_icrs = coord_grid[0].flatten() dec_icrs = coord_grid[1].flatten() (xpup_icrs, ypup_icrs) = pupilCoordsFromRaDec(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=False) (x_focal_icrs, y_focal_icrs) = focalPlaneCoordsFromPupilCoords(xpup_icrs, ypup_icrs, camera=lsst_camera()) ra_obs, dec_obs = observedFromICRS(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=False) ra_obs_rad = np.radians(ra_obs) dec_obs_rad = np.radians(dec_obs) (ra_deprecessed_rad, dec_deprecessed_rad) = phosim_mixin._dePrecess( ra_obs_rad, dec_obs_rad, obs) (xpup_deprecessed, ypup_deprecessed) = _naivePupilCoordsFromObserved( ra_deprecessed_rad, dec_deprecessed_rad, obs._pointingRA, obs._pointingDec, obs._rotSkyPos) (x_focal_deprecessed, y_focal_deprecessed) = focalPlaneCoordsFromPupilCoords( xpup_deprecessed, ypup_deprecessed, camera=lsst_camera()) dd = np.sqrt((x_focal_icrs - x_focal_deprecessed)**2 + (y_focal_icrs - y_focal_deprecessed)**2) self.assertLess(dd.max(), 1.0e-8)
def test_pixel_positions(self): """ Test that CatSim pixel positions are close to PhoSim pixel positions. This is complicated by the fact that PhoSim uses the camera team definition of pixel space, which differs from the DM definition of pixel space as follows: Camera +y = DM +x Camera +x = DM -y Camera +z = DM +z This has been verified both by consulting documentation -- the documentation for afwCameraGeom says that +x is along the serial readout direction; LCA-13381 indicates that, in the Camera team's definition, the serial readout is along +y -- and phenomenologically by comparing the relationship between pixelCoordsFromPupilCoords() to visual inspection of PhoSim-generated FITS images. """ self.assertGreater(len(self.data), 10) for ix in range(len(self.data)): in_name = self.data['chipName'][ix] chip_name = in_name[0] + ':' + in_name[1] + ',' + in_name[2] chip_name += ' ' + in_name[3] + ':' + in_name[4] + ',' + in_name[5] corner_pixels = getCornerPixels(chip_name, lsst_camera()) x_center_dm = 0.25 * (corner_pixels[0][0] + corner_pixels[1][0] + corner_pixels[2][0] + corner_pixels[3][0]) y_center_dm = 0.25 * (corner_pixels[0][1] + corner_pixels[1][1] + corner_pixels[2][1] + corner_pixels[3][1]) obs = ObservationMetaData(pointingRA=self.data['pointingRA'][ix], pointingDec=self.data['pointingDec'][ix], rotSkyPos=self.data['rotSkyPos'][ix], mjd=59580.0) xpix, ypix = pixelCoordsFromRaDecLSST(self.data['objRA'][ix], self.data['objDec'][ix], obs_metadata=obs) raObs, decObs = observedFromICRS(self.data['objRA'][ix], self.data['objDec'][ix], obs_metadata=obs, epoch=2000.0) # find displacement from center of DM coordinates of the # objects as placed by PhoSim d_y_phosim = y_center_dm - self.data['xpix'][ix] d_x_phosim = self.data['ypix'][ix] - x_center_dm # displacement from center of DM coordinates as calculated # by DM d_x_dm = xpix - x_center_dm d_y_dm = ypix - y_center_dm d_pix = np.sqrt((d_x_dm - d_x_phosim)**2 + (d_y_dm - d_y_phosim)**2) # demand that the difference between the two displacements is less # than 0.05 of the total displacement from the center of the object # as calculated by DM msg = 'dx %e; dy %e' % (d_x_dm, d_y_dm) self.assertLess(d_pix, 0.05 * np.sqrt(d_x_dm**2 + d_y_dm**2), msg=msg)
import numpy as np from PhoSimTransform import PhoSimPixelTransformer from lsst.afw.cameraGeom import SCIENCE from lsst.sims.coordUtils import lsst_camera if __name__ == "__main__": coord_converter = PhoSimPixelTransformer() camera = lsst_camera() rng = np.random.RandomState(213) det_name_list = [] for det in camera: if det.getType() != SCIENCE: continue det_name_list.append(det.getName()) n_test = 20 test_name_list = rng.choice(det_name_list, size=n_test, replace=True) xpix_list = rng.random_sample(n_test)*4000.0 ypix_list = rng.random_sample(n_test)*4000.0 for xpix, ypix, test_name in zip(xpix_list, ypix_list, test_name_list): xmm, ymm = coord_converter.mmFromPix(xpix, ypix, test_name) xpix1, ypix1 = coord_converter.pixFromMM(xmm, ymm, test_name) dd = np.sqrt((xpix-xpix1)**2+(ypix-ypix1)**2) assert dd<1.0e-10
theta = rng.random_sample(n_sources)*2.0*np.pi from lsst.sims.coordUtils import pupilCoordsFromPixelCoordsLSST from lsst.sims.coordUtils import lsst_camera from lsst.afw.cameraGeom import SCIENCE xpix = np.arange(200.0, 3801.0, 200.0) ypix = np.arange(200.0, 3801.0, 200.0) mesh = np.meshgrid(xpix, ypix) xpix_mesh =mesh[0].flatten() ypix_mesh = mesh[1].flatten() xpix = [] ypix = [] chip = [] for det in lsst_camera(): if det.getType()!=SCIENCE: continue for xx, yy in zip(xpix_mesh, ypix_mesh): xpix.append(xx) ypix.append(yy) chip.append(det.getName()) xpix = np.array(xpix) ypix = np.array(ypix) chip = np.array(chip) xp, yp = pupilCoordsFromPixelCoordsLSST(xpix, ypix, chipName=chip, band='r') ra, dec = raDecFromPupilCoords(xp, yp, obs_metadata=obs_root, includeRefraction=False) out_dir = 'ratio_test/catalogs'
def test_pixel_positions(self): """ Test that CatSim pixel positions are close to PhoSim pixel positions. This is complicated by the fact that PhoSim uses the camera team definition of pixel space, which differs from the DM definition of pixel space as follows: Camera +y = DM +x Camera +x = DM -y Camera +z = DM +z This has been verified both by consulting documentation -- the documentation for afwCameraGeom says that +x is along the serial readout direction; LCA-13381 indicates that, in the Camera team's definition, the serial readout is along +y -- and phenomenologically by comparing the relationship between pixelCoordsFromPupilCoords() to visual inspection of PhoSim-generated FITS images. """ self.assertGreater(len(self.data), 10) for ix in range(len(self.data)): in_name = self.data['chipName'][ix] chip_name = in_name[0]+':'+in_name[1]+','+in_name[2] chip_name += ' '+in_name[3]+':'+in_name[4]+','+in_name[5] corner_pixels = getCornerPixels(chip_name, lsst_camera()) x_center_dm = 0.25*(corner_pixels[0][0] + corner_pixels[1][0] + corner_pixels[2][0] + corner_pixels[3][0]) y_center_dm = 0.25*(corner_pixels[0][1] + corner_pixels[1][1] + corner_pixels[2][1] + corner_pixels[3][1]) obs = ObservationMetaData(pointingRA=self.data['pointingRA'][ix], pointingDec=self.data['pointingDec'][ix], rotSkyPos=self.data['rotSkyPos'][ix], mjd=59580.0) xpix, ypix = pixelCoordsFromRaDecLSST(self.data['objRA'][ix], self.data['objDec'][ix], obs_metadata=obs) raObs, decObs = observedFromICRS(self.data['objRA'][ix], self.data['objDec'][ix], obs_metadata=obs, epoch=2000.0) # find displacement from center of DM coordinates of the # objects as placed by PhoSim d_y_phosim = y_center_dm - self.data['xpix'][ix] d_x_phosim = self.data['ypix'][ix] - x_center_dm # displacement from center of DM coordinates as calculated # by DM d_x_dm = xpix - x_center_dm d_y_dm = ypix - y_center_dm d_pix = np.sqrt((d_x_dm - d_x_phosim)**2 + (d_y_dm - d_y_phosim)**2) # demand that the difference between the two displacements is less # than 0.05 of the total displacement from the center of the object # as calculated by DM msg = 'dx %e; dy %e' % (d_x_dm, d_y_dm) self.assertLess(d_pix, 0.05*np.sqrt(d_x_dm**2+d_y_dm**2), msg=msg)
def test_avro_alert_generation_diff_dmag(self): """ Make sure everything works properly when the AlertDataGenerator and the AvroAlertGenerator have different dmag thresholds """ dmag_cutoff_sqlite = 0.005 dmag_cutoff_avro = 0.2 mag_name_to_int = {'u': 0, 'g': 1, 'r': 2, 'i': 3, 'z': 4, 'y': 5} star_db = StarAlertTestDBObj_avro(database=self.star_db_name, driver='sqlite') # assemble a dict of all of the alerts that need to be generated obshistid_list = [] for obs in self.obs_list: obshistid_list.append(obs.OpsimMetaData['obsHistID']) obshistid_max = max(obshistid_list) obshistid_bits = int(np.ceil(np.log(obshistid_max) / np.log(2.0))) true_alert_dict = {} obs_dict = {} ignored_sqlite = 0 # count number of alerts written to sqlite, but not avro for obs in self.obs_list: obs_dict[obs.OpsimMetaData['obsHistID']] = obs obshistid = obs.OpsimMetaData['obsHistID'] cat = TestAlertsTruthCat_avro(star_db, obs_metadata=obs) cat.camera = lsst_camera() for line in cat.iter_catalog(): if line[1] is None: continue dmag = line[2] mag = line[3] if (np.abs(dmag) > dmag_cutoff_avro and mag <= self.obs_mag_cutoff[mag_name_to_int[obs.bandpass]]): alertId = (line[0] << obshistid_bits) + obshistid self.assertNotIn(alertId, true_alert_dict) true_alert_dict[alertId] = {} true_alert_dict[alertId]['chipName'] = line[1] true_alert_dict[alertId]['dmag'] = dmag true_alert_dict[alertId]['mag'] = mag true_alert_dict[alertId]['ra'] = np.degrees(line[4]) true_alert_dict[alertId]['decl'] = np.degrees(line[5]) true_alert_dict[alertId]['xPix'] = line[6] true_alert_dict[alertId]['yPix'] = line[7] elif np.abs(dmag) > dmag_cutoff_sqlite: ignored_sqlite += 1 self.assertGreater(len(true_alert_dict), 10) self.assertGreater(ignored_sqlite, 50) # just make sure that some sqlite # alerts were ignored by the more # stringent avro cut log_file_name = tempfile.mktemp(dir=self.alert_data_output_dir, suffix='log.txt') alert_gen = AlertDataGenerator(testing=True) alert_gen.subdivide_obs(self.obs_list, htmid_level=6) for htmid in alert_gen.htmid_list: alert_gen.alert_data_from_htmid( htmid, star_db, photometry_class=TestAlertsVarCat_avro, output_prefix='alert_test', output_dir=self.alert_data_output_dir, dmag_cutoff=dmag_cutoff_sqlite, log_file_name=log_file_name) obshistid_to_htmid = {} for htmid in alert_gen.htmid_list: for obs in alert_gen.obs_from_htmid(htmid): obshistid = obs.OpsimMetaData['obsHistID'] if obshistid not in obshistid_to_htmid: obshistid_to_htmid[obshistid] = [] obshistid_to_htmid[obshistid].append(htmid) avro_gen = AvroAlertGenerator() avro_gen.load_schema( os.path.join(getPackageDir('sims_catUtils'), 'tests', 'testData', 'avroSchema')) sql_prefix_list = ['alert_test'] out_prefix = 'test_avro' log_file_name = tempfile.mktemp(dir=self.avro_out_dir, prefix='test_avro', suffix='log.txt') for obshistid in obshistid_list: avro_gen.write_alerts(obshistid, self.alert_data_output_dir, sql_prefix_list, obshistid_to_htmid[obshistid], self.avro_out_dir, out_prefix, dmag_cutoff_avro, lock=None, log_file_name=log_file_name) list_of_avro_files = os.listdir(self.avro_out_dir) self.assertGreater(len(list_of_avro_files), 2) alert_ct = 0 dummy_sed = Sed() bp_dict = BandpassDict.loadTotalBandpassesFromFiles() photParams = PhotometricParameters() diasourceId_set = set() for avro_file_name in list_of_avro_files: if avro_file_name.endswith('log.txt'): continue full_name = os.path.join(self.avro_out_dir, avro_file_name) with DataFileReader(open(full_name, 'rb'), DatumReader()) as data_reader: for alert in data_reader: alert_ct += 1 obshistid = alert['alertId'] >> 20 obs = obs_dict[obshistid] uniqueId = alert['diaObject']['diaObjectId'] true_alert_id = (uniqueId << obshistid_bits) + obshistid self.assertIn(true_alert_id, true_alert_dict) self.assertEqual(alert['l1dbId'], uniqueId) true_alert = true_alert_dict[true_alert_id] diaSource = alert['diaSource'] self.assertAlmostEqual(diaSource['ra'], true_alert['ra'], 10) self.assertAlmostEqual(diaSource['decl'], true_alert['decl'], 10) self.assertAlmostEqual(diaSource['x'], true_alert['xPix'], 3) self.assertAlmostEqual(diaSource['y'], true_alert['yPix'], 3) self.assertAlmostEqual(diaSource['midPointTai'], obs.mjd.TAI, 4) true_tot_flux = dummy_sed.fluxFromMag(true_alert['mag']) true_q_mag = true_alert['mag'] - true_alert['dmag'] true_q_flux = dummy_sed.fluxFromMag(true_q_mag) true_dflux = true_tot_flux - true_q_flux self.assertAlmostEqual(diaSource['psFlux'] / true_dflux, 1.0, 6) self.assertAlmostEqual( diaSource['totFlux'] / true_tot_flux, 1.0, 6) self.assertAlmostEqual(diaSource['diffFlux'] / true_dflux, 1.0, 6) true_tot_snr, gamma = calcSNR_m5(true_alert['mag'], bp_dict[obs.bandpass], obs.m5[obs.bandpass], photParams) true_q_snr, gamma = calcSNR_m5( true_q_mag, bp_dict[obs.bandpass], self.obs_mag_cutoff[mag_name_to_int[obs.bandpass]], photParams) true_tot_err = true_tot_flux / true_tot_snr true_q_err = true_q_flux / true_q_snr true_diff_err = np.sqrt(true_tot_err**2 + true_q_err**2) self.assertAlmostEqual( diaSource['snr'] / np.abs(true_dflux / true_diff_err), 1.0, 6) self.assertAlmostEqual( diaSource['totFluxErr'] / true_tot_err, 1.0, 6) self.assertAlmostEqual( diaSource['diffFluxErr'] / true_diff_err, 1.0, 6) chipnum = int(true_alert['chipName'].replace( 'R', '').replace('S', '').replace(',', '').replace( ':', '').replace(' ', '')) true_ccdid = (chipnum * 10**7) + obshistid self.assertEqual(true_ccdid, diaSource['ccdVisitId']) self.assertEqual(uniqueId, diaSource['diaObjectId']) self.assertNotIn(diaSource['diaSourceId'], diasourceId_set) diasourceId_set.add(diaSource['diaSourceId']) diaObject = alert['diaObject'] obj_dex = (uniqueId // 1024) - 1 self.assertAlmostEqual( 0.001 * diaObject['pmRa'] / self.pmra_truth[obj_dex], 1.0, 5) self.assertAlmostEqual( 0.001 * diaObject['pmDecl'] / self.pmdec_truth[obj_dex], 1.0, 5) self.assertAlmostEqual( 0.001 * diaObject['parallax'] / self.px_truth[obj_dex], 1.0, 5) (true_ra_base, true_dec_base) = applyProperMotion( self.ra_truth[obj_dex], self.dec_truth[obj_dex], self.pmra_truth[obj_dex], self.pmdec_truth[obj_dex], self.px_truth[obj_dex], self.vrad_truth[obj_dex], mjd=ModifiedJulianDate(TAI=diaObject['radecTai'])) self.assertAlmostEqual(true_ra_base, diaObject['ra'], 7) self.assertAlmostEqual(true_dec_base, diaObject['decl'], 7) self.assertEqual(alert_ct, len(true_alert_dict))
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 __init__(self): self._camera = lsst_camera()
obs.site = site_no_atm assert np.abs(obs.site.pressure) < 1.0e-6 assert np.abs(obs.site.humidity) < 1.0e-6 x_pix_arr = np.arange(700.0, 3301.0, 700.0) y_pix_arr = np.arange(700.0, 3301.0, 700.0) pix_grid = np.meshgrid(x_pix_arr, y_pix_arr) x_pix_arr = pix_grid[0].flatten() y_pix_arr = pix_grid[1].flatten() x_mm = [] y_mm = [] x_pix = [] y_pix = [] camera = lsst_camera() det_name_list = [] for det in camera: if det.getType() == SCIENCE: det_name_list.append(det.getName()) det_name_list.sort() for det_name in det_name_list: if args.chip is not None and args.chip != det_name: continue for xpix, ypix in zip(x_pix_arr, y_pix_arr): xmm, ymm = coord_converter.mmFromPix(xpix, ypix, det_name) x_mm.append(xmm) y_mm.append(ymm) x_pix.append(xpix) y_pix.append(ypix)
from lsst.sims.coordUtils import getCornerRaDec from lsst.sims.coordUtils import focalPlaneCoordsFromRaDec from lsst.sims.coordUtils import pixelCoordsFromRaDec from lsst.sims.coordUtils import chipNameFromRaDec if __name__ == "__main__": header_msg = '# This catalog was generated by\n#\n' header_msg += '# SIMS_COORDUTILS_DIR/tests/lsstCameraData/make_test_catalog.py\n' header_msg += '#\n# It contains data we will use to verify that we have\n' header_msg += '# correctly updated sims_coordUtils whenever the API for\n' header_msg += '# afwCameraGeom changes. If obs_lsstSim ever changes in a\n' header_msg += '# physically meaningful way, this catalog will need to be\n' header_msg += '# regenerated.\n#\n' camera = lsst_camera() ra = 25.0 dec = -62.0 obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, rotSkyPos=57.2, mjd=59586.2) ra_range = np.arange(ra-4.0, ra+4.0, 0.1) dec_range = np.arange(dec-4.0, dec+4.0, 0.1) ra_grid, dec_grid = np.meshgrid(ra_range, dec_range) ra_grid = ra_grid.flatten() dec_grid = dec_grid.flatten() chip_name_grid = chipNameFromRaDec(ra_grid, dec_grid, obs_metadata=obs, camera=camera)
def pupilCoordsFromPixelCoordsLSST(xPix, yPix, chipName=None, band="r", includeDistortion=True): """ Convert pixel coordinates into radians on the pupil Parameters ---------- xPix -- the x pixel coordinate yPix -- the y pixel coordinate chipName -- the name(s) of the chips on which xPix, yPix are reckoned band -- the filter we are simulating (default=r) includeDistortion -- a boolean which turns on or off optical distortions (default=True) Returns ------- a 2-D numpy array in which the first row is the x pupil coordinate and the second row is the y pupil coordinate (both in radians) """ if not includeDistortion: return pupilCoordsFromPixelCoords(xPix, yPix, chipName=chipName, camera=lsst_camera(), includeDistortion=includeDistortion) are_arrays, \ chipNameList = _validate_inputs_and_chipname([xPix, yPix], ['xPix', 'yPix'], "pupilCoordsFromPixelCoords", chipName, chipname_can_be_none=False) pixel_to_focal_dict = {} camera = lsst_camera() name_to_int = {} name_to_int[None] = 0 name_to_int['None'] = 0 ii = 1 if are_arrays: chip_name_int = np.zeros(len(xPix), dtype=int) have_transform = set() for i_obj, name in enumerate(chipNameList): if name not in have_transform and name is not None and name != 'None': pixel_to_focal_dict[name] = camera[name].getTransform( PIXELS, FOCAL_PLANE) name_to_int[name] = ii have_transform.add(name) ii += 1 if are_arrays: chip_name_int[i_obj] = name_to_int[name] if are_arrays: x_f = np.zeros(len(xPix), dtype=float) y_f = np.zeros(len(yPix), dtype=float) for name in name_to_int: local_int = name_to_int[name] local_valid = np.where(chip_name_int == local_int) if len(local_valid[0]) == 0: continue if name is None or name == 'None': x_f[local_valid] = np.NaN y_f[local_valid] = np.NaN continue pixel_pt_arr = [ geom.Point2D(xPix[ii], yPix[ii]) for ii in local_valid[0] ] focal_pt_arr = pixel_to_focal_dict[name].applyForward(pixel_pt_arr) focal_coord_arr = np.array([[pt.getX(), pt.getY()] for pt in focal_pt_arr]).transpose() x_f[local_valid] = focal_coord_arr[0] y_f[local_valid] = focal_coord_arr[1] else: if chipNameList[0] is None or chipNameList[0] == 'None': x_f = np.NaN y_f = np.NaN else: pixel_pt = geom.Point2D(xPix, yPix) focal_pt = pixel_to_focal_dict[chipNameList[0]].applyForward( pixel_pt) x_f = focal_pt.getX() y_f = focal_pt.getY() return pupilCoordsFromFocalPlaneCoordsLSST(x_f, y_f, band=band)
def chipNameFromPupilCoordsLSST(xPupil_in, yPupil_in, allow_multiple_chips=False, band='r'): """ Return the names of LSST detectors that see the object specified by either (xPupil, yPupil). @param [in] xPupil_in is the x pupil coordinate in radians. Must be a numpy array. @param [in] yPupil_in is the y pupil coordinate in radians. Must be a numpy array. @param [in] allow_multiple_chips is a boolean (default False) indicating whether or not this method will allow objects to be visible on more than one chip. If it is 'False' and an object appears on more than one chip, only the first chip will appear in the list of chipNames and warning will be emitted. If it is 'True' and an object falls on more than one chip, a list of chipNames will appear for that object. @param[in] band is the bandpass being simulated (default='r') @param [out] a numpy array of chip names """ if (not hasattr(chipNameFromPupilCoordsLSST, '_focal_map') or not hasattr(chipNameFromPupilCoordsLSST, '_detector_arr') or len(chipNameFromPupilCoordsLSST._detector_arr) == 0): focal_map = _build_lsst_focal_coord_map() chipNameFromPupilCoordsLSST._focal_map = focal_map camera = lsst_camera() detector_arr = np.zeros(len(focal_map['name']), dtype=object) for ii in range(len(focal_map['name'])): detector_arr[ii] = camera[focal_map['name'][ii]] chipNameFromPupilCoordsLSST._detector_arr = detector_arr # build a Box2D that contains all of the detectors in the camera focal_to_field = camera.getTransformMap().getTransform( FOCAL_PLANE, FIELD_ANGLE) focal_bbox = camera.getFpBBox() focal_corners = focal_bbox.getCorners() camera_bbox = geom.Box2D() x_focal_max = None x_focal_min = None y_focal_max = None y_focal_min = None for cc in focal_corners: xx = cc.getX() yy = cc.getY() if x_focal_max is None or xx > x_focal_max: x_focal_max = xx if x_focal_min is None or xx < x_focal_min: x_focal_min = xx if y_focal_max is None or yy > y_focal_max: y_focal_max = yy if y_focal_min is None or yy < y_focal_min: y_focal_min = yy chipNameFromPupilCoordsLSST._x_focal_center = 0.5 * (x_focal_max + x_focal_min) chipNameFromPupilCoordsLSST._y_focal_center = 0.5 * (y_focal_max + y_focal_min) radius_sq_max = None for cc in focal_corners: xx = cc.getX() yy = cc.getY() radius_sq = ( (xx - chipNameFromPupilCoordsLSST._x_focal_center)**2 + (yy - chipNameFromPupilCoordsLSST._y_focal_center)**2) if radius_sq_max is None or radius_sq > radius_sq_max: radius_sq_max = radius_sq chipNameFromPupilCoordsLSST._camera_focal_radius_sq = radius_sq_max * 1.1 are_arrays = _validate_inputs([xPupil_in, yPupil_in], ['xPupil_in', 'yPupil_in'], "chipNameFromPupilCoordsLSST") if not are_arrays: xPupil_in = np.array([xPupil_in]) yPupil_in = np.array([yPupil_in]) xFocal, yFocal = focalPlaneCoordsFromPupilCoordsLSST(xPupil_in, yPupil_in, band=band) radius_sq_list = ( (xFocal - chipNameFromPupilCoordsLSST._x_focal_center)**2 + (yFocal - chipNameFromPupilCoordsLSST._y_focal_center)**2) with np.errstate(invalid='ignore'): good_radii = np.where(radius_sq_list < chipNameFromPupilCoordsLSST. _camera_focal_radius_sq) if len(good_radii[0]) == 0: return np.array([None] * len(xPupil_in)) xFocal_good = xFocal[good_radii] yFocal_good = yFocal[good_radii] ############################################################ # in the code below, we will only consider those points which # passed the 'good_radii' test above; the other points will # be added in with chipName == None at the end # focalPointList = [ geom.Point2D(xFocal[i_pt], yFocal[i_pt]) for i_pt in good_radii[0] ] # Loop through every detector on the camera. For each detector, assemble a list of points # whose centers are within 1.1 detector radii of the center of the detector. x_cam_list = chipNameFromPupilCoordsLSST._focal_map['xx'] y_cam_list = chipNameFromPupilCoordsLSST._focal_map['yy'] rrsq_lim_list = (1.1 * chipNameFromPupilCoordsLSST._focal_map['dp'])**2 possible_points = [] for i_chip, (x_cam, y_cam, rrsq_lim) in \ enumerate(zip(x_cam_list, y_cam_list, rrsq_lim_list)): local_possible_pts = np.where(((xFocal_good - x_cam)**2 + (yFocal_good - y_cam)**2) < rrsq_lim)[0] possible_points.append(local_possible_pts) nameList_good = _findDetectorsListLSST( focalPointList, chipNameFromPupilCoordsLSST._detector_arr, possible_points, allow_multiple_chips=allow_multiple_chips) #################################################################### # initialize output as an array of Nones, effectively adding back in # the points which failed the initial radius cut nameList = np.array([None] * len(xPupil_in)) nameList[good_radii] = nameList_good if not are_arrays: return nameList[0] return nameList
from lsst.sims.coordUtils import lsst_camera from lsst.sims.catUtils.exampleCatalogDefinitions import write_phoSim_header from lsst.sims.utils import observedFromICRS from lsst.sims.utils import Site from lsst.sims.GalSimInterface import LSSTCameraWrapper from lsst.sims.coordUtils import focalPlaneCoordsFromRaDec from lsst.afw.cameraGeom import SCIENCE if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('--obs', type=int, default=230) args = parser.parse_args() camera = lsst_camera() det_name_list = [] for det in camera: if det.getType() != SCIENCE: continue det_name_list.append(det.getName()) det_name_list.sort() opsimdb = os.path.join('/Users', 'danielsf', 'physics', 'lsst_150412', 'Development', 'garage', 'OpSimData', 'minion_1016_sqlite.db') assert os.path.exists(opsimdb) obs_gen = ObservationMetaDataGenerator(database=opsimdb) obs_list = obs_gen.getObservationMetaData(obsHistID=args.obs) obs = obs_list[0]
def test_naive_focal_plane_position(self): """ Test deprecession of PhoSim coordinates by comparing the focal plane position predicted by CatSim from ICRS with the focal plane position predicted by CatSim from deprecessed coordinates. """ phosim_mixin = PhoSimAstrometryBase() mjd = 59587.2 # create site with no atmosphere so that we can avoid # refraction site = Site(name="LSST", pressure=0.0, humidity=0.0) obs = ObservationMetaData(mjd=mjd, site=site) ra, dec = raDecFromAltAz(31.0, 112.0, obs) d_sun = distanceToSun(ra, dec, obs.mjd) self.assertGreater(d_sun, 45.0) obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, rotSkyPos=27.3, mjd=mjd, site=site) ra_icrs = np.arange(obs.pointingRA-2.0, obs.pointingRA+2.0, 0.05) dec_icrs = np.arange(obs.pointingDec-2.0, obs.pointingDec+2.0, 0.05) coord_grid = np.meshgrid(ra_icrs, dec_icrs) ra_icrs = coord_grid[0].flatten() dec_icrs = coord_grid[1].flatten() (xpup_icrs, ypup_icrs) = pupilCoordsFromRaDec(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=False) (x_focal_icrs, y_focal_icrs) = focalPlaneCoordsFromPupilCoords(xpup_icrs, ypup_icrs, camera=lsst_camera()) ra_obs, dec_obs = observedFromICRS(ra_icrs, dec_icrs, obs_metadata=obs, epoch=2000.0, includeRefraction=False) ra_obs_rad = np.radians(ra_obs) dec_obs_rad = np.radians(dec_obs) (ra_deprecessed_rad, dec_deprecessed_rad) = phosim_mixin._dePrecess(ra_obs_rad, dec_obs_rad, obs) (xpup_deprecessed, ypup_deprecessed) = _naivePupilCoordsFromObserved(ra_deprecessed_rad, dec_deprecessed_rad, obs._pointingRA, obs._pointingDec, obs._rotSkyPos) (x_focal_deprecessed, y_focal_deprecessed) = focalPlaneCoordsFromPupilCoords(xpup_deprecessed, ypup_deprecessed, camera=lsst_camera()) dd = np.sqrt((x_focal_icrs-x_focal_deprecessed)**2 +(y_focal_icrs-y_focal_deprecessed)**2) self.assertLess(dd.max(), 5.0e-8)
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 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(135.0, 112.0, obs_mjd) obs = ObservationMetaData(pointingRA=ra, pointingDec=dec, mjd=obs_mjd.mjd, rotSkyPos=22.4, bandpassName='u') 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 = pixelCoordsFromPupilCoordsLSST(x_pup, y_pup, chipName=name, band=obs.bandpass) (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_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, name, obs) 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 = raDecFromPixelCoordsLSST(x_pix, y_pix, name, obs_metadata=obs, band=obs.bandpass) (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-4, rtol=0.0) np.testing.assert_allclose(x_pix_inv, 2.0 * center_pix.getY() - y_pix, atol=1.0e-4, 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 __init__(self): self._camera = coordUtils.lsst_camera()
def test_dmPixFromCameraPix(self): """ Test that the method to return DM pixel coordinates from Camera Team pixel coordinates works. """ camera = lsst_camera() camera_wrapper = LSSTCameraWrapper() obs = ObservationMetaData(bandpassName='u') npts = 100 rng = np.random.RandomState(1824) dm_x_pix_list = rng.random_sample(npts) * 4000.0 dm_y_pix_list = rng.random_sample(npts) * 4000.0 name_list = [] for det in camera: name_list.append(det.getName()) chip_name_list = rng.choice(name_list, size=npts) (xPup_list, yPup_list) = pupilCoordsFromPixelCoordsLSST(dm_x_pix_list, dm_y_pix_list, chipName=chip_name_list, band=obs.bandpass) (cam_x_pix_list, cam_y_pix_list) = camera_wrapper.pixelCoordsFromPupilCoords( xPup_list, yPup_list, chip_name_list, obs) (dm_x_test, dm_y_test) = camera_wrapper.dmPixFromCameraPix( cam_x_pix_list, cam_y_pix_list, chip_name_list) np.testing.assert_array_almost_equal(dm_x_test, dm_x_pix_list, decimal=4) np.testing.assert_array_almost_equal(dm_y_test, dm_y_pix_list, decimal=4) # test transformations made one at a time for ii in range(len(cam_x_pix_list)): dm_x, dm_y = camera_wrapper.dmPixFromCameraPix( cam_x_pix_list[ii], cam_y_pix_list[ii], chip_name_list[ii]) self.assertAlmostEqual(dm_x_pix_list[ii], dm_x, 4) self.assertAlmostEqual(dm_y_pix_list[ii], dm_y, 4) # test case where an array of points is on a single chip chip_name = chip_name_list[10] (xPup_list, yPup_list) = pupilCoordsFromPixelCoordsLSST(dm_x_pix_list, dm_y_pix_list, chipName=chip_name, band=obs.bandpass) (cam_x_pix_list, cam_y_pix_list) = camera_wrapper.pixelCoordsFromPupilCoords( xPup_list, yPup_list, chip_name, obs) (dm_x_test, dm_y_test) = camera_wrapper.dmPixFromCameraPix( cam_x_pix_list, cam_y_pix_list, chip_name) np.testing.assert_array_almost_equal(dm_x_test, dm_x_pix_list, decimal=4) np.testing.assert_array_almost_equal(dm_y_test, dm_y_pix_list, decimal=4) del camera del camera_wrapper del lsst_camera._lsst_camera
def testObjectPlacement(self): """ Test that GalSim places objects on the correct pixel by drawing images containing single objects and no background, reading those images back in, and comparing the flux-averaged centroids of the images with the expected pixel positions of the input objects. """ scratchDir = tempfile.mkdtemp(dir=ROOT, prefix='testLSSTObjectPlacement-') if os.path.exists(scratchDir): shutil.rmtree(scratchDir) os.mkdir(scratchDir) detector = lsst_camera()['R:0,3 S:2,2'] det_name = 'R03_S22' magNorm = 19.0 pixel_transformer = DMtoCameraPixelTransformer() for band in 'ugrizy': obs = self.obs_dict[band] catName = os.path.join(scratchDir, 'placementCatalog.dat') imageRoot = os.path.join(scratchDir, 'placementImage') dbFileName = os.path.join(scratchDir, 'placementInputCatalog.dat') imageName = '%s_%s_%s.fits' % (imageRoot, det_name, obs.bandpass) ra_c, dec_c = raDecFromPixelCoordsLSST(2000.0, 2000.0, detector.getName(), band=obs.bandpass, obs_metadata=obs) nSamples = 30 rng = np.random.RandomState(42) fwhm = 0.12 for iteration in range(nSamples): if os.path.exists(dbFileName): os.unlink(dbFileName) ra_obj = ra_c + rng.random_sample()*0.2 - 0.1 dec_obj = dec_c + rng.random_sample()*0.2 - 0.1 dmx_wrong, dmy_wrong = pixelCoordsFromRaDec(ra_obj, dec_obj, chipName=detector.getName(), obs_metadata=obs, camera=lsst_camera()) dmx_pix, dmy_pix = pixelCoordsFromRaDecLSST(ra_obj, dec_obj, chipName=detector.getName(), obs_metadata=obs, band=obs.bandpass) x_pix, y_pix = pixel_transformer.cameraPixFromDMPix(dmx_pix, dmy_pix, detector.getName()) x_pix_wrong, y_pix_wrong = pixel_transformer.cameraPixFromDMPix(dmx_wrong, dmy_wrong, detector.getName()) d_ra = 360.0*(ra_obj - obs.pointingRA) # in arcseconds d_dec = 360.0*(dec_obj - obs.pointingDec) create_text_catalog(obs, dbFileName, np.array([d_ra]), np.array([d_dec]), mag_norm=[magNorm]) db = LSSTPlacementFileDBObj(dbFileName, runtable='test') cat = LSSTPlacementCatalog(db, obs_metadata=obs) cat.camera_wrapper = LSSTCameraWrapper() psf = SNRdocumentPSF(fwhm=fwhm) cat.setPSF(psf) cat.write_catalog(catName) cat.write_images(nameRoot=imageRoot) im = afwImage.ImageF(imageName).getArray() tot_flux = im.sum() self.assertGreater(tot_flux, 10.0) y_centroid = sum([ii*im[ii,:].sum() for ii in range(im.shape[0])])/tot_flux x_centroid = sum([ii*im[:,ii].sum() for ii in range(im.shape[1])])/tot_flux dd = np.sqrt((x_pix-x_centroid)**2 + (y_pix-y_centroid)**2) self.assertLess(dd, 0.5*fwhm) dd_wrong = np.sqrt((x_pix_wrong-x_centroid)**2 + (y_pix_wrong-y_centroid)**2) self.assertLess(dd, dd_wrong) if os.path.exists(dbFileName): os.unlink(dbFileName) if os.path.exists(catName): os.unlink(catName) if os.path.exists(imageName): os.unlink(imageName) if os.path.exists(scratchDir): shutil.rmtree(scratchDir)
def test_avro_alert_generation_diff_dmag(self): """ Make sure everything works properly when the AlertDataGenerator and the AvroAlertGenerator have different dmag thresholds """ dmag_cutoff_sqlite = 0.005 dmag_cutoff_avro = 0.2 mag_name_to_int = {'u': 0, 'g': 1, 'r': 2, 'i': 3, 'z': 4, 'y': 5} star_db = StarAlertTestDBObj_avro(database=self.star_db_name, driver='sqlite') # assemble a dict of all of the alerts that need to be generated obshistid_list = [] for obs in self.obs_list: obshistid_list.append(obs.OpsimMetaData['obsHistID']) obshistid_max = max(obshistid_list) obshistid_bits = int(np.ceil(np.log(obshistid_max)/np.log(2.0))) true_alert_dict = {} obs_dict = {} ignored_sqlite = 0 # count number of alerts written to sqlite, but not avro for obs in self.obs_list: obs_dict[obs.OpsimMetaData['obsHistID']] = obs obshistid = obs.OpsimMetaData['obsHistID'] cat = TestAlertsTruthCat_avro(star_db, obs_metadata=obs) cat.camera = lsst_camera() for line in cat.iter_catalog(): if line[1] is None: continue dmag = line[2] mag = line[3] if (np.abs(dmag) > dmag_cutoff_avro and mag <= self.obs_mag_cutoff[mag_name_to_int[obs.bandpass]]): alertId = (line[0] << obshistid_bits) + obshistid self.assertNotIn(alertId, true_alert_dict) true_alert_dict[alertId] = {} true_alert_dict[alertId]['chipName'] = line[1] true_alert_dict[alertId]['dmag'] = dmag true_alert_dict[alertId]['mag'] = mag true_alert_dict[alertId]['ra'] = np.degrees(line[4]) true_alert_dict[alertId]['decl'] = np.degrees(line[5]) true_alert_dict[alertId]['xPix'] = line[6] true_alert_dict[alertId]['yPix'] = line[7] elif np.abs(dmag) > dmag_cutoff_sqlite: ignored_sqlite += 1 self.assertGreater(len(true_alert_dict), 10) self.assertGreater(ignored_sqlite, 50) # just make sure that some sqlite # alerts were ignored by the more # stringent avro cut log_file_name = tempfile.mktemp(dir=self.alert_data_output_dir, suffix='log.txt') alert_gen = AlertDataGenerator(testing=True) alert_gen.subdivide_obs(self.obs_list, htmid_level=6) for htmid in alert_gen.htmid_list: alert_gen.alert_data_from_htmid(htmid, star_db, photometry_class=TestAlertsVarCat_avro, output_prefix='alert_test', output_dir=self.alert_data_output_dir, dmag_cutoff=dmag_cutoff_sqlite, log_file_name=log_file_name) obshistid_to_htmid = {} for htmid in alert_gen.htmid_list: for obs in alert_gen.obs_from_htmid(htmid): obshistid = obs.OpsimMetaData['obsHistID'] if obshistid not in obshistid_to_htmid: obshistid_to_htmid[obshistid] = [] obshistid_to_htmid[obshistid].append(htmid) avro_gen = AvroAlertGenerator() avro_gen.load_schema(os.path.join(getPackageDir('sims_catUtils'), 'tests', 'testData', 'avroSchema')) sql_prefix_list = ['alert_test'] out_prefix = 'test_avro' log_file_name = tempfile.mktemp(dir=self.avro_out_dir, prefix='test_avro', suffix='log.txt') for obshistid in obshistid_list: avro_gen.write_alerts(obshistid, self.alert_data_output_dir, sql_prefix_list, obshistid_to_htmid[obshistid], self.avro_out_dir, out_prefix, dmag_cutoff_avro, lock=None, log_file_name=log_file_name) list_of_avro_files = os.listdir(self.avro_out_dir) self.assertGreater(len(list_of_avro_files), 2) alert_ct = 0 dummy_sed = Sed() bp_dict = BandpassDict.loadTotalBandpassesFromFiles() photParams = PhotometricParameters() diasourceId_set = set() for avro_file_name in list_of_avro_files: if avro_file_name.endswith('log.txt'): continue full_name = os.path.join(self.avro_out_dir, avro_file_name) with DataFileReader(open(full_name, 'rb'), DatumReader()) as data_reader: for alert in data_reader: alert_ct += 1 obshistid = alert['alertId'] >> 20 obs = obs_dict[obshistid] uniqueId = alert['diaObject']['diaObjectId'] true_alert_id = (uniqueId << obshistid_bits) + obshistid self.assertIn(true_alert_id, true_alert_dict) self.assertEqual(alert['l1dbId'], uniqueId) true_alert = true_alert_dict[true_alert_id] diaSource = alert['diaSource'] self.assertAlmostEqual(diaSource['ra'], true_alert['ra'], 10) self.assertAlmostEqual(diaSource['decl'], true_alert['decl'], 10) self.assertAlmostEqual(diaSource['x'], true_alert['xPix'], 3) self.assertAlmostEqual(diaSource['y'], true_alert['yPix'], 3) self.assertAlmostEqual(diaSource['midPointTai'], obs.mjd.TAI, 4) true_tot_flux = dummy_sed.fluxFromMag(true_alert['mag']) true_q_mag = true_alert['mag'] - true_alert['dmag'] true_q_flux = dummy_sed.fluxFromMag(true_q_mag) true_dflux = true_tot_flux - true_q_flux self.assertAlmostEqual(diaSource['psFlux']/true_dflux, 1.0, 6) self.assertAlmostEqual(diaSource['totFlux']/true_tot_flux, 1.0, 6) self.assertAlmostEqual(diaSource['diffFlux']/true_dflux, 1.0, 6) true_tot_snr, gamma = calcSNR_m5(true_alert['mag'], bp_dict[obs.bandpass], obs.m5[obs.bandpass], photParams) true_q_snr, gamma = calcSNR_m5(true_q_mag, bp_dict[obs.bandpass], self.obs_mag_cutoff[mag_name_to_int[obs.bandpass]], photParams) true_tot_err = true_tot_flux/true_tot_snr true_q_err = true_q_flux/true_q_snr true_diff_err = np.sqrt(true_tot_err**2 + true_q_err**2) self.assertAlmostEqual(diaSource['snr']/np.abs(true_dflux/true_diff_err), 1.0, 6) self.assertAlmostEqual(diaSource['totFluxErr']/true_tot_err, 1.0, 6) self.assertAlmostEqual(diaSource['diffFluxErr']/true_diff_err, 1.0, 6) chipnum = int(true_alert['chipName'].replace('R', '').replace('S', ''). replace(',', '').replace(':', '').replace(' ', '')) true_ccdid = (chipnum*10**7)+obshistid self.assertEqual(true_ccdid, diaSource['ccdVisitId']) self.assertEqual(uniqueId, diaSource['diaObjectId']) self.assertNotIn(diaSource['diaSourceId'], diasourceId_set) diasourceId_set.add(diaSource['diaSourceId']) diaObject = alert['diaObject'] obj_dex = (uniqueId//1024) - 1 self.assertAlmostEqual(0.001*diaObject['pmRa']/self.pmra_truth[obj_dex], 1.0, 5) self.assertAlmostEqual(0.001*diaObject['pmDecl']/self.pmdec_truth[obj_dex], 1.0, 5) self.assertAlmostEqual(0.001*diaObject['parallax']/self.px_truth[obj_dex], 1.0, 5) (true_ra_base, true_dec_base) = applyProperMotion(self.ra_truth[obj_dex], self.dec_truth[obj_dex], self.pmra_truth[obj_dex], self.pmdec_truth[obj_dex], self.px_truth[obj_dex], self.vrad_truth[obj_dex], mjd=ModifiedJulianDate(TAI=diaObject['radecTai'])) self.assertAlmostEqual(true_ra_base, diaObject['ra'], 7) self.assertAlmostEqual(true_dec_base, diaObject['decl'], 7) self.assertEqual(alert_ct, len(true_alert_dict))