Add support for maximal elongations of Mercury and Venustags/v0.6.0
| @@ -6,8 +6,9 @@ | |||||
| \usepackage{graphicx} | \usepackage{graphicx} | ||||
| \usepackage{hyperref} | \usepackage{hyperref} | ||||
| % Fix non-break spaces issues | |||||
| % Fix Unicode issues | |||||
| \DeclareUnicodeCharacter{202F}{~} | \DeclareUnicodeCharacter{202F}{~} | ||||
| \DeclareUnicodeCharacter{00B0}{$^\circ$} | |||||
| \hypersetup{pdfinfo={ | \hypersetup{pdfinfo={ | ||||
| Title={+++DOCUMENT-TITLE+++}, | Title={+++DOCUMENT-TITLE+++}, | ||||
| @@ -18,30 +18,13 @@ | |||||
| from shutil import rmtree | from shutil import rmtree | ||||
| from pathlib import Path | from pathlib import Path | ||||
| from typing import Union | |||||
| from skyfield.api import Loader | from skyfield.api import Loader | ||||
| from skyfield.timelib import Time | from skyfield.timelib import Time | ||||
| from skyfield.nutationlib import iau2000b | from skyfield.nutationlib import iau2000b | ||||
| from .data import Star, Planet, Satellite, MOON_PHASES, MoonPhase | |||||
| from .i18n import _ | |||||
| CACHE_FOLDER = str(Path.home()) + '/.kosmorro-cache' | CACHE_FOLDER = str(Path.home()) + '/.kosmorro-cache' | ||||
| MONTHS = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'] | |||||
| ASTERS = [Star(_('Sun'), 'SUN'), | |||||
| Satellite(_('Moon'), 'MOON'), | |||||
| Planet(_('Mercury'), 'MERCURY'), | |||||
| Planet(_('Venus'), 'VENUS'), | |||||
| Planet(_('Mars'), 'MARS'), | |||||
| Planet(_('Jupiter'), 'JUPITER BARYCENTER'), | |||||
| Planet(_('Saturn'), 'SATURN BARYCENTER'), | |||||
| Planet(_('Uranus'), 'URANUS BARYCENTER'), | |||||
| Planet(_('Neptune'), 'NEPTUNE BARYCENTER'), | |||||
| Planet(_('Pluto'), 'PLUTO BARYCENTER')] | |||||
| def get_loader(): | def get_loader(): | ||||
| return Loader(CACHE_FOLDER) | return Loader(CACHE_FOLDER) | ||||
| @@ -63,43 +46,6 @@ def clear_cache(): | |||||
| rmtree(CACHE_FOLDER) | rmtree(CACHE_FOLDER) | ||||
| def skyfield_to_moon_phase(times: [Time], vals: [int], now: Time) -> Union[MoonPhase, None]: | |||||
| tomorrow = get_timescale().utc(now.utc_datetime().year, now.utc_datetime().month, now.utc_datetime().day + 1) | |||||
| phases = list(MOON_PHASES.keys()) | |||||
| current_phase = None | |||||
| current_phase_time = None | |||||
| next_phase_time = None | |||||
| i = 0 | |||||
| if len(times) == 0: | |||||
| return None | |||||
| for i, time in enumerate(times): | |||||
| if now.utc_iso() <= time.utc_iso(): | |||||
| if vals[i] in [0, 2, 4, 6]: | |||||
| if time.utc_datetime() < tomorrow.utc_datetime(): | |||||
| current_phase_time = time | |||||
| current_phase = phases[vals[i]] | |||||
| else: | |||||
| i -= 1 | |||||
| current_phase_time = None | |||||
| current_phase = phases[vals[i]] | |||||
| else: | |||||
| current_phase = phases[vals[i]] | |||||
| break | |||||
| for j in range(i + 1, len(times)): | |||||
| if vals[j] in [0, 2, 4, 6]: | |||||
| next_phase_time = times[j] | |||||
| break | |||||
| return MoonPhase(current_phase, | |||||
| current_phase_time.utc_datetime() if current_phase_time is not None else None, | |||||
| next_phase_time.utc_datetime() if next_phase_time is not None else None) | |||||
| def flatten_list(the_list: list): | def flatten_list(the_list: list): | ||||
| new_list = [] | new_list = [] | ||||
| for item in the_list: | for item in the_list: | ||||
| @@ -20,8 +20,10 @@ from abc import ABC, abstractmethod | |||||
| from typing import Union | from typing import Union | ||||
| from datetime import datetime | from datetime import datetime | ||||
| from skyfield.api import Topos | |||||
| from skyfield.api import Topos, Time | |||||
| from skyfield.vectorlib import VectorSum as SkfPlanet | |||||
| from .core import get_skf_objects, get_timescale | |||||
| from .i18n import _ | from .i18n import _ | ||||
| MOON_PHASES = { | MOON_PHASES = { | ||||
| @@ -37,7 +39,8 @@ MOON_PHASES = { | |||||
| EVENTS = { | EVENTS = { | ||||
| 'OPPOSITION': {'message': _('%s is in opposition')}, | 'OPPOSITION': {'message': _('%s is in opposition')}, | ||||
| 'CONJUNCTION': {'message': _('%s and %s are in conjunction')} | |||||
| 'CONJUNCTION': {'message': _('%s and %s are in conjunction')}, | |||||
| 'MAXIMAL_ELONGATION': {'message': _("%s's largest elongation")} | |||||
| } | } | ||||
| @@ -115,6 +118,9 @@ class Object(ABC): | |||||
| self.skyfield_name = skyfield_name | self.skyfield_name = skyfield_name | ||||
| self.ephemerides = ephemerides | self.ephemerides = ephemerides | ||||
| def get_skyfield_object(self) -> SkfPlanet: | |||||
| return get_skf_objects()[self.skyfield_name] | |||||
| @abstractmethod | @abstractmethod | ||||
| def get_type(self) -> str: | def get_type(self) -> str: | ||||
| pass | pass | ||||
| @@ -142,23 +148,77 @@ class Satellite(Object): | |||||
| class Event: | class Event: | ||||
| def __init__(self, event_type: str, objects: [Object], start_time: datetime, | def __init__(self, event_type: str, objects: [Object], start_time: datetime, | ||||
| end_time: Union[datetime, None] = None): | |||||
| end_time: Union[datetime, None] = None, details: str = None): | |||||
| if event_type not in EVENTS.keys(): | if event_type not in EVENTS.keys(): | ||||
| raise ValueError('event_type parameter must be one of the following: %s (got %s)' % ( | |||||
| ', '.join(EVENTS.keys()), | |||||
| event_type) | |||||
| ) | |||||
| accepted_types = ', '.join(EVENTS.keys()) | |||||
| raise ValueError('event_type parameter must be one of the following: %s (got %s)' % (accepted_types, | |||||
| event_type)) | |||||
| self.event_type = event_type | self.event_type = event_type | ||||
| self.objects = objects | self.objects = objects | ||||
| self.start_time = start_time | self.start_time = start_time | ||||
| self.end_time = end_time | self.end_time = end_time | ||||
| self.details = details | |||||
| def get_description(self) -> str: | |||||
| return EVENTS[self.event_type]['message'] % self._get_objects_name() | |||||
| def get_description(self, show_details: bool = True) -> str: | |||||
| description = EVENTS[self.event_type]['message'] % self._get_objects_name() | |||||
| if show_details and self.details is not None: | |||||
| description += ' ({:s})'.format(self.details) | |||||
| return description | |||||
| def _get_objects_name(self): | def _get_objects_name(self): | ||||
| if len(self.objects) == 1: | if len(self.objects) == 1: | ||||
| return self.objects[0].name | return self.objects[0].name | ||||
| return tuple(object.name for object in self.objects) | return tuple(object.name for object in self.objects) | ||||
| def skyfield_to_moon_phase(times: [Time], vals: [int], now: Time) -> Union[MoonPhase, None]: | |||||
| tomorrow = get_timescale().utc(now.utc_datetime().year, now.utc_datetime().month, now.utc_datetime().day + 1) | |||||
| phases = list(MOON_PHASES.keys()) | |||||
| current_phase = None | |||||
| current_phase_time = None | |||||
| next_phase_time = None | |||||
| i = 0 | |||||
| if len(times) == 0: | |||||
| return None | |||||
| for i, time in enumerate(times): | |||||
| if now.utc_iso() <= time.utc_iso(): | |||||
| if vals[i] in [0, 2, 4, 6]: | |||||
| if time.utc_datetime() < tomorrow.utc_datetime(): | |||||
| current_phase_time = time | |||||
| current_phase = phases[vals[i]] | |||||
| else: | |||||
| i -= 1 | |||||
| current_phase_time = None | |||||
| current_phase = phases[vals[i]] | |||||
| else: | |||||
| current_phase = phases[vals[i]] | |||||
| break | |||||
| for j in range(i + 1, len(times)): | |||||
| if vals[j] in [0, 2, 4, 6]: | |||||
| next_phase_time = times[j] | |||||
| break | |||||
| return MoonPhase(current_phase, | |||||
| current_phase_time.utc_datetime() if current_phase_time is not None else None, | |||||
| next_phase_time.utc_datetime() if next_phase_time is not None else None) | |||||
| MONTHS = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'] | |||||
| ASTERS = [Star(_('Sun'), 'SUN'), | |||||
| Satellite(_('Moon'), 'MOON'), | |||||
| Planet(_('Mercury'), 'MERCURY'), | |||||
| Planet(_('Venus'), 'VENUS'), | |||||
| Planet(_('Mars'), 'MARS'), | |||||
| Planet(_('Jupiter'), 'JUPITER BARYCENTER'), | |||||
| Planet(_('Saturn'), 'SATURN BARYCENTER'), | |||||
| Planet(_('Uranus'), 'URANUS BARYCENTER'), | |||||
| Planet(_('Neptune'), 'NEPTUNE BARYCENTER'), | |||||
| Planet(_('Pluto'), 'PLUTO BARYCENTER')] | |||||
| @@ -24,8 +24,8 @@ from skyfield.searchlib import find_discrete, find_maxima | |||||
| from skyfield.timelib import Time | from skyfield.timelib import Time | ||||
| from skyfield.constants import tau | from skyfield.constants import tau | ||||
| from .data import Object, Position, AsterEphemerides, MoonPhase | |||||
| from .core import get_skf_objects, get_timescale, get_iau2000b, ASTERS, MONTHS, skyfield_to_moon_phase | |||||
| from .data import Object, Position, AsterEphemerides, MoonPhase, ASTERS, MONTHS, skyfield_to_moon_phase | |||||
| from .core import get_skf_objects, get_timescale, get_iau2000b | |||||
| RISEN_ANGLE = -0.8333 | RISEN_ANGLE = -0.8333 | ||||
| @@ -88,6 +88,7 @@ class EphemeridesComputer: | |||||
| rise_times, arr = find_discrete(start_time, end_time, is_risen) | rise_times, arr = find_discrete(start_time, end_time, is_risen) | ||||
| try: | try: | ||||
| culmination_time, _ = find_maxima(start_time, end_time, f=get_angle, epsilon=1./3600/24, num=12) | 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: | except ValueError: | ||||
| culmination_time = None | culmination_time = None | ||||
| @@ -98,12 +99,15 @@ class EphemeridesComputer: | |||||
| rise_time = rise_times[0] if arr[0] else None | rise_time = rise_times[0] if arr[0] else None | ||||
| set_time = rise_times[0] if not arr[0] else None | set_time = rise_times[0] if not arr[0] else None | ||||
| culmination_time = culmination_time[0] if culmination_time is not None else None | |||||
| # Convert the Time instances to Python datetime objects | # Convert the Time instances to Python datetime objects | ||||
| rise_time = rise_time.utc_datetime().replace(microsecond=0) | |||||
| culmination_time = culmination_time.utc_datetime().replace(microsecond=0) | |||||
| set_time = set_time.utc_datetime().replace(microsecond=0) | |||||
| 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) | aster.ephemerides = AsterEphemerides(rise_time, culmination_time, set_time) | ||||
| return aster | return aster | ||||
| @@ -19,10 +19,10 @@ | |||||
| from datetime import date as date_type | from datetime import date as date_type | ||||
| from skyfield.timelib import Time | from skyfield.timelib import Time | ||||
| from skyfield.almanac import find_discrete | |||||
| from skyfield.searchlib import find_discrete, find_maxima | |||||
| from .data import Event, Planet | |||||
| from .core import get_timescale, get_skf_objects, ASTERS, flatten_list | |||||
| from .data import Event, Planet, ASTERS | |||||
| from .core import get_timescale, get_skf_objects, flatten_list | |||||
| def _search_conjunction(start_time: Time, end_time: Time) -> [Event]: | def _search_conjunction(start_time: Time, end_time: Time) -> [Event]: | ||||
| @@ -91,11 +91,41 @@ def _search_oppositions(start_time: Time, end_time: Time) -> [Event]: | |||||
| return events | return events | ||||
| 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 search_events(date: date_type) -> [Event]: | def search_events(date: date_type) -> [Event]: | ||||
| start_time = get_timescale().utc(date.year, date.month, date.day) | start_time = get_timescale().utc(date.year, date.month, date.day) | ||||
| end_time = get_timescale().utc(date.year, date.month, date.day + 1) | end_time = get_timescale().utc(date.year, date.month, date.day + 1) | ||||
| return sorted(flatten_list([ | return sorted(flatten_list([ | ||||
| _search_oppositions(start_time, end_time), | _search_oppositions(start_time, end_time), | ||||
| _search_conjunction(start_time, end_time) | |||||
| _search_conjunction(start_time, end_time), | |||||
| _search_maximal_elongations(start_time, end_time) | |||||
| ]), key=lambda event: event.start_time) | ]), key=lambda event: event.start_time) | ||||
| @@ -8,7 +8,7 @@ msgid "" | |||||
| msgstr "" | msgstr "" | ||||
| "Project-Id-Version: kosmorro 0.5.2\n" | "Project-Id-Version: kosmorro 0.5.2\n" | ||||
| "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | ||||
| "POT-Creation-Date: 2020-02-17 20:58+0100\n" | |||||
| "POT-Creation-Date: 2020-02-21 20:14+0100\n" | |||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | "Language-Team: LANGUAGE <LL@li.org>\n" | ||||
| @@ -17,86 +17,91 @@ msgstr "" | |||||
| "Content-Transfer-Encoding: 8bit\n" | "Content-Transfer-Encoding: 8bit\n" | ||||
| "Generated-By: Babel 2.8.0\n" | "Generated-By: Babel 2.8.0\n" | ||||
| #: kosmorrolib/core.py:34 | |||||
| msgid "Sun" | |||||
| #: kosmorrolib/data.py:30 | |||||
| msgid "New Moon" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/core.py:35 | |||||
| msgid "Moon" | |||||
| #: kosmorrolib/data.py:31 | |||||
| msgid "Waxing crescent" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/core.py:36 | |||||
| msgid "Mercury" | |||||
| #: kosmorrolib/data.py:32 | |||||
| msgid "First Quarter" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/core.py:37 | |||||
| msgid "Venus" | |||||
| #: kosmorrolib/data.py:33 | |||||
| msgid "Waxing gibbous" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/core.py:38 | |||||
| msgid "Mars" | |||||
| #: kosmorrolib/data.py:34 | |||||
| msgid "Full Moon" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/core.py:39 | |||||
| msgid "Jupiter" | |||||
| #: kosmorrolib/data.py:35 | |||||
| msgid "Waning gibbous" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/core.py:40 | |||||
| msgid "Saturn" | |||||
| #: kosmorrolib/data.py:36 | |||||
| msgid "Last Quarter" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/core.py:41 | |||||
| msgid "Uranus" | |||||
| #: kosmorrolib/data.py:37 | |||||
| msgid "Waning crescent" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/core.py:42 | |||||
| msgid "Neptune" | |||||
| #: kosmorrolib/data.py:41 | |||||
| #, python-format | |||||
| msgid "%s is in opposition" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/core.py:43 | |||||
| msgid "Pluto" | |||||
| #: kosmorrolib/data.py:42 | |||||
| #, python-format | |||||
| msgid "%s and %s are in conjunction" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/data.py:28 | |||||
| msgid "New Moon" | |||||
| #: kosmorrolib/data.py:43 | |||||
| #, python-format | |||||
| msgid "%s's largest elongation" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/data.py:29 | |||||
| msgid "Waxing crescent" | |||||
| #: kosmorrolib/data.py:215 | |||||
| msgid "Sun" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/data.py:30 | |||||
| msgid "First Quarter" | |||||
| #: kosmorrolib/data.py:216 | |||||
| msgid "Moon" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/data.py:31 | |||||
| msgid "Waxing gibbous" | |||||
| #: kosmorrolib/data.py:217 | |||||
| msgid "Mercury" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/data.py:32 | |||||
| msgid "Full Moon" | |||||
| #: kosmorrolib/data.py:218 | |||||
| msgid "Venus" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/data.py:33 | |||||
| msgid "Waning gibbous" | |||||
| #: kosmorrolib/data.py:219 | |||||
| msgid "Mars" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/data.py:34 | |||||
| msgid "Last Quarter" | |||||
| #: kosmorrolib/data.py:220 | |||||
| msgid "Jupiter" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/data.py:35 | |||||
| msgid "Waning crescent" | |||||
| #: kosmorrolib/data.py:221 | |||||
| msgid "Saturn" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/data.py:39 | |||||
| #, python-format | |||||
| msgid "%s is in opposition" | |||||
| #: kosmorrolib/data.py:222 | |||||
| msgid "Uranus" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/data.py:40 | |||||
| #, python-format | |||||
| msgid "%s and %s are in conjunction" | |||||
| #: kosmorrolib/data.py:223 | |||||
| msgid "Neptune" | |||||
| msgstr "" | |||||
| #: kosmorrolib/data.py:224 | |||||
| msgid "Pluto" | |||||
| msgstr "" | msgstr "" | ||||
| #: kosmorrolib/dumper.py:35 | #: kosmorrolib/dumper.py:35 | ||||
| @@ -23,7 +23,17 @@ class DumperTestCase(unittest.TestCase): | |||||
| ' "Mars"\n' | ' "Mars"\n' | ||||
| ' ],\n' | ' ],\n' | ||||
| ' "start_time": "2019-10-14T23:00:00",\n' | ' "start_time": "2019-10-14T23:00:00",\n' | ||||
| ' "end_time": null\n' | |||||
| ' "end_time": null,\n' | |||||
| ' "details": null\n' | |||||
| ' },\n' | |||||
| ' {\n' | |||||
| ' "event_type": "MAXIMAL_ELONGATION",\n' | |||||
| ' "objects": [\n' | |||||
| ' "Venus"\n' | |||||
| ' ],\n' | |||||
| ' "start_time": "2019-10-14T12:00:00",\n' | |||||
| ' "end_time": null,\n' | |||||
| ' "details": "42.0\\u00b0"\n' | |||||
| ' }\n' | ' }\n' | ||||
| ' ],\n' | ' ],\n' | ||||
| ' "ephemerides": [\n' | ' "ephemerides": [\n' | ||||
| @@ -52,7 +62,17 @@ class DumperTestCase(unittest.TestCase): | |||||
| ' "Mars"\n' | ' "Mars"\n' | ||||
| ' ],\n' | ' ],\n' | ||||
| ' "start_time": "2019-10-14T23:00:00",\n' | ' "start_time": "2019-10-14T23:00:00",\n' | ||||
| ' "end_time": null\n' | |||||
| ' "end_time": null,\n' | |||||
| ' "details": null\n' | |||||
| ' },\n' | |||||
| ' {\n' | |||||
| ' "event_type": "MAXIMAL_ELONGATION",\n' | |||||
| ' "objects": [\n' | |||||
| ' "Venus"\n' | |||||
| ' ],\n' | |||||
| ' "start_time": "2019-10-14T12:00:00",\n' | |||||
| ' "end_time": null,\n' | |||||
| ' "details": "42.0\\u00b0"\n' | |||||
| ' }\n' | ' }\n' | ||||
| ' ],\n' | ' ],\n' | ||||
| ' "ephemerides": [\n' | ' "ephemerides": [\n' | ||||
| @@ -92,15 +112,16 @@ class DumperTestCase(unittest.TestCase): | |||||
| def test_text_dumper_with_events(self): | def test_text_dumper_with_events(self): | ||||
| ephemerides = self._get_data() | ephemerides = self._get_data() | ||||
| self.assertEqual('Monday October 14, 2019\n\n' | |||||
| 'Object Rise time Culmination time Set time\n' | |||||
| '-------- ----------- ------------------ ----------\n' | |||||
| 'Mars - - -\n\n' | |||||
| 'Moon phase: Full Moon\n' | |||||
| 'Last Quarter on Monday October 21, 2019 at 00:00\n\n' | |||||
| 'Expected events:\n' | |||||
| '23:00 Mars is in opposition\n\n' | |||||
| 'Note: All the hours are given in UTC.', | |||||
| self.assertEqual("Monday October 14, 2019\n\n" | |||||
| "Object Rise time Culmination time Set time\n" | |||||
| "-------- ----------- ------------------ ----------\n" | |||||
| "Mars - - -\n\n" | |||||
| "Moon phase: Full Moon\n" | |||||
| "Last Quarter on Monday October 21, 2019 at 00:00\n\n" | |||||
| "Expected events:\n" | |||||
| "23:00 Mars is in opposition\n" | |||||
| "12:00 Venus's largest elongation (42.0°)\n\n" | |||||
| "Note: All the hours are given in UTC.", | |||||
| TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) | TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) | ||||
| def test_text_dumper_without_ephemerides_and_with_events(self): | def test_text_dumper_without_ephemerides_and_with_events(self): | ||||
| @@ -109,7 +130,8 @@ class DumperTestCase(unittest.TestCase): | |||||
| 'Moon phase: Full Moon\n' | 'Moon phase: Full Moon\n' | ||||
| 'Last Quarter on Monday October 21, 2019 at 00:00\n\n' | 'Last Quarter on Monday October 21, 2019 at 00:00\n\n' | ||||
| 'Expected events:\n' | 'Expected events:\n' | ||||
| '23:00 Mars is in opposition\n\n' | |||||
| '23:00 Mars is in opposition\n' | |||||
| "12:00 Venus's largest elongation (42.0°)\n\n" | |||||
| 'Note: All the hours are given in UTC.', | 'Note: All the hours are given in UTC.', | ||||
| TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) | TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) | ||||
| @@ -122,7 +144,8 @@ class DumperTestCase(unittest.TestCase): | |||||
| 'Moon phase: Full Moon\n' | 'Moon phase: Full Moon\n' | ||||
| 'Last Quarter on Monday October 21, 2019 at 01:00\n\n' | 'Last Quarter on Monday October 21, 2019 at 01:00\n\n' | ||||
| 'Expected events:\n' | 'Expected events:\n' | ||||
| 'Oct 15, 00:00 Mars is in opposition\n\n' | |||||
| 'Oct 15, 00:00 Mars is in opposition\n' | |||||
| "13:00 Venus's largest elongation (42.0°)\n\n" | |||||
| 'Note: All the hours are given in the UTC+1 timezone.', | 'Note: All the hours are given in the UTC+1 timezone.', | ||||
| TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False, timezone=1).to_string()) | TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False, timezone=1).to_string()) | ||||
| @@ -134,7 +157,8 @@ class DumperTestCase(unittest.TestCase): | |||||
| 'Moon phase: Full Moon\n' | 'Moon phase: Full Moon\n' | ||||
| 'Last Quarter on Sunday October 20, 2019 at 23:00\n\n' | 'Last Quarter on Sunday October 20, 2019 at 23:00\n\n' | ||||
| 'Expected events:\n' | 'Expected events:\n' | ||||
| '22:00 Mars is in opposition\n\n' | |||||
| '22:00 Mars is in opposition\n' | |||||
| "11:00 Venus's largest elongation (42.0°)\n\n" | |||||
| 'Note: All the hours are given in the UTC-1 timezone.', | 'Note: All the hours are given in the UTC-1 timezone.', | ||||
| TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False, timezone=-1).to_string()) | TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False, timezone=-1).to_string()) | ||||
| @@ -146,6 +170,7 @@ class DumperTestCase(unittest.TestCase): | |||||
| self.assertRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') | self.assertRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') | ||||
| self.assertRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') | self.assertRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') | ||||
| self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}') | self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}') | ||||
| self.assertRegex(latex, r"\\event\{12:00\}\{Venus's largest elongation \(42.0°\)\}") | |||||
| latex = _LatexDumper(self._get_data(aster_rise_set=True), | latex = _LatexDumper(self._get_data(aster_rise_set=True), | ||||
| self._get_events(), date=date(2019, 10, 14)).to_string() | self._get_events(), date=date(2019, 10, 14)).to_string() | ||||
| @@ -157,6 +182,7 @@ class DumperTestCase(unittest.TestCase): | |||||
| self.assertRegex(latex, 'Full Moon') | self.assertRegex(latex, 'Full Moon') | ||||
| self.assertRegex(latex, r'\\section{\\sffamily Expected events}') | self.assertRegex(latex, r'\\section{\\sffamily Expected events}') | ||||
| self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}') | self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}') | ||||
| self.assertRegex(latex, r"\\event\{12:00\}\{Venus's largest elongation \(42.0°\)\}") | |||||
| self.assertNotRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') | self.assertNotRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') | ||||
| self.assertNotRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') | self.assertNotRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') | ||||
| @@ -186,7 +212,10 @@ class DumperTestCase(unittest.TestCase): | |||||
| def _get_events(): | def _get_events(): | ||||
| return [Event('OPPOSITION', | return [Event('OPPOSITION', | ||||
| [Planet('Mars', 'MARS')], | [Planet('Mars', 'MARS')], | ||||
| datetime(2019, 10, 14, 23, 00)) | |||||
| datetime(2019, 10, 14, 23, 00)), | |||||
| Event('MAXIMAL_ELONGATION', | |||||
| [Planet('Venus', 'VENUS')], | |||||
| datetime(2019, 10, 14, 12, 00), details='42.0°'), | |||||
| ] | ] | ||||
| @@ -55,6 +55,33 @@ class MyTestCase(unittest.TestCase): | |||||
| i += 1 | i += 1 | ||||
| def test_find_maximal_elongation(self): | |||||
| e = events.search_events(date(2020, 2, 10)) | |||||
| self.assertEquals(1, len(e), 'Expected 1 events, got %d.' % len(e)) | |||||
| e = e[0] | |||||
| self.assertEquals('MAXIMAL_ELONGATION', e.event_type) | |||||
| self.assertEquals(1, len(e.objects)) | |||||
| self.assertEquals('MERCURY', e.objects[0].skyfield_name) | |||||
| self.assertEqual('18.2°', e.details) | |||||
| self.assertEquals((2020, 2, 10, 13, 46), (e.start_time.year, e.start_time.month, e.start_time.day, | |||||
| e.start_time.hour, e.start_time.minute)) | |||||
| e = events.search_events(date(2020, 3, 24)) | |||||
| self.assertEquals(2, len(e), 'Expected 2 events, got %d.' % len(e)) | |||||
| self.assertEquals('MAXIMAL_ELONGATION', e[0].event_type) | |||||
| self.assertEquals(1, len(e[0].objects)) | |||||
| self.assertEquals('MERCURY', e[0].objects[0].skyfield_name) | |||||
| self.assertEqual('27.8°', e[0].details) | |||||
| self.assertEquals((2020, 3, 24, 1, 56), (e[0].start_time.year, e[0].start_time.month, e[0].start_time.day, | |||||
| e[0].start_time.hour, e[0].start_time.minute)) | |||||
| self.assertEquals('MAXIMAL_ELONGATION', e[1].event_type) | |||||
| self.assertEquals(1, len(e[1].objects)) | |||||
| self.assertEquals('VENUS', e[1].objects[0].skyfield_name) | |||||
| self.assertEqual('46.1°', e[1].details) | |||||
| self.assertEquals((2020, 3, 24, 21, 58), (e[1].start_time.year, e[1].start_time.month, e[1].start_time.day, | |||||
| e[1].start_time.hour, e[1].start_time.minute)) | |||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||
| unittest.main() | unittest.main() | ||||