def _next_fall_equinox(jd): '''Return the julian day count of the previous fall equinox.''' y, _, _ = gregorian.from_jd(jd) eqx = Sun.get_equinox_solstice(y, "autumn").jde() if eqx < jd: eqx = Sun.get_equinox_solstice(y + 1, "autumn").jde() return eqx
def equinox_jd(gyear): """Calculate Julian day during which the March equinox, reckoned from the Tehran meridian, occurred for a given Gregorian year.""" mean_jd = Sun.get_equinox_solstice(gyear, target='spring') deltat_jd = mean_jd - Epoch.tt2ut(gyear, 3) / (24 * 60 * 60.) # Apparent JD in universal time apparent_jd = deltat_jd + (Sun.equation_of_time(deltat_jd)[0] / (24 * 60.)) # Correct for meridian of Tehran + 52.5 degrees return floor(apparent_jd.jde() + (52.5 / 360))
def gregorian_day_of_nawruz(year): if year == 2059: return 20 # get time of spring equinox equinox = Sun.get_equinox_solstice(year, "spring") # get sunset times in Tehran latitude = Angle(35.6944) longitude = Angle(51.4215) # get time of sunset in Tehran days = [19, 20, 21] sunsets = list( map(lambda x: Epoch(year, 3, x).rise_set(latitude, longitude)[1], days)) # compare if equinox < sunsets[1]: if equinox < sunsets[0]: return 19 else: return 20 else: if equinox < sunsets[2]: return 21 else: return 22
def test_sun_apparent_longitude_coarse(): """Tests apparent_longitude_coarse() method of Sun class""" epoch = Epoch(1992, 10, 13) alon, r = Sun.apparent_longitude_coarse(epoch) assert alon.dms_str(n_dec=0) == "199d 54' 32.0''", \ "ERROR: 1st apparent_longitude_coarse() test, 'alon' doesn't match"
def test_sun_get_equinox_solstice(): """Tests the get_equinox_solstice() method of Sun class""" epoch = Sun.get_equinox_solstice(1962, target="summer") y, m, d, h, mi, s = epoch.get_full_date() st = "{}/{}/{} {}:{}:{}".format(y, m, d, h, mi, round(s, 0)) assert st == "1962/6/21 21:24:42.0", \ "ERROR: 1st get_equinox_solstice() test, time stamp doesn't match"
def test_sun_true_longitude_coarse(): """Tests the true_longitude_coarse() method of Sun class""" epoch = Epoch(1992, 10, 13) true_lon, r = Sun.true_longitude_coarse(epoch) assert true_lon.dms_str(n_dec=0) == "199d 54' 36.0''", \ "ERROR: 1st true_longitude_coarse() test, 'true_lon' doesn't match" assert abs(round(r, 5) - 0.99766) < TOL, \ "ERROR: 2nd true_longitude_coarse() test, 'r' value doesn't match"
def test_sun_equation_of_time(): """Tests the equation_of_time() method of Sun class""" epoch = Epoch(1992, 10, 13.0) m, s = Sun.equation_of_time(epoch) assert abs(m) - 13 < TOL, \ "ERROR: 1st equation_of_time() test, 'm' doesn't match" assert abs(round(s, 1)) - 42.6 < TOL, \ "ERROR: 2nd equation_of_time() test, 's' doesn't match"
def test_sun_apparent_rightascension_declination_coarse(): """Tests apparent_rightascension_declination_coarse() method of Sun class""" epoch = Epoch(1992, 10, 13) ra, delta, r = Sun.apparent_rightascension_declination_coarse(epoch) assert ra.ra_str(n_dec=1) == "13h 13' 31.4''", \ "ERROR: 1st rightascension_declination_coarse() test doesn't match" assert delta.dms_str(n_dec=0) == "-7d 47' 6.0''", \ "ERROR: 2nd rightascension_declination_coarse() test doesn't match"
def test_rectangular_coordinates_mean_equinox(): """Tests rectangular_coordinates_mean_equinox() method of Sun class""" epoch = Epoch(1992, 10, 13.0) x, y, z = Sun.rectangular_coordinates_mean_equinox(epoch) assert abs(round(x, 7) - (-0.9379963)) < TOL, \ "ERROR: 1st rectangular_coordinates_mean_equinox(), 'x' doesn't match" assert abs(round(y, 6) - (-0.311654)) < TOL, \ "ERROR: 2nd rectangular_coordinates_mean_equinox(), 'y' doesn't match" assert abs(round(z, 7) - (-0.1351207)) < TOL, \ "ERROR: 3rd rectangular_coordinates_mean_equinox(), 'z' doesn't match"
def test_sun_apparent_geocentric_position(): """Tests the apparent_geocentric_position() method of Sun class""" epoch = Epoch(1992, 10, 13.0) lon, lat, r = Sun.apparent_geocentric_position(epoch) assert lon.to_positive().dms_str(n_dec=3) == "199d 54' 21.548''", \ "ERROR: 1st apparent_geocentric_position() test, 'lon' doesn't match" assert lat.dms_str(n_dec=3) == "0.721''", \ "ERROR: 2nd apparent_geocentric_position() test, 'lat' doesn't match" assert abs(round(r, 8) - 0.99760852) < TOL, \ "ERROR: 3rd apparent_geocentric_position() test, 'r' doesn't match"
def test_rectangular_coordinates_b1950(): """Tests rectangular_coordinates_b1950() method of Sun class""" epoch = Epoch(1992, 10, 13.0) x, y, z = Sun.rectangular_coordinates_b1950(epoch) assert abs(round(x, 8) - (-0.94149557)) < TOL, \ "ERROR: 1st rectangular_coordinates_b1950() test, 'x' doesn't match" assert abs(round(y, 8) - (-0.30259922)) < TOL, \ "ERROR: 2nd rectangular_coordinates_b1950() test, 'y' doesn't match" assert abs(round(z, 8) - (-0.11578695)) < TOL, \ "ERROR: 3rd rectangular_coordinates_b1950() test, 'z' doesn't match"
def test_sun_ephemeris_physical_observations(): """Tests the ephemeris_physical_observations() method of Sun class""" epoch = Epoch(1992, 10, 13) p, b0, l0 = Sun.ephemeris_physical_observations(epoch) assert abs(round(p, 2)) - 26.27 < TOL, \ "ERROR: 1st ephemeris_physical_observations() test, 'p' doesn't match" assert abs(round(b0, 2)) - 5.99 < TOL, \ "ERROR: 2nd ephemeris_physical_observations() test, 'b0' doesn't match" assert abs(round(l0, 2)) - 238.63 < TOL, \ "ERROR: 3rd ephemeris_physical_observations() test, 'l0' doesn't match"
def test_sun_geometric_geocentric_position(): """Tests the geometric_geocentric_position() method of Sun class""" epoch = Epoch(1992, 10, 13.0) lon, lat, r = Sun.geometric_geocentric_position(epoch, tofk5=False) assert abs(round(lon.to_positive(), 6) - 199.907297) < TOL, \ "ERROR: 1st geometric_geocentric_position() test, 'lon' doesn't match" assert lat.dms_str(n_dec=3) == "0.744''", \ "ERROR: 2nd geometric_geocentric_position() test, 'lat' doesn't match" assert abs(round(r, 8) - 0.99760852) < TOL, \ "ERROR: 3rd geometric_geocentric_position() test, 'r' doesn't match"
def test_rectangular_coordinates_j2000(): """Tests rectangular_coordinates_j2000() method of Sun class""" epoch = Epoch(1992, 10, 13.0) x, y, z = Sun.rectangular_coordinates_j2000(epoch) assert abs(round(x, 8) - (-0.93740485)) < TOL, \ "ERROR: 1st rectangular_coordinates_j2000() test, 'x' doesn't match" assert abs(round(y, 8) - (-0.3131474)) < TOL, \ "ERROR: 2nd rectangular_coordinates_j2000() test, 'y' doesn't match" assert abs(round(z, 8) - (-0.13577045)) < TOL, \ "ERROR: 3rd rectangular_coordinates_j2000() test, 'z' doesn't match"
def test_rectangular_coordinates_equinox(): """Tests rectangular_coordinates_equinox() method of Sun class""" epoch = Epoch(1992, 10, 13.0) e_equinox = Epoch(2467616.0) x, y, z = Sun.rectangular_coordinates_equinox(epoch, e_equinox) assert abs(round(x, 8) - (-0.93368986)) < TOL, \ "ERROR: 1st rectangular_coordinates_equinox() test, 'x' doesn't match" assert abs(round(y, 8) - (-0.32235085)) < TOL, \ "ERROR: 2nd rectangular_coordinates_equinox() test, 'y' doesn't match" assert abs(round(z, 8) - (-0.13977098)) < TOL, \ "ERROR: 3rd rectangular_coordinates_equinox() test, 'z' doesn't match"
def gregorian_nawruz(year): ''' Return Nawruz in the Gregorian calendar. Returns a tuple (month, day), where month is always 3 ''' if year == 2059: return 3, 20 # Timestamp of spring equinox. equinox = Sun.get_equinox_solstice(year, "spring") # Get times of sunsets in Tehran near vernal equinox. x, y = Angle(TEHRAN[0]), Angle(TEHRAN[1]) days = trunc(equinox.get_date()[2]), ceil(equinox.get_date()[2]) for day in days: sunset = Epoch(year, 3, day).rise_set(y, x)[1] if sunset > equinox: return 3, day
def geocentric_position(self, epoch): """This method computes the geocentric position of a minor celestial body (right ascension and declination) for the given epoch, and referred to the standard equinox J2000.0. Additionally, it also computes the elongation angle to the Sun. :param epoch: Epoch to compute geocentric position, as an Epoch object :type epoch: :py:class:`Epoch` :returns: A tuple containing the right ascension, the declination and the elongation angle to the Sun, as Angle objects :rtype: tuple :raises: TypeError if input value is of wrong type. >>> a = 2.2091404 >>> e = 0.8502196 >>> q = a * (1.0 - e) >>> i = Angle(11.94524) >>> omega = Angle(334.75006) >>> w = Angle(186.23352) >>> t = Epoch(1990, 10, 28.54502) >>> minor = Minor(q, e, i, omega, w, t) >>> epoch = Epoch(1990, 10, 6.0) >>> ra, dec, p = minor.geocentric_position(epoch) >>> print(ra.ra_str(n_dec=1)) 10h 34' 13.7'' >>> print(dec.dms_str(n_dec=0)) 19d 9' 32.0'' >>> print(round(p, 2)) 40.51 >>> t = Epoch(1998, 4, 14.4358) >>> q = 1.487469 >>> e = 1.0 >>> i = Angle(0.0) >>> omega = Angle(0.0) >>> w = Angle(0.0) >>> minor = Minor(q, e, i, omega, w, t) >>> epoch = Epoch(1998, 8, 5.0) >>> ra, dec, p = minor.geocentric_position(epoch) >>> print(ra.ra_str(n_dec=1)) 5h 45' 34.5'' >>> print(dec.dms_str(n_dec=0)) 23d 23' 53.0'' >>> print(round(p, 2)) 45.73 """ # First check that input value is of correct types if not isinstance(epoch, Epoch): raise TypeError("Invalid input type") # Get internal parameters aa, bb, cc = self._aa, self._bb, self._cc am, bm, cm = self._am, self._bm, self._cm # Get the mean motion and other orbital parameters n = self._n a = self._a e = self._e w = self._w t = self._t # Time since perihelion t_peri = epoch - t # Now, compute the mean anomaly, in degrees m = t_peri * n m = Angle(m) if e < 0.98: # Elliptic case # With the mean anomaly, use Kepler's equation to find E and v ee, v = kepler_equation(e, m) ee = Angle(ee).to_positive() # Get r er = ee.rad() rr = a * (1.0 - e * cos(er)) elif abs(e - 1.0) < self._tol: # Parabolic case q = self._q ww = (0.03649116245 * (epoch - self._t)) / (q * sqrt(q)) sp = ww / 3.0 iterate = True while iterate: s = (2.0 * sp * sp * sp + ww) / (3.0 * (sp * sp + 1.0)) iterate = abs(s - sp) > self._tol sp = s v = 2.0 * atan(s) v = Angle(v, radians=True) rr = q * (1.0 + s * s) else: # We are in the near-parabolic case v, rr = self._near_parabolic(t_peri) # Compute the heliocentric rectangular equatorial coordinates wr = w.rad() vr = Angle(v).rad() x = rr * am * sin(aa + wr + vr) y = rr * bm * sin(bb + wr + vr) z = rr * cm * sin(cc + wr + vr) # Now let's compute Sun's rectangular coordinates xs, ys, zs = Sun.rectangular_coordinates_j2000(epoch) xi = x + xs eta = y + ys zeta = z + zs delta = sqrt(xi * xi + eta * eta + zeta * zeta) # We need to correct for the effect of light-time. Compute delay tau tau = 0.0057755183 * delta # Recompute some critical parameters t_peri = epoch - t - tau # Now, compute the mean anomaly, in degrees m = t_peri * n m = Angle(m) if e < 0.98: # Elliptic case # With the mean anomaly, use Kepler's equation to find E and v ee, v = kepler_equation(e, m) ee = Angle(ee).to_positive() # Get r er = ee.rad() rr = a * (1.0 - e * cos(er)) elif abs(e - 1.0) < self._tol: # Parabolic case q = self._q ww = (0.03649116245 * (epoch - self._t)) / (q * sqrt(q)) sp = ww / 3.0 iterate = True while iterate: s = (2.0 * sp * sp * sp + ww) / (3.0 * (sp * sp + 1.0)) iterate = abs(s - sp) > self._tol sp = s v = 2.0 * atan(s) v = Angle(v, radians=True) rr = q * (1.0 + s * s) else: # We are in the near-parabolic case v, rr = self._near_parabolic(t_peri) # Compute the heliocentric rectangular equatorial coordinates wr = w.rad() vr = Angle(v).rad() x = rr * am * sin(aa + wr + vr) y = rr * bm * sin(bb + wr + vr) z = rr * cm * sin(cc + wr + vr) xi = x + xs eta = y + ys zeta = z + zs ra = Angle(atan2(eta, xi), radians=True) dec = Angle(atan2(zeta, sqrt(xi * xi + eta * eta)), radians=True) r_sun = sqrt(xs * xs + ys * ys + zs * zs) psi = acos((xi * xs + eta * ys + zeta * zs) / (r_sun * delta)) psi = Angle(psi, radians=True) return ra, dec, psi
def geocentric_position(epoch): """This method computes the geocentric position of Pluto (right ascension and declination) for the given epoch, for the standard equinox J2000.0. :param epoch: Epoch to compute geocentric position, as an Epoch object :type epoch: :py:class:`Epoch` :returns: A tuple containing the right ascension and the declination as Angle objects :rtype: tuple :raises: TypeError if input value is of wrong type. :raises: ValueError if input epoch outside the 1885-2099 range. >>> epoch = Epoch(1992, 10, 13.0) >>> ra, dec = Pluto.geocentric_position(epoch) >>> print(ra.ra_str(n_dec=1)) 15h 31' 43.7'' >>> print(dec.dms_str(n_dec=0)) -4d 27' 29.0'' """ # First check that input value is of correct types if not isinstance(epoch, Epoch): raise TypeError("Invalid input type") # Check that the input epoch is within valid range y = epoch.year() if y < 1885.0 or y > 2099.0: raise ValueError("Epoch outside the 1885-2099 range") # Compute the heliocentric position of Pluto ll, b, r = Pluto.geometric_heliocentric_position(epoch) # Change angles to radians ll = ll.rad() b = b.rad() # Values corresponding to obliquity of ecliptic (epsilon) for J2000.0 sine = 0.397777156 cose = 0.917482062 x = r * cos(ll) * cos(b) y = r * (sin(ll) * cos(b) * cose - sin(b) * sine) z = r * (sin(ll) * cos(b) * sine + sin(b) * cose) # Compute Sun's J2000.0 rectacngular coordinates xs, ys, zs = Sun.rectangular_coordinates_j2000(epoch) # Compute auxiliary quantities xi = x + xs eta = y + ys zeta = z + zs # Compute Pluto's distance to Earth delta = sqrt(xi * xi + eta * eta + zeta * zeta) # Get the light-time difference tau = 0.0057755183 * delta # Repeat the computations using the light-time correction ll, b, r = Pluto.geometric_heliocentric_position(epoch - tau) # Change angles to radians ll = ll.rad() b = b.rad() x = r * cos(ll) * cos(b) y = r * (sin(ll) * cos(b) * cose - sin(b) * sine) z = r * (sin(ll) * cos(b) * sine + sin(b) * cose) # Compute auxiliary quantities xi = x + xs eta = y + ys zeta = z + zs # Compute Pluto's distance to Earth delta = sqrt(xi * xi + eta * eta + zeta * zeta) # Compute right ascension and declination alpha = Angle(atan2(eta, xi), radians=True) dec = Angle(asin(zeta / delta), radians=True) return alpha.to_positive(), dec