def setUp(self): self.testDir = os.path.dirname(__file__) def computeLstHA(data): """Return LST, Hour Angle, computed from VisitInfoData.""" localEra = data.era + data.observatory.getLongitude() hourAngle = localEra - data.boresightRaDec[0] return localEra, hourAngle fields = [ 'exposureId', 'exposureTime', 'darkTime', 'date', 'ut1', 'era', 'boresightRaDec', 'boresightAzAlt', 'boresightAirmass', 'boresightRotAngle', 'rotType', 'observatory', 'weather' ] VisitInfoData = collections.namedtuple("VisitInfoData", fields) data1 = VisitInfoData( exposureId=10313423, exposureTime=10.01, darkTime=11.02, date=DateTime(65321.1, DateTime.MJD, DateTime.TAI), ut1=12345.1, era=45.1 * degrees, boresightRaDec=SpherePoint(23.1 * degrees, 73.2 * degrees), boresightAzAlt=SpherePoint(134.5 * degrees, 33.3 * degrees), boresightAirmass=1.73, boresightRotAngle=73.2 * degrees, rotType=afwImage.RotType.SKY, observatory=Observatory(11.1 * degrees, 22.2 * degrees, 0.333), weather=Weather(1.1, 2.2, 34.5), ) self.data1 = data1 self.localEra1, self.hourAngle1 = computeLstHA(data1) data2 = VisitInfoData( exposureId=1, exposureTime=15.5, darkTime=17.8, date=DateTime(55321.2, DateTime.MJD, DateTime.TAI), ut1=312345.1, era=25.1 * degrees, boresightRaDec=SpherePoint(2.1 * degrees, 33.2 * degrees), boresightAzAlt=SpherePoint(13.5 * degrees, 83.3 * degrees), boresightAirmass=2.05, boresightRotAngle=-53.2 * degrees, rotType=afwImage.RotType.HORIZON, observatory=Observatory(22.2 * degrees, 33.3 * degrees, 0.444), weather=Weather(2.2, 3.3, 44.4), ) self.data2 = data2 self.localEra2, self.hourAngle2 = computeLstHA(data2)
def setArgDict(self, md, argDict): """Set an argument dict for VisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ MakeRawVisitInfo.setArgDict(self, md, argDict) argDict["darkTime"] = self.popFloat(md, "DARKTIME") argDict["boresightAzAlt"] = Coord( self.popAngle(md, "TELAZ"), self.popAngle(md, "TELALT"), ) argDict["boresightRaDec"] = IcrsCoord( self.popAngle( md, "RA_DEG", ), self.popAngle(md, "DEC_DEG"), ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["observatory"] = Observatory( self.popAngle(md, "LONGITUD"), self.popAngle(md, "LATITUDE"), 4204, # from Wikipedia ) argDict["weather"] = Weather( self.popFloat(md, "TEMPERAT"), self.popFloat(md, "PRESSURE") * 100.0, # 100 Pascal per millibar self.popFloat(md, "RELHUMID"), ) # Using LST to compute ERA until we get UT1 (see: DM-8053) LST = self.popAngle(md, "LST-OBS", units=astropy.units.h) argDict['era'] = self.eraFromLstAndLongitude( LST, argDict["observatory"].getLongitude())
class MakeGotoRawVisitInfo(MakeRawVisitInfo): """Make a VisitInfo from the FITS header of a GOTO image """ observatory = Observatory(-17.882 * degrees, 28.761 * degrees, 2332) # long, lat, elev def setArgDict(self, md, argDict): """Set an argument dict for makeVisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ argDict["exposureTime"] = self.popFloat(md, 'EXPTIME') startDate = self.popIsoDate(md, "DATE-OBS") argDict["date"] = self.offsetDate(startDate, 0.5 * argDict["exposureTime"]) argDict["boresightAzAlt"] = SpherePoint( self.popAngle(md, "AZ"), self.popAngle(md, "ALT"), ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["observatory"] = self.observatory argDict['darkTime'] = argDict['exposureTime']
class MakeSuperbitRawVisitInfo(MakeRawVisitInfo): """Make a VisitInfo from the FITS header of a SuperBIT image """ #Hmm - bit tricky for a floaty observatory; let's hope it's not important #Having said that, if you have a record of the telescopes position #at the time of observation, you may be able to use that. # # Put in coordinates of CSBF as a placeholder, with an elevation of 30,000 m # hopefully that doesn't make limit of elev fail? --JEM observatory = Observatory(31.779524 * degrees, 95.712369 * degrees, 30000) # long, lat, elev def setArgDict(self, md, argDict): """Set an argument dict for makeVisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ #I believe the names in capitals come from the header. You'll need #to change these to reflect your header keywords. startDate = self.popIsoDate(md, "DATE_OBS") argDict["exposureTime"] = self.popFloat(md, 'EXPTIME') argDict['darkTime'] = argDict['exposureTime'] argDict["date"] = self.offsetDate(startDate, 0.5 * argDict["exposureTime"]) argDict["boresightAzAlt"] = SpherePoint( self.popAngle(md, "AZ"), self.popAngle(md, "EL"), ) #argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["observatory"] = self.observatory
def setArgDict(self, md, argDict): """Set an argument dict for VisitInfo and pop associated metadata Parameters ---------- md : `lsst.daf.base.PropertyList` or `lsst.daf.base.PropertySet` Metadata to extract from. Extracted values are removed. argdict : `dict` A dict of arguments to add to values to. """ MakeRawVisitInfo.setArgDict(self, md, argDict) argDict["darkTime"] = self.popFloat(md, "DARKTIME") argDict["boresightAzAlt"] = SpherePoint( self.popAngle(md, "TELAZ"), self.popAngle(md, "TELALT"), ) argDict["boresightRaDec"] = SpherePoint( self.popAngle(md, "RA_DEG",), self.popAngle(md, "DEC_DEG"), ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["observatory"] = Observatory( self.popAngle(md, "LONGITUD"), self.popAngle(md, "LATITUDE"), 4204, # from Wikipedia ) argDict["weather"] = Weather( self.popFloat(md, "TEMPERAT"), self.popFloat(md, "PRESSURE")*100.0, # 100 Pascal per millibar self.popFloat(md, "RELHUMID"), ) # Using LST to compute ERA until we get UT1 (see: DM-8053) LST = self.popAngle(md, "LST-OBS", units=astropy.units.h) argDict['era'] = self.eraFromLstAndLongitude(LST, argDict["observatory"].getLongitude())
def setArgDict(self, md, argDict): """Set an argument dict for VisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ MakeRawVisitInfo.setArgDict(self, md, argDict) argDict["darkTime"] = self.popFloat(md, "DARKTIME") argDict["boresightAzAlt"] = Coord( self.popAngle(md, "AZ"), self.altitudeFromZenithDistance(self.popAngle(md, "ZD")), ) argDict["boresightRaDec"] = IcrsCoord( self.popAngle(md, "TELRA", units=astropy.units.h), self.popAngle(md, "TELDEC"), ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["observatory"] = Observatory( self.popAngle(md, "OBS-LONG"), self.popAngle(md, "OBS-LAT"), self.popFloat(md, "OBS-ELEV"), ) argDict["weather"] = Weather( self.popFloat(md, "OUTTEMP"), self.pascalFromMmHg(self.popFloat(md, "PRESSURE")), self.popFloat(md, "HUMIDITY")) longitude = argDict["observatory"].getLongitude() argDict['era'] = self.decamGetEra(md, argDict["boresightRaDec"][0], longitude)
class MakeLsstSimRawVisitInfo(MakeRawVisitInfo): """Make a VisitInfo from the FITS header of a raw LSST simulated image The convention for ROTANG is as follows: at 0 degrees E = +Y CCD = -X Focal Plane, N = +X CCD = +Y Focal Plane: 0 boresightRotAng at 90 degrees E = -X CCD = -Y Focal Plane, N = +Y CCD = -X Focal Plane: 270 boresightRotAng So boresightRotAng = -ROTANG """ observatory = Observatory(-70.749417*degrees, -30.244633*degrees, 2663) # long, lat, elev def setArgDict(self, md, argDict): """Set an argument dict for VisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ MakeRawVisitInfo.setArgDict(self, md, argDict) argDict["darkTime"] = self.popFloat(md, "DARKTIME") argDict["boresightAzAlt"] = SpherePoint( self.popAngle(md, "AZIMUTH"), self.altitudeFromZenithDistance(self.popAngle(md, "ZENITH")), ) argDict["boresightRaDec"] = SpherePoint( self.popAngle(md, "RA_DEG"), self.popAngle(md, "DEC_DEG"), ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["boresightRotAngle"] = -self.popAngle(md, "ROTANG") argDict["rotType"] = RotType.SKY argDict["observatory"] = self.observatory weather = defaultWeather(self.observatory.getElevation()) temperature = self.defaultMetadata(self.popFloat(md, "TEMPERA"), weather.getAirTemperature(), minimum=-10, maximum=40.) pressure = self.defaultMetadata(self.pascalFromMmHg(self.popFloat(md, "PRESS")), weather.getAirPressure(), minimum=50000., maximum=90000.) humidity = 40. # Not currently supplied by phosim, so set to a typical value. argDict["weather"] = Weather(temperature, pressure, humidity) longitude = argDict["observatory"].getLongitude() RA = argDict["boresightRaDec"][0] # phosim doesn't supply LST, HA, or UT1, and the alt/az/ra/dec/time can be inconsistent. # We will leave ERA as NaN until a better answer is available. try: # Other simulation tools don't have the same problem, and need hour angle if it is available. HA = self.popAngle(md, "HA", units=astropy.units.h) argDict['era'] = HA + RA - longitude except Exception: self.log.warn("Hour angle missing from metadata, will be NAN") return VisitInfo(**argDict) def getDateAvg(self, md, exposureTime): """Return date at the middle of the exposure @param[in,out] md FITS metadata; changed in place @param[in] exposureTime exposure time in sec """ startDate = self.popMjdDate(md, "TAI", timesys="TAI") return self.offsetDate(startDate, 0.5*exposureTime)
def createVisitInfo(): return lsst.afw.image.VisitInfo( 10313423, 10.01, 11.02, DateTime(65321.1, DateTime.MJD, DateTime.TAI), 12345.1, 45.1 * degrees, SpherePoint(23.1 * degrees, 73.2 * degrees), SpherePoint(134.5 * degrees, 33.3 * degrees), 1.73, 73.2 * degrees, lsst.afw.image.RotType.SKY, Observatory(11.1 * degrees, 22.2 * degrees, 0.333), Weather(1.1, 2.2, 34.5), "testCam")
class MakeHscRawVisitInfo(MakeRawVisitInfo): """Make a VisitInfo from the FITS header of a Subaru HSC image """ observatory = Observatory(-155.476667 * degrees, 19.825556 * degrees, 4139) # long, lat, elev def setArgDict(self, md, argDict): """Set an argument dict for VisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ MakeRawVisitInfo.setArgDict(self, md, argDict) #argDict["boresightRaDec"] = SpherePoint( #self.popAngle(md, "RA", units=astropy.units.h), #self.popAngle(md, "DEC"), #) #altitude = self.popAngle(md, "ALTITUDE") #altitude = self.popAngle(md, "EL") #if altitude > 90*degrees: # Sometimes during day observations, when not tracking # if self.log is not None: # self.log.warn("Clipping altitude (%f) at 90 degrees", altitude) # altitude = 90*degrees #argDict["boresightAzAlt"] = SpherePoint( # self.popAngle(md, "AZ"), # altitude, # ) #argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") #argDict["observatory"] = self.observatory #argDict["weather"] = Weather( # self.centigradeFromKelvin(self.popFloat(md, "OUT-TMP")), # self.pascalFromMmHg(self.popFloat(md, "OUT-PRS")), # self.popFloat(md, "OUT-HUM"), #) #LST = self.popAngle(md, "LST-STR", units=astropy.units.h) #argDict['era'] = self.eraFromLstAndLongitude(LST, self.observatory.getLongitude()) argDict['darkTime'] = argDict['exposureTime'] # Rotation angle formula determined empirically from visual inspection # of HSC images. See DM-9111. #rotAngle = (270.0*degrees - self.popAngle(md, "INST-PA")).wrap() #argDict['boresightRotAngle'] = rotAngle #argDict['rotType'] = RotType.SKY def getDateAvg(self, md, exposureTime): """Return date at the middle of the exposure @param[in,out] md FITS metadata; changed in place @param[in] exposureTime exposure time in sec """ startDate = self.popMjdDate(md, "MJD-STR") return self.offsetDate(startDate, 0.5 * exposureTime)
def setUp(self): """Define parameters used by every test.""" lsstLat = -30.244639 * degrees lsstLon = -70.749417 * degrees lsstAlt = 2663. lsstTemperature = 20. * units.Celsius # in degrees Celsius lsstHumidity = 10. # in percent lsstPressure = 73892. * units.pascal # 1 atmosphere. np.random.seed(5) self.weather = Weather(lsstTemperature / units.Celsius, lsstPressure / units.pascal, lsstHumidity) self.observatory = Observatory(lsstLon, lsstLat, lsstAlt)
class MakeLsstSimRawVisitInfo(MakeRawVisitInfo): """Make a VisitInfo from the FITS header of a raw LSST simulated image The convention for ROTANG is as follows: at 0 degrees E = +Y CCD = -X Focal Plane, N = +X CCD = +Y Focal Plane: 0 boresightRotAng at 90 degrees E = -X CCD = -Y Focal Plane, N = +Y CCD = -X Focal Plane: 270 boresightRotAng So boresightRotAng = -ROTANG """ observatory = Observatory(-70.749417 * degrees, -30.244633 * degrees, 2663) # long, lat, elev def setArgDict(self, md, argDict): """Set an argument dict for VisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ MakeRawVisitInfo.setArgDict(self, md, argDict) argDict["darkTime"] = self.popFloat(md, "DARKTIME") argDict["boresightAzAlt"] = Coord( self.popAngle(md, "AZIMUTH"), self.altitudeFromZenithDistance(self.popAngle(md, "ZENITH")), ) argDict["boresightRaDec"] = IcrsCoord( self.popAngle(md, "RA_DEG"), self.popAngle(md, "DEC_DEG"), ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["boresightRotAngle"] = -self.popAngle(md, "ROTANG") argDict["rotType"] = RotType.SKY argDict["observatory"] = self.observatory argDict["weather"] = Weather( self.popFloat(md, "TEMPERA"), self.pascalFromMmHg(self.popFloat(md, "PRESS")), float("nan"), ) # phosim doesn't supply LST, HA, or UT1, and the alt/az/ra/dec/time can be inconsistent. # We will leave ERA as NaN until a better answer is available. return VisitInfo(**argDict) def getDateAvg(self, md, exposureTime): """Return date at the middle of the exposure @param[in,out] md FITS metadata; changed in place @param[in] exposureTime exposure time in sec """ startDate = self.popMjdDate(md, "TAI", timesys="TAI") return self.offsetDate(startDate, 0.5 * exposureTime)
def makeVisitInfo(): """Return a non-NaN visitInfo.""" return afwImage.VisitInfo(exposureId=10313423, exposureTime=10.01, darkTime=11.02, date=dafBase.DateTime(65321.1, dafBase.DateTime.MJD, dafBase.DateTime.TAI), ut1=12345.1, era=45.1*afwGeom.degrees, boresightRaDec=afwGeom.SpherePoint(23.1, 73.2, afwGeom.degrees), boresightAzAlt=afwGeom.SpherePoint(134.5, 33.3, afwGeom.degrees), boresightAirmass=1.73, boresightRotAngle=73.2*afwGeom.degrees, rotType=afwImage.RotType.SKY, observatory=Observatory(11.1*afwGeom.degrees, 22.2*afwGeom.degrees, 0.333), weather=Weather(1.1, 2.2, 34.5), )
def makeVisitInfo(): return lsst.afw.image.VisitInfo( 10313423, 10.01, 11.02, DateTime(65321.1, DateTime.MJD, DateTime.TAI), 12345.1, 45.1*lsst.afw.geom.degrees, lsst.afw.geom.SpherePoint(23.1, 73.2, lsst.afw.geom.degrees), lsst.afw.geom.SpherePoint(134.5, 33.3, lsst.afw.geom.degrees), 1.73, 73.2*lsst.afw.geom.degrees, lsst.afw.image.RotType.SKY, Observatory(11.1*lsst.afw.geom.degrees, 22.2*lsst.afw.geom.degrees, 0.333), Weather(1.1, 2.2, 34.5), )
class MakeHscRawVisitInfo(MakeRawVisitInfo): """Make a VisitInfo from the FITS header of a Subaru HSC image """ observatory = Observatory(-155.476667 * degrees, 19.825556 * degrees, 4139) # long, lat, elev def setArgDict(self, md, argDict): """Set an argument dict for VisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ MakeRawVisitInfo.setArgDict(self, md, argDict) argDict["boresightRaDec"] = IcrsCoord( self.popAngle(md, "RA2000", units=astropy.units.h), self.popAngle(md, "DEC2000"), ) argDict["boresightAzAlt"] = Coord( self.popAngle(md, "AZIMUTH"), self.popAngle(md, "ALTITUDE"), ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["observatory"] = self.observatory argDict["weather"] = Weather( self.centigradeFromKelvin(self.popFloat(md, "OUT-TMP")), self.pascalFromMmHg(self.popFloat(md, "OUT-PRS")), self.popFloat(md, "OUT-HUM"), ) LST = self.popAngle(md, "LST-STR", units=astropy.units.h) argDict['era'] = self.eraFromLstAndLongitude( LST, self.observatory.getLongitude()) argDict['darkTime'] = argDict['exposureTime'] # Rotation angle formula determined empirically from visual inspection # of HSC images. See DM-9111. rotAngle = (270.0 * degrees - self.popAngle(md, "INST-PA")).wrap() argDict['boresightRotAngle'] = rotAngle argDict['rotType'] = RotType.SKY def getDateAvg(self, md, exposureTime): """Return date at the middle of the exposure @param[in,out] md FITS metadata; changed in place @param[in] exposureTime exposure time in sec """ startDate = self.popMjdDate(md, "MJD-STR") return self.offsetDate(startDate, 0.5 * exposureTime)
class MakeTestRawVisitInfo(MakeRawVisitInfo): """Make a VisitInfo from the FITS header of a test image Since the test data is extracted from LSST Sim data, this is a copy of MakeLsstSimRawVisitInfo (using a copy avoids undesireable dependencies) """ observatory = Observatory(-70.749417 * degrees, -30.244633 * degrees, 2663) # long, lat, elev def setArgDict(self, md, argDict): """Set an argument dict for VisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ MakeRawVisitInfo.setArgDict(self, md, argDict) argDict["darkTime"] = self.popFloat(md, "DARKTIME") argDict["boresightAzAlt"] = SpherePoint( self.popAngle(md, "AZIMUTH"), self.altitudeFromZenithDistance(self.popAngle(md, "ZENITH")), ) argDict["boresightRaDec"] = SpherePoint( self.popAngle(md, "RA_DEG"), self.popAngle(md, "DEC_DEG"), ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["boresightRotAngle"] = -self.popAngle(md, "ROTANG") argDict["rotType"] = RotType.SKY argDict["observatory"] = self.observatory argDict["weather"] = Weather( self.popFloat(md, "TEMPERA"), self.pascalFromMmHg(self.popFloat(md, "PRESS")), float("nan"), ) return VisitInfo(**argDict) def getDateAvg(self, md, exposureTime): """Return date at the middle of the exposure @param[in,out] md FITS metadata; changed in place @param[in] exposureTime exposure time in sec """ startDate = self.popMjdDate(md, "TAI", timesys="TAI") return self.offsetDate(startDate, 0.5 * exposureTime)
class MakeGotoRawVisitInfo(MakeRawVisitInfo): """Make a VisitInfo from the FITS header of a Subaru HSC image Boresight rotation angle could probably be set from one of: - INST-PT (but apparently only available for HSC, not suprimecam) - INR-TR, INR-END (but appears to not be SKY; so probably not interesting) """ observatory = Observatory(-155.476667 * degrees, 19.825556 * degrees, 4139) # long, lat, elev def setArgDict(self, md, argDict): """Set an argument dict for makeVisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ MakeRawVisitInfo.setArgDict(self, md, argDict) argDict["boresightRaDec"] = IcrsCoord( self.popAngle(md, "RA2000", units=astropy.units.h), self.popAngle(md, "DEC2000"), ) # argDict["boresightAzAlt"] = Coord( # self.popAngle(md, "AZIMUTH"), # self.popAngle(md, "ALTITUDE"), # ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["observatory"] = self.observatory argDict["weather"] = Weather( self.centigradeFromKelvin(self.popFloat(md, "OUT-TMP")), self.pascalFromMmHg(self.popFloat(md, "OUT-PRS")), self.popFloat(md, "OUT-HUM"), ) LST = self.popAngle(md, "LST-STR", units=astropy.units.h) argDict['era'] = self.eraFromLstAndLongitude( LST, self.observatory.getLongitude()) argDict['darkTime'] = argDict['exposureTime'] def getDateAvg(self, md, exposureTime): """Return date at the middle of the exposure @param[in,out] md FITS metadata; changed in place @param[in] exposureTime exposure time in sec """ startDate = self.popMjdDate(md, "MJD-STR") return self.offsetDate(startDate, 0.5 * exposureTime)
def setArgDict(self, md, argDict): """Set an argument dict for VisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments """ MakeRawVisitInfo.setArgDict(self, md, argDict) argDict["darkTime"] = self.popFloat(md, "DARKTIME") argDict["boresightAzAlt"] = SpherePoint( self.popAngle(md, "AZ"), self.altitudeFromZenithDistance(self.popAngle(md, "ZD")), ) argDict["boresightRaDec"] = SpherePoint( self.popAngle(md, "TELRA", units=astropy.units.h), self.popAngle(md, "TELDEC"), ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["observatory"] = Observatory( self.popAngle(md, "OBS-LONG"), self.popAngle(md, "OBS-LAT"), self.popFloat(md, "OBS-ELEV"), ) # Default weather is based on typical conditions at an altitude of 2215 meters. temperature = self.defaultMetadata(self.popFloat(md, "OUTTEMP"), 10., minimum=-10., maximum=40.) pressure = self.defaultMetadata(self.pascalFromMmHg( self.popFloat(md, "PRESSURE")), 77161.1, minimum=70000., maximum=85000.) humidity = self.defaultMetadata(self.popFloat(md, "HUMIDITY"), 40., minimum=0., maximum=100.) argDict["weather"] = Weather(temperature, pressure, humidity) longitude = argDict["observatory"].getLongitude() argDict['era'] = self.decamGetEra(md, argDict["boresightRaDec"][0], longitude)
class MakeCtmoRawVisitInfo(MakeRawVisitInfo): "Make a VisitInfo from the FITS header of a CTMO image" # longitude, latitude, elevation observatory = Observatory(-97.568956 * degrees, 25.995789 * degrees, 12) def setArgDict(self, md, argDict): """Set an argument dict for makeVisitInfo and pop associated metadata @param[in,out] md metadata, as an lsst.daf.base.PropertyList or PropertySet @param[in,out] argdict a dict of arguments While a Make<>RawVisitInfo file is mandatory for processCcd.py to run, it isn't mandatory for it to actually do anything. Hence this one simply contains a pass statement. However, it's recommended that you at least include the exposure time from the image header and observatory information (for the latter, remember to edit and uncomment the "observatory" variable above.) """ argDict["exposureTime"] = self.popFloat(md, "EXPTIME") argDict["observatory"] = self.observatory
def __call__(self, md, exposureId=None): """Construct a VisitInfo and strip associated data from the metadata. Parameters ---------- md : `lsst.daf.base.PropertyList` or `lsst.daf.base.PropertySet` Metadata to pull from. Items that are used are stripped from the metadata. exposureId : `int`, optional Ignored. Here for compatibility with `MakeRawVisitInfo`. Returns ------- visitInfo : `lsst.afw.image.VisitInfo` `~lsst.afw.image.VisitInfo` derived from the header using a `~astro_metadata_translator.MetadataTranslator`. """ argDict = dict() obsInfo = ObservationInfo(md, translator_class=self.metadataTranslator) # Strip all the cards out that were used for c in obsInfo.cards_used: del md[c] # Map the translated information into a form suitable for VisitInfo if obsInfo.exposure_time is not None: argDict["exposureTime"] = obsInfo.exposure_time.to_value("s") if obsInfo.dark_time is not None: argDict["darkTime"] = obsInfo.dark_time.to_value("s") argDict["exposureId"] = obsInfo.detector_exposure_id # VisitInfo uses the middle of the observation for the date if obsInfo.datetime_begin is not None and obsInfo.datetime_end is not None: tdelta = obsInfo.datetime_end - obsInfo.datetime_begin middle = obsInfo.datetime_begin + 0.5 * tdelta # DateTime uses nanosecond resolution, regardless of the resolution # of the original date middle.precision = 9 # isot is ISO8601 format with "T" separating date and time and no # time zone argDict["date"] = DateTime(middle.tai.isot, DateTime.TAI) # Derive earth rotation angle from UT1 (being out by a second is not # a big deal given the uncertainty over exactly what part of the # observation we are needing it for). # ERFA needs a UT1 time split into two floats # We ignore any problems with DUT1 not being defined for now. try: ut1time = middle.ut1 except iers.IERSRangeError: ut1time = middle era = erfa.era00(ut1time.jd1, ut1time.jd2) argDict["era"] = era * radians else: argDict["date"] = DateTime() # Coordinates if obsInfo.tracking_radec is not None: icrs = obsInfo.tracking_radec.transform_to("icrs") argDict["boresightRaDec"] = SpherePoint(icrs.ra.degree, icrs.dec.degree, units=degrees) altaz = obsInfo.altaz_begin if altaz is not None: argDict["boresightAzAlt"] = SpherePoint(altaz.az.degree, altaz.alt.degree, units=degrees) argDict["boresightAirmass"] = obsInfo.boresight_airmass if obsInfo.boresight_rotation_angle is not None: argDict[ "boresightRotAngle"] = obsInfo.boresight_rotation_angle.degree * degrees if obsInfo.boresight_rotation_coord is not None: rotType = RotType.UNKNOWN if obsInfo.boresight_rotation_coord == "sky": rotType = RotType.SKY argDict["rotType"] = rotType # Weather and Observatory Location temperature = float("nan") if obsInfo.temperature is not None: temperature = obsInfo.temperature.to_value( "deg_C", astropy.units.temperature()) pressure = float("nan") if obsInfo.pressure is not None: pressure = obsInfo.pressure.to_value("Pa") relative_humidity = float("nan") if obsInfo.relative_humidity is not None: relative_humidity = obsInfo.relative_humidity argDict["weather"] = Weather(temperature, pressure, relative_humidity) if obsInfo.location is not None: geolocation = obsInfo.location.to_geodetic() argDict["observatory"] = Observatory( geolocation.lon.degree * degrees, geolocation.lat.degree * degrees, geolocation.height.to_value("m")) for key in list( argDict.keys()): # use a copy because we may delete items if argDict[key] is None: self.log.warn("argDict[{}] is None; stripping".format( key, argDict[key])) del argDict[key] return VisitInfo(**argDict)
def observationInfo2visitInfo(obsInfo, log=None): """Construct a `~lsst.afw.image.VisitInfo` from an `~astro_metadata_translator.ObservationInfo` Parameters ---------- obsInfo : `astro_metadata_translator.ObservationInfo` Information gathered from the observation metadata. log : `logging.Logger` or `lsst.log.Log`, optional Logger to use for logging informational messages. If `None` logging will be disabled. Returns ------- visitInfo : `lsst.afw.image.VisitInfo` `~lsst.afw.image.VisitInfo` derived from the supplied `~astro_metadata_translator.ObservationInfo`. """ argDict = dict() # Map the translated information into a form suitable for VisitInfo if obsInfo.exposure_time is not None: argDict["exposureTime"] = obsInfo.exposure_time.to_value("s") if obsInfo.dark_time is not None: argDict["darkTime"] = obsInfo.dark_time.to_value("s") argDict["exposureId"] = obsInfo.detector_exposure_id # VisitInfo uses the middle of the observation for the date if obsInfo.datetime_begin is not None and obsInfo.datetime_end is not None: tdelta = obsInfo.datetime_end - obsInfo.datetime_begin middle = obsInfo.datetime_begin + 0.5 * tdelta # DateTime uses nanosecond resolution, regardless of the resolution # of the original date middle.precision = 9 # isot is ISO8601 format with "T" separating date and time and no # time zone argDict["date"] = DateTime(middle.tai.isot, DateTime.TAI) # Derive earth rotation angle from UT1 (being out by a second is # not a big deal given the uncertainty over exactly what part of # the observation we are needing it for). # ERFA needs a UT1 time split into two floats # We ignore any problems with DUT1 not being defined for now. try: # Catch any warnings about the time being in the future # since there is nothing we can do about that for simulated # data and it tells us nothing for data from the past. with warnings.catch_warnings(): # If we are using the real erfa it is not an AstropyWarning # During transition period filter both warnings.simplefilter( "ignore", category=astropy.utils.exceptions.AstropyWarning) if ErfaWarning is not None: warnings.simplefilter("ignore", category=ErfaWarning) ut1time = middle.ut1 except iers.IERSRangeError: ut1time = middle era = erfa.era00(ut1time.jd1, ut1time.jd2) argDict["era"] = era * radians else: argDict["date"] = DateTime() # Coordinates if obsInfo.tracking_radec is not None: icrs = obsInfo.tracking_radec.transform_to("icrs") argDict["boresightRaDec"] = SpherePoint(icrs.ra.degree, icrs.dec.degree, units=degrees) altaz = obsInfo.altaz_begin if altaz is not None: argDict["boresightAzAlt"] = SpherePoint(altaz.az.degree, altaz.alt.degree, units=degrees) argDict["boresightAirmass"] = obsInfo.boresight_airmass if obsInfo.boresight_rotation_angle is not None: argDict[ "boresightRotAngle"] = obsInfo.boresight_rotation_angle.degree * degrees if obsInfo.boresight_rotation_coord is not None: rotType = RotType.UNKNOWN if obsInfo.boresight_rotation_coord == "sky": rotType = RotType.SKY argDict["rotType"] = rotType # Weather and Observatory Location temperature = float("nan") if obsInfo.temperature is not None: temperature = obsInfo.temperature.to_value( "deg_C", astropy.units.temperature()) pressure = float("nan") if obsInfo.pressure is not None: pressure = obsInfo.pressure.to_value("Pa") relative_humidity = float("nan") if obsInfo.relative_humidity is not None: relative_humidity = obsInfo.relative_humidity argDict["weather"] = Weather(temperature, pressure, relative_humidity) if obsInfo.location is not None: geolocation = obsInfo.location.to_geodetic() argDict["observatory"] = Observatory( geolocation.lon.degree * degrees, geolocation.lat.degree * degrees, geolocation.height.to_value("m")) for key in list( argDict.keys()): # use a copy because we may delete items if argDict[key] is None: if log is not None: log.warn("argDict[%s] is None; stripping", key) del argDict[key] return VisitInfo(**argDict)
def makeMockVisitSummary(visit, ra_center=0.0, dec_center=-45.0, physical_filter='TEST-I', band='i', mjd=59234.7083333334, psf_sigma=3.0, zenith_distance=45.0, zero_point=30.0, sky_background=100.0, sky_noise=10.0, mean_var=100.0, exposure_time=100.0, detector_size=200, pixel_scale=0.2): """Make a mock visit summary catalog. This will contain two square detectors with the same metadata, with a small (20 pixel) gap between the detectors. There is no rotation, as each detector is simply offset in RA from the specified boresight. Parameters ---------- visit : `int` Visit number. ra_center : `float` Right ascension of the center of the "camera" boresight (degrees). dec_center : `float` Declination of the center of the "camera" boresight (degrees). physical_filter : `str` Arbitrary name for the physical filter. band : `str` Name of the associated band. mjd : `float` Modified Julian Date. psf_sigma : `float` Sigma width of Gaussian psf. zenith_distance : `float` Distance from zenith of the visit (degrees). zero_point : `float` Constant zero point for the visit (magnitudes). sky_background : `float` Background level for the visit (counts). sky_noise : `float` Noise level for the background of the visit (counts). mean_var : `float` Mean of the variance plane of the visit (counts). exposure_time : `float` Exposure time of the visit (seconds). detector_size : `int` Size of each square detector in the visit (pixels). pixel_scale : `float` Size of the pixel in arcseconds per pixel. Returns ------- visit_summary : `lsst.afw.table.ExposureCatalog` """ # We are making a 2 detector "camera" n_detector = 2 schema = ConsolidateVisitSummaryTask()._makeVisitSummarySchema() visit_summary = afwTable.ExposureCatalog(schema) visit_summary.resize(n_detector) bbox = geom.Box2I(x=geom.IntervalI(min=0, max=detector_size - 1), y=geom.IntervalI(min=0, max=detector_size - 1)) for detector_id in range(n_detector): row = visit_summary[detector_id] row['id'] = detector_id row.setBBox(bbox) row['visit'] = visit row['physical_filter'] = physical_filter row['band'] = band row['zenithDistance'] = zenith_distance row['zeroPoint'] = zero_point row['skyBg'] = sky_background row['skyNoise'] = sky_noise row['meanVar'] = mean_var # Generate a photocalib instFluxMag0 = 10.**(zero_point / 2.5) row.setPhotoCalib( afwImage.makePhotoCalibFromCalibZeroPoint(instFluxMag0)) # Generate a WCS and set values accordingly crpix = geom.Point2D(detector_size / 2., detector_size / 2.) # Create a 20 pixel gap between the two detectors (each offset 10 pixels). if detector_id == 0: delta_ra = -1.0 * ((detector_size + 10) * pixel_scale / 3600.) / np.cos(np.deg2rad(dec_center)) delta_dec = 0.0 elif detector_id == 1: delta_ra = ((detector_size + 10) * pixel_scale / 3600.) / np.cos( np.deg2rad(dec_center)) delta_dec = 0.0 crval = geom.SpherePoint(ra_center + delta_ra, dec_center + delta_dec, geom.degrees) cd_matrix = afwGeom.makeCdMatrix(scale=pixel_scale * geom.arcseconds, orientation=0.0 * geom.degrees) wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=crval, cdMatrix=cd_matrix) row.setWcs(wcs) sph_pts = wcs.pixelToSky(geom.Box2D(bbox).getCorners()) row['raCorners'] = np.array( [float(sph.getRa().asDegrees()) for sph in sph_pts]) row['decCorners'] = np.array( [float(sph.getDec().asDegrees()) for sph in sph_pts]) sph_pt = wcs.pixelToSky(bbox.getCenter()) row['ra'] = sph_pt.getRa().asDegrees() row['decl'] = sph_pt.getDec().asDegrees() # Generate a visitInfo. # This does not need to be consistent with the zenith angle in the table, # it just needs to be valid and have sufficient information to compute # exposure time and parallactic angle. date = DateTime(date=mjd, system=DateTime.DateSystem.MJD) visit_info = afwImage.VisitInfo( exposureId=visit, exposureTime=exposure_time, date=date, darkTime=0.0, boresightRaDec=geom.SpherePoint(ra_center, dec_center, geom.degrees), era=45.1 * geom.degrees, observatory=Observatory(11.1 * geom.degrees, 0.0 * geom.degrees, 0.333), boresightRotAngle=0.0 * geom.degrees, rotType=afwImage.RotType.SKY) row.setVisitInfo(visit_info) # Generate a PSF and set values accordingly psf = GaussianPsf(15, 15, psf_sigma) row.setPsf(psf) psfAvgPos = psf.getAveragePosition() shape = psf.computeShape(psfAvgPos) row['psfSigma'] = psf.getSigma() row['psfIxx'] = shape.getIxx() row['psfIyy'] = shape.getIyy() row['psfIxy'] = shape.getIxy() row['psfArea'] = shape.getArea() return visit_summary
def makeVisitInfo( exposureId=0, exposureTime=nanFloat, darkTime=nanFloat, date=DateTime(), ut1=nanFloat, era=nanAngle, boresightRaDec=IcrsCoord(nanAngle, nanAngle), boresightAzAlt=Coord(nanAngle, nanAngle), boresightAirmass=nanFloat, boresightRotAngle=nanAngle, rotType=RotType_UNKNOWN, observatory=Observatory(nanAngle, nanAngle, nanFloat), weather=Weather(nanFloat, nanFloat, nanFloat), ): """Make a VisitInfo from keyword arguments This function will be replaced by a VisitInfo constructor once we switch to pybind11 (it is too much hassle with SWIG). @param[in] exposureId exposure ID (int, defaults to 0) @param[in] exposureTime exposure duration (shutter open time); (float, sec, defaults to NaN) @param[in] darkTime time from CCD flush to readout, including shutter open time (despite the name); (float, sec, defaults to NaN) @param[in] date TAI (international atomic time) MJD date at middle of exposure (lsst.daf.base.DateTime; defaults to date of unix epoch) @param[in] ut1 UT1 (universal time) MJD date at middle of exposure (float, defaults to Nan) @param[in] era earth rotation angle at middle of exposure (lsst.afw.geom.Angle, defaults to Angle(Nan)) @param[in] boresightRaDec ICRS RA/Dec of boresight at middle of exposure (lsst.afw.coord.IcrsCoord; defaults to IcrsCoord(Nan, Nan)); other Coord types are accepted and converted to Icrs @param[in] boresightAzAlt refracted apparent topocentric Az/Alt of boresight at middle of exposure; (lsst.afw.coord.Coord; defaults to Coord(Nan, Nan)) @param[in] boresightAirmass airmass at the boresight, relative to zenith at sea level (float, defaults to Nan) @param[in] boresightRotAngle rotation angle at boresight at middle of exposure; see getBoresightRotAngle for details (lsst.afw.geom.Angle, defaults to Angle(Nan)) @param[in] rotType rotation type; one of the lsst.afw.image.RotType_ constants, defaults to RotType_UNKNOWN @param[in] observatory observatory longitude, latitude and altitude, (lsst.afw.coord.Observatory, defaults to Observatory(Angle(Nan), Angle(Nan), Nan)) @param[in] weather basic weather information for computing air mass, (lsst.afw.coord.Weather, defaults to Weather(NaN, NaN, NaN)) """ return VisitInfo( exposureId, exposureTime, darkTime, date, ut1, era, boresightRaDec.toIcrs(), boresightAzAlt, boresightAirmass, boresightRotAngle, rotType, observatory, weather, )
def testComputeExposureSummary(self): """Make a fake exposure and background and compute summary. """ np.random.seed(12345) # Make an exposure with a noise image exposure = afwImage.ExposureF(100, 100) skySigma = 10.0 exposure.getImage().getArray()[:, :] = np.random.normal(0.0, skySigma, size=(100, 100)) exposure.getVariance().getArray()[:, :] = skySigma**2. # Set the visitInfo date = DateTime(date=59234.7083333334, system=DateTime.DateSystem.MJD) observatory = Observatory(-70.7366 * lsst.geom.degrees, -30.2407 * lsst.geom.degrees, 2650.) visitInfo = afwImage.VisitInfo(exposureTime=10.0, date=date, observatory=observatory) exposure.getInfo().setVisitInfo(visitInfo) # Install a Gaussian PSF psfSize = 2.0 psf = GaussianPsf(5, 5, psfSize) exposure.setPsf(psf) # Install a simple WCS scale = 0.2 * lsst.geom.arcseconds raCenter = 300.0 * lsst.geom.degrees decCenter = 0.0 * lsst.geom.degrees cdMatrix = makeCdMatrix(scale=scale) skyWcs = makeSkyWcs(crpix=exposure.getBBox().getCenter(), crval=lsst.geom.SpherePoint(raCenter, decCenter), cdMatrix=cdMatrix) exposure.setWcs(skyWcs) # Install a simple photoCalib photoCalib = afwImage.PhotoCalib(calibrationMean=0.3) zp = 2.5 * np.log10(photoCalib.getInstFluxAtZeroMagnitude()) exposure.setPhotoCalib(photoCalib) # Compute the background image bgGridSize = 10 bctrl = afwMath.BackgroundControl(afwMath.Interpolate.NATURAL_SPLINE) bctrl.setNxSample( int(exposure.getMaskedImage().getWidth() / bgGridSize) + 1) bctrl.setNySample( int(exposure.getMaskedImage().getHeight() / bgGridSize) + 1) backobj = afwMath.makeBackground(exposure.getMaskedImage().getImage(), bctrl) background = afwMath.BackgroundList() background.append(backobj) # Run the task expSummaryTask = ComputeExposureSummaryStatsTask() summary = expSummaryTask.run(exposure, None, background) # Test the outputs self.assertFloatsAlmostEqual(summary.psfSigma, psfSize) self.assertFloatsAlmostEqual(summary.psfIxx, psfSize**2.) self.assertFloatsAlmostEqual(summary.psfIyy, psfSize**2.) self.assertFloatsAlmostEqual(summary.psfIxy, 0.0) self.assertFloatsAlmostEqual(summary.psfArea, 23.088975164455444) delta = (scale * 50).asDegrees() for a, b in zip(summary.raCorners, [ raCenter.asDegrees() + delta, raCenter.asDegrees() - delta, raCenter.asDegrees() - delta, raCenter.asDegrees() + delta ]): self.assertFloatsAlmostEqual(a, b, atol=1e-10) for a, b in zip(summary.decCorners, [ decCenter.asDegrees() - delta, decCenter.asDegrees() - delta, decCenter.asDegrees() + delta, decCenter.asDegrees() + delta ]): self.assertFloatsAlmostEqual(a, b, atol=1e-10) self.assertFloatsAlmostEqual(summary.ra, raCenter.asDegrees(), atol=1e-10) self.assertFloatsAlmostEqual(summary.decl, decCenter.asDegrees(), atol=1e-10) self.assertFloatsAlmostEqual(summary.zeroPoint, zp) # Need to compare background level and noise # These are only approximately 0+/-10 because of the small image self.assertFloatsAlmostEqual(summary.skyBg, -0.079, atol=1e-3) self.assertFloatsAlmostEqual(summary.meanVar, skySigma**2.) self.assertFloatsAlmostEqual(summary.zenithDistance, 30.57112, atol=1e-5)
def test_getObservatory(self): observatory = Observatory(afwGeom.Angle(-70.749417, afwGeom.degrees), afwGeom.Angle(-30.244633, afwGeom.degrees), 2663) self.assertEqual(observatory, self.visit_info.getObservatory())
class MakeTestRawVisitInfo(MakeRawVisitInfo): """Make a VisitInfo from the FITS header of a test image. Notes ----- Since the test data is extracted from LSST Sim data, this is a copy of MakeLsstSimRawVisitInfo (using a copy avoids undesireable dependencies). """ observatory = Observatory(-70.749417 * degrees, -30.244633 * degrees, 2663) # long, lat, elev def setArgDict(self, md, argDict): """Set an argument dict for VisitInfo and pop associated metadata. Parameters ---------- md : `lsst.daf.base.PropertySet` Image metadata. argDict : `dict` A dict of arguments for the `lsst.afw.image.VisitInfo` constructor. Updated by this call. Returns ------- visitInfo : `lsst.afw.image.VisitInfo` Visit information. """ MakeRawVisitInfo.setArgDict(self, md, argDict) argDict["darkTime"] = self.popFloat(md, "DARKTIME") argDict["boresightAzAlt"] = SpherePoint( self.popAngle(md, "AZIMUTH"), self.altitudeFromZenithDistance(self.popAngle(md, "ZENITH")), ) argDict["boresightRaDec"] = SpherePoint( self.popAngle(md, "RA_DEG"), self.popAngle(md, "DEC_DEG"), ) argDict["boresightAirmass"] = self.popFloat(md, "AIRMASS") argDict["boresightRotAngle"] = -self.popAngle(md, "ROTANG") argDict["rotType"] = RotType.SKY argDict["observatory"] = self.observatory argDict["weather"] = Weather( self.popFloat(md, "TEMPERA"), self.pascalFromMmHg(self.popFloat(md, "PRESS")), float("nan"), ) return VisitInfo(**argDict) def getDateAvg(self, md, exposureTime): """Return date at the middle of the exposure. Parameters ---------- md : `lsst.daf.base.PropertySet` Image metadata. exposureTime : `float` Exposure time, in sec Returns ------- dateAvg : `lsst.daf.base.DateTime` Date at middle of the exposure, or `lsst.daf.base.DateTime()` if the metadata item ``TAI`` is not found. """ startDate = self.popMjdDate(md, "TAI", timesys="TAI") return self.offsetDate(startDate, 0.5 * exposureTime)