def yr_frac_mon_to_jd(year, mon, gregorian=True): """Convert a year and fractional month in the Julian or Gregorian calendars to the Julian Day Number (Meeus 7.1). Arguments: - `year` : (int) year - `mon` : (int, float) month Keywords: - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Returns: - (float) """ year = np.atleast_1d(year) mon = np.atleast_1d(mon).astype(np.float64) day = np.atleast_1d(0.0).astype(np.float64) year, mon, day = map(np.array, np.broadcast_arrays(year, mon, day)) fmon = mon - mon.astype("i") mask = fmon > 0 if np.any(mask): mon = mon.astype("i") next_mon = np.copy(mon) + 1 next_year = np.copy(year) next_mon_mask = next_mon == 13 next_year[next_mon_mask] = next_year[next_mon_mask] + 1 next_mon[next_mon_mask] = 1 days_in_mon = cal_to_jd(next_year[mask], next_mon[mask]) - cal_to_jd(year[mask], mon[mask]) day[mask] = days_in_mon * fmon[mask] return _scalar_if_one(cal_to_jd(year, mon) + day) return _scalar_if_one(cal_to_jd(year, mon))
def frac_yr_to_jd(year, gregorian=True): """Convert a date in the Julian or Gregorian fractional year to the Julian Day Number (Meeus 7.1). Arguments: - `year` : (int, float) year Keywords: - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Returns: - (float) """ year = np.atleast_1d(year) day = np.atleast_1d(0.0).astype(np.float64) year, day = map(np.array, np.broadcast_arrays(year, day)) # For float years abuse the day variable fyear = year - year.astype('i') mask = fyear > 0 if np.any(mask): year = year.astype('i') days_in_year = cal_to_jd(year[mask] + 1) - cal_to_jd(year[mask]) day[mask] = days_in_year * fyear[mask] return _scalar_if_one(cal_to_jd(year) + day) return _scalar_if_one(cal_to_jd(year))
def frac_yr_to_jd(year, gregorian=True): """Convert a date in the Julian or Gregorian fractional year to the Julian Day Number (Meeus 7.1). Arguments: - `year` : (int, float) year Keywords: - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Returns: - (float) """ year = np.atleast_1d(year) day = np.atleast_1d(0.0).astype(np.float64) year, day = list(map(np.array, np.broadcast_arrays(year, day))) # For float years abuse the day variable fyear = year - year.astype('i') mask = fyear > 0 if np.any(mask): year = year.astype('i') days_in_year = cal_to_jd(year[mask] + 1) - cal_to_jd(year[mask]) day[mask] = days_in_year*fyear[mask] return _scalar_if_one(cal_to_jd(year) + day) return _scalar_if_one(cal_to_jd(year))
def is_leap_year(year, gregorian=True): """Return True if this is a leap year in the Julian or Gregorian calendars Arguments: - `year` : (int) year Keywords: - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Returns: - (bool) True is this is a leap year, else False. """ year = np.atleast_1d(year).astype(np.int64) x = np.fmod(year, 4) if gregorian: x = np.fmod(year, 4) y = np.fmod(year, 100) z = np.fmod(year, 400) return _scalar_if_one( np.logical_and(np.logical_not(x), np.logical_or(y, np.logical_not(z)))) else: return _scalar_if_one(x == 0)
def day_of_year_to_cal(year, N, gregorian=True): """Convert a day of year number to a month and day in the Julian or Gregorian calendars. Arguments: - `year` : year - `N` : day of year, 1..365 (or 366 for leap years) Keywords: - `gregorian` : If True, use Gregorian calendar, else use Julian calendar (default: True) Return: - (month, day) : (tuple) """ year = np.atleast_1d(year) N = np.atleast_1d(N) year, N = np.broadcast_arrays(year, N) K = np.ones_like(N) K[:] = 2 K[np.atleast_1d(is_leap_year(year, gregorian))] = 1 mon = (9 * (K + N) / 275.0 + 0.98).astype(np.int64) mon[N < 32] = 1 day = (N - (275 * mon / 9.0).astype(np.int64) + K * ((mon + 9) / 12.0).astype(np.int64) + 30).astype(np.int64) return _scalar_if_one(mon), _scalar_if_one(day)
def jd_to_cal(julian_day, gregorian=True): """Convert a Julian day number to a date in the Julian or Gregorian calendars. Arguments: - `julian_day` : (int) Julian Day Number Keywords: - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Return: - (year, month, day) : (tuple) day may be fractional """ julian_day = np.atleast_1d(julian_day) F, Z = np.modf(julian_day + 0.5) if gregorian: alpha = ((Z - 1867216.25) / 36524.25).astype(np.int64) A = Z + 1 + alpha - (alpha / 4).astype(np.int64) else: A = Z B = A + 1524 C = ((B - 122.1) / 365.25).astype(np.int64) D = (365.25 * C).astype(np.int64) E = ((B - D) / 30.6001).astype(np.int64) day = B - D - (30.6001 * E).astype(np.int64) + F mon = E - 13 mon[E < 14] = E[E < 14] - 1 year = C - 4715 year[mon > 2] = C[mon > 2] - 4716 return _scalar_if_one(year), _scalar_if_one(mon), _scalar_if_one(day)
def yr_frac_mon_to_jd(year, mon, gregorian=True): """Convert a year and fractional month in the Julian or Gregorian calendars to the Julian Day Number (Meeus 7.1). Arguments: - `year` : (int) year - `mon` : (int, float) month Keywords: - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Returns: - (float) """ year = np.atleast_1d(year) mon = np.atleast_1d(mon).astype(np.float64) day = np.atleast_1d(0.0).astype(np.float64) year, mon, day = map(np.array, np.broadcast_arrays(year, mon, day)) fmon = mon - mon.astype('i') mask = fmon > 0 if np.any(mask): mon = mon.astype('i') next_mon = np.copy(mon) + 1 next_year = np.copy(year) next_mon_mask = next_mon == 13 next_year[next_mon_mask] = next_year[next_mon_mask] + 1 next_mon[next_mon_mask] = 1 days_in_mon = cal_to_jd(next_year[mask], next_mon[mask]) - cal_to_jd( year[mask], mon[mask]) day[mask] = days_in_mon * fmon[mask] return _scalar_if_one(cal_to_jd(year, mon) + day) return _scalar_if_one(cal_to_jd(year, mon))
def cal_to_day_of_year(year, mon, day, gregorian=True): """Convert a date in the Julian or Gregorian calendars to day of the year (Meeus 7.1). Arguments: - `year` : (int) year - `mon` : (int) month - `day` : (int) day Keywords: - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Return: - day number : 1 = Jan 1...365 (or 366 for leap years) = Dec 31. """ year = np.atleast_1d(year).astype(np.int64) mon = np.atleast_1d(mon).astype(np.int64) day = np.atleast_1d(day).astype(np.int64) year, mon, day = np.broadcast_arrays(year, mon, day) K = np.ones_like(year) K[:] = 2 K[np.atleast_1d(is_leap_year(year, gregorian))] = 1 return _scalar_if_one((275 * mon / 9.0).astype(np.int64) - (K * ((mon + 9) / 12.0).astype(np.int64)) + day - 30)
def dimension(self, jd, planet, dim): """Return one of heliocentric ecliptic longitude, latitude and radius. [Meeus-1998: pg 218] Arguments: - `jd` : Julian Day in dynamical time - `planet` : must be one of ("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune") - `dim` : must be one of "L" (longitude) or "B" (latitude) or "R" (radius) Returns: - longitude in radians, or latitude in radians, or radius in au, depending on the value of `dim`. """ jd = np.atleast_1d(jd) X = 0.0 tauN = 1.0 tau = jd_to_jcent(jd)/10.0 c = _planets[(planet, dim)] for s in c: X += np.sum([A*np.cos(B + C*tau) for A, B, C in s])*tauN tauN = tauN*tau # last calculation is wasted if dim == "L": X = modpi2(X) return _scalar_if_one(X)
def cal_to_jd(year, mon=1, day=1, gregorian=True): """Convert a date in the Julian or Gregorian calendars to the Julian Day Number (Meeus 7.1). Arguments: - `year` : (int) year Keywords: - `mon` : (int, default=1) month - `day` : (int, float, default=1) day, may be fractional day - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Returns: - (int, float) """ year = np.atleast_1d(year) mon = np.atleast_1d(mon) day = np.atleast_1d(day).astype(np.float64) fyear = year - year.astype('i') mask = fyear > 0 if np.any(mask): raise ValueError('Year must be integer. Use frac_yr_to_jd instead.') fmon = mon - mon.astype('i') mask = fmon > 0 if np.any(mask): raise ValueError( 'Month must be integer. Use yr_frac_mon_to_jd instead.') if np.any(mon > 12) or np.any(mon < 1): raise ValueError('Month must be from 1 to 12') if np.any(day > 31) or np.any(day < 1): raise ValueError('Day must be from 1 to 31') year, mon, day = map(np.array, np.broadcast_arrays(year, mon, day)) for thirtydays in [9, 4, 6, 11]: daytestarr = mon == thirtydays if np.any(day[daytestarr] > 30): raise ValueError('Day must be from 1 to 30') leapyeartest = np.atleast_1d(is_leap_year(year, gregorian)) if np.any(np.logical_and(day[leapyeartest] > 29, mon[leapyeartest] == 2)): raise ValueError('Day must be from 1 to 29') if np.any(np.logical_and(day[~leapyeartest] > 28, mon[~leapyeartest] == 2)): raise ValueError('Day must be from 1 to 28') testarr = mon <= 2 year[testarr] -= 1 mon[testarr] += 12 if gregorian: A = (year / 100).astype(np.int64) B = 2 - A + (A / 4).astype(np.int64) else: B = 0 return _scalar_if_one((365.25 * (year + 4716)).astype(np.int64) + (30.6001 * (mon + 1)).astype(np.int64) + day + B - 1524.5)
def cal_to_day_of_year(year, mon, day, gregorian=True): """Convert a date in the Julian or Gregorian calendars to day of the year (Meeus 7.1). Arguments: - `year` : (int) year - `mon` : (int) month - `day` : (int) day Keywords: - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Return: - day number : 1 = Jan 1...365 (or 366 for leap years) = Dec 31. """ year = np.atleast_1d(year).astype(np.int64) mon = np.atleast_1d(mon).astype(np.int64) day = np.atleast_1d(day).astype(np.int64) year, mon, day = np.broadcast_arrays(year, mon, day) K = np.ones_like(year) K[:] = 2 K[np.atleast_1d(is_leap_year(year, gregorian))] = 1 return _scalar_if_one( (275 * mon / 9.0).astype(np.int64) - (K * ((mon + 9) / 12.0).astype(np.int64)) + day - 30)
def mean_longitude(self, jd): """Return mean longitude. Arguments: - `jd` : Julian Day in dynamical time Returns: - Longitude in radians """ jd = np.atleast_1d(jd) T = jd_to_jcent(jd) # From astrolabe #X = polynomial((d_to_r(100.466457), # d_to_r(36000.7698278), # d_to_r(0.00030322), # d_to_r(0.000000020)), T) # From AA, Naughter # Takes T/10.0 X = polynomial((d_to_r(100.4664567), d_to_r(360007.6982779), d_to_r(0.03032028), d_to_r(1.0/49931), d_to_r(-1.0/15300), d_to_r(-1.0/2000000)), T/10.0) X = modpi2(X + np.pi) return _scalar_if_one(X)
def dimension(self, jd, planet, dim): """Return one of heliocentric ecliptic longitude, latitude and radius. [Meeus-1998: pg 218] Arguments: - `jd` : Julian Day in dynamical time - `planet` : must be one of ("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune") - `dim` : must be one of "L" (longitude) or "B" (latitude) or "R" (radius) Returns: - longitude in radians, or latitude in radians, or radius in au, depending on the value of `dim`. """ jd = np.atleast_1d(jd) X = 0.0 tauN = 1.0 tau = jd_to_jcent(jd) / 10.0 c = _planets[(planet, dim)] for s in c: X += np.sum([A * np.cos(B + C * tau) for A, B, C in s]) * tauN tauN = tauN * tau # last calculation is wasted if dim == "L": X = modpi2(X) return _scalar_if_one(X)
def mean_longitude(self, jd): """Return mean longitude. Arguments: - `jd` : Julian Day in dynamical time Returns: - Longitude in radians """ jd = np.atleast_1d(jd) T = jd_to_jcent(jd) # From astrolabe #X = polynomial((d_to_r(100.466457), # d_to_r(36000.7698278), # d_to_r(0.00030322), # d_to_r(0.000000020)), T) # From AA, Naughter # Takes T/10.0 X = polynomial( (d_to_r(100.4664567), d_to_r(360007.6982779), d_to_r(0.03032028), d_to_r(1.0 / 49931), d_to_r(-1.0 / 15300), d_to_r( -1.0 / 2000000)), T / 10.0) X = modpi2(X + np.pi) return _scalar_if_one(X)
def cal_to_jd(year, mon=1, day=1, gregorian=True): """Convert a date in the Julian or Gregorian calendars to the Julian Day Number (Meeus 7.1). Arguments: - `year` : (int) year Keywords: - `mon` : (int, default=1) month - `day` : (int, float, default=1) day, may be fractional day - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Returns: - (int, float) """ year = np.atleast_1d(year) mon = np.atleast_1d(mon) day = np.atleast_1d(day).astype(np.float64) fyear = year - year.astype('i') mask = fyear > 0 if np.any(mask): raise ValueError('Year must be integer. Use frac_yr_to_jd instead.') fmon = mon - mon.astype('i') mask = fmon > 0 if np.any(mask): raise ValueError('Month must be integer. Use yr_frac_mon_to_jd instead.') if np.any(mon > 12) or np.any(mon < 1): raise ValueError('Month must be from 1 to 12') if np.any(day > 31) or np.any(day < 1): raise ValueError('Day must be from 1 to 31') year, mon, day = list(map(np.array, np.broadcast_arrays(year, mon, day))) for thirtydays in [9, 4, 6, 11]: daytestarr = mon == thirtydays if np.any(day[daytestarr] > 30): raise ValueError('Day must be from 1 to 30') leapyeartest = np.atleast_1d(is_leap_year(year, gregorian)) if np.any(np.logical_and(day[leapyeartest] > 29, mon[leapyeartest] == 2)): raise ValueError('Day must be from 1 to 29') if np.any(np.logical_and(day[~leapyeartest] > 28, mon[~leapyeartest] == 2)): raise ValueError('Day must be from 1 to 28') testarr = mon <= 2 year[testarr] -= 1 mon[testarr] += 12 if gregorian: A = (year / 100).astype(np.int64) B = 2 - A + (A / 4).astype(np.int64) else: B = 0 return _scalar_if_one( (365.25*(year + 4716)).astype(np.int64) + (30.6001*(mon + 1)).astype(np.int64) + day + B - 1524.5)
def jd_to_jcent(julian_day): """Return the number of Julian centuries since J2000.0 Arguments: - `julian_day` : (int) Julian Day number Return: - Julian centuries : (int) """ julian_day = np.atleast_1d(julian_day) return _scalar_if_one((julian_day - 2451545.0) / 36525.0)
def easter(year, gregorian=True): """Return the date of Western ecclesiastical Easter for a year in the Julian or Gregorian calendars. Arguments: - `year` : (int) year Keywords: - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Return: - (month, day) : (tuple) """ year = np.atleast_1d(year) if gregorian: a = year % 19 b = year // 100 c = year % 100 d = b // 4 e = b % 4 f = (b + 8) // 25 g = (b - f + 1) // 3 h = (19 * a + b - d - g + 15) % 30 i = c // 4 k = c % 4 l = (32 + 2 * e + 2 * i - h - k) % 7 m = (a + 11 * h + 22 * l) // 451 tmp = h + l - 7 * m + 114 else: a = year % 4 b = year % 7 c = year % 19 d = (19 * c + 15) % 30 e = (2 * a + 4 * b - d + 34) % 7 tmp = d + e + 114 mon = tmp // 31 day = (tmp % 31) + 1 return _scalar_if_one(mon), _scalar_if_one(day)
def vsop_to_fk5(jd, L, B): """Convert VSOP to FK5 coordinates. This is required only when using the full precision of the VSOP model. [Meeus-1998: pg 219] Arguments: - `jd` : Julian Day in dynamical time - `L` : longitude in radians - `B` : latitude in radians Returns: - corrected longitude in radians - corrected latitude in radians """ jd = np.atleast_1d(jd) T = jd_to_jcent(jd) L1 = polynomial([L, _k0, _k1], T) cosL1 = np.cos(L1) sinL1 = np.sin(L1) deltaL = _k2 + _k3*(cosL1 + sinL1)*np.tan(B) deltaB = _k3*(cosL1 - sinL1) return _scalar_if_one(modpi2(L + deltaL)), _scalar_if_one(B + deltaB)
def jd_to_day_of_week(julian_day): """Return the day of week for a Julian Day Number. The Julian Day Number must be for 0h UT. Arguments: - `julian_day` : (int) Julian Day number Returns: - day of week : (int) 0 = Sunday...6 = Saturday. """ julian_day = np.atleast_1d(julian_day) i = (julian_day + 1.5).astype(np.int64) return _scalar_if_one(i % 7)
def vsop_to_fk5(jd, L, B): """Convert VSOP to FK5 coordinates. This is required only when using the full precision of the VSOP model. [Meeus-1998: pg 219] Arguments: - `jd` : Julian Day in dynamical time - `L` : longitude in radians - `B` : latitude in radians Returns: - corrected longitude in radians - corrected latitude in radians """ jd = np.atleast_1d(jd) T = jd_to_jcent(jd) L1 = polynomial([L, _k0, _k1], T) cosL1 = np.cos(L1) sinL1 = np.sin(L1) deltaL = _k2 + _k3 * (cosL1 + sinL1) * np.tan(B) deltaB = _k3 * (cosL1 - sinL1) return _scalar_if_one(modpi2(L + deltaL)), _scalar_if_one(B + deltaB)
def apparent_longitude_low(jd, L): """Correct the geometric longitude for nutation and aberration. Low precision. [Meeus-1998: pg 164] Arguments: - `jd` : Julian Day in dynamical time - `L` : longitude in radians Returns: - corrected longitude in radians """ jd = np.atleast_1d(jd) T = jd_to_jcent(jd) omega = _lk0 - _lk1 * T return _scalar_if_one(modpi2(L - _lk2 - _lk3 * np.sin(omega)))
def mean_longitude_perigee(self, jd): """Return mean longitude of solar perigee. Arguments: - `jd` : Julian Day in dynamical time Returns: - Longitude of solar perigee in radians """ jd = np.atleast_1d(jd) T = jd_to_jcent(jd) X = polynomial((1012395.0, 6189.03, 1.63, 0.012), (T + 1)) / 3600.0 X = d_to_r(X) X = modpi2(X) return _scalar_if_one(X)
def dimension(self, jd, dim): """Return one of geocentric ecliptic longitude, latitude and radius. Arguments: - jd : Julian Day in dynamical time - dim : one of "L" (longitude) or "B" (latitude) or "R" (radius). Returns: - Either longitude in radians, or latitude in radians, or radius in au, depending on value of `dim`. """ jd = np.atleast_1d(jd) X = self.vsop.dimension(jd, "Earth", dim) if dim == "L": X = modpi2(X + np.pi) elif dim == "B": X = -X return _scalar_if_one(X)
def mean_longitude_perigee(self, jd): """Return mean longitude of solar perigee. Arguments: - `jd` : Julian Day in dynamical time Returns: - Longitude of solar perigee in radians """ jd = np.atleast_1d(jd) T = jd_to_jcent(jd) X = polynomial((1012395.0, 6189.03, 1.63, 0.012), (T + 1))/3600.0 X = d_to_r(X) X = modpi2(X) return _scalar_if_one(X)
def cal_to_jde(year, mon=1, day=1, hour=0, minute=0, sec=0.0, gregorian=True): """Convert a date in the Julian or Gregorian calendars to the Julian Day Ephemeris (Meeus 22.1). Arguments: - `year` : year Keywords: - `mon` : (int, default=1) month - `day` : (int, default=1) day, may be fractional day - `hour` : (int, default=0) hour - `minute` : (int, default=0) minute - `sec` : (float, default=0.0) second - `gregorian` : (bool, default=True) If True, use Gregorian calendar, else use Julian calendar Returns: - julian day ephemeris : (float) """ jde = cal_to_jd(year, mon, day, gregorian) return _scalar_if_one(jde + hms_to_fday(hour, minute, sec))