Browse Source

feat(event): add support for Earth seasons (#24)

* chore: fix files to commit on tag

* fix(ephemerides): fix a bug that made the ephemerides calculations impossible for the Poles (#21)

* chore: fix the target branch on Dependabot's config

* ci: remove Commitlint workflow (replaced by semantic-pull-request) (#25)

* ci: remove Commitlint workflow (replaced by semantic-pull-request)

* ci: fix doctests not running correctly on some OS and Python versions

* Add season change event in events.py and enum.py

* Add minor change in season change event

* Add documentation, change enum constants, change output object of _search_earth_season_change

* Minor changes to _search_earth_season_change

* Update EventType enum, update class of details

* Fix minor bugs

* docs: Update docs for _search_earth_season_change and _search_conjunction.chore: make minor changes to _search_earth_season_change

* Update: minor changes to match Python coding style.

* Update: minor changes to match Python coding style. Docs: update docstring of _search_earth_season_change and _search_conjunction

* test:update legacy tests for events.py. update: update enum.py and events.py to match black coding style.

* Fix some minor issues with Black and Event.details field

Co-authored-by: Jérôme Deuchnord <jerome@deuchnord.fr>
Co-authored-by: Jérôme Deuchnord <Deuchnord@users.noreply.github.com>

BREAKING CHANGE: the `Event.details` field is now a dictionary (was previously a string).
pull/22/head
LiamNg 3 years ago
committed by GitHub
parent
commit
5e537f6ef2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 102 additions and 39 deletions
  1. +1
    -1
      .github/dependabot.yml
  2. +0
    -21
      .github/workflows/commitlint.yml
  3. +2
    -2
      .github/workflows/tests.yml
  4. +1
    -1
      Makefile
  5. +9
    -1
      kosmorrolib/enum.py
  6. +19
    -1
      kosmorrolib/ephemerides.py
  7. +66
    -8
      kosmorrolib/events.py
  8. +1
    -1
      kosmorrolib/model.py
  9. +3
    -3
      tests/events.py

+ 1
- 1
.github/dependabot.yml View File

@@ -7,7 +7,7 @@ updates:
interval: daily
time: "04:00"
open-pull-requests-limit: 10
target-branch: master
target-branch: main
reviewers:
- Deuchnord
commit-message:


+ 0
- 21
.github/workflows/commitlint.yml View File

@@ -1,21 +0,0 @@
name: Commit

on:
push:
branches: [main, features]
pull_request:
branches: [main, features]

jobs:
commitlint:
name: Message validation
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: wagoid/commitlint-github-action@v2
with:
helpURL: 'https://github.com/Kosmorro/kosmorro/blob/master/CONTRIBUTING.md#commiting'


+ 2
- 2
.github/workflows/tests.yml View File

@@ -108,8 +108,8 @@ jobs:
run: |
make coverage-doctests

- name: Run doc tests
if: ${{ matrix.os != 'ubuntu-20.04' && matrix.python_version != '3.9' }}
- name: Run doc tests (without coverage)
if: ${{ matrix.os != 'ubuntu-20.04' || matrix.python_version != '3.9' }}
run: |
make doctests



+ 1
- 1
Makefile View File

@@ -33,7 +33,7 @@ changelog:
@echo -e " When everything is good, finish the release with 'make tag'."

tag: env
git add CHANGELOG.md
git add CHANGELOG.md kosmorrolib/__version__.py
git commit -m "build: bump version $$RELEASE_NUMBER"
git tag "v$$RELEASE_NUMBER"
git checkout features


+ 9
- 1
kosmorrolib/enum.py View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3

from enum import Enum, auto
from enum import Enum


class MoonPhaseType(Enum):
@@ -16,6 +16,13 @@ class MoonPhaseType(Enum):
WANING_CRESCENT = 8


class SeasonType(Enum):
MARCH_EQUINOX = 0
JUNE_SOLSTICE = 1
SEPTEMBER_EQUINOX = 2
DECEMBER_SOLSTICE = 3


class EventType(Enum):
"""An enumeration for the supported event types."""

@@ -25,6 +32,7 @@ class EventType(Enum):
MAXIMAL_ELONGATION = 4
MOON_PERIGEE = 5
MOON_APOGEE = 6
SEASON_CHANGE = 7


class ObjectType(Enum):


+ 19
- 1
kosmorrolib/ephemerides.py View File

@@ -127,6 +127,22 @@ def get_ephemerides(

>>> get_ephemerides(pos, datetime.date(2021, 6, 9), timezone=2)
[<AsterEphemerides rise_time=2021-06-09 05:36:00 culmination_time=2021-06-09 13:47:00 set_time=2021-06-09 21:58:00 aster=<Object type=STAR name=SUN />>, <AsterEphemerides rise_time=2021-06-09 04:59:00 culmination_time=2021-06-09 13:02:00 set_time=2021-06-09 21:16:00 aster=<Object type=SATELLITE name=MOON />>, <AsterEphemerides rise_time=2021-06-09 06:06:00 culmination_time=2021-06-09 13:58:00 set_time=2021-06-09 21:49:00 aster=<Object type=PLANET name=MERCURY />>, <AsterEphemerides rise_time=2021-06-09 06:52:00 culmination_time=2021-06-09 15:13:00 set_time=2021-06-09 23:34:00 aster=<Object type=PLANET name=VENUS />>, <AsterEphemerides rise_time=2021-06-09 08:38:00 culmination_time=2021-06-09 16:40:00 set_time=2021-06-09 00:44:00 aster=<Object type=PLANET name=MARS />>, <AsterEphemerides rise_time=2021-06-09 01:47:00 culmination_time=2021-06-09 06:54:00 set_time=2021-06-09 12:01:00 aster=<Object type=PLANET name=JUPITER />>, <AsterEphemerides rise_time=2021-06-09 01:06:00 culmination_time=2021-06-09 05:41:00 set_time=2021-06-09 10:16:00 aster=<Object type=PLANET name=SATURN />>, <AsterEphemerides rise_time=2021-06-09 03:56:00 culmination_time=2021-06-09 11:18:00 set_time=2021-06-09 18:40:00 aster=<Object type=PLANET name=URANUS />>, <AsterEphemerides rise_time=2021-06-09 02:27:00 culmination_time=2021-06-09 08:13:00 set_time=2021-06-09 13:59:00 aster=<Object type=PLANET name=NEPTUNE />>, <AsterEphemerides rise_time=2021-06-09 00:26:00 culmination_time=2021-06-09 04:32:00 set_time=2021-06-09 08:38:00 aster=<Object type=PLANET name=PLUTO />>]

If an objet does not rise nor set due to your latitude, then both rise and set will be `None`:

>>> north_pole = Position(70, 20)
>>> south_pole = Position(-70, 20)
>>> get_ephemerides(north_pole, datetime.date(2021, 6, 20))
[<AsterEphemerides rise_time=None culmination_time=2021-06-20 10:42:00 set_time=None aster=<Object type=STAR name=SUN />>, <AsterEphemerides rise_time=2021-06-20 14:30:00 culmination_time=2021-06-20 18:44:00 set_time=2021-06-20 22:53:00 aster=<Object type=SATELLITE name=MOON />>, <AsterEphemerides rise_time=2021-06-20 22:56:00 culmination_time=2021-06-20 09:47:00 set_time=2021-06-20 20:34:00 aster=<Object type=PLANET name=MERCURY />>, <AsterEphemerides rise_time=None culmination_time=2021-06-20 12:20:00 set_time=None aster=<Object type=PLANET name=VENUS />>, <AsterEphemerides rise_time=None culmination_time=2021-06-20 13:17:00 set_time=None aster=<Object type=PLANET name=MARS />>, <AsterEphemerides rise_time=2021-06-20 23:06:00 culmination_time=2021-06-20 03:04:00 set_time=2021-06-20 06:58:00 aster=<Object type=PLANET name=JUPITER />>, <AsterEphemerides rise_time=2021-06-20 23:28:00 culmination_time=2021-06-20 01:48:00 set_time=2021-06-20 04:05:00 aster=<Object type=PLANET name=SATURN />>, <AsterEphemerides rise_time=2021-06-20 21:53:00 culmination_time=2021-06-20 07:29:00 set_time=2021-06-20 17:02:00 aster=<Object type=PLANET name=URANUS />>, <AsterEphemerides rise_time=2021-06-20 22:51:00 culmination_time=2021-06-20 04:22:00 set_time=2021-06-20 09:50:00 aster=<Object type=PLANET name=NEPTUNE />>, <AsterEphemerides rise_time=None culmination_time=2021-06-20 00:40:00 set_time=None aster=<Object type=PLANET name=PLUTO />>]

>>> get_ephemerides(north_pole, datetime.date(2021, 12, 21))
[<AsterEphemerides rise_time=None culmination_time=2021-12-21 10:38:00 set_time=None aster=<Object type=STAR name=SUN />>, <AsterEphemerides rise_time=None culmination_time=2021-12-21 00:04:00 set_time=None aster=<Object type=SATELLITE name=MOON />>, <AsterEphemerides rise_time=None culmination_time=2021-12-21 11:33:00 set_time=None aster=<Object type=PLANET name=MERCURY />>, <AsterEphemerides rise_time=2021-12-21 11:58:00 culmination_time=2021-12-21 12:33:00 set_time=2021-12-21 13:08:00 aster=<Object type=PLANET name=VENUS />>, <AsterEphemerides rise_time=None culmination_time=2021-12-21 08:54:00 set_time=None aster=<Object type=PLANET name=MARS />>, <AsterEphemerides rise_time=2021-12-21 11:07:00 culmination_time=2021-12-21 14:43:00 set_time=2021-12-21 18:19:00 aster=<Object type=PLANET name=JUPITER />>, <AsterEphemerides rise_time=2021-12-21 11:32:00 culmination_time=2021-12-21 13:33:00 set_time=2021-12-21 15:33:00 aster=<Object type=PLANET name=SATURN />>, <AsterEphemerides rise_time=2021-12-21 09:54:00 culmination_time=2021-12-21 19:13:00 set_time=2021-12-21 04:37:00 aster=<Object type=PLANET name=URANUS />>, <AsterEphemerides rise_time=2021-12-21 10:49:00 culmination_time=2021-12-21 16:05:00 set_time=2021-12-21 21:21:00 aster=<Object type=PLANET name=NEPTUNE />>, <AsterEphemerides rise_time=None culmination_time=2021-12-21 12:31:00 set_time=None aster=<Object type=PLANET name=PLUTO />>]

>>> get_ephemerides(south_pole, datetime.date(2021, 6, 20))
[<AsterEphemerides rise_time=None culmination_time=2021-06-20 10:42:00 set_time=None aster=<Object type=STAR name=SUN />>, <AsterEphemerides rise_time=2021-06-20 11:10:00 culmination_time=2021-06-20 19:06:00 set_time=2021-06-20 01:20:00 aster=<Object type=SATELLITE name=MOON />>, <AsterEphemerides rise_time=2021-06-20 07:47:00 culmination_time=2021-06-20 09:47:00 set_time=2021-06-20 11:48:00 aster=<Object type=PLANET name=MERCURY />>, <AsterEphemerides rise_time=None culmination_time=2021-06-20 12:20:00 set_time=None aster=<Object type=PLANET name=VENUS />>, <AsterEphemerides rise_time=2021-06-20 12:14:00 culmination_time=2021-06-20 13:17:00 set_time=2021-06-20 14:21:00 aster=<Object type=PLANET name=MARS />>, <AsterEphemerides rise_time=2021-06-20 18:32:00 culmination_time=2021-06-20 03:04:00 set_time=2021-06-20 11:32:00 aster=<Object type=PLANET name=JUPITER />>, <AsterEphemerides rise_time=2021-06-20 15:20:00 culmination_time=2021-06-20 01:48:00 set_time=2021-06-20 12:12:00 aster=<Object type=PLANET name=SATURN />>, <AsterEphemerides rise_time=2021-06-20 04:32:00 culmination_time=2021-06-20 07:29:00 set_time=2021-06-20 10:26:00 aster=<Object type=PLANET name=URANUS />>, <AsterEphemerides rise_time=2021-06-20 21:28:00 culmination_time=2021-06-20 04:22:00 set_time=2021-06-20 11:13:00 aster=<Object type=PLANET name=NEPTUNE />>, <AsterEphemerides rise_time=None culmination_time=2021-06-20 00:40:00 set_time=None aster=<Object type=PLANET name=PLUTO />>]

>>> get_ephemerides(south_pole, datetime.date(2021, 12, 22))
[<AsterEphemerides rise_time=None culmination_time=2021-12-22 10:39:00 set_time=None aster=<Object type=STAR name=SUN />>, <AsterEphemerides rise_time=None culmination_time=2021-12-22 01:01:00 set_time=None aster=<Object type=SATELLITE name=MOON />>, <AsterEphemerides rise_time=None culmination_time=2021-12-22 11:35:00 set_time=None aster=<Object type=PLANET name=MERCURY />>, <AsterEphemerides rise_time=None culmination_time=2021-12-22 12:27:00 set_time=None aster=<Object type=PLANET name=VENUS />>, <AsterEphemerides rise_time=None culmination_time=2021-12-22 08:53:00 set_time=None aster=<Object type=PLANET name=MARS />>, <AsterEphemerides rise_time=2021-12-22 05:52:00 culmination_time=2021-12-22 14:40:00 set_time=2021-12-22 23:26:00 aster=<Object type=PLANET name=JUPITER />>, <AsterEphemerides rise_time=2021-12-22 02:41:00 culmination_time=2021-12-22 13:29:00 set_time=2021-12-22 00:21:00 aster=<Object type=PLANET name=SATURN />>, <AsterEphemerides rise_time=2021-12-22 16:01:00 culmination_time=2021-12-22 19:09:00 set_time=2021-12-22 22:17:00 aster=<Object type=PLANET name=URANUS />>, <AsterEphemerides rise_time=2021-12-22 08:59:00 culmination_time=2021-12-22 16:01:00 set_time=2021-12-22 23:04:00 aster=<Object type=PLANET name=NEPTUNE />>, <AsterEphemerides rise_time=None culmination_time=2021-12-22 12:27:00 set_time=None aster=<Object type=PLANET name=PLUTO />>]
"""
ephemerides = []

@@ -173,10 +189,12 @@ def get_ephemerides(
except ValueError:
culmination_time = None

rise_time, set_time = None, 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:
elif len(rise_times) == 1:
rise_time = rise_times[0] if arr[0] else None
set_time = rise_times[0] if not arr[0] else None



+ 66
- 8
kosmorrolib/events.py View File

@@ -5,16 +5,34 @@ from datetime import date
from skyfield.errors import EphemerisRangeError
from skyfield.timelib import Time
from skyfield.searchlib import find_discrete, find_maxima, find_minima
from skyfield import almanac
from numpy import pi

from .model import Event, Star, Planet, ASTERS
from .dateutil import translate_to_timezone
from .enum import EventType, ObjectIdentifier
from .exceptions import OutOfRangeDateError
from .core import get_timescale, get_skf_objects, flatten_list
from kosmorrolib.model import Event, Star, Planet, ASTERS
from kosmorrolib.dateutil import translate_to_timezone
from kosmorrolib.enum import EventType, ObjectIdentifier, SeasonType
from kosmorrolib.exceptions import OutOfRangeDateError
from kosmorrolib.core import get_timescale, get_skf_objects, flatten_list


def _search_conjunction(start_time: Time, end_time: Time, timezone: int) -> [Event]:
"""Function to search conjunction.

**Warning:** this is an internal function, not intended for use by end-developers.

Will return MOON and VENUS opposition on 2021-06-12:

>>> conjunction = _search_conjunction(get_timescale().utc(2021,6,12),get_timescale().utc(2021,6,13),0)
>>> len(conjunction)
1
>>> conjunction[0].objects
[<Object type=SATELLITE name=MOON />, <Object type=PLANET name=VENUS />]

Will return nothing if no conjunction happens:

>>> _search_conjunction(get_timescale().utc(2021,6,17),get_timescale().utc(2021,6,18),0)
[]
"""
earth = get_skf_objects()["earth"]
aster1 = None
aster2 = None
@@ -177,13 +195,13 @@ def _search_maximal_elongations(
)

for i, time in enumerate(times):
elongation = elongations[i]
elongation = round(elongations[i], 1)
events.append(
Event(
EventType.MAXIMAL_ELONGATION,
[aster],
translate_to_timezone(time.utc_datetime(), timezone),
details="{:.3n}°".format(elongation),
details={"deg": elongation},
)
)

@@ -245,6 +263,45 @@ def _search_moon_perigee(start_time: Time, end_time: Time, timezone: int) -> [Ev
return events


def _search_earth_season_change(
start_time: Time, end_time: Time, timezone: int
) -> [Event]:
"""Function to find earth season change event.

**Warning:** this is an internal function, not intended for use by end-developers.

Will return JUNE SOLSTICE on 2020/06/20:

>>> season_change = _search_earth_season_change(get_timescale().utc(2020, 6, 20), get_timescale().utc(2020, 6, 21), 0)
>>> len(season_change)
1
>>> season_change[0].event_type
<EventType.SEASON_CHANGE: 7>
>>> season_change[0].details
{'season': <SeasonType.JUNE_SOLSTICE: 1>}

Will return nothing if there is no season change event in the period of time being calculated:

>>> _search_earth_season_change(get_timescale().utc(2021, 6, 17), get_timescale().utc(2021, 6, 18), 0)
[]
"""
events = []
event_time, event_id = almanac.find_discrete(
start_time, end_time, almanac.seasons(get_skf_objects())
)
if len(event_time) == 0:
return []
events.append(
Event(
EventType.SEASON_CHANGE,
[],
translate_to_timezone(event_time.utc_datetime()[0], timezone),
details={"season": SeasonType(event_id[0])},
)
)
return events


def get_events(for_date: date = date.today(), timezone: int = 0) -> [Event]:
"""Calculate and return a list of events for the given date, adjusted to the given timezone if any.

@@ -265,7 +322,7 @@ def get_events(for_date: date = date.today(), timezone: int = 0) -> [Event]:

If there is no events for the given date, then an empty list is returned:

>>> get_events(date(2021, 3, 20))
>>> get_events(date(2021, 4, 20))
[]

:param for_date: the date for which the events must be calculated
@@ -289,6 +346,7 @@ def get_events(for_date: date = date.today(), timezone: int = 0) -> [Event]:
_search_maximal_elongations,
_search_moon_apogee,
_search_moon_perigee,
_search_earth_season_change,
]:
found_events.append(fun(start_time, end_time, timezone))



+ 1
- 1
kosmorrolib/model.py View File

@@ -154,7 +154,7 @@ class Event(Serializable):
objects: [Object],
start_time: datetime,
end_time: Union[datetime, None] = None,
details: str = None,
details: {str: any} = None,
):
self.event_type = event_type
self.objects = objects


+ 3
- 3
tests/events.py View File

@@ -74,7 +74,7 @@ EXPECTED_EVENTS = [
EventType.MAXIMAL_ELONGATION,
[ASTERS[2]],
datetime(2020, 2, 10, 13, 46),
details="18.2°",
details={"deg": 18.2},
),
Event(EventType.MOON_PERIGEE, [ASTERS[1]], datetime(2020, 2, 10, 20, 34)),
],
@@ -86,14 +86,14 @@ EXPECTED_EVENTS = [
EventType.MAXIMAL_ELONGATION,
[ASTERS[2]],
datetime(2020, 3, 24, 1, 56),
details="27.8°",
details={"deg": 27.8},
),
Event(EventType.MOON_APOGEE, [ASTERS[1]], datetime(2020, 3, 24, 15, 39)),
Event(
EventType.MAXIMAL_ELONGATION,
[ASTERS[3]],
datetime(2020, 3, 24, 21, 58),
details="46.1°",
details={"deg": 46.1},
),
],
),


Loading…
Cancel
Save