def test_errwarn_reporting(): """ Test that the ERFA error reporting mechanism works as it should """ # no warning erfa.dat(1990, 1, 1, 0.5) # check warning is raised for a scalar with catch_warnings() as w: erfa.dat(100, 1, 1, 0.5) assert len(w) == 1 assert w[0].category == erfa.ErfaWarning assert '1 of "dubious year (Note 1)"' in str(w[0].message) # and that the count is right for a vector. with catch_warnings() as w: erfa.dat([100, 200, 1990], 1, 1, 0.5) assert len(w) == 1 assert w[0].category == erfa.ErfaWarning assert '2 of "dubious year (Note 1)"' in str(w[0].message) try: erfa.dat(1990, [1, 34, 2], [1, 1, 43], 0.5) except erfa.ErfaError as e: if '1 of "bad day (Note 3)", 1 of "bad month"' not in e.args[0]: assert False, 'Raised the correct type of error, but wrong message: ' + e.args[ 0] try: erfa.dat(200, [1, 34, 2], [1, 1, 43], 0.5) except erfa.ErfaError as e: if 'warning' in e.args[0]: assert False, 'Raised the correct type of error, but there were warnings mixed in: ' + e.args[ 0]
def test_update_leap_seconds(self): assert erfa.dat(2018, 1, 1, 0.) == 37.0 leap_seconds = erfa.leap_seconds.get() # Get old and new leap seconds old_leap_seconds = leap_seconds[leap_seconds['year'] < 2017] new_leap_seconds = leap_seconds[leap_seconds['year'] >= 2017] # Updating with either of these should do nothing. n_update = erfa.leap_seconds.update(new_leap_seconds) assert n_update == 0 assert_array_equal(erfa.leap_seconds.get(), self.erfa_ls) n_update = erfa.leap_seconds.update(old_leap_seconds) assert n_update == 0 assert_array_equal(erfa.leap_seconds.get(), self.erfa_ls) # But after setting to older part, update with newer should work. erfa.leap_seconds.set(old_leap_seconds) # Check the 2017 leap second is indeed missing. assert erfa.dat(2018, 1, 1, 0.) == 36.0 # Update with missing leap seconds. n_update = erfa.leap_seconds.update(new_leap_seconds) assert n_update == len(new_leap_seconds) assert erfa.dat(2018, 1, 1, 0.) == 37.0 # Also a final try with overlapping data. erfa.leap_seconds.set(old_leap_seconds) n_update = erfa.leap_seconds.update(leap_seconds) assert n_update == len(new_leap_seconds) assert erfa.dat(2018, 1, 1, 0.) == 37.0
def test_set_leap_seconds(self): assert erfa.dat(2018, 1, 1, 0.) == 37.0 leap_seconds = erfa.leap_seconds.get() # Set to a table that misses the 2017 leap second. part_leap_seconds = leap_seconds[leap_seconds['year'] < 2017] erfa.leap_seconds.set(part_leap_seconds) new_leap_seconds = erfa.leap_seconds.get() assert_array_equal(new_leap_seconds, part_leap_seconds) # Check the 2017 leap second is indeed missing. assert erfa.dat(2018, 1, 1, 0.) == 36.0 # And that this would be expected from the expiration date. assert erfa.leap_seconds.expires < datetime(2018, 1, 1) assert erfa.leap_seconds.expired # Reset and check it is back. erfa.leap_seconds.set() assert erfa.dat(2018, 1, 1, 0.) == 37.0
def test_auto_update_leap_seconds(self): # Sanity check. assert erfa.dat(2018, 1, 1, 0.) == 37.0 # Set expired leap seconds expired = self.erfa_ls[self.erfa_ls['year'] < 2017] expired.update_erfa_leap_seconds(initialize_erfa='empty') # Check the 2017 leap second is indeed missing. assert erfa.dat(2018, 1, 1, 0.) == 36.0 # Update with missing leap seconds. n_update = update_leap_seconds([iers.IERS_LEAP_SECOND_FILE]) assert n_update >= 1 assert erfa.leap_seconds.expires == self.built_in.expires assert erfa.dat(2018, 1, 1, 0.) == 37.0 # Doing it again does not change anything n_update2 = update_leap_seconds([iers.IERS_LEAP_SECOND_FILE]) assert n_update2 == 0 assert erfa.dat(2018, 1, 1, 0.) == 37.0
def test_validation(self, table, match): with pytest.raises(ValueError, match=match): erfa.leap_seconds.set(table) # Check leap-second table is not corrupted. assert_array_equal(erfa.leap_seconds.get(), self.erfa_ls) assert erfa.dat(2018, 1, 1, 0.) == 37.0
def utc2cel06a_parameters(t, eop, iau55=False): """ 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: jd is the julian date (always xxx.5 because it is based on a noon day break) in days ttb is the leap second offset in fractions of a day utb is the UT1 offset in fractions of a day xp and yp are the coordinates (in radians) of the Celestial Intermediate Pole with respect to the International Terrestrial Reference System (see IERS Conventions 2003), measured along the meridians to 0 and 90 deg west respectively (as extrapolated from between the two published points before and after). dx06 and dy06 are the CIP offsets wrt IAU 2006/2000A (mas->radians) as extrapolated from between the two published points before and after """ year, month, day, hour, minute, second = t.year, t.month, t.day, t.hour, t.minute, t.second # TT (MJD). */ djmjd0, date = erfa.cal2jd(iy=year, im=month, id=day) jd = djmjd0 + date day_frac = (60.0 * (60 * hour + minute) + second) / DAYSEC dat_s = erfa.dat(year, month, day, day_frac) ttb = dat_s / DAYSEC + 32.184 / DAYSEC # Polar motion (arcsec->radians) xp_l = eop["x"][date] yp_l = eop["y"][date] xp_h = eop["x"][date + 1] yp_h = eop["y"][date + 1] xp = (xp_l * (1 - day_frac) + xp_h * day_frac) * DAS2R yp = (yp_l * (1 - day_frac) + yp_h * day_frac) * DAS2R # UT1-UTC (s). */ dut_l = eop["UT1-UTC"][date] dut_h = eop["UT1-UTC"][date + 1] dut1 = (dut_l * (1 - day_frac) + dut_h * day_frac) # CIP offsets wrt IAU 2006/2000A (mas->radians). */ dx_l = eop["dX"][date] dx_h = eop["dX"][date + 1] dy_l = eop["dY"][date] dy_h = eop["dY"][date + 1] dx06 = (dx_l * (1 - day_frac) + dx_h * day_frac) * DAS2R dy06 = (dy_l * (1 - day_frac) + dy_h * day_frac) * DAS2R if iau55: # CIP offsets wrt IAU 2006/2000A (mas->radians). */ dx06 = float64(0.1750 * DMAS2R, dtype="f64") dy06 = float64(-0.2259 * DMAS2R, dtype="f64") # UT1-UTC (s). */ dut1 = float64(-0.072073685, dtype="f64") # Polar motion (arcsec->radians) xp = float64(0.0349282 * DAS2R, dtype="f64") yp = float64(0.4833163 * DAS2R, dtype="f64") # UT1. */ utb = day_frac + dut1 / DAYSEC return jd, ttb, utb, xp, dx06, yp, dy06
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