This repository has been archived by the owner on Sep 6, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ephemeris API via Sunpy/Horizons
- Loading branch information
1 parent
fc8cb1d
commit eda312d
Showing
7 changed files
with
146 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from datetime import datetime | ||
from typing import Iterable | ||
|
||
from astropy.coordinates import SkyCoord | ||
|
||
from .horizons import Horizons | ||
from helios_exceptions import HeliosException | ||
|
||
# Use lower case for key names | ||
_providers = { | ||
'horizons': Horizons | ||
} | ||
|
||
def Get(provider: str, body: str, dates: Iterable[datetime]) -> SkyCoord: | ||
try: | ||
# Use lower case so any variation of PrOvIdEr will execute the | ||
# selected provider. | ||
return _providers[provider.lower()].Get(body, dates) | ||
except KeyError: | ||
raise HeliosException(f"Unknown provider: {provider}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from datetime import datetime | ||
from typing import Iterable | ||
|
||
from astropy.coordinates import SkyCoord | ||
from sunpy.coordinates import get_horizons_coord | ||
|
||
from api.ephemeris.provider import CoordinateProvider | ||
|
||
class Horizons(CoordinateProvider): | ||
@classmethod | ||
def Query(cls, body: str, dates: Iterable[datetime]) -> list[SkyCoord]: | ||
""" | ||
Queries JPL Horizons for coordinates and returns them | ||
Parameters | ||
---------- | ||
body: `str` | ||
Body to request coordinates for | ||
dates: `list[datetime]` | ||
List of dates. A coordinate will be returned for each date in the list | ||
""" | ||
return get_horizons_coord(body, dates) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from abc import ABC, abstractmethod | ||
from datetime import datetime | ||
from typing import Iterable | ||
|
||
from astropy.coordinates import SkyCoord | ||
|
||
from get_heeq import convert_skycoords_to_heeq | ||
|
||
class CoordinateProvider(ABC): | ||
@classmethod | ||
def Get(cls, body: str, dates: Iterable[datetime]) -> list[dict]: | ||
""" | ||
Queries the underlying source for coordinates and transforms them to | ||
Helios's coordinate system. | ||
Parameters | ||
---------- | ||
body: `str` | ||
The body to query coordinates for. Could be an observatory, planet, etc. | ||
dates: `list[datetime]` | ||
A list of datetime objects to query coordinates for. | ||
One coordinate will be returned for each date. | ||
""" | ||
coordinates = cls.Query(body, dates) | ||
return CoordinateProvider.ConvertSkyCoords(coordinates) | ||
|
||
@classmethod | ||
def ConvertSkyCoords(cls, coords: Iterable[SkyCoord]) -> list[dict]: | ||
""" | ||
Converts SkyCoords to Helios coordinates. | ||
""" | ||
return list(map(lambda x: convert_skycoords_to_heeq(x), coords)) | ||
|
||
@classmethod | ||
@abstractmethod | ||
def Query(cls, body: str, dates: Iterable[datetime]) -> list[SkyCoord]: | ||
""" | ||
Queries the underlying source for coordinates and returns them | ||
Parameters | ||
---------- | ||
body: `str` | ||
Body to request coordinates for | ||
dates: `list[datetime]` | ||
List of dates. A coordinate will be returned for each date in the list | ||
""" | ||
raise NotImplementedError() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from datetime import datetime | ||
|
||
import sunpy | ||
import pytest | ||
|
||
from api.ephemeris.horizons import Horizons | ||
from get_heeq import convert_skycoords_to_heeq | ||
|
||
def test_horizons_get(): | ||
test_dates = [datetime(2023, 1, 1), datetime(2022, 1, 1)] | ||
# 399 is the unique ID for Earth's geocenter. "Earth" is ambiguous because | ||
# it can be Earth's geocenter or the Earth-Moon barycenter and Horizons | ||
# requests that you use the ID to select one. | ||
coordinates = Horizons.Get("399", test_dates) | ||
for idx, test_date in enumerate(test_dates): | ||
sunpy_earth = convert_skycoords_to_heeq(sunpy.coordinates.get_earth(test_date)) | ||
# Assert that horizons and sunpy's coordinates for earth are approximately the same. | ||
# This confirms the query is working as expected. | ||
assert coordinates[idx]['x'] == pytest.approx(sunpy_earth['x']) | ||
assert coordinates[idx]['y'] == pytest.approx(sunpy_earth['y']) | ||
assert coordinates[idx]['z'] == pytest.approx(sunpy_earth['z']) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import pytest | ||
|
||
from main import app | ||
|
||
from api.ephemeris.horizons import Horizons | ||
|
||
@pytest.fixture | ||
def client(): | ||
return app.test_client() | ||
|
||
def test_ephemeris_no_provider(client): | ||
response = client.get("/ephemeris/shouldbreak/SDO") | ||
assert response.status_code == 400 | ||
assert "Unknown provider" in response.json['error'] | ||
|
||
def test_ephemeris_horizons(client, monkeypatch): | ||
# Don't actually query horizons for this test. | ||
def fake_horizons(*args, **kwargs) -> list[dict]: | ||
return [{'x': 1, 'y': 2, 'z': 3}] | ||
monkeypatch.setattr(Horizons, "Get", fake_horizons) | ||
|
||
horizons_providers = ['Horizons', 'horizons'] | ||
for horizons in horizons_providers: | ||
response = client.get(f"/ephemeris/{horizons}/SDO") | ||
assert response.status_code == 200 | ||
assert response.json[0]['x'] == 1 | ||
assert response.json[0]['y'] == 2 | ||
assert response.json[0]['z'] == 3 |