def test_gcal2jd_with_astropy_erfa_cal2jd(): """Compare gcal2jd with astropy._erfa.cal2jd.""" import random import numpy as np from astropy import _erfa n = 1000 mday = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] # sla_cldj needs year > -4699 i.e., 4700 BC. year = [random.randint(-4699, 2200) for i in range(n)] month = [random.randint(1, 12) for i in range(n)] day = [random.randint(1, 31) for i in range(n)] for i in range(n): x = 0 if is_leap(year[i]) and month[i] == 2: x = 1 if day[i] > mday[month[i]] + x: day[i] = mday[month[i]] jd_jdcal = np.array( [gcal2jd(y, m, d) for y, m, d in zip(year, month, day)]) jd_erfa = np.array(_erfa.cal2jd(year, month, day)).T assert np.allclose(jd_jdcal, jd_erfa)
def _test_erfa_conversion(leap, i_f): i_i, f_i = i_f assume(0 <= f_i < 1) if leap: assume(i_i in leap_sec_days) else: assume(i_i not in leap_sec_days) jd1_in, jd2_in = day_frac(erfa.DJM0 + i_i, f_i) y, mo, d, f = erfa.jd2cal(jd1_in, jd2_in) assert 0 < y < 3000 assert 0 < mo <= 12 assert 0 <= d < 32 assert 0 <= f < 1 jd1_temp, jd2_temp = erfa.cal2jd(y, mo, d) jd1_temp, jd2_temp = day_frac(jd1_temp, jd2_temp) # improve numerics jd1_temp, jd2_temp = day_frac(jd1_temp, jd2_temp + f) jd_change = abs((jd1_temp - jd1_in) + (jd2_temp - jd2_in)) * u.day assert jd_change.to(u.ns) < 1 * u.ns ft = 24 * f h = safe_kind_conversion(np.floor(ft), dtype=int) ft -= h ft *= 60 m = safe_kind_conversion(np.floor(ft), dtype=int) ft -= m ft *= 60 s = ft assert 0 <= h < 24 assert 0 <= m < 60 assert 0 <= s < 60 jd1, jd2 = erfa.dtf2d("UTC", y, mo, d, h, m, s) y2, mo2, d2, f2 = erfa.jd2cal(jd1, jd2) # assert (y, mo, d) == (y2, mo2, d2) # assert (abs(f2-f)*u.day).to(u.s) < 1*u.ns assert jd1 == np.floor(jd1) + 0.5 assert 0 <= jd2 < 1 jd1, jd2 = day_frac(jd1, jd2) jd_change = abs((jd1 - jd1_in) + (jd2 - jd2_in)) * u.day if leap: assert jd_change.to(u.s) < 1 * u.s else: assert jd_change.to(u.ns) < 2 * u.ns # assert jd_change.to(u.ns) < 1 * u.ns return i_o, f_o = day_frac(jd1 - erfa.DJM0, jd2) mjd_change = abs((i_o - i_i) + (f_o - f_i)) * u.day if leap: assert mjd_change.to(u.s) < 1 * u.s else: assert mjd_change.to(u.ns) < 1 * u.ns
def value(self): if self._scale == 'utc': # Do the reverse of the above calculation # Note this will return an incorrect value during # leap seconds, so raise an exception in that # case. y, mo, d, hmsf = erfa.d2dtf('UTC',9,self.jd1,self.jd2) if 60 in hmsf[...,2]: raise ValueError('UTC times during a leap second cannot be represented in pulsar_mjd format') j1, j2 = erfa.cal2jd(y,mo,d) return (j1 - erfa.DJM0 + j2) + (hmsf[...,0]/24.0 + hmsf[...,1]/1440.0 + hmsf[...,2]/86400.0 + hmsf[...,3]/86400.0e9) else: # As in TimeMJD return (self.jd1 - erfa.DJM0) + self.jd2
def value(self): if self._scale == 'utc': # Do the reverse of the above calculation # Note this will return an incorrect value during # leap seconds, so raise an exception in that # case. y, mo, d, hmsf = erfa.d2dtf('UTC', 9, self.jd1, self.jd2) if 60 in hmsf[..., 2]: raise ValueError( 'UTC times during a leap second cannot be represented in pulsar_mjd format' ) j1, j2 = erfa.cal2jd(y, mo, d) return (j1 - erfa.DJM0 + j2) + (hmsf[..., 0] / 24.0 + hmsf[..., 1] / 1440.0 + hmsf[..., 2] / 86400.0 + hmsf[..., 3] / 86400.0e9) else: # As in TimeMJD return (self.jd1 - erfa.DJM0) + self.jd2
def value(self): if self._scale == 'utc': # Do the reverse of the above calculation # Note this will return an incorrect value during # leap seconds, so raise an exception in that # case. y, mo, d, hmsf = erfa.d2dtf('UTC',9,self.jd1,self.jd2) # For ASTROPY_LT_3_1, convert to the new structured array dtype that # is returned by the new erfa gufuncs. if not hmsf.dtype.names: hmsf = hmsf.view(self._new_ihmsfs_dtype) if numpy.any(hmsf['s'] == 60): raise ValueError('UTC times during a leap second cannot be represented in pulsar_mjd format') j1, j2 = erfa.cal2jd(y,mo,d) return (j1 - erfa.DJM0 + j2) + (hmsf['h']/24.0 + hmsf['m']/1440.0 + hmsf['s']/86400.0 + hmsf['f']/86400.0e9) else: # As in TimeMJD return (self.jd1 - erfa.DJM0) + self.jd2
def jds_to_mjds_pulsar(jd1, jd2): # Do the reverse of the above calculation # Note this will return an incorrect value during # leap seconds, so raise an exception in that # case. y, mo, d, hmsf = erfa.d2dtf("UTC", _digits, jd1, jd2) # For ASTROPY_LT_3_1, convert to the new structured array dtype that # is returned by the new erfa gufuncs. if not hmsf.dtype.names: hmsf = hmsf.view(_new_ihmsfs_dtype)[..., 0] if np.any((hmsf["s"] == 60) & (hmsf["f"] != 0)): # if f is exactly zero, this is probably fine to treat as the end of the day. raise ValueError( "UTC times during a leap second cannot be represented in pulsar_mjd format" ) j1, j2 = erfa.cal2jd(y, mo, d) return day_frac( j1 - erfa.DJM0 + j2, hmsf["h"] / 24.0 + hmsf["m"] / 1440.0 + hmsf["s"] / 86400.0 + hmsf["f"] / 86400.0 / 10 ** _digits, )
def test_gcal2jd_with_astropy_erfa_cal2jd(): """Compare gcal2jd with astropy._erfa.cal2jd.""" import random import numpy as np from astropy import _erfa n = 1000 mday = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] # sla_cldj needs year > -4699 i.e., 4700 BC. year = [random.randint(-4699, 2200) for i in range(n)] month = [random.randint(1, 12) for i in range(n)] day = [random.randint(1, 31) for i in range(n)] for i in range(n): x = 0 if is_leap(year[i]) and month[i] == 2: x = 1 if day[i] > mday[month[i]] + x: day[i] = mday[month[i]] jd_jdcal = np.array([gcal2jd(y, m, d) for y, m, d in zip(year, month, day)]) jd_erfa = np.array(_erfa.cal2jd(year, month, day)).T assert np.allclose(jd_jdcal, jd_erfa)
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