def _search_maximal_elongations(start_time: Time, end_time: Time) -> [Event]: earth = get_skf_objects()['earth'] sun = get_skf_objects()['sun'] aster = None def get_elongation(time: Time): sun_pos = (sun - earth).at(time) aster_pos = (aster.get_skyfield_object() - earth).at(time) separation = sun_pos.separation_from(aster_pos) return separation.degrees get_elongation.rough_period = 1.0 events = [] for aster in ASTERS: if aster.skyfield_name not in ['MERCURY', 'VENUS']: continue times, elongations = find_maxima(start_time, end_time, f=get_elongation, epsilon=1. / 24 / 3600, num=12) for i, time in enumerate(times): elongation = elongations[i] events.append( Event('MAXIMAL_ELONGATION', [aster], time.utc_datetime(), details='{:.3n}°'.format(elongation))) return events
def test_we_get_two_results_for_barely_separate_maxima(): t0, t1 = make_t() enough = 1.51 * epsilon f = make_mountain_range_f([0.5 - enough, 0.5 + enough]) t, y = find_maxima(t0, t1, f, epsilon, 12) print(list(t.tt)) assert len(t.tt) == len(y) == 2
def test_finding_enough_maxima(): # If the rough period is close, no maxima should be skipped. t0, t1 = make_t() f = make_mountain_range_f(np.linspace(0.01, 0.99, 30)) f.rough_period = 1.0 / 30.0 t, y = find_maxima(t0, t1, f, epsilon, 12) assert len(t) == len(y) == 30
def test_finding_enough_maxima(): # If the step size is small enough, no maxima should be skipped. t0, t1 = make_t() f = make_mountain_range_f(np.linspace(0.01, 0.99, 30)) f.step_days = 0.03 / 2.0 # Half of the expected period t, y = find_maxima(t0, t1, f, epsilon, 12) assert len(t) == len(y) == 30
def get_asters_ephemerides_for_aster(aster, date: datetime.date, position: Position) -> Object: skyfield_aster = get_skf_objects()[aster.skyfield_name] def get_angle(time: Time) -> float: return position.get_planet_topos().at(time).observe( skyfield_aster).apparent().altaz()[0].degrees def is_risen(time: Time) -> bool: return get_angle(time) > RISEN_ANGLE get_angle.rough_period = 1.0 is_risen.rough_period = 0.5 start_time = get_timescale().utc(date.year, date.month, date.day) end_time = get_timescale().utc(date.year, date.month, date.day, 23, 59, 59) rise_times, arr = find_discrete(start_time, end_time, is_risen) try: culmination_time, _ = find_maxima(start_time, end_time, f=get_angle, epsilon=1. / 3600 / 24, num=12) culmination_time = culmination_time[0] if len( culmination_time) > 0 else None except ValueError: culmination_time = None if len(rise_times) == 2: rise_time = rise_times[0 if arr[0] else 1] set_time = rise_times[1 if not arr[1] else 0] else: rise_time = rise_times[0] if arr[0] else None set_time = rise_times[0] if not arr[0] else None # Convert the Time instances to Python datetime objects if rise_time is not None: rise_time = rise_time.utc_datetime().replace(microsecond=0) if culmination_time is not None: culmination_time = culmination_time.utc_datetime().replace( microsecond=0) if set_time is not None: set_time = set_time.utc_datetime().replace( microsecond=0) if set_time is not None else None aster.ephemerides = AsterEphemerides(rise_time, culmination_time, set_time) return aster
retval.append(dates[i]) if not skip: retval.append(dates[n - 1]) return retval # Returns a copy of floats, limiting precision for easier comparison. def rounded(floats, places): shift = 10**places return [round(shift * f) / shift for f in floats] #### peri_date, peri_dist = sfs.find_minima(t0, t1, sun_earth_dist) apo_date, apo_dist = sfs.find_maxima(t0, t1, sun_earth_dist) ephem_dates = np.empty(2 * nyr) ephem_dates[0::2] = dedup([p.tt for p in peri_date]) ephem_dates[1::2] = dedup([a.tt for a in apo_date]) k0 = np.array([yr0 - 2000 + i / 2. for i in range(2 * nyr)]) print('Published coefficients:') c0 = [328.41, 316.13, 346.20, 136.95, 249.52] b0 = [132.788585, 584.903153, 450.380738, 659.306737, 329.653368] a0p = [1.278, -0.055, -0.091, -0.056, -0.045] a0a = [-1.352, 0.061, 0.062, 0.029, 0.031] print(c0) print(b0) print(a0p)
def get_ephemerides(date: datetime.date, position: Position, timezone: int = 0) -> [AsterEphemerides]: ephemerides = [] def get_angle(for_aster: Object): def fun(time: Time) -> float: return position.get_planet_topos().at(time).observe(for_aster.get_skyfield_object()).apparent().altaz()[0]\ .degrees fun.rough_period = 1.0 return fun def is_risen(for_aster: Object): def fun(time: Time) -> bool: return get_angle(for_aster)(time) > RISEN_ANGLE fun.rough_period = 0.5 return fun start_time = get_timescale().utc(date.year, date.month, date.day, -timezone) end_time = get_timescale().utc(date.year, date.month, date.day, 23 - timezone, 59, 59) try: for aster in ASTERS: rise_times, arr = find_discrete(start_time, end_time, is_risen(aster)) try: culmination_time, _ = find_maxima(start_time, end_time, f=get_angle(aster), epsilon=1. / 3600 / 24, num=12) culmination_time = culmination_time[0] if len( culmination_time) > 0 else None except ValueError: culmination_time = None if len(rise_times) == 2: rise_time = rise_times[0 if arr[0] else 1] set_time = rise_times[1 if not arr[1] else 0] else: rise_time = rise_times[0] if arr[0] else None set_time = rise_times[0] if not arr[0] else None # Convert the Time instances to Python datetime objects if rise_time is not None: rise_time = translate_to_timezone( rise_time.utc_datetime().replace(microsecond=0), to_tz=timezone) if culmination_time is not None: culmination_time = translate_to_timezone( culmination_time.utc_datetime().replace(microsecond=0), to_tz=timezone) if set_time is not None: set_time = translate_to_timezone( set_time.utc_datetime().replace(microsecond=0), to_tz=timezone) ephemerides.append( AsterEphemerides(rise_time, culmination_time, set_time, aster=aster)) except EphemerisRangeError as error: start = translate_to_timezone(error.start_time.utc_datetime(), timezone) end = translate_to_timezone(error.end_time.utc_datetime(), timezone) start = datetime.date(start.year, start.month, start.day + 1) end = datetime.date(end.year, end.month, end.day - 1) raise OutOfRangeDateError(start, end) return ephemerides
def test_finding_maxima_near_edges(): t0, t1 = make_t() f = make_mountain_range_f([bump, 1.0 - bump]) t, y = find_maxima(t0, t1, f, epsilon, 12) assert is_close(t.tt, (bump, 1.0 - bump)) assert is_close(y, 0.0)
def test_we_only_get_one_result_for_a_jagged_maximum(): t0, t1 = make_t() almost = 0.49 * epsilon f = make_mountain_range_f([0.5 - almost, 0.5 + almost]) t, y = find_maxima(t0, t1, f, epsilon, 12) assert len(t.tt) == len(y) == 1
def test_that_we_ignore_maxima_slightly_beyond_range(): t0, t1 = make_t() f = make_mountain_range_f([-bump, 1.0 + bump]) t, y = find_maxima(t0, t1, f, epsilon, 12) assert len(t.tt) == 0 assert len(y) == 0
def test_finding_no_maxima_at_all_with_no_near_misses(): t0, t1 = make_t() f = make_mountain_range_f([-100, 101]) t, y = find_maxima(t0, t1, f, epsilon, 12) assert list(t.tt) == [] assert list(y) == []
def test_finding_no_maxima_at_all_but_having_near_misses(): t0, t1 = make_t() f = make_mountain_range_f([-bump, 1.0 + bump]) t, y = find_maxima(t0, t1, f, epsilon, 12) assert list(t.tt) == [] assert list(y) == []
from skyfield.api import load from skyfield.searchlib import find_maxima ts = load.timescale(builtin=True) planets = load("de421.bsp") earth, sun, venus = planets["earth"], planets["sun"], planets["venus"] venus_elongation_degrees.rough_period = 1.0 t1 = ts.utc(2018) t2 = ts.utc(2023) t, values = find_maxima(t1, t2, venus_elongation_degrees) def venus_elongation_degrees(time): e = earth.at(time) s = e.observe(sun).apparent() v = e.observe(venus).apparent() return s.separation_from(v).degrees