ruststartracker 0.2.3__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/PKG-INFO +12 -1
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/README.md +11 -0
- ruststartracker-0.2.4/build_script.py +126 -0
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/pyproject.toml +4 -2
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/ruststartracker/catalog.py +29 -9
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/ruststartracker/libruststartracker.pyi +2 -0
- ruststartracker-0.2.4/ruststartracker/test_catalog.py +101 -0
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/ruststartracker/test_integration.py +1 -1
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/ruststartracker/test_star.py +1 -3
- ruststartracker-0.2.3/build_script.py +0 -65
- ruststartracker-0.2.3/ruststartracker/test_catalog.py +0 -61
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/LICENSE +0 -0
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/ruststartracker/__init__.py +0 -0
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/ruststartracker/py.typed +0 -0
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/ruststartracker/star.py +0 -0
- {ruststartracker-0.2.3 → ruststartracker-0.2.4}/ruststartracker/test_backend.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: ruststartracker
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Lightweight Python Star Tracker With Rust Backend
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Nicolas Tobler
|
|
@@ -113,3 +113,14 @@ Gaia DR3 data is © European Space Agency and is released under the [**Creative
|
|
|
113
113
|
> Gaia Collaboration, Vallenari et al. (2022), *A\&A* **674**, A1.
|
|
114
114
|
> [DOI: 10.1051/0004-6361/202243940](https://doi.org/10.1051/0004-6361/202243940)
|
|
115
115
|
|
|
116
|
+
### Hipparcos and Tycho Data
|
|
117
|
+
|
|
118
|
+
This project includes data from the European Space Agency (ESA) mission **Hipparcos**.
|
|
119
|
+
|
|
120
|
+
The Hipparcos and Tycho Catalogues were processed by the Hipparcos and Tycho Data Analysis Consortium.
|
|
121
|
+
|
|
122
|
+
The Hipparcos and Tycho Catalogues are © European Space Agency and are released under the [**Creative Commons Attribution 3.0 IGO (CC BY 3.0 IGO)**](https://creativecommons.org/licenses/by/3.0/igo/) license.
|
|
123
|
+
|
|
124
|
+
> Perryman, M. A. C., et al. (1997), *Astronomy & Astrophysics* **323**, L49-L52.
|
|
125
|
+
1997A&A...323L..49P
|
|
126
|
+
|
|
@@ -91,3 +91,14 @@ Gaia DR3 data is © European Space Agency and is released under the [**Creative
|
|
|
91
91
|
|
|
92
92
|
> Gaia Collaboration, Vallenari et al. (2022), *A\&A* **674**, A1.
|
|
93
93
|
> [DOI: 10.1051/0004-6361/202243940](https://doi.org/10.1051/0004-6361/202243940)
|
|
94
|
+
|
|
95
|
+
### Hipparcos and Tycho Data
|
|
96
|
+
|
|
97
|
+
This project includes data from the European Space Agency (ESA) mission **Hipparcos**.
|
|
98
|
+
|
|
99
|
+
The Hipparcos and Tycho Catalogues were processed by the Hipparcos and Tycho Data Analysis Consortium.
|
|
100
|
+
|
|
101
|
+
The Hipparcos and Tycho Catalogues are © European Space Agency and are released under the [**Creative Commons Attribution 3.0 IGO (CC BY 3.0 IGO)**](https://creativecommons.org/licenses/by/3.0/igo/) license.
|
|
102
|
+
|
|
103
|
+
> Perryman, M. A. C., et al. (1997), *Astronomy & Astrophysics* **323**, L49-L52.
|
|
104
|
+
1997A&A...323L..49P
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Build rust backend.
|
|
2
|
+
|
|
3
|
+
This script is automatically run when the pyproject is installed.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import csv
|
|
7
|
+
import io
|
|
8
|
+
import pathlib
|
|
9
|
+
import shutil
|
|
10
|
+
import subprocess
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def download_gaia_data(output_file: pathlib.Path) -> None:
|
|
14
|
+
"""Download Gaia data and save it to the specified output file.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
output_file: Path to save the downloaded Gaia data (csv).
|
|
18
|
+
"""
|
|
19
|
+
from astroquery.gaia import Gaia
|
|
20
|
+
|
|
21
|
+
Gaia.ROW_LIMIT = -1
|
|
22
|
+
|
|
23
|
+
query = """
|
|
24
|
+
SELECT source_id, ra, dec, parallax, pmra, pmdec, phot_g_mean_mag
|
|
25
|
+
FROM gaiadr3.gaia_source
|
|
26
|
+
WHERE phot_g_mean_mag < 7
|
|
27
|
+
AND parallax > 0
|
|
28
|
+
AND astrometric_params_solved = 31
|
|
29
|
+
AND visibility_periods_used >= 8
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
print("Executing query on Gaia database...")
|
|
33
|
+
job = Gaia.launch_job_async(
|
|
34
|
+
query,
|
|
35
|
+
dump_to_file=True,
|
|
36
|
+
output_format="csv",
|
|
37
|
+
output_file=str(output_file.absolute()),
|
|
38
|
+
verbose=True,
|
|
39
|
+
)
|
|
40
|
+
if not job.is_finished():
|
|
41
|
+
print("Job did not finish successfully.")
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
print(f"Saved to: {output_file}")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def download_hipparcos_data(output_file: pathlib.Path) -> None:
|
|
48
|
+
"""Download Hipparcos data and save it to the specified output file.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
output_file: Path to save the downloaded Hipparcos data (csv).
|
|
52
|
+
"""
|
|
53
|
+
from astroquery.vizier import Vizier
|
|
54
|
+
|
|
55
|
+
Vizier.ROW_LIMIT = -1
|
|
56
|
+
|
|
57
|
+
print("Executing query on Hipparcos database...")
|
|
58
|
+
query = Vizier.query_constraints(
|
|
59
|
+
catalog=["I/311/hip2"],
|
|
60
|
+
Hpmag="<7",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
if not query:
|
|
64
|
+
print("Job did not finish successfully.")
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
# Initialize a string buffer to write the CSV data to
|
|
68
|
+
csv_output = io.StringIO()
|
|
69
|
+
writer = csv.writer(csv_output)
|
|
70
|
+
|
|
71
|
+
# Write the header row
|
|
72
|
+
# Use column names that are common in Gaia and Hipparcos
|
|
73
|
+
header = ["source_id", "ra", "dec", "parallax", "pmra", "pmdec", "phot_g_mean_mag"]
|
|
74
|
+
writer.writerow(header)
|
|
75
|
+
|
|
76
|
+
# Iterate over the rows of the Astropy table
|
|
77
|
+
for row in query[0]:
|
|
78
|
+
# Extract the required data points
|
|
79
|
+
source_id = row["HIP"]
|
|
80
|
+
ra = row["RArad"]
|
|
81
|
+
dec = row["DErad"]
|
|
82
|
+
parallax = row["Plx"]
|
|
83
|
+
pmra = row["pmRA"]
|
|
84
|
+
pmdec = row["pmDE"]
|
|
85
|
+
# Use Vmag as the proxy for phot_g_mean_mag
|
|
86
|
+
phot_g_mean_mag = row["Hpmag"]
|
|
87
|
+
|
|
88
|
+
# Create a list for the new row and write it to the CSV writer
|
|
89
|
+
new_row = [source_id, ra, dec, parallax, pmra, pmdec, phot_g_mean_mag]
|
|
90
|
+
writer.writerow(new_row)
|
|
91
|
+
|
|
92
|
+
# Get the complete CSV string from the buffer
|
|
93
|
+
csv_string = csv_output.getvalue()
|
|
94
|
+
|
|
95
|
+
# You can save this string to a file
|
|
96
|
+
with output_file.open("w") as f:
|
|
97
|
+
f.write(csv_string)
|
|
98
|
+
|
|
99
|
+
print(f"Saved to: {output_file}")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def build_script() -> None:
|
|
103
|
+
"""Build rust backend and move shared library to correct folder."""
|
|
104
|
+
cwd = pathlib.Path(__file__).parent.expanduser().absolute()
|
|
105
|
+
|
|
106
|
+
gaia_file = cwd / "ruststartracker/gaia_data_j2016.csv"
|
|
107
|
+
if not gaia_file.exists():
|
|
108
|
+
download_gaia_data(gaia_file)
|
|
109
|
+
|
|
110
|
+
hipparcos_file = cwd / "ruststartracker/hipparcos_data_j1991.25.csv"
|
|
111
|
+
if not hipparcos_file.exists():
|
|
112
|
+
download_hipparcos_data(hipparcos_file)
|
|
113
|
+
|
|
114
|
+
subprocess.check_call( # noqa: S603
|
|
115
|
+
["cargo", "build", "--release", "--features", "improc,gaia,hipparcos"], # noqa: S607
|
|
116
|
+
cwd=cwd,
|
|
117
|
+
stdout=None,
|
|
118
|
+
stderr=None,
|
|
119
|
+
)
|
|
120
|
+
shutil.copy(
|
|
121
|
+
cwd / "target/release/libruststartracker.so", cwd / "ruststartracker/libruststartracker.so"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
build_script()
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "ruststartracker"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.4"
|
|
4
4
|
description = "Lightweight Python Star Tracker With Rust Backend"
|
|
5
5
|
authors = ["Nicolas Tobler <nitobler@gmail.com>"]
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "MIT"
|
|
8
8
|
include = [
|
|
9
9
|
{ path = "ruststartracker/gaia_data_j2016.csv", format = ["sdist", "wheel"] },
|
|
10
|
+
{ path = "ruststartracker/hipparcos_data_j1991.25.csv", format = ["sdist", "wheel"] },
|
|
10
11
|
{ path = "ruststartracker/libruststartracker.so", format = ["wheel"] },
|
|
11
12
|
]
|
|
12
13
|
|
|
@@ -33,6 +34,7 @@ scipy-stubs = "^1.14.1.5"
|
|
|
33
34
|
ruff = "^0.9.3"
|
|
34
35
|
bump-my-version = "^1.2.0"
|
|
35
36
|
astroquery = "^0.4.10"
|
|
37
|
+
typing-extensions = "^4.12.2"
|
|
36
38
|
|
|
37
39
|
[tool.poetry.build]
|
|
38
40
|
script = "build_script.py"
|
|
@@ -42,7 +44,7 @@ requires = ["poetry-core", "astroquery>=0.4.10"]
|
|
|
42
44
|
build-backend = "poetry.core.masonry.api"
|
|
43
45
|
|
|
44
46
|
[tool.bumpversion]
|
|
45
|
-
current_version = "0.2.
|
|
47
|
+
current_version = "0.2.4"
|
|
46
48
|
commit = true
|
|
47
49
|
tag = true
|
|
48
50
|
tag_name = "v{new_version}"
|
|
@@ -7,14 +7,17 @@ import pathlib
|
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
9
|
import numpy.typing as npt
|
|
10
|
+
from typing_extensions import Self
|
|
10
11
|
|
|
11
12
|
AU: float = 149597870.693
|
|
12
13
|
"""Astronomical unit."""
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
GAIA_CATALOG_FILE = pathlib.Path(__file__).parent.expanduser().absolute() / "gaia_data_j2016.csv"
|
|
16
|
+
"""Location of the internal Gaia star catalog file."""
|
|
17
|
+
HIPPARCOS_CATALOG_FILE = (
|
|
18
|
+
pathlib.Path(__file__).parent.expanduser().absolute() / "hipparcos_data_j1991.25.csv"
|
|
16
19
|
)
|
|
17
|
-
"""Location of the internal star catalog file."""
|
|
20
|
+
"""Location of the internal Hipparcos star catalog file."""
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
def time_to_epoch(t: datetime.datetime) -> float:
|
|
@@ -44,24 +47,41 @@ class StarCatalog:
|
|
|
44
47
|
"""Proper motion of the declination in mad."""
|
|
45
48
|
magnitude: npt.NDArray[np.float32]
|
|
46
49
|
"""Magnitude values."""
|
|
47
|
-
epoch: float
|
|
50
|
+
epoch: float
|
|
48
51
|
"""Epoch of the catalog in years."""
|
|
49
52
|
|
|
53
|
+
@classmethod
|
|
54
|
+
def from_gaia(cls, *, max_magnitude: float = 6.0) -> Self:
|
|
55
|
+
"""Read internally provided Gaia catalog file.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
max_magnitude: Maximum magnitude to include.
|
|
59
|
+
"""
|
|
60
|
+
return cls(GAIA_CATALOG_FILE, epoch=2016.0, max_magnitude=max_magnitude)
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def from_hipparcos(cls, *, max_magnitude: float = 6.0) -> Self:
|
|
64
|
+
"""Read internally provided Hipparcos catalog file.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
max_magnitude: Maximum magnitude to include.
|
|
68
|
+
"""
|
|
69
|
+
return cls(HIPPARCOS_CATALOG_FILE, epoch=1991.25, max_magnitude=max_magnitude)
|
|
70
|
+
|
|
50
71
|
def __init__(
|
|
51
|
-
self, filename: pathlib.Path | str
|
|
72
|
+
self, filename: pathlib.Path | str, *, epoch: float, max_magnitude: float = 6.0
|
|
52
73
|
) -> None:
|
|
53
74
|
"""Read catalog from file.
|
|
54
75
|
|
|
55
76
|
Args:
|
|
56
77
|
filename: Star catalog filename.
|
|
78
|
+
epoch: Epoch of the catalog in years.
|
|
57
79
|
max_magnitude: Maximum magnitude to include.
|
|
58
80
|
"""
|
|
59
|
-
|
|
60
|
-
filename = INTERNAL_CATALOG_FILE if filename is None else pathlib.Path(filename)
|
|
61
|
-
|
|
81
|
+
self.epoch = epoch
|
|
62
82
|
keep_columns = ("ra", "dec", "parallax", "pmra", "pmdec", "phot_g_mean_mag")
|
|
63
83
|
|
|
64
|
-
with filename.open("r") as f:
|
|
84
|
+
with pathlib.Path(filename).open("r") as f:
|
|
65
85
|
it = csv.reader(f, delimiter=",", strict=True)
|
|
66
86
|
|
|
67
87
|
# Get columns
|
|
@@ -84,6 +84,8 @@ def extract_observations(
|
|
|
84
84
|
class StarCatalog:
|
|
85
85
|
@classmethod
|
|
86
86
|
def from_gaia(cls, *, max_magnitude: float | None) -> Self: ...
|
|
87
|
+
@classmethod
|
|
88
|
+
def from_hipparcos(cls, *, max_magnitude: float | None) -> Self: ...
|
|
87
89
|
def normalized_positions(
|
|
88
90
|
self, *, epoch: float | None, observer_position: np.ndarray | None
|
|
89
91
|
) -> npt.NDArray[np.float32]: ...
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
import astropy.time # type: ignore[import]
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
import ruststartracker.catalog
|
|
9
|
+
import ruststartracker.libruststartracker
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_time_to_epoch():
|
|
13
|
+
np.testing.assert_allclose(
|
|
14
|
+
ruststartracker.catalog.time_to_epoch(
|
|
15
|
+
datetime.datetime.fromisoformat("2000-01-01T11:58:56")
|
|
16
|
+
),
|
|
17
|
+
2000.0,
|
|
18
|
+
rtol=1e-20,
|
|
19
|
+
atol=1 / (365 * 86400),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.mark.parametrize(
|
|
24
|
+
"iso_date",
|
|
25
|
+
[
|
|
26
|
+
"2000-01-01T11:58:56",
|
|
27
|
+
"2024-01-01T11:58:56",
|
|
28
|
+
],
|
|
29
|
+
)
|
|
30
|
+
def test_time_to_epoch_astropy(iso_date: str):
|
|
31
|
+
ground_truth = float(astropy.time.Time(iso_date).jyear) # type: ignore
|
|
32
|
+
np.testing.assert_allclose(
|
|
33
|
+
ruststartracker.catalog.time_to_epoch(datetime.datetime.fromisoformat(iso_date)),
|
|
34
|
+
ground_truth,
|
|
35
|
+
rtol=1e-20,
|
|
36
|
+
atol=64 / (365 * 86400),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_extract_observations():
|
|
41
|
+
positions = ruststartracker.catalog.StarCatalog.from_gaia().normalized_positions()
|
|
42
|
+
|
|
43
|
+
assert positions.ndim == 2
|
|
44
|
+
assert positions.shape[1] == 3
|
|
45
|
+
np.testing.assert_allclose(np.linalg.norm(positions, axis=-1), 1.0, rtol=1e-5)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_gaia_python_rust():
|
|
49
|
+
t0 = time.monotonic()
|
|
50
|
+
positions = ruststartracker.catalog.StarCatalog.from_gaia().normalized_positions(epoch=2025.0)
|
|
51
|
+
print(f"Python catalog took {time.monotonic() - t0:.3f} seconds")
|
|
52
|
+
t0 = time.monotonic()
|
|
53
|
+
positions2 = ruststartracker.libruststartracker.StarCatalog.from_gaia(
|
|
54
|
+
max_magnitude=6.0
|
|
55
|
+
).normalized_positions(epoch=2025.0, observer_position=None)
|
|
56
|
+
print(f"Rust catalog took {time.monotonic() - t0:.3f} seconds")
|
|
57
|
+
np.testing.assert_allclose(positions, positions2, rtol=1e-5, atol=1e-5)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_hipparcos_python_rust():
|
|
61
|
+
t0 = time.monotonic()
|
|
62
|
+
positions = ruststartracker.catalog.StarCatalog.from_hipparcos().normalized_positions(
|
|
63
|
+
epoch=2025.0
|
|
64
|
+
)
|
|
65
|
+
print(f"Python catalog took {time.monotonic() - t0:.3f} seconds")
|
|
66
|
+
t0 = time.monotonic()
|
|
67
|
+
positions2 = ruststartracker.libruststartracker.StarCatalog.from_hipparcos(
|
|
68
|
+
max_magnitude=6.0
|
|
69
|
+
).normalized_positions(epoch=2025.0, observer_position=None)
|
|
70
|
+
print(f"Rust catalog took {time.monotonic() - t0:.3f} seconds")
|
|
71
|
+
np.testing.assert_allclose(positions, positions2, rtol=1e-5, atol=1e-5)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_compare_hipparcos_gaia():
|
|
75
|
+
def filt(cat: ruststartracker.catalog.StarCatalog, m: float = 0):
|
|
76
|
+
positions = cat.normalized_positions(epoch=2025.0)
|
|
77
|
+
mags = cat.magnitude
|
|
78
|
+
mask = (positions[..., 2] > 0.9) * (mags > 5 - m) * (mags < 8 - m)
|
|
79
|
+
return positions[mask]
|
|
80
|
+
|
|
81
|
+
positions_hipparcos = filt(ruststartracker.catalog.StarCatalog.from_hipparcos(max_magnitude=8))
|
|
82
|
+
positions_gaia = filt(ruststartracker.catalog.StarCatalog.from_gaia(max_magnitude=8), m=0.9)
|
|
83
|
+
|
|
84
|
+
dists = np.linalg.norm(
|
|
85
|
+
positions_hipparcos[np.newaxis, :, :] - positions_gaia[:, np.newaxis, :], axis=-1
|
|
86
|
+
)
|
|
87
|
+
matches = np.min(dists, axis=0) < 0.00005
|
|
88
|
+
|
|
89
|
+
assert np.mean(matches > 0.9)
|
|
90
|
+
|
|
91
|
+
if False:
|
|
92
|
+
import matplotlib.pyplot as plt
|
|
93
|
+
|
|
94
|
+
plt.plot(positions_gaia[..., 0], positions_gaia[..., 1], "+", label="gaia")
|
|
95
|
+
plt.plot(positions_hipparcos[..., 0], positions_hipparcos[..., 1], "x", label="hipparcos")
|
|
96
|
+
plt.legend()
|
|
97
|
+
plt.show()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
pytest.main([__file__])
|
|
@@ -24,7 +24,7 @@ def prepare() -> tuple[ruststartracker.StarTracker, np.ndarray]:
|
|
|
24
24
|
|
|
25
25
|
dist_coefs = np.array([-0.44120807, -0.15954202, 0.00767012, -0.00213292, -1.64788247])
|
|
26
26
|
|
|
27
|
-
catalog = ruststartracker.StarCatalog()
|
|
27
|
+
catalog = ruststartracker.StarCatalog.from_gaia()
|
|
28
28
|
star_catalog_vecs = catalog.normalized_positions(epoch=2024)
|
|
29
29
|
star_catalog_magnitudes = catalog.magnitude
|
|
30
30
|
|
|
@@ -20,12 +20,10 @@ def test_extract_observations(impl: str):
|
|
|
20
20
|
t0 = time.monotonic()
|
|
21
21
|
if impl == "python":
|
|
22
22
|
centers, intensities = ruststartracker.star._extract_observations(img, threshold=30)
|
|
23
|
-
|
|
23
|
+
else:
|
|
24
24
|
centers, intensities = ruststartracker.libruststartracker.extract_observations(
|
|
25
25
|
img, 30, 3, 300
|
|
26
26
|
)
|
|
27
|
-
else:
|
|
28
|
-
raise AssertionError
|
|
29
27
|
print(f"Extracting observations took {time.monotonic() - t0:.5f} seconds")
|
|
30
28
|
|
|
31
29
|
assert isinstance(centers, np.ndarray)
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"""Build rust backend.
|
|
2
|
-
|
|
3
|
-
This script is automatically run when the pyproject is installed.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import pathlib
|
|
7
|
-
import shutil
|
|
8
|
-
import subprocess
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def download_gaia_data(output_file: pathlib.Path) -> None:
|
|
12
|
-
"""Download Gaia data and save it to the specified output file.
|
|
13
|
-
|
|
14
|
-
Args:
|
|
15
|
-
output_file: Path to save the downloaded Gaia data (csv).
|
|
16
|
-
"""
|
|
17
|
-
from astroquery.gaia import Gaia
|
|
18
|
-
|
|
19
|
-
Gaia.ROW_LIMIT = 10000
|
|
20
|
-
|
|
21
|
-
query = """
|
|
22
|
-
SELECT source_id, ra, dec, parallax, pmra, pmdec, phot_g_mean_mag
|
|
23
|
-
FROM gaiadr3.gaia_source
|
|
24
|
-
WHERE phot_g_mean_mag < 7
|
|
25
|
-
AND parallax > 0
|
|
26
|
-
AND astrometric_params_solved = 31
|
|
27
|
-
AND visibility_periods_used >= 8
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
print("Executing query on Gaia database...")
|
|
31
|
-
job = Gaia.launch_job_async(
|
|
32
|
-
query,
|
|
33
|
-
dump_to_file=True,
|
|
34
|
-
output_format="csv",
|
|
35
|
-
output_file=str(output_file.absolute()),
|
|
36
|
-
verbose=True,
|
|
37
|
-
)
|
|
38
|
-
if not job.is_finished():
|
|
39
|
-
print("Job did not finish successfully.")
|
|
40
|
-
return
|
|
41
|
-
|
|
42
|
-
print(f"Saved to: {output_file}")
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def build_script() -> None:
|
|
46
|
-
"""Build rust backend and move shared library to correct folder."""
|
|
47
|
-
cwd = pathlib.Path(__file__).parent.expanduser().absolute()
|
|
48
|
-
|
|
49
|
-
gaia_file = cwd / "ruststartracker/gaia_data_j2016.csv"
|
|
50
|
-
if not gaia_file.exists():
|
|
51
|
-
download_gaia_data(gaia_file)
|
|
52
|
-
|
|
53
|
-
subprocess.check_call( # noqa: S603
|
|
54
|
-
["cargo", "build", "--release", "--features", "improc,gaia"], # noqa: S607
|
|
55
|
-
cwd=cwd,
|
|
56
|
-
stdout=None,
|
|
57
|
-
stderr=None,
|
|
58
|
-
)
|
|
59
|
-
shutil.copy(
|
|
60
|
-
cwd / "target/release/libruststartracker.so", cwd / "ruststartracker/libruststartracker.so"
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if __name__ == "__main__":
|
|
65
|
-
build_script()
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
import time
|
|
3
|
-
|
|
4
|
-
import astropy.time # type: ignore[import]
|
|
5
|
-
import numpy as np
|
|
6
|
-
import pytest
|
|
7
|
-
|
|
8
|
-
import ruststartracker.catalog
|
|
9
|
-
import ruststartracker.libruststartracker
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def test_time_to_epoch():
|
|
13
|
-
np.testing.assert_allclose(
|
|
14
|
-
ruststartracker.catalog.time_to_epoch(
|
|
15
|
-
datetime.datetime.fromisoformat("2000-01-01T11:58:56")
|
|
16
|
-
),
|
|
17
|
-
2000.0,
|
|
18
|
-
rtol=1e-20,
|
|
19
|
-
atol=1 / (365 * 86400),
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@pytest.mark.parametrize(
|
|
24
|
-
"iso_date",
|
|
25
|
-
[
|
|
26
|
-
"2000-01-01T11:58:56",
|
|
27
|
-
"2024-01-01T11:58:56",
|
|
28
|
-
],
|
|
29
|
-
)
|
|
30
|
-
def test_time_to_epoch_astropy(iso_date: str):
|
|
31
|
-
ground_truth = float(astropy.time.Time(iso_date).jyear) # type: ignore
|
|
32
|
-
np.testing.assert_allclose(
|
|
33
|
-
ruststartracker.catalog.time_to_epoch(datetime.datetime.fromisoformat(iso_date)),
|
|
34
|
-
ground_truth,
|
|
35
|
-
rtol=1e-20,
|
|
36
|
-
atol=64 / (365 * 86400),
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def test_extract_observations():
|
|
41
|
-
positions = ruststartracker.catalog.StarCatalog().normalized_positions()
|
|
42
|
-
|
|
43
|
-
assert positions.ndim == 2
|
|
44
|
-
assert positions.shape[1] == 3
|
|
45
|
-
np.testing.assert_allclose(np.linalg.norm(positions, axis=-1), 1.0, rtol=1e-5)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def test_python_rust():
|
|
49
|
-
t0 = time.monotonic()
|
|
50
|
-
positions = ruststartracker.catalog.StarCatalog().normalized_positions(epoch=2025.0)
|
|
51
|
-
print(f"Python catalog took {time.monotonic() - t0:.3f} seconds")
|
|
52
|
-
t0 = time.monotonic()
|
|
53
|
-
positions2 = ruststartracker.libruststartracker.StarCatalog.from_gaia(
|
|
54
|
-
max_magnitude=6.0
|
|
55
|
-
).normalized_positions(epoch=2025.0, observer_position=None)
|
|
56
|
-
print(f"Rust catalog took {time.monotonic() - t0:.3f} seconds")
|
|
57
|
-
np.testing.assert_allclose(positions, positions2, rtol=1e-5, atol=1e-5)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if __name__ == "__main__":
|
|
61
|
-
pytest.main([__file__])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|