def factory(cls, stamp_im, metadata, index): """This method is needed to service the FITS reader. We need a standard interface to construct objects like this. Parameters needed to construct this object are passed in via a metadata dictionary and then passed to the constructor of this class. If lists of values are passed with the following keys, they will be passed to the constructor, otherwise dummy values will be passed: RA_DEG, DEC_DEG. They should each point to lists of values. Parameters ---------- stamp : `lsst.afw.image.MaskedImage` Pixel data to pass to the constructor metadata : `dict` Dictionary containing the information needed by the constructor. idx : `int` Index into the lists in ``metadata`` Returns ------- stamp : `Stamp` An instance of this class """ if 'RA_DEG' in metadata and 'DEC_DEG' in metadata: return cls(stamp_im=stamp_im, position=SpherePoint( Angle(metadata.getArray('RA_DEG')[index], degrees), Angle(metadata.getArray('DEC_DEG')[index], degrees))) else: return cls(stamp_im=stamp_im, position=SpherePoint(Angle(numpy.nan), Angle(numpy.nan)))
class Stamp(AbstractStamp): """Single stamp Parameters ---------- stamp_im : `lsst.afw.image.MaskedImageF` The actual pixel values for the postage stamp position : `lsst.geom.SpherePoint`, optional Position of the center of the stamp. Note the user must keep track of the coordinate system """ stamp_im: afwImage.maskedImage.MaskedImageF archive_element: Optional[afwTable.io.Persistable] = None position: Optional[SpherePoint] = SpherePoint(Angle(numpy.nan), Angle(numpy.nan)) @classmethod def factory(cls, stamp_im, metadata, index, archive_element=None): """This method is needed to service the FITS reader. We need a standard interface to construct objects like this. Parameters needed to construct this object are passed in via a metadata dictionary and then passed to the constructor of this class. If lists of values are passed with the following keys, they will be passed to the constructor, otherwise dummy values will be passed: RA_DEG, DEC_DEG. They should each point to lists of values. Parameters ---------- stamp : `lsst.afw.image.MaskedImage` Pixel data to pass to the constructor metadata : `dict` Dictionary containing the information needed by the constructor. idx : `int` Index into the lists in ``metadata`` archive_element : `afwTable.io.Persistable`, optional Archive element (e.g. Transform or WCS) associated with this stamp. Returns ------- stamp : `Stamp` An instance of this class """ if 'RA_DEG' in metadata and 'DEC_DEG' in metadata: return cls(stamp_im=stamp_im, archive_element=archive_element, position=SpherePoint( Angle(metadata.getArray('RA_DEG')[index], degrees), Angle(metadata.getArray('DEC_DEG')[index], degrees))) else: return cls(stamp_im=stamp_im, archive_element=archive_element, position=SpherePoint(Angle(numpy.nan), Angle(numpy.nan)))
def test_repr(self): """Test that eval(repr(Angle)) round-trips for finite and non-finite values. """ from lsst.geom import Angle, degrees # need symbols in scope for eval d = 4.0 / 7.0 self.assertEqual(eval(repr(Angle(d, degrees))), Angle(d, degrees)) self.assertEqual(eval(repr(Angle(float("inf"), degrees))), Angle(float("inf"), degrees)) self.assertTrue( np.isnan(eval(repr(Angle(float("NaN"), degrees))).asDegrees()))
def evaluate(self, angle_start: Angle, angle_end: Optional[Angle] = None): """Get y-band background image array for a range of angles. It is hypothesized that the instrument rotator rotates at a constant angular velocity. This is not strictly true, but should be a sufficient approximation for the relatively short exposure times typical for HSC. Parameters ---------- angle_start : `float` Instrument rotation angle in degrees at the start of the exposure. angle_end : `float`, optional Instrument rotation angle in degrees at the end of the exposure. If not provided, the returned array will reflect a snapshot at `angle_start`. Returns ------- ccd_img : `numpy.ndarray` Background data for this exposure. """ hdulist = fits.open(self._filename) header = hdulist[0].header # full-size ccd height & channel width ccd_h, ch_w = header["F_NAXIS2"], header["F_NAXIS1"] # saved data is compressed to 1/2**scale_level of the original size image_scale_level = header["WTLEVEL2"], header["WTLEVEL1"] angle_scale_level = header["WTLEVEL3"] ccd_w = ch_w * len(hdulist) ccd_img = numpy.empty(shape=(ccd_h, ccd_w), dtype=numpy.float32) for ch, hdu in enumerate(hdulist): volume = _upscale_volume(hdu.data, angle_scale_level) if angle_end is None: img = volume(angle_start.asDegrees()) else: img = (volume.integrate(angle_start.asDegrees(), angle_end.asDegrees()) * (1.0 / (angle_end.asDegrees() - angle_start.asDegrees()))) ccd_img[:, ch_w * ch:ch_w * (ch + 1)] = _upscale_image( img, (ccd_h, ch_w), image_scale_level) # Some regions don't have useful values because the amplifier is dead # when the darks were taken # is_bad = ccd_img > BAD_THRESHOLD # ccd_img[is_bad] = numpy.median(ccd_img[~is_bad]) return ccd_img
def __init__(self, config=None): if config is None: config = self.ConfigClass() config.freeze() # just to be sure, e.g. for pickling self.config = config self._tractInfoList = [] self._wcsFactory = detail.WcsFactory( pixelScale=Angle(self.config.pixelScale, arcseconds), projection=self.config.projection, rotation=Angle(self.config.rotation, degrees), ) self._sha1 = None
def _horizonRotAngle(self): """!Compute rotation angle of camera with respect to horizontal coordinates from self.visitInfo. @returns horizon rotation angle. """ observatory = self.visitInfo.getObservatory() lat = observatory.getLatitude() lon = observatory.getLongitude() radec = self.visitInfo.getBoresightRaDec() ra = radec.getRa() dec = radec.getDec() era = self.visitInfo.getEra() ha = (era + lon - ra).wrap() alt = self.visitInfo.getBoresightAzAlt().getLatitude() # parallactic angle sinParAng = (np.cos(lat.asRadians()) * np.sin(ha.asRadians()) / np.cos(alt.asRadians())) cosParAng = np.sqrt(1 - sinParAng * sinParAng) if dec > lat: cosParAng = -cosParAng parAng = Angle(np.arctan2(sinParAng, cosParAng)) bra = self.visitInfo.getBoresightRotAngle() return (bra - parAng).wrap()
def __init__(self, config=None): """Construct a BaseSkyMap @param[in] config: an instance of self.ConfigClass; if None the default config is used """ if config is None: config = self.ConfigClass() config.freeze() # just to be sure, e.g. for pickling self.config = config self._tractInfoList = [] self._wcsFactory = detail.WcsFactory( pixelScale=Angle(self.config.pixelScale, arcseconds), projection=self.config.projection, rotation=Angle(self.config.rotation, degrees), ) self._sha1 = None
def testParallacticAngleSouthMeridian(self): """An observation on the Meridian that is South of zenith has a parallactic angle of zero.""" meridianBoresightRA = self.data1.era + self.data1.observatory.getLongitude() southBoresightDec = self.data1.observatory.getLatitude() - 10.*degrees visitInfo = afwImage.VisitInfo(era=self.data1.era, boresightRaDec=SpherePoint(meridianBoresightRA, southBoresightDec), observatory=self.data1.observatory, ) self.assertAnglesAlmostEqual(visitInfo.getBoresightParAngle(), Angle(0.))