def iod_obs_tod(location: EarthLocation, epoch: Time): """ Get the true of date (tod) position-velocity vector of the observatory Parameters ---------- location: `~astropy.coordinates.EarthLocation` Position vector in body fixed reference frame. epoch: `~astropy.time.Time` Returns ------- pos, vel: ~astropy.units.Quantity Position and velocity vector of the observation, in tod frame """ from astropy.coordinates.earth import OMEGA_EARTH from astropy import _erfa as erfa assert isinstance(location, EarthLocation) assert isinstance(epoch, Time) dut = epoch.get_delta_ut1_utc(iers_table=iers_table) ut1 = Time(epoch.mjd + dut.to_value('day'), format='mjd', scale='ut1') earth_rotation_angle = erfa.era00(ut1.jd1, ut1.jd2) * u.rad loc = location.get_itrs() unit = loc.x.unit loc = np.array([loc.x.value, loc.y.value, loc.z.value]) pos = np.matmul(rotation_matrix(-earth_rotation_angle, 'z'), loc) vel = [-OMEGA_EARTH.value * pos[1], OMEGA_EARTH.value * pos[0], 0.0] acc = [-OMEGA_EARTH.value**2 * pos[0], -OMEGA_EARTH.value**2 * pos[1], 0.0] return pos * unit, \ vel * unit * OMEGA_EARTH.unit, \ acc * unit * OMEGA_EARTH.unit * OMEGA_EARTH.unit
def delta_obs_ra_to_cirs_ra(mjd, longitude, latitude): """ difference between radio astronomers observed coords and CIRS coords Args ==== mjd: (float) modified Julian date longitude: (float) in degrees or as astropy Angle latitude: (float) in degrees or as astropy Angle Return ====== hour angle as astropy.coordinates.Angle """ from astropy import _erfa as erfa from astropy.coordinates.builtin_frames.utils import get_jd12 # get the Earth Rotation Angle era = erfa.era00(*get_jd12(APt.Time(mjd, format='mjd'), 'ut1')) logger.debug("delta_obs_ra_to_cirs_ra: ERA = %f rad", era) logger.debug("delta_obs_ra_to_cirs_ra: ERA = %s", format_angles(era * 12 / pi)) theta_earth = APc.Angle(era, unit='rad') # get the time of observation obs_time = APt.Time(mjd, format='mjd', location=(APc.Angle(longitude, unit="deg"), APc.Angle(latitude, unit="deg"))) # Greenwich apparent sidereal time of observation gast = obs_time.sidereal_time('apparent', longitude=0) # Greenwich ST logger.debug("delta_obs_ra_to_cirs_ra: GAST = %s", gast) logger.debug("delta_obs_ra_to_cirs_ra: delta = %s", gast - theta_earth) return (gast - theta_earth)
def cirs_to_tee_ra(cirs_ra, time): from astropy import _erfa as erfa from astropy.coordinates.builtin_frames.utils import get_jd12 era = erfa.era00(*get_jd12(time, 'ut1')) theta_earth = Angle(era, unit='rad') assert (isinstance(time, Time)) assert (isinstance(cirs_ra, Angle)) gast = time.sidereal_time('apparent', longitude=0) tee_ra = cirs_ra + (gast - theta_earth) return tee_ra
def cirs_to_itrs_mat(time): # compute the polar motion p-matrix xp, yp = get_polar_motion(time) sp = erfa.sp00(*get_jd12(time, 'tt')) pmmat = erfa.pom00(xp, yp, sp) # now determine the Earth Rotation Angle for the input obstime # era00 accepts UT1, so we convert if need be era = erfa.era00(*get_jd12(time, 'ut1')) # c2tcio expects a GCRS->CIRS matrix, but we just set that to an I-matrix # because we're already in CIRS return erfa.c2tcio(np.eye(3), era, pmmat)
def _pvobs(self): '''calculates position and velocity of the observatory returns position/velocity in AU and AU/d in GCRS reference frame ''' # convert obs position from WGS84 (lat long) to ITRF geocentric coords in AU xyz = self.location.to(u.AU).value # now we need to convert this position to Celestial Coords # specifically, the GCRS coords. # conversion from celestial to terrestrial coords given by # [TRS] = RPOM * R_3(ERA) * RC2I * [CRS] # where: # [CRS] is vector in GCRS (geocentric celestial system) # [TRS] is vector in ITRS (International Terrestrial Ref System) # ERA is earth rotation angle # RPOM = polar motion matrix tt = self.tt mjd = self.utc.mjd # we need the IERS values to correct for the precession/nutation of the Earth iers_tab = IERS.open() # Find UT1, which is needed to calculate ERA # uses IERS_B by default , for more recent times use IERS_A download try: ut1 = self.ut1 except: try: iers_a_file = download_file(IERS_A_URL, cache=True) iers_a = IERS_A.open(iers_a_file) print "Trying to download...", iers_a_file self.delta_ut1_utc = self.get_delta_ut1_utc(iers_a) ut1 = self.ut1 except: # fall back to UTC with degraded accuracy warnings.warn('Cannot calculate UT1: using UTC with degraded accuracy') ut1 = self.utc # Gets x,y coords of Celestial Intermediate Pole (CIP) and CIO locator s # CIO = Celestial Intermediate Origin # Both in GCRS X,Y,S = erfa.xys00a(tt.jd1,tt.jd2) # Get dX and dY from IERS B dX = np.interp(mjd, iers_tab['MJD'], iers_tab['dX_2000A']) * u.arcsec dY = np.interp(mjd, iers_tab['MJD'], iers_tab['dY_2000A']) * u.arcsec # Get GCRS to CIRS matrix # can be used to convert to Celestial Intermediate Ref Sys # from GCRS. rc2i = erfa.c2ixys(X+dX.to(u.rad).value, Y+dY.to(u.rad).value, S) # Gets the Terrestrial Intermediate Origin (TIO) locator s' # Terrestrial Intermediate Ref Sys (TIRS) defined by TIO and CIP. # TIRS related to to CIRS by Earth Rotation Angle sp = erfa.sp00(tt.jd1,tt.jd2) # Get X and Y from IERS B # X and Y are xp = np.interp(mjd, iers_tab['MJD'], iers_tab['PM_x']) * u.arcsec yp = np.interp(mjd, iers_tab['MJD'], iers_tab['PM_y']) * u.arcsec # Get the polar motion matrix. Relates ITRF to TIRS. rpm = erfa.pom00(xp.to(u.rad).value, yp.to(u.rad).value, sp) # multiply ITRF position of obs by transpose of polar motion matrix # Gives Intermediate Ref Frame position of obs x,y,z = np.array([rpmMat.T.dot(xyz) for rpmMat in rpm]).T # Functions of Earth Rotation Angle, theta # Theta is angle bewtween TIO and CIO (along CIP) # USE UT1 here. theta = erfa.era00(ut1.jd1,ut1.jd2) S,C = np.sin(theta),np.cos(theta) # Position #GOT HERE pos = np.asarray([C*x - S*y, S*x + C*y, z]).T # multiply by inverse of GCRS to CIRS matrix # different methods for scalar times vs arrays if pos.ndim > 1: pos = np.array([np.dot(rc2i[j].T,pos[j]) for j in range(len(pos))]) else: pos = np.dot(rc2i.T,pos) # Velocity vel = np.asarray([SR*(-S*x - C*y), SR*(C*x-S*y), np.zeros_like(x)]).T # multiply by inverse of GCRS to CIRS matrix if vel.ndim > 1: vel = np.array([np.dot(rc2i[j].T,vel[j]) for j in range(len(pos))]) else: vel = np.dot(rc2i.T,vel) #return position and velocity return pos,vel
def _pvobs(self): '''calculates position and velocity of the observatory returns position/velocity in AU and AU/d in GCRS reference frame ''' # convert obs position from WGS84 (lat long) to ITRF geocentric coords in AU xyz = self.location.to(u.AU).value # now we need to convert this position to Celestial Coords # specifically, the GCRS coords. # conversion from celestial to terrestrial coords given by # [TRS] = RPOM * R_3(ERA) * RC2I * [CRS] # where: # [CRS] is vector in GCRS (geocentric celestial system) # [TRS] is vector in ITRS (International Terrestrial Ref System) # ERA is earth rotation angle # RPOM = polar motion matrix tt = self.tt mjd = self.utc.mjd # we need the IERS values to correct for the precession/nutation of the Earth iers_tab = IERS.open() # Find UT1, which is needed to calculate ERA # uses IERS_B by default , for more recent times use IERS_A download try: ut1 = self.ut1 except: try: iers_a_file = download_file(IERS_A_URL, cache=True) iers_a = IERS_A.open(iers_a_file) self.delta_ut1_utc = self.get_delta_ut1_utc(iers_a) ut1 = self.ut1 except: # fall back to UTC with degraded accuracy warnings.warn( 'Cannot calculate UT1: using UTC with degraded accuracy') ut1 = self.utc # Gets x,y coords of Celestial Intermediate Pole (CIP) and CIO locator s # CIO = Celestial Intermediate Origin # Both in GCRS X, Y, S = erfa.xys00a(tt.jd1, tt.jd2) # Get dX and dY from IERS B dX = np.interp(mjd, iers_tab['MJD'], iers_tab['dX_2000A']) * u.arcsec dY = np.interp(mjd, iers_tab['MJD'], iers_tab['dY_2000A']) * u.arcsec # Get GCRS to CIRS matrix # can be used to convert to Celestial Intermediate Ref Sys # from GCRS. rc2i = erfa.c2ixys(X + dX.to(u.rad).value, Y + dY.to(u.rad).value, S) # Gets the Terrestrial Intermediate Origin (TIO) locator s' # Terrestrial Intermediate Ref Sys (TIRS) defined by TIO and CIP. # TIRS related to to CIRS by Earth Rotation Angle sp = erfa.sp00(tt.jd1, tt.jd2) # Get X and Y from IERS B # X and Y are xp = np.interp(mjd, iers_tab['MJD'], iers_tab['PM_x']) * u.arcsec yp = np.interp(mjd, iers_tab['MJD'], iers_tab['PM_y']) * u.arcsec # Get the polar motion matrix. Relates ITRF to TIRS. rpm = erfa.pom00(xp.to(u.rad).value, yp.to(u.rad).value, sp) # multiply ITRF position of obs by transpose of polar motion matrix # Gives Intermediate Ref Frame position of obs x, y, z = np.array([rpmMat.T.dot(xyz) for rpmMat in rpm]).T # Functions of Earth Rotation Angle, theta # Theta is angle bewtween TIO and CIO (along CIP) # USE UT1 here. theta = erfa.era00(ut1.jd1, ut1.jd2) S, C = np.sin(theta), np.cos(theta) # Position #GOT HERE pos = np.asarray([C * x - S * y, S * x + C * y, z]).T # multiply by inverse of GCRS to CIRS matrix # different methods for scalar times vs arrays if pos.ndim > 1: pos = np.array( [np.dot(rc2i[j].T, pos[j]) for j in range(len(pos))]) else: pos = np.dot(rc2i.T, pos) # Velocity vel = np.asarray( [SR * (-S * x - C * y), SR * (C * x - S * y), np.zeros_like(x)]).T # multiply by inverse of GCRS to CIRS matrix if vel.ndim > 1: vel = np.array( [np.dot(rc2i[j].T, vel[j]) for j in range(len(pos))]) else: vel = np.dot(rc2i.T, vel) #return position and velocity return pos, vel
def gcrs2irts_matrix_b(t, eop): """ Ref: http://www.iausofa.org/sofa_pn_c.pdf Purpose: This function calculates the cartesian transformation matrix for transforming GCRS to ITRS or vice versa :param eop: eop is a dataframe containing the Earth Orientation Parameters as per IAU definitions :param t: t is a datetime object or a list of datetime objects with the UTC times for the transformation matrix to be calculated for :return: matrix is a [3,3] numpy array or list of arrays used for transforming GCRS to ITRS or vice versa at the specified times; ITRS = matrix @ GCRS """ if not (isinstance(t, Iterable)): t = [t] matrix = [] for ti in t: year = ti.year month = ti.month day = ti.day hour = ti.hour minute = ti.minute second = ti.second # TT (MJD). */ djmjd0, date = erfa.cal2jd(iy=year, im=month, id=day) # jd = djmjd0 + date day_frac = (60.0 * (60.0 * hour + minute) + second) / DAYSEC utc = date + day_frac Dat = erfa.dat(year, month, day, day_frac) tai = utc + Dat / DAYSEC tt = tai + 32.184 / DAYSEC # UT1. */ dut1 = eop["UT1-UTC"][date] * ( 1 - day_frac) + eop["UT1-UTC"][date + 1] * day_frac tut = day_frac + dut1 / DAYSEC # ut1 = date + tut # CIP and CIO, IAU 2006/2000A. */ x, y, s = erfa.xys06a(djmjd0, tt) # X, Y offsets dx06 = (eop["dX"][date] * (1 - day_frac) + eop["dX"][date + 1] * day_frac) * DAS2R dy06 = (eop["dY"][date] * (1 - day_frac) + eop["dY"][date + 1] * day_frac) * DAS2R # Add CIP corrections. */ x = x + dx06 y = y + dy06 # GCRS to CIRS matrix. */ rc2i = erfa.c2ixys(x, y, s) # Earth rotation angle. */ era = erfa.era00(djmjd0 + date, tut) # Form celestial-terrestrial matrix (no polar motion yet). */ rc2ti = erfa.cr(rc2i) rc2ti = eraRZ(era, rc2ti) #rc2ti = erfa.rz(era, rc2ti) # Polar motion matrix (TIRS->ITRS, IERS 2003). */ xp = (eop["x"][date] * (1 - day_frac) + eop["x"][date + 1] * day_frac) * DAS2R yp = (eop["y"][date] * (1 - day_frac) + eop["y"][date + 1] * day_frac) * DAS2R rpom = erfa.pom00(xp, yp, erfa.sp00(djmjd0, tt)) # Form celestial-terrestrial matrix (including polar motion). */ rc2it = erfa.rxr(rpom, rc2ti) matrix.append(rc2it) if len(matrix) == 1: matrix = matrix[0] return matrix
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 gcrs_posvel_from_itrf(loc, toas, obsname="obs"): """Return a list of PosVel instances for the observatory at the TOA times. Observatory location should be given in the loc argument as an astropy EarthLocation object. This location will be in the ITRF frame (i.e. co-rotating with the Earth). The optional obsname argument will be used as label in the returned PosVel instance. This routine returns a list of PosVel instances, containing the positions (m) and velocities (m / s) at the times of the toas and referenced to the Earth-centered Inertial (ECI, aka GCRS) coordinates. This routine is basically SOFA's pvtob() [Position and velocity of a terrestrial observing station] with an extra rotation from c2ixys() [Form the celestial to intermediate-frame-of-date matrix given the CIP X,Y and the CIO locator s]. """ unpack = False # If the input is a single TOA (i.e. a row from the table), # then put it into a list if type(toas) == table.row.Row: ttoas = Time([toas["mjd"]]) unpack = True elif type(toas) == table.table.Table: ttoas = toas["mjd"] elif isinstance(toas, Time): if toas.isscalar: ttoas = Time([toas]) unpack = True else: ttoas = toas else: if np.isscalar(toas): ttoas = Time([toas], format="mjd") unpack = True else: ttoas = toas N = len(ttoas) if len(ttoas.shape) != 1: raise ValueError("At most one-dimensional array of times possible, " "shape was {}".format(ttoas.shape)) # Get various times from the TOAs as arrays tts = np.asarray([(t.jd1, t.jd2) for t in ttoas.tt]).T ut1s = np.asarray([(t.jd1, t.jd2) for t in ttoas.ut1]).T mjds = np.asarray(ttoas.mjd) iers_b = get_iers_b_up_to_date(mjds.max()) # Get x, y coords of Celestial Intermediate Pole and CIO locator s X, Y, S = erfa.xys00a(*tts) # Get dX and dY from IERS A in arcsec and convert to radians # dX = np.interp(mjds, iers_tab['MJD'], iers_tab['dX_2000A_B']) * asec2rad # dY = np.interp(mjds, iers_tab['MJD'], iers_tab['dY_2000A_B']) * asec2rad # Get dX and dY from IERS B in arcsec and convert to radians dX = np.interp(mjds, iers_b["MJD"].to_value(u.d), iers_b["dX_2000A"].to_value(u.rad)) dY = np.interp(mjds, iers_b["MJD"].to_value(u.d), iers_b["dY_2000A"].to_value(u.rad)) # Get GCRS to CIRS matrices rc2i = erfa.c2ixys(X + dX, Y + dY, S) # Gets the TIO locator s' sp = erfa.sp00(*tts) # Get X and Y from IERS A in arcsec and convert to radians # xp = np.interp(mjds, iers_tab['MJD'], iers_tab['PM_X_B']) * asec2rad # yp = np.interp(mjds, iers_tab['MJD'], iers_tab['PM_Y_B']) * asec2rad # Get X and Y from IERS B in arcsec and convert to radians xp = np.interp(mjds, iers_b["MJD"].to_value(u.d), iers_b["PM_x"].to_value(u.rad)) yp = np.interp(mjds, iers_b["MJD"].to_value(u.d), iers_b["PM_y"].to_value(u.rad)) # Get the polar motion matrices rpm = erfa.pom00(xp, yp, sp) # Observatory geocentric coords in m xyzm = np.array([a.to_value(u.m) for a in loc.geocentric]) x, y, z = np.dot(xyzm, rpm).T # Functions of Earth Rotation Angle theta = erfa.era00(*ut1s) s, c = np.sin(theta), np.cos(theta) sx, cx = s * x, c * x sy, cy = s * y, c * y # Initial positions and velocities iposs = np.asarray([cx - sy, sx + cy, z]).T ivels = np.asarray([OM * (-sx - cy), OM * (cx - sy), np.zeros_like(x)]).T # There is probably a way to do this with np.einsum or something... # and here it is . poss = np.empty((N, 3), dtype=np.float64) vels = np.empty((N, 3), dtype=np.float64) poss = np.einsum("ij,ijk->ik", iposs, rc2i) vels = np.einsum("ij,ijk->ik", ivels, rc2i) r = PosVel(poss.T * u.m, vels.T * u.m / u.s, obj=obsname, origin="earth") if unpack: return r[0] else: return r
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(): warnings.simplefilter("ignore", category=astropy.utils.exceptions.AstropyWarning) 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[{}] is None; stripping".format(key, argDict[key])) del argDict[key] return VisitInfo(**argDict)
def JD2era(JD): JD_time = Time(JD, format="jd", scale="ut1") era = _erfa.era00(JD_time.jd1, JD_time.jd2) return era