Skip to content

Commit 7211bf0

Browse files
committed
feat: add options to localize seasons
1 parent c0de2d6 commit 7211bf0

3 files changed

Lines changed: 101 additions & 36 deletions

File tree

kosmorrolib/enum.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,60 @@ class SeasonType(Enum):
3838
SEPTEMBER_EQUINOX = 2
3939
DECEMBER_SOLSTICE = 3
4040

41+
def localize(self, position: Position) -> LocalizedSeasonType:
42+
"""Return the local season that corresponds to the given position's latitude.
43+
44+
Args:
45+
season (SeasonType): The season to localize.
46+
position (Position): The position to localize the season for.
47+
48+
Returns:
49+
SeasonType: The localized season.
50+
51+
Raises:
52+
ValueError: If the latitude is 0 (equator).
53+
54+
)
55+
56+
>>> from kosmorrolib import Position
57+
>>> SeasonType.MARCH_EQUINOX.localize(Position(0, 1))
58+
Traceback (most recent call last):
59+
...
60+
ValueError: Cannot localize seasons for this latitude.
61+
62+
>>> SeasonType.MARCH_EQUINOX.localize(Position(1, 1))
63+
<LocalizedSeasonType.SPRING: 1>
64+
65+
>>> SeasonType.MARCH_EQUINOX.localize(Position(-1, 1))
66+
<LocalizedSeasonType.AUTUMN: 3>
67+
"""
68+
if position.latitude == 0: # Equator
69+
raise ValueError("Cannot localize seasons for this latitude.")
70+
71+
if position.latitude < 0: # Southern hemisphere
72+
seasons = {
73+
self.MARCH_EQUINOX: LocalizedSeasonType.AUTUMN,
74+
self.JUNE_SOLSTICE: LocalizedSeasonType.WINTER,
75+
self.SEPTEMBER_EQUINOX: LocalizedSeasonType.SPRING,
76+
self.DECEMBER_SOLSTICE: LocalizedSeasonType.SUMMER,
77+
}
78+
79+
else: # Nothern hemisphere
80+
seasons = {
81+
self.MARCH_EQUINOX: LocalizedSeasonType.SPRING,
82+
self.JUNE_SOLSTICE: LocalizedSeasonType.SUMMER,
83+
self.SEPTEMBER_EQUINOX: LocalizedSeasonType.AUTUMN,
84+
self.DECEMBER_SOLSTICE: LocalizedSeasonType.WINTER,
85+
}
86+
87+
return seasons[self]
88+
89+
90+
class LocalizedSeasonType(Enum):
91+
WINTER = 0
92+
SPRING = 1
93+
SUMMER = 2
94+
AUTUMN = 3
4195

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

kosmorrolib/events.py

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from kosmorrolib.model import (
2929
Event,
3030
Object,
31+
Position,
3132
Star,
3233
Planet,
3334
get_aster,
@@ -347,43 +348,52 @@ def f(start_time: Time, end_time: Time, timezone: int) -> [Event]:
347348
return f
348349

349350

350-
def _search_earth_season_change(
351-
start_time: Time, end_time: Time, timezone: int
352-
) -> [Event]:
353-
"""Function to find earth season change event.
351+
def _search_earth_season_change(position: Position|None):
352+
def f(
353+
start_time: Time, end_time: Time, timezone: int
354+
) -> [Event]:
355+
"""Function to find earth season change event.
354356
355-
**Warning:** this is an internal function, not intended for use by end-developers.
357+
**Warning:** this is an internal function, not intended for use by end-developers.
356358
357-
Will return JUNE SOLSTICE on 2020/06/20:
359+
Will return JUNE SOLSTICE on 2020/06/20:
358360
359-
>>> season_change = _search_earth_season_change(get_timescale().utc(2020, 6, 20), get_timescale().utc(2020, 6, 21), 0)
360-
>>> len(season_change)
361-
1
362-
>>> season_change[0].event_type
363-
<EventType.SEASON_CHANGE: 7>
364-
>>> season_change[0].details
365-
{'season': <SeasonType.JUNE_SOLSTICE: 1>}
361+
>>> season_change = _search_earth_season_change(get_timescale().utc(2020, 6, 20), get_timescale().utc(2020, 6, 21), 0)
362+
>>> len(season_change)
363+
1
364+
>>> season_change[0].event_type
365+
<EventType.SEASON_CHANGE: 7>
366+
>>> season_change[0].details
367+
{'season': <SeasonType.JUNE_SOLSTICE: 1>}
366368
367-
Will return nothing if there is no season change event in the period of time being calculated:
369+
Will return nothing if there is no season change event in the period of time being calculated:
368370
369-
>>> _search_earth_season_change(get_timescale().utc(2021, 6, 17), get_timescale().utc(2021, 6, 18), 0)
370-
[]
371-
"""
372-
events = []
373-
event_time, event_id = almanac.find_discrete(
374-
start_time, end_time, almanac.seasons(get_skf_objects())
375-
)
376-
if len(event_time) == 0:
377-
return []
378-
events.append(
379-
Event(
380-
EventType.SEASON_CHANGE,
381-
[],
382-
translate_to_timezone(event_time.utc_datetime()[0], timezone),
383-
details={"season": SeasonType(event_id[0])},
371+
>>> _search_earth_season_change(get_timescale().utc(2021, 6, 17), get_timescale().utc(2021, 6, 18), 0)
372+
[]
373+
"""
374+
events = []
375+
event_time, event_id = almanac.find_discrete(
376+
start_time, end_time, almanac.seasons(get_skf_objects())
384377
)
385-
)
386-
return events
378+
if len(event_time) == 0:
379+
return []
380+
381+
season = SeasonType(event_id[0])
382+
383+
if position is not None:
384+
season = season.localize(position)
385+
386+
events.append(
387+
Event(
388+
EventType.SEASON_CHANGE,
389+
[],
390+
translate_to_timezone(event_time.utc_datetime()[0], timezone),
391+
details={"season": season},
392+
)
393+
)
394+
return events
395+
396+
return f
387397

388398

389399
def _search_lunar_eclipse(start_time: Time, end_time: Time, timezone: int) -> [Event]:
@@ -458,7 +468,7 @@ def is_in_penumbra(time: Time):
458468
return events
459469

460470

461-
def get_events(for_date: date = date.today(), timezone: int = 0) -> [Event]:
471+
def get_events(for_date: date = date.today(), timezone: int = 0, position: Position|None = None) -> [Event]:
462472
"""Calculate and return a list of events for the given date, adjusted to the given timezone if any.
463473
464474
Find events that happen on April 4th, 2020 (show hours in UTC):
@@ -491,6 +501,7 @@ def get_events(for_date: date = date.today(), timezone: int = 0) -> [Event]:
491501
492502
:param for_date: the date for which the events must be calculated
493503
:param timezone: the timezone to adapt the results to. If not given, defaults to 0.
504+
:param position: the position to localize the events to.
494505
:return: a list of events found for the given date.
495506
"""
496507

@@ -512,7 +523,7 @@ def get_events(for_date: date = date.today(), timezone: int = 0) -> [Event]:
512523
_search_perigee(ASTERS[1]),
513524
_search_apogee(EARTH, from_aster=ASTERS[0]),
514525
_search_perigee(EARTH, from_aster=ASTERS[0]),
515-
_search_earth_season_change,
526+
_search_earth_season_change(position),
516527
_search_lunar_eclipse,
517528
]:
518529
found_events.append(fun(start_time, end_time, timezone))
@@ -529,7 +540,7 @@ def get_events(for_date: date = date.today(), timezone: int = 0) -> [Event]:
529540

530541

531542
def search_events(
532-
event_types: [EventType], end: date, start: date = date.today(), timezone: int = 0
543+
event_types: [EventType], end: date, start: date = date.today(), timezone: int = 0, position: Position|None = None
533544
) -> [Event]:
534545
"""Search between `start` and `end` dates, and return a list of matching events for the given time range, adjusted to a given timezone.
535546
@@ -606,7 +617,7 @@ def search_all_perigee_events(start: date, end: date, timezone: int = 0) -> [Eve
606617
EventType.MAXIMAL_ELONGATION: _search_maximal_elongations,
607618
EventType.APOGEE: search_all_apogee_events,
608619
EventType.PERIGEE: search_all_perigee_events,
609-
EventType.SEASON_CHANGE: _search_earth_season_change,
620+
EventType.SEASON_CHANGE: _search_earth_season_change(position),
610621
EventType.LUNAR_ECLIPSE: _search_lunar_eclipse,
611622
}
612623

tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
failures = 0
1010
tests = 0
1111

12-
for module in [events, ephemerides, model]:
12+
for module in [events, ephemerides, model, enum]:
1313
(f, t) = testmod(module, optionflags=NORMALIZE_WHITESPACE)
1414
failures += f
1515
tests += t

0 commit comments

Comments
 (0)