def __init__(self, afwDetector, afwCamera, obs_metadata, epoch): """ @param [in] afwDetector is an instantiation of afw.cameraGeom.Detector @param [in] afwCamera is an instantiation of afw.cameraGeom.Camera @param [in] obs_metadata is an instantiation of ObservationMetaData characterizing the telescope pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured """ tanSipWcs = tanSipWcsFromDetector(afwDetector, afwCamera, obs_metadata, epoch) self.afwDetector = afwDetector self.afwCamera = afwCamera self.obs_metadata = obs_metadata self.epoch = epoch self.fitsHeader = tanSipWcs.getFitsMetadata() self.fitsHeader.set("EXTTYPE", "IMAGE") self.crpix1 = self.fitsHeader.get("CRPIX1") self.crpix2 = self.fitsHeader.get("CRPIX2") self.afw_crpix1 = self.crpix1 self.afw_crpix2 = self.crpix2 self.crval1 = self.fitsHeader.get("CRVAL1") self.crval2 = self.fitsHeader.get("CRVAL2") self.origin = galsim.PositionD(x=self.crpix1, y=self.crpix2)
def testTanSipWcs(self): """ Test that tanSipWcsFromDetector works by fitting a TAN WCS and a TAN-SIP WCS to a detector with distortions and verifying that the TAN-SIP WCS better approximates the truth. """ tanWcs = tanWcsFromDetector(self.detector.getName(), self.camera_wrapper, self.obs, self.epoch) tanSipWcs = tanSipWcsFromDetector(self.detector.getName(), self.camera_wrapper, self.obs, self.epoch) tanWcsRa = [] tanWcsDec = [] tanSipWcsRa = [] tanSipWcsDec = [] xPixList = [] yPixList = [] for xx in np.arange(0.0, 4001.0, 100.0): for yy in np.arange(0.0, 4001.0, 100.0): xPixList.append(xx) yPixList.append(yy) pt = afwGeom.Point2D(xx, yy) skyPt = tanWcs.pixelToSky(pt).getPosition(LsstGeom.degrees) tanWcsRa.append(skyPt.getX()) tanWcsDec.append(skyPt.getY()) skyPt = tanSipWcs.pixelToSky(pt).getPosition(LsstGeom.degrees) tanSipWcsRa.append(skyPt.getX()) tanSipWcsDec.append(skyPt.getY()) tanWcsRa = np.radians(np.array(tanWcsRa)) tanWcsDec = np.radians(np.array(tanWcsDec)) tanSipWcsRa = np.radians(np.array(tanSipWcsRa)) tanSipWcsDec = np.radians(np.array(tanSipWcsDec)) xPixList = np.array(xPixList) yPixList = np.array(yPixList) (raTest, decTest) = self.camera_wrapper._raDecFromPixelCoords(xPixList, yPixList, [self.detector.getName()]*len(xPixList), obs_metadata=self.obs, epoch=self.epoch) tanDistanceList = arcsecFromRadians(haversine(raTest, decTest, tanWcsRa, tanWcsDec)) tanSipDistanceList = arcsecFromRadians(haversine(raTest, decTest, tanSipWcsRa, tanSipWcsDec)) maxDistanceTan = tanDistanceList.max() maxDistanceTanSip = tanSipDistanceList.max() msg = 'max error in TAN WCS %e arcsec; in TAN-SIP %e arcsec' % (maxDistanceTan, maxDistanceTanSip) self.assertLess(maxDistanceTanSip, 0.01, msg=msg) self.assertGreater(maxDistanceTan-maxDistanceTanSip, 1.0e-10, msg=msg)
def testTanSipWcs(self): """ Test that tanSipWcsFromDetector works by fitting a TAN WCS and a TAN-SIP WCS to a detector with distortions and verifying that the TAN-SIP WCS better approximates the truth. """ tanWcs = tanWcsFromDetector(self.detector, self.camera, self.obs, self.epoch) tanSipWcs = tanSipWcsFromDetector(self.detector, self.camera, self.obs, self.epoch) tanWcsRa = [] tanWcsDec = [] tanSipWcsRa = [] tanSipWcsDec = [] xPixList = [] yPixList = [] for xx in numpy.arange(0.0, 4001.0, 100.0): for yy in numpy.arange(0.0, 4001.0, 100.0): xPixList.append(xx) yPixList.append(yy) pt = afwGeom.Point2D(xx ,yy) skyPt = tanWcs.pixelToSky(pt).getPosition() tanWcsRa.append(skyPt.getX()) tanWcsDec.append(skyPt.getY()) skyPt = tanSipWcs.pixelToSky(pt).getPosition() tanSipWcsRa.append(skyPt.getX()) tanSipWcsDec.append(skyPt.getY()) tanWcsRa = numpy.radians(numpy.array(tanWcsRa)) tanWcsDec = numpy.radians(numpy.array(tanWcsDec)) tanSipWcsRa = numpy.radians(numpy.array(tanSipWcsRa)) tanSipWcsDec = numpy.radians(numpy.array(tanSipWcsDec)) xPixList = numpy.array(xPixList) yPixList = numpy.array(yPixList) raTest, decTest = _raDecFromPixelCoords(xPixList, yPixList, [self.detector.getName()]*len(xPixList), camera=self.camera, obs_metadata=self.obs, epoch=self.epoch) tanDistanceList = arcsecFromRadians(haversine(raTest, decTest, tanWcsRa, tanWcsDec)) tanSipDistanceList = arcsecFromRadians(haversine(raTest, decTest, tanSipWcsRa, tanSipWcsDec)) maxDistanceTan = tanDistanceList.max() maxDistanceTanSip = tanSipDistanceList.max() msg = 'max error in TAN WCS %e arcsec; in TAN-SIP %e arcsec' % (maxDistanceTan, maxDistanceTanSip) self.assertLess(maxDistanceTanSip, 0.01, msg=msg) self.assertGreater(maxDistanceTan-maxDistanceTanSip, 1.0e-10, msg=msg)
def __init__(self, afwDetector, afwCamera, obs_metadata, epoch, photParams=None, wcs=None): """ @param [in] afwDetector is an instantiation of afw.cameraGeom.Detector @param [in] afwCamera is an instantiation of afw.cameraGeom.Camera @param [in] obs_metadata is an instantiation of ObservationMetaData characterizing the telescope pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured @param [in] photParams is an instantiation of PhotometricParameters (it will contain information about gain, exposure time, etc.) @param [in] wcs is a kwarg that is used by the method _newOrigin(). The wcs kwarg in this constructor method should not be used by users. """ if wcs is None: self._tanSipWcs = tanSipWcsFromDetector(afwDetector, afwCamera, obs_metadata, epoch) else: self._tanSipWcs = wcs self.afwDetector = afwDetector self.afwCamera = afwCamera self.obs_metadata = obs_metadata self.photParams = photParams self.epoch = epoch self.fitsHeader = self._tanSipWcs.getFitsMetadata() self.fitsHeader.set("EXTTYPE", "IMAGE") if self.obs_metadata.bandpass is not None: if not isinstance(self.obs_metadata.bandpass, list) and not isinstance(self.obs_metadata.bandpass, numpy.ndarray): self.fitsHeader.set("FILTER", self.obs_metadata.bandpass) if self.obs_metadata.mjd is not None: self.fitsHeader.set("MJD-OBS", self.obs_metadata.mjd.TAI) if self.photParams is not None: self.fitsHeader.set("EXPTIME", self.photParams.nexp*self.photParams.exptime) self.crpix1 = self.fitsHeader.get("CRPIX1") self.crpix2 = self.fitsHeader.get("CRPIX2") self.afw_crpix1 = self.crpix1 self.afw_crpix2 = self.crpix2 self.crval1 = self.fitsHeader.get("CRVAL1") self.crval2 = self.fitsHeader.get("CRVAL2") self.origin = galsim.PositionD(x=self.crpix1, y=self.crpix2)
def __init__(self, detectorName, cameraWrapper, obs_metadata, epoch, photParams=None, wcs=None): """ @param [in] detectorName is the name of the detector as stored by afw @param [in] cameraWrapper is an instantionat of a GalSimCameraWrapper @param [in] obs_metadata is an instantiation of ObservationMetaData characterizing the telescope pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured @param [in] photParams is an instantiation of PhotometricParameters (it will contain information about gain, exposure time, etc.) @param [in] wcs is a kwarg that is used by the method _newOrigin(). The wcs kwarg in this constructor method should not be used by users. """ if not isinstance(cameraWrapper, GalSimCameraWrapper): raise RuntimeError( "You must pass GalSim_afw_TanSipWCS an instantiation " "of GalSimCameraWrapper or one of its daughter " "classes") if wcs is None: self._tanSipWcs = tanSipWcsFromDetector(detectorName, cameraWrapper, obs_metadata, epoch) else: self._tanSipWcs = wcs self.detectorName = detectorName self.cameraWrapper = cameraWrapper self.obs_metadata = obs_metadata self.photParams = photParams self.epoch = epoch # this is needed to match the GalSim v1.5 API self._color = None self.fitsHeader = self._tanSipWcs.getFitsMetadata() self.fitsHeader.set("EXTTYPE", "IMAGE") if self.obs_metadata.bandpass is not None: if (not isinstance(self.obs_metadata.bandpass, list) and not isinstance(self.obs_metadata.bandpass, np.ndarray)): self.fitsHeader.set("FILTER", self.obs_metadata.bandpass) if self.obs_metadata.mjd is not None: self.fitsHeader.set("MJD-OBS", self.obs_metadata.mjd.TAI) if self.photParams is not None: self.fitsHeader.set("EXPTIME", self.photParams.nexp * self.photParams.exptime) # Add pointing information to FITS header. if self.obs_metadata.pointingRA is not None: self.fitsHeader.set('RATEL', obs_metadata.pointingRA) if self.obs_metadata.pointingDec is not None: self.fitsHeader.set('DECTEL', obs_metadata.pointingDec) if self.obs_metadata.rotSkyPos is not None: self.fitsHeader.set('ROTANGLE', obs_metadata.rotSkyPos) self.crpix1 = self.fitsHeader.getScalar("CRPIX1") self.crpix2 = self.fitsHeader.getScalar("CRPIX2") self.afw_crpix1 = self.crpix1 self.afw_crpix2 = self.crpix2 self.crval1 = self.fitsHeader.getScalar("CRVAL1") self.crval2 = self.fitsHeader.getScalar("CRVAL2") self.origin = galsim.PositionD(x=self.crpix1, y=self.crpix2) self._color = None
def __init__(self, afwDetector, afwCamera, obs_metadata, epoch, photParams=None, wcs=None): """ @param [in] afwDetector is an instantiation of afw.cameraGeom.Detector @param [in] afwCamera is an instantiation of afw.cameraGeom.Camera @param [in] obs_metadata is an instantiation of ObservationMetaData characterizing the telescope pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured @param [in] photParams is an instantiation of PhotometricParameters (it will contain information about gain, exposure time, etc.) @param [in] wcs is a kwarg that is used by the method _newOrigin(). The wcs kwarg in this constructor method should not be used by users. """ if wcs is None: self._tanSipWcs = tanSipWcsFromDetector(afwDetector, afwCamera, obs_metadata, epoch) else: self._tanSipWcs = wcs self.afwDetector = afwDetector self.afwCamera = afwCamera self.obs_metadata = obs_metadata self.photParams = photParams self.epoch = epoch self.fitsHeader = self._tanSipWcs.getFitsMetadata() self.fitsHeader.set("EXTTYPE", "IMAGE") if self.obs_metadata.bandpass is not None: if (not isinstance(self.obs_metadata.bandpass, list) and not isinstance(self.obs_metadata.bandpass, np.ndarray)): self.fitsHeader.set("FILTER", self.obs_metadata.bandpass) if self.obs_metadata.mjd is not None: self.fitsHeader.set("MJD-OBS", self.obs_metadata.mjd.TAI) if self.photParams is not None: self.fitsHeader.set("EXPTIME", self.photParams.nexp * self.photParams.exptime) self.crpix1 = self.fitsHeader.get("CRPIX1") self.crpix2 = self.fitsHeader.get("CRPIX2") self.afw_crpix1 = self.crpix1 self.afw_crpix2 = self.crpix2 self.crval1 = self.fitsHeader.get("CRVAL1") self.crval2 = self.fitsHeader.get("CRVAL2") self.origin = galsim.PositionD(x=self.crpix1, y=self.crpix2)
def __init__(self, detectorName, cameraWrapper, obs_metadata, epoch, photParams=None, wcs=None): """ @param [in] detectorName is the name of the detector as stored by afw @param [in] cameraWrapper is an instantionat of a GalSimCameraWrapper @param [in] obs_metadata is an instantiation of ObservationMetaData characterizing the telescope pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured @param [in] photParams is an instantiation of PhotometricParameters (it will contain information about gain, exposure time, etc.) @param [in] wcs is a kwarg that is used by the method _newOrigin(). The wcs kwarg in this constructor method should not be used by users. """ if not isinstance(cameraWrapper, GalSimCameraWrapper): raise RuntimeError("You must pass GalSim_afw_TanSipWCS an instantiation " "of GalSimCameraWrapper or one of its daughter " "classes") if wcs is None: self._tanSipWcs = tanSipWcsFromDetector(detectorName, cameraWrapper, obs_metadata, epoch) else: self._tanSipWcs = wcs self.detectorName = detectorName self.cameraWrapper = cameraWrapper self.obs_metadata = obs_metadata self.photParams = photParams self.epoch = epoch # this is needed to match the GalSim v1.5 API self._color = None self.fitsHeader = self._tanSipWcs.getFitsMetadata() self.fitsHeader.set("EXTTYPE", "IMAGE") if self.obs_metadata.bandpass is not None: if (not isinstance(self.obs_metadata.bandpass, list) and not isinstance(self.obs_metadata.bandpass, np.ndarray)): self.fitsHeader.set("FILTER", self.obs_metadata.bandpass) if self.obs_metadata.mjd is not None: self.fitsHeader.set("MJD-OBS", self.obs_metadata.mjd.TAI) mjd_obs = astropy.time.Time(self.obs_metadata.mjd.TAI, format='mjd') self.fitsHeader.set('DATE-OBS', mjd_obs.isot) if self.photParams is not None: exptime = self.photParams.nexp*self.photParams.exptime self.fitsHeader.set("EXPTIME", exptime) with warnings.catch_warnings(): warnings.filterwarnings('ignore', 'ERFA function', ErfaWarning) mjd_end = mjd_obs + astropy.time.TimeDelta(exptime, format='sec') self.fitsHeader.set('DATE-END', mjd_end.isot) # Add pointing information to FITS header. if self.obs_metadata.pointingRA is not None: self.fitsHeader.set('RATEL', obs_metadata.pointingRA) if self.obs_metadata.pointingDec is not None: self.fitsHeader.set('DECTEL', obs_metadata.pointingDec) if self.obs_metadata.rotSkyPos is not None: self.fitsHeader.set('ROTANGLE', obs_metadata.rotSkyPos) # Add airmass, needed by jointcal. if self.obs_metadata.OpsimMetaData is not None: try: airmass = self.obs_metadata.OpsimMetaData['airmass'] except KeyError: pass else: self.fitsHeader.set('AIRMASS', airmass) # Add boilerplate keywords requested by DM. self.fitsHeader.set('TELESCOP', 'LSST') self.fitsHeader.set('INSTRUME', 'CAMERA') self.fitsHeader.set('SIMULATE', True) self.fitsHeader.set('ORIGIN', 'IMSIM') observatory = LsstObservatory() self.fitsHeader.set('OBS-LONG', observatory.getLongitude().asDegrees()) self.fitsHeader.set('OBS-LAT', observatory.getLatitude().asDegrees()) self.fitsHeader.set('OBS-ELEV', observatory.getElevation()) obs_location = observatory.getLocation() self.fitsHeader.set('OBSGEO-X', obs_location.geocentric[0].value) self.fitsHeader.set('OBSGEO-Y', obs_location.geocentric[1].value) self.fitsHeader.set('OBSGEO-Z', obs_location.geocentric[2].value) self.crpix1 = self.fitsHeader.getScalar("CRPIX1") self.crpix2 = self.fitsHeader.getScalar("CRPIX2") self.afw_crpix1 = self.crpix1 self.afw_crpix2 = self.crpix2 self.crval1 = self.fitsHeader.getScalar("CRVAL1") self.crval2 = self.fitsHeader.getScalar("CRVAL2") self.origin = galsim.PositionD(x=self.crpix1, y=self.crpix2) self._color = None
def make_star_grid_instcat(instcat, star_truth_db=None, detectors=None, x_pixels=None, y_pixels=None, mag_range=(16.3, 21), max_x_offset=0, max_y_offset=0, y_stagger=4, outdir=None, sorted_mags=False): """ Create an instance catalog consisting of grids of stars on each chip, using the instance catalog from a simulated visit to provide the info for constructing the WCS per CCD. Parameters ---------- instcat: str The instance catalog corresponding to the desired visit. star_truth_db: str [None] sqlite3 file containing the truth_summary table for stars so that the true band-specific magnitudes can be used for selection. If None, then make selection using the mag_norm value. detectors: sequence of ints [None] The detectors to process. If None, then use range(189). x_pixels: sequence of ints [None] The pixel coordinates in the x (i.e., serial)-direction. If None, then use np.linspace(150, 4050, 40). y_pixels: sequence of ints [None] The pixel coordinates in the y (i.e., parallel)-direction. If None, then use np.linspace(100, 3900, 39). mag_range: tuple [(16.3, 21)] Range of magnituide values to sample from the input star_cat file. max_x_offset: float [0] Maximum offset in pixels to be drawn in the x-direction to displace each star from its nominal grid position. These offsets helps prevent failures in the astrometric solution that arises from trying to match to a regular grid of reference stars. max_y_offset: float [0] Maximum offset in pixels to be drawn in the y-direction to displace each star from its nominal grid position. These offsets helps prevent failures in the astrometric solution that arises from trying to match to a regular grid of reference stars. y_stagger: int [4] Stagger rows by y_step/y_stagger*(ix % ystagger) outdir: str [None] Output directory for instance catalog files. If None, then use f'v{visit}-{band}_grid'. sorted_mags: bool [False] Flag to sort magnitudes so that brightest objects are at the bottom of the CCD. Returns ------- The full path to the star grid instance catalog. """ if detectors is None: detectors = range(189) if x_pixels is None: x_pixels = np.linspace(200, 3800, 36) if y_pixels is None: y_pixels = np.linspace(200, 3800, 36) star_cat, visit, band = parse_instcat(instcat) obs_md \ = desc.imsim.phosim_obs_metadata(desc.imsim.metadata_from_file(instcat)) num_stars = len(detectors) * len(x_pixels) * len(y_pixels) stars = shuffled_objects(star_cat, band, star_truth_db=star_truth_db, mag_range=mag_range)[:num_stars] num_stars = min(num_stars, len(stars)) if sorted_mags: stars.sort() if outdir is None: outdir = f'v{visit}-{band}_grid' os.makedirs(outdir, exist_ok=True) star_grid_cat = 'star_grid_{visit}.txt'.format(**locals()) phosim_cat_file = write_phosim_cat(instcat, outdir, star_grid_cat) outfile = os.path.join(outdir, star_grid_cat) y_step = y_pixels[1] - y_pixels[0] with open(outfile, 'w') as output: my_id = 0 for detector in detectors: print("processing", detector) wcs = tanSipWcsFromDetector(det_name[detector], camera_wrapper, obs_md, epoch=2000.) if not sorted_mags: # Re-shuffle the entries for each CCD. np.random.shuffle(stars) for ix, x_pix in enumerate(x_pixels): # Stagger rows by quarter steps y_offset = y_step / y_stagger * (ix % y_stagger) for y_pix in y_pixels: dx = np.random.uniform(high=max_x_offset) dy = np.random.uniform(high=max_y_offset) ra, dec = [ _.asDegrees() for _ in wcs.pixelToSky(x_pix + dx, y_pix + dy + y_offset) ] tokens = stars[my_id % num_stars].split() # Replace the uniqueID, ra, dec fields with the # recomputed values. tokens[1] = str(my_id) tokens[2] = f'{ra:.15f}' tokens[3] = f'{dec:.15f}' output.write(' '.join(tokens) + '\n') my_id += 1 return phosim_cat_file