def visible_crescent(self, date): """Return S. K. Shaukat's criterion for likely visibility of crescent moon on eve of date 'date', at location 'location'.""" tee = self.universal_from_standard(self.dusk(date - 1, mpf(4.5))) phase = Lunar.lunar_phase(tee) altitude = self.lunar_altitude(tee) arc_of_light = arccos_degrees(cos_degrees(Lunar.lunar_latitude(tee)) * cos_degrees(phase)) return ((Lunar.NEW < phase < Lunar.FIRST_QUARTER) and (mpf(10.6) <= arc_of_light <= 90) and (altitude > mpf(4.1)))
def lunar_altitude(self, tee): """Return the geocentric altitude of moon at moment, tee, at location, location, as a small positive/negative angle in degrees, ignoring parallax and refraction. Adapted from 'Astronomical Algorithms' by Jean Meeus, Willmann_Bell, Inc., 1998.""" lamb = Lunar.lunar_longitude(tee) beta = Lunar.lunar_latitude(tee) alpha = Astro.right_ascension(tee, beta, lamb) delta = Astro.declination(tee, beta, lamb) theta0 = Astro.sidereal_from_moment(tee) cap_H = mod(theta0 + self.longitude - alpha, 360) altitude = arcsin_degrees( (sin_degrees(self.latitude) * sin_degrees(delta)) + (cos_degrees(self.latitude) * cos_degrees(delta) * cos_degrees(cap_H))) return mod(altitude + 180, 360) - 180
def phasis_on_or_before(self, date): """Return the closest fixed date on or before date 'date', when crescent moon first became visible at location 'location'.""" mean = date - ifloor(Lunar.lunar_phase(date + 1) / 360.0 * Lunar.MEAN_SYNODIC_MONTH) tau = ((mean - 30) if (((date - mean) <= 3) and (not self.visible_crescent(date))) else (mean - 2)) return next_int(tau, lambda d: self.visible_crescent(d))
def lunar_parallax(self, tee): """Return the parallax of moon at moment, tee, at location, location. Adapted from "Astronomical Algorithms" by Jean Meeus, Willmann_Bell, Inc., 1998.""" geo = self.lunar_altitude(tee) Delta = Lunar.lunar_distance(tee) alt = 6378140 / Delta arg = alt * cos_degrees(geo) return arcsin_degrees(arg)
def moonrise(self, date): """Return the standard time of moonrise on fixed, date, and location, location.""" t = self.universal_from_standard(date) waning = (Lunar.lunar_phase(t) > 180) alt = self.observed_lunar_altitude(t) offset = alt / 360 if waning and (offset > 0): approx = t + 1 - offset elif waning: approx = t - offset else: approx = t + (1 / 2) + offset rise = binary_search(approx - Clock.days_from_hours(3), approx + Clock.days_from_hours(3), lambda u, l: ((u - l) < Clock.days_from_hours(1/60)), lambda x: self.observed_lunar_altitude(x) > 0) if rise < (t + 1): return self.standard_from_universal(rise) raise ValueError()
def sidereal_lunar_longitude(tee): """Return sidereal lunar longitude at moment, tee.""" return mod(Lunar.lunar_longitude(tee) - Astro.precession(tee) + SIDEREAL_START, 360)
def new_moon_on_or_after(cls, fixed_date): """Return fixed date (Beijing) of first new moon on or after fixed date, 'fixed_date'.""" tee = Lunar.new_moon_at_or_after(cls.midnight(fixed_date)) return ifloor(cls.chinese_location(tee).standard_from_universal(tee))
def new_moon_before(cls, fixed_date): """Return fixed date (Beijing) of first new moon before fixed date, 'fixed_date'.""" tee = Lunar.new_moon_before(cls.midnight(fixed_date)) return ifloor(cls.location(tee).standard_from_universal(tee))
def phasis_on_or_after(cls, fixed_date, location): """Return closest fixed date on or after date, date, on the eve of which crescent moon first became visible at location, location.""" mean = fixed_date - ifloor(Lunar.lunar_phase(fixed_date + 1) / mpf(360) * Lunar.MEAN_SYNODIC_MONTH) tau = fixed_date if fixed_date - mean <= 3 and not location.visible_crescent(fixed_date - 1) else mean + 29 return next_int(tau, lambda d: location.visible_crescent(d))