exotools 0.0.1__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.
- exotools-0.0.1/LICENSE +21 -0
- exotools-0.0.1/MANIFEST.in +7 -0
- exotools-0.0.1/PKG-INFO +125 -0
- exotools-0.0.1/README.md +66 -0
- exotools-0.0.1/exotools/__init__.py +47 -0
- exotools-0.0.1/exotools/datasets/__init__.py +13 -0
- exotools-0.0.1/exotools/datasets/_exoplanet_dataset_reducer.py +96 -0
- exotools-0.0.1/exotools/datasets/candidate_exoplanets.py +44 -0
- exotools-0.0.1/exotools/datasets/gaia_parameters.py +68 -0
- exotools-0.0.1/exotools/datasets/known_exoplanets.py +124 -0
- exotools-0.0.1/exotools/datasets/lightcurves.py +58 -0
- exotools-0.0.1/exotools/datasets/tess.py +91 -0
- exotools-0.0.1/exotools/db/__init__.py +21 -0
- exotools-0.0.1/exotools/db/base_db.py +74 -0
- exotools-0.0.1/exotools/db/exo_db.py +113 -0
- exotools-0.0.1/exotools/db/gaia_db.py +62 -0
- exotools-0.0.1/exotools/db/lightcurve_db.py +112 -0
- exotools-0.0.1/exotools/db/lightcurve_plus.py +196 -0
- exotools-0.0.1/exotools/db/star_system/__init__.py +14 -0
- exotools-0.0.1/exotools/db/star_system/planet.py +90 -0
- exotools-0.0.1/exotools/db/star_system/star.py +26 -0
- exotools-0.0.1/exotools/db/star_system/star_system.py +87 -0
- exotools-0.0.1/exotools/db/star_system/uncertain_data.py +29 -0
- exotools-0.0.1/exotools/db/starsystem_db.py +38 -0
- exotools-0.0.1/exotools/db/tic_db.py +23 -0
- exotools-0.0.1/exotools/db/toi_db.py +13 -0
- exotools-0.0.1/exotools/db/urls_db.py +36 -0
- exotools-0.0.1/exotools/downloaders/__init__.py +22 -0
- exotools-0.0.1/exotools/downloaders/_utils.py +22 -0
- exotools-0.0.1/exotools/downloaders/dataset_downloader.py +98 -0
- exotools-0.0.1/exotools/downloaders/exoplanets_downloader.py +103 -0
- exotools-0.0.1/exotools/downloaders/gaia_downloader.py +135 -0
- exotools-0.0.1/exotools/downloaders/lightcurve_downloader.py +107 -0
- exotools-0.0.1/exotools/downloaders/tap_service.py +84 -0
- exotools-0.0.1/exotools/downloaders/tess_catalog_downloader.py +155 -0
- exotools-0.0.1/exotools/downloaders/tess_observations_downloader.py +61 -0
- exotools-0.0.1/exotools/downloaders/toi_exoplanets_downloader.py +52 -0
- exotools-0.0.1/exotools/io/__init__.py +11 -0
- exotools-0.0.1/exotools/io/base_storage.py +33 -0
- exotools-0.0.1/exotools/io/fs_storage.py +158 -0
- exotools-0.0.1/exotools/io/hdf5_storage.py +164 -0
- exotools-0.0.1/exotools/py.typed +0 -0
- exotools-0.0.1/exotools/utils/__init__.py +6 -0
- exotools-0.0.1/exotools/utils/download.py +7 -0
- exotools-0.0.1/exotools/utils/observations_fix.py +57 -0
- exotools-0.0.1/exotools/utils/qtable_utils.py +55 -0
- exotools-0.0.1/exotools/utils/unit_mapper.py +67 -0
- exotools-0.0.1/exotools.egg-info/PKG-INFO +125 -0
- exotools-0.0.1/exotools.egg-info/SOURCES.txt +73 -0
- exotools-0.0.1/exotools.egg-info/dependency_links.txt +1 -0
- exotools-0.0.1/exotools.egg-info/requires.txt +15 -0
- exotools-0.0.1/exotools.egg-info/top_level.txt +1 -0
- exotools-0.0.1/pyproject.toml +53 -0
- exotools-0.0.1/requirements.txt +17 -0
- exotools-0.0.1/setup.cfg +4 -0
- exotools-0.0.1/setup.py +11 -0
- exotools-0.0.1/tests/__init__.py +0 -0
- exotools-0.0.1/tests/conftest.py +54 -0
- exotools-0.0.1/tests/test_assets/generate_test_data.py +45 -0
- exotools-0.0.1/tests/test_assets/qtables/candidate_exoplanets.ecsv +730 -0
- exotools-0.0.1/tests/test_assets/qtables/candidate_exoplanets_header.json +536 -0
- exotools-0.0.1/tests/test_assets/qtables/known_exoplanets.ecsv +2081 -0
- exotools-0.0.1/tests/test_assets/qtables/known_exoplanets_header.json +1736 -0
- exotools-0.0.1/tests/test_assets/qtables/known_gaia_astro_parameters.ecsv +472 -0
- exotools-0.0.1/tests/test_assets/qtables/known_gaia_astro_parameters_header.json +140 -0
- exotools-0.0.1/tests/test_assets/qtables/tess_observations.ecsv +1241 -0
- exotools-0.0.1/tests/test_assets/qtables/tess_observations_header.json +44 -0
- exotools-0.0.1/tests/test_comparison.py +9 -0
- exotools-0.0.1/tests/test_fs_storage.py +164 -0
- exotools-0.0.1/tests/test_hdf5_storage.py +218 -0
- exotools-0.0.1/tests/tmp/known_exoplanets_header.json +1736 -0
- exotools-0.0.1/tests/tmp/known_gaia_astro_parameters_header.json +140 -0
- exotools-0.0.1/tests/utils/__init__.py +0 -0
- exotools-0.0.1/tests/utils/comparison.py +168 -0
- exotools-0.0.1/tests/zucc.py +13 -0
exotools-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Christian Cardin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
exotools-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: exotools
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Tools for working with exoplanet data
|
|
5
|
+
Author-email: Christian <astro.sech@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 Christian Cardin
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/sechlol/exotools
|
|
29
|
+
Project-URL: Bug Tracker, https://github.com/sechlol/exotools/issues
|
|
30
|
+
Project-URL: Documentation, https://github.com/sechlol/exotools
|
|
31
|
+
Classifier: Programming Language :: Python :: 3
|
|
32
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Operating System :: OS Independent
|
|
37
|
+
Classifier: Development Status :: 4 - Beta
|
|
38
|
+
Classifier: Intended Audience :: Science/Research
|
|
39
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
40
|
+
Requires-Python: >=3.8
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
License-File: LICENSE
|
|
43
|
+
Requires-Dist: numpy
|
|
44
|
+
Requires-Dist: pandas
|
|
45
|
+
Requires-Dist: pandas[performance]
|
|
46
|
+
Requires-Dist: tables
|
|
47
|
+
Requires-Dist: pyarrow==18.1.0
|
|
48
|
+
Requires-Dist: h5py
|
|
49
|
+
Requires-Dist: pydantic
|
|
50
|
+
Requires-Dist: oktopus
|
|
51
|
+
Requires-Dist: lightkurve
|
|
52
|
+
Requires-Dist: astropy
|
|
53
|
+
Requires-Dist: astroquery
|
|
54
|
+
Requires-Dist: casjobs
|
|
55
|
+
Requires-Dist: tqdm
|
|
56
|
+
Requires-Dist: tabulate
|
|
57
|
+
Requires-Dist: pyvo
|
|
58
|
+
Dynamic: license-file
|
|
59
|
+
|
|
60
|
+
# exotools
|
|
61
|
+
|
|
62
|
+
Python tools for working with exoplanet data from various sources including NASA's Exoplanet Archive, TESS, and Gaia.
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install exotools
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Features
|
|
71
|
+
|
|
72
|
+
- Access to multiple exoplanet datasets:
|
|
73
|
+
- Known exoplanets from NASA's Exoplanet Archive
|
|
74
|
+
- Candidate exoplanets
|
|
75
|
+
- TESS observations
|
|
76
|
+
- Gaia parameters
|
|
77
|
+
- Lightcurve data
|
|
78
|
+
- Efficient data storage options (HDF5, ECSV, Feather)
|
|
79
|
+
- Unified API for accessing different data sources
|
|
80
|
+
- Comprehensive database management for exoplanet data
|
|
81
|
+
|
|
82
|
+
## Usage
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import exotools
|
|
86
|
+
|
|
87
|
+
# Get known exoplanets dataset
|
|
88
|
+
from exotools import KnownExoplanetsDataset
|
|
89
|
+
dataset = KnownExoplanetsDataset()
|
|
90
|
+
exoplanets = dataset.get_data()
|
|
91
|
+
print(f"Found {len(exoplanets)} exoplanets")
|
|
92
|
+
|
|
93
|
+
# Access candidate exoplanets
|
|
94
|
+
from exotools import CandidateExoplanetsDataset
|
|
95
|
+
candidates = CandidateExoplanetsDataset().get_data()
|
|
96
|
+
|
|
97
|
+
# Work with TESS data
|
|
98
|
+
from exotools import TessDataset
|
|
99
|
+
tess_data = TessDataset().get_data()
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Storage Options
|
|
103
|
+
|
|
104
|
+
exotools provides multiple storage backends for efficient data handling:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from exotools.io import Hdf5Storage, EcsvStorage, FeatherStorage
|
|
108
|
+
|
|
109
|
+
# Use HDF5 for unified storage of tables and metadata
|
|
110
|
+
storage = Hdf5Storage("path/to/data.h5")
|
|
111
|
+
|
|
112
|
+
# Or use ECSV for human-readable storage
|
|
113
|
+
storage = EcsvStorage("path/to/data_dir")
|
|
114
|
+
|
|
115
|
+
# Or use Feather for high-performance storage
|
|
116
|
+
storage = FeatherStorage("path/to/data_dir")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
122
|
+
|
|
123
|
+
## Contributing
|
|
124
|
+
|
|
125
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
exotools-0.0.1/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# exotools
|
|
2
|
+
|
|
3
|
+
Python tools for working with exoplanet data from various sources including NASA's Exoplanet Archive, TESS, and Gaia.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install exotools
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Access to multiple exoplanet datasets:
|
|
14
|
+
- Known exoplanets from NASA's Exoplanet Archive
|
|
15
|
+
- Candidate exoplanets
|
|
16
|
+
- TESS observations
|
|
17
|
+
- Gaia parameters
|
|
18
|
+
- Lightcurve data
|
|
19
|
+
- Efficient data storage options (HDF5, ECSV, Feather)
|
|
20
|
+
- Unified API for accessing different data sources
|
|
21
|
+
- Comprehensive database management for exoplanet data
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import exotools
|
|
27
|
+
|
|
28
|
+
# Get known exoplanets dataset
|
|
29
|
+
from exotools import KnownExoplanetsDataset
|
|
30
|
+
dataset = KnownExoplanetsDataset()
|
|
31
|
+
exoplanets = dataset.get_data()
|
|
32
|
+
print(f"Found {len(exoplanets)} exoplanets")
|
|
33
|
+
|
|
34
|
+
# Access candidate exoplanets
|
|
35
|
+
from exotools import CandidateExoplanetsDataset
|
|
36
|
+
candidates = CandidateExoplanetsDataset().get_data()
|
|
37
|
+
|
|
38
|
+
# Work with TESS data
|
|
39
|
+
from exotools import TessDataset
|
|
40
|
+
tess_data = TessDataset().get_data()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Storage Options
|
|
44
|
+
|
|
45
|
+
exotools provides multiple storage backends for efficient data handling:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from exotools.io import Hdf5Storage, EcsvStorage, FeatherStorage
|
|
49
|
+
|
|
50
|
+
# Use HDF5 for unified storage of tables and metadata
|
|
51
|
+
storage = Hdf5Storage("path/to/data.h5")
|
|
52
|
+
|
|
53
|
+
# Or use ECSV for human-readable storage
|
|
54
|
+
storage = EcsvStorage("path/to/data_dir")
|
|
55
|
+
|
|
56
|
+
# Or use Feather for high-performance storage
|
|
57
|
+
storage = FeatherStorage("path/to/data_dir")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
63
|
+
|
|
64
|
+
## Contributing
|
|
65
|
+
|
|
66
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""ExoTools - Tools for working with exoplanet data."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0"
|
|
4
|
+
|
|
5
|
+
from .db.star_system import Star, Planet, StarSystem, UncertainValue, UncertainDataSource
|
|
6
|
+
from exotools.datasets.known_exoplanets import KnownExoplanetsDataset
|
|
7
|
+
from exotools.datasets.candidate_exoplanets import CandidateExoplanetsDataset
|
|
8
|
+
from exotools.datasets.tess import TessDataset
|
|
9
|
+
from exotools.datasets.lightcurves import LightcurveDataset
|
|
10
|
+
|
|
11
|
+
from .db import (
|
|
12
|
+
CandidateDB,
|
|
13
|
+
ExoDB,
|
|
14
|
+
GaiaDB,
|
|
15
|
+
StarSystemDB,
|
|
16
|
+
LightcurveDB,
|
|
17
|
+
LightCurvePlus,
|
|
18
|
+
TessMetaDB,
|
|
19
|
+
TicDB,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from .utils.download import DownloadParams
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
# Main dataset classes
|
|
26
|
+
"KnownExoplanetsDataset",
|
|
27
|
+
"CandidateExoplanetsDataset",
|
|
28
|
+
"TessDataset",
|
|
29
|
+
"LightcurveDataset",
|
|
30
|
+
# Database classes
|
|
31
|
+
"CandidateDB",
|
|
32
|
+
"ExoDB",
|
|
33
|
+
"GaiaDB",
|
|
34
|
+
"StarSystemDB",
|
|
35
|
+
"LightcurveDB",
|
|
36
|
+
"LightCurvePlus",
|
|
37
|
+
"TessMetaDB",
|
|
38
|
+
"TicDB",
|
|
39
|
+
# Star system types
|
|
40
|
+
"Star",
|
|
41
|
+
"Planet",
|
|
42
|
+
"StarSystem",
|
|
43
|
+
"UncertainValue",
|
|
44
|
+
"UncertainDataSource",
|
|
45
|
+
# Utility types
|
|
46
|
+
"DownloadParams",
|
|
47
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from exotools.datasets.candidate_exoplanets import CandidateExoplanetsDataset
|
|
2
|
+
from exotools.datasets.known_exoplanets import KnownExoplanetsDataset
|
|
3
|
+
from exotools.datasets.tess import TessDataset
|
|
4
|
+
from exotools.datasets.lightcurves import LightcurveDataset
|
|
5
|
+
from exotools.datasets.gaia_parameters import GaiaParametersDataset
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"CandidateExoplanetsDataset",
|
|
9
|
+
"KnownExoplanetsDataset",
|
|
10
|
+
"TessDataset",
|
|
11
|
+
"LightcurveDataset",
|
|
12
|
+
"GaiaParametersDataset",
|
|
13
|
+
]
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from astropy.table import QTable
|
|
4
|
+
|
|
5
|
+
from exotools.db import ExoDB
|
|
6
|
+
from exotools.utils.qtable_utils import get_empty_table_header, TableColumnInfo, QTableHeader
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _get_subset_df(table: QTable) -> pd.DataFrame:
|
|
10
|
+
"""Select a subset of data from the main exoplanet dataset, including upper and lower bounds"""
|
|
11
|
+
err_cols = []
|
|
12
|
+
dataset_columns = ["tic_id", "gaia_id", "disc_telescope", "rowupdate"]
|
|
13
|
+
star_columns = ["hostname", "hostname_lowercase", "st_rad", "st_rad_gaia", "st_mass"]
|
|
14
|
+
planet_columns = [
|
|
15
|
+
"pl_name",
|
|
16
|
+
"pl_rade",
|
|
17
|
+
"pl_masse",
|
|
18
|
+
"pl_dens",
|
|
19
|
+
"pl_orbeccen",
|
|
20
|
+
"pl_orbper",
|
|
21
|
+
"pl_orblper",
|
|
22
|
+
"pl_orbincl",
|
|
23
|
+
"pl_orbsmax",
|
|
24
|
+
"pl_tranmid",
|
|
25
|
+
"pl_trandur",
|
|
26
|
+
"pl_trandep",
|
|
27
|
+
"pl_imppar",
|
|
28
|
+
"pl_ratror",
|
|
29
|
+
"pl_ratdor",
|
|
30
|
+
]
|
|
31
|
+
fields = dataset_columns + star_columns + planet_columns
|
|
32
|
+
for p in fields:
|
|
33
|
+
if f"{p}_lower" in table.colnames:
|
|
34
|
+
err_cols.extend([f"{p}_lower", f"{p}_upper"])
|
|
35
|
+
return table[fields + err_cols].to_pandas()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _reduce_group(group: pd.DataFrame) -> pd.Series:
|
|
39
|
+
"""
|
|
40
|
+
For each column, select the first element that is not null.
|
|
41
|
+
Parameters:
|
|
42
|
+
- group: a dataframe grouped by planet name, and sorted by "rowupdate" in descending order
|
|
43
|
+
"""
|
|
44
|
+
first_non_null = group.apply(lambda col: col.dropna().iloc[0] if not col.dropna().empty else np.nan)
|
|
45
|
+
return first_non_null
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _reduce_df(table: QTable) -> pd.DataFrame:
|
|
49
|
+
"""
|
|
50
|
+
Reduce all the planets having multiple rows to only one single row, taking the most updated not-null value
|
|
51
|
+
available in the dataset.
|
|
52
|
+
"""
|
|
53
|
+
df = _get_subset_df(table)
|
|
54
|
+
# Sort by update date
|
|
55
|
+
sorted_df = df.sort_values("rowupdate", ascending=False)
|
|
56
|
+
|
|
57
|
+
# Group by 'pl_name' and apply reduce_group
|
|
58
|
+
grouped = sorted_df.groupby("pl_name", as_index=True)
|
|
59
|
+
reduced_groups = grouped.apply(_reduce_group, include_groups=False).reset_index(drop=False)
|
|
60
|
+
return reduced_groups
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _flag_invalid_planets(dataset: pd.DataFrame):
|
|
64
|
+
"""
|
|
65
|
+
Adds a pl_valid_flag to the planets which have all the required parameters
|
|
66
|
+
"""
|
|
67
|
+
# Without these we can't fit the transits
|
|
68
|
+
mandatory_fields = ["pl_rade", "pl_trandur", "pl_tranmid", "pl_orbsmax"]
|
|
69
|
+
|
|
70
|
+
# Add the validation flag to the dataset
|
|
71
|
+
dataset["pl_valid_flag"] = ~dataset[mandatory_fields].isna().any(axis=1)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def reduce_exoplanet_dataset(exo_db: ExoDB) -> tuple[QTable, QTableHeader]:
|
|
75
|
+
"""
|
|
76
|
+
Post-processes the Known exoplanets dataset to select only the transiting planets, and reducing multiple
|
|
77
|
+
entries for each planet to only one. Additionally, impute some missing values using GAIA data.
|
|
78
|
+
"""
|
|
79
|
+
# Load datasets, limiting to only Tess and Kepler transiting planets
|
|
80
|
+
exo_db = exo_db.get_transiting_planets(kepler_or_tess_only=False)
|
|
81
|
+
|
|
82
|
+
# Reduce exoplanet dataset
|
|
83
|
+
reduced_df = _reduce_df(exo_db.dataset_copy)
|
|
84
|
+
_flag_invalid_planets(reduced_df)
|
|
85
|
+
|
|
86
|
+
# Assign units and convert to QTable
|
|
87
|
+
units_map = {c: exo_db.view[c].unit for c in reduced_df.columns if c in exo_db.view.colnames}
|
|
88
|
+
reduced_table = QTable.from_pandas(reduced_df, units=units_map)
|
|
89
|
+
|
|
90
|
+
# Assign units to reduced dataset and convert to QTable
|
|
91
|
+
reduced_header = get_empty_table_header(reduced_table)
|
|
92
|
+
reduced_header["pl_valid_flag"] = TableColumnInfo(
|
|
93
|
+
unit=None, description="True if the planet has all the " "parameters to determine transit events"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return reduced_table, reduced_header
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from astropy.table import QTable
|
|
4
|
+
|
|
5
|
+
from exotools.db import ExoDB, CandidateDB
|
|
6
|
+
from exotools.downloaders import CandidateExoplanetsDownloader
|
|
7
|
+
from exotools.io import BaseStorage
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CandidateExoplanetsDataset:
|
|
11
|
+
_DATASET_NAME_CANDIDATES = "candidate_exoplanets"
|
|
12
|
+
|
|
13
|
+
def __init__(self, storage: BaseStorage):
|
|
14
|
+
self._storage = storage
|
|
15
|
+
|
|
16
|
+
def load_candidate_exoplanets_dataset(self) -> Optional[CandidateDB]:
|
|
17
|
+
try:
|
|
18
|
+
candidate_qtable = self._storage.read_qtable(table_name=self._DATASET_NAME_CANDIDATES)
|
|
19
|
+
except ValueError:
|
|
20
|
+
print(
|
|
21
|
+
"Candidate Exoplanets dataset not found. "
|
|
22
|
+
"You need to download it first by calling download_candidate_exoplanets(store=True)."
|
|
23
|
+
)
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
return _create_candidate_db(candidate_dataset=candidate_qtable)
|
|
27
|
+
|
|
28
|
+
def download_candidate_exoplanets(self, limit: Optional[int] = None, store: bool = True) -> CandidateDB:
|
|
29
|
+
print("Preparing to download candidate exoplanets dataset...")
|
|
30
|
+
candidate_qtable, candidate_header = CandidateExoplanetsDownloader().download(limit=limit)
|
|
31
|
+
|
|
32
|
+
if store:
|
|
33
|
+
self._storage.write_qtable(
|
|
34
|
+
table=candidate_qtable,
|
|
35
|
+
header=candidate_header,
|
|
36
|
+
table_name=self._DATASET_NAME_CANDIDATES,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
return _create_candidate_db(candidate_qtable)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _create_candidate_db(candidate_dataset: QTable) -> CandidateDB:
|
|
43
|
+
ExoDB.compute_bounds(candidate_dataset)
|
|
44
|
+
return CandidateDB(candidate_dataset)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from typing import Optional, Sequence
|
|
2
|
+
|
|
3
|
+
from astropy.table import QTable
|
|
4
|
+
|
|
5
|
+
from exotools.db import GaiaDB
|
|
6
|
+
from exotools.downloaders import GaiaDownloader
|
|
7
|
+
from exotools.io import BaseStorage
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GaiaParametersDataset:
|
|
11
|
+
_DATASET_GAIA = "known_gaia_astro_parameters"
|
|
12
|
+
|
|
13
|
+
def __init__(self, storage: BaseStorage):
|
|
14
|
+
self._storage = storage
|
|
15
|
+
|
|
16
|
+
def load_gaia_parameters_dataset(self) -> Optional[GaiaDB]:
|
|
17
|
+
"""
|
|
18
|
+
Load Gaia parameters dataset from storage.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
GaiaDB: Database containing Gaia parameters, or None if not found.
|
|
22
|
+
"""
|
|
23
|
+
try:
|
|
24
|
+
gaia_qtable = self._storage.read_qtable(table_name=self._DATASET_GAIA)
|
|
25
|
+
return self._create_gaia_db(gaia_qtable)
|
|
26
|
+
except ValueError:
|
|
27
|
+
print("Gaia dataset not found. You need to download it first by " "calling download_gaia_parameters().")
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
def download_gaia_parameters(self, gaia_ids: Sequence[int], store: bool = True) -> GaiaDB:
|
|
31
|
+
"""
|
|
32
|
+
Download Gaia DR3 data for the given Gaia IDs.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
gaia_ids: Sequence of Gaia IDs to download data for.
|
|
36
|
+
store: Whether to store the downloaded data.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
GaiaDB: Database containing the downloaded Gaia parameters.
|
|
40
|
+
"""
|
|
41
|
+
print(f"Preparing to download Gaia DR3 data for {len(gaia_ids)} stars...")
|
|
42
|
+
|
|
43
|
+
gaia_qtable, gaia_header = GaiaDownloader().download_by_id(ids=gaia_ids)
|
|
44
|
+
if store:
|
|
45
|
+
self._storage.write_qtable(
|
|
46
|
+
table=gaia_qtable,
|
|
47
|
+
header=gaia_header,
|
|
48
|
+
table_name=self._DATASET_GAIA,
|
|
49
|
+
override=True,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
return self._create_gaia_db(gaia_qtable)
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def _create_gaia_db(gaia_dataset: QTable) -> GaiaDB:
|
|
56
|
+
"""
|
|
57
|
+
Create a GaiaDB instance from a QTable dataset.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
gaia_dataset: QTable containing Gaia data.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
GaiaDB: Database containing processed Gaia parameters.
|
|
64
|
+
"""
|
|
65
|
+
GaiaDB.impute_radius(gaia_dataset)
|
|
66
|
+
GaiaDB.compute_mean_temperature(gaia_dataset)
|
|
67
|
+
GaiaDB.compute_habitable_zone(gaia_dataset)
|
|
68
|
+
return GaiaDB(gaia_dataset)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from astropy.table import QTable
|
|
5
|
+
|
|
6
|
+
from exotools.datasets.gaia_parameters import GaiaParametersDataset
|
|
7
|
+
from exotools.db import ExoDB, GaiaDB, StarSystemDB
|
|
8
|
+
from exotools.downloaders import KnownExoplanetsDownloader
|
|
9
|
+
from exotools.io import BaseStorage
|
|
10
|
+
from ._exoplanet_dataset_reducer import reduce_exoplanet_dataset
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class KnownExoplanetsDataset:
|
|
14
|
+
_DATASET_EXO = "known_exoplanets"
|
|
15
|
+
_DATASET_EXO_REDUCED = "known_exoplanets_reduced"
|
|
16
|
+
|
|
17
|
+
def __init__(self, storage: BaseStorage):
|
|
18
|
+
self._storage = storage
|
|
19
|
+
self._gaia_dataset = GaiaParametersDataset(storage)
|
|
20
|
+
|
|
21
|
+
def load_known_exoplanets_dataset(self, with_gaia_star_data: bool = True) -> Optional[ExoDB]:
|
|
22
|
+
gaia_db = None
|
|
23
|
+
if with_gaia_star_data:
|
|
24
|
+
gaia_db = self._gaia_dataset.load_gaia_parameters_dataset()
|
|
25
|
+
if gaia_db is None:
|
|
26
|
+
print(
|
|
27
|
+
"Gaia dataset not found. You need to download it first by "
|
|
28
|
+
"calling download_known_exoplanets(with_gaia_star_data=True, store=True)."
|
|
29
|
+
)
|
|
30
|
+
return None
|
|
31
|
+
try:
|
|
32
|
+
exo_qtable = self._storage.read_qtable(table_name=self._DATASET_EXO)
|
|
33
|
+
except ValueError:
|
|
34
|
+
print(
|
|
35
|
+
"Known Exoplanets dataset not found. "
|
|
36
|
+
"You need to download it first by calling download_known_exoplanets(store=True)."
|
|
37
|
+
)
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
return _create_exo_db(exo_dataset=exo_qtable, gaia_db=gaia_db)
|
|
41
|
+
|
|
42
|
+
def load_star_system_dataset(self) -> Optional[StarSystemDB]:
|
|
43
|
+
try:
|
|
44
|
+
# Try to load reduced dataset
|
|
45
|
+
reduced_exo_dataset = self._storage.read_qtable(table_name=self._DATASET_EXO_REDUCED)
|
|
46
|
+
return _create_star_system_db(reduced_exo_dataset)
|
|
47
|
+
except ValueError:
|
|
48
|
+
# If it doesn't exist, compute it from the full datasets
|
|
49
|
+
gaia_db = self._gaia_dataset.load_gaia_parameters_dataset()
|
|
50
|
+
if gaia_db is None:
|
|
51
|
+
print(
|
|
52
|
+
"Gaia dataset not found. You need to download it first by "
|
|
53
|
+
"calling download_known_exoplanets(with_gaia_star_data=True, store=True)."
|
|
54
|
+
)
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
exo_qtable = self._storage.read_qtable(table_name=self._DATASET_EXO)
|
|
59
|
+
except ValueError:
|
|
60
|
+
print(
|
|
61
|
+
"Known Exoplanets dataset not found. "
|
|
62
|
+
"You need to download it first by calling download_known_exoplanets(store=True)."
|
|
63
|
+
)
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
return self._create_star_system_db_from_scratch(exo_dataset=exo_qtable, gaia_db=gaia_db)
|
|
67
|
+
|
|
68
|
+
def download_known_exoplanets(
|
|
69
|
+
self,
|
|
70
|
+
limit: Optional[int] = None,
|
|
71
|
+
with_gaia_star_data: bool = False,
|
|
72
|
+
store: bool = True,
|
|
73
|
+
) -> ExoDB:
|
|
74
|
+
print("Preparing to download known exoplanets dataset...")
|
|
75
|
+
exo_qtable, exo_header = KnownExoplanetsDownloader().download(limit=limit)
|
|
76
|
+
|
|
77
|
+
if store:
|
|
78
|
+
self._storage.write_qtable(table=exo_qtable, header=exo_header, table_name=self._DATASET_EXO, override=True)
|
|
79
|
+
|
|
80
|
+
if with_gaia_star_data:
|
|
81
|
+
gaia_ids = np.unique(exo_qtable["gaia_id"].value).tolist()
|
|
82
|
+
gaia_db = self._gaia_dataset.download_gaia_parameters(gaia_ids=gaia_ids, store=store)
|
|
83
|
+
else:
|
|
84
|
+
gaia_db = None
|
|
85
|
+
|
|
86
|
+
return _create_exo_db(exo_qtable, gaia_db)
|
|
87
|
+
|
|
88
|
+
def _create_star_system_db_from_scratch(self, exo_dataset: QTable, gaia_db: GaiaDB) -> StarSystemDB:
|
|
89
|
+
# Disable parsing Time columns; we need them as Quantities to copy units to the transiting qtable.
|
|
90
|
+
exo_db = _create_exo_db(exo_dataset=exo_dataset, gaia_db=gaia_db, convert_time_columns=False)
|
|
91
|
+
|
|
92
|
+
# Reduce exoplanet dataset to a compact representation
|
|
93
|
+
reduced_exo_dataset, header = reduce_exoplanet_dataset(exo_db=exo_db)
|
|
94
|
+
|
|
95
|
+
# Store the reduced dataset for future use
|
|
96
|
+
self._storage.write_qtable(
|
|
97
|
+
table=reduced_exo_dataset,
|
|
98
|
+
header=header,
|
|
99
|
+
table_name=self._DATASET_EXO_REDUCED,
|
|
100
|
+
override=True,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
return _create_star_system_db(reduced_exo_dataset)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _create_exo_db(exo_dataset: QTable, gaia_db: Optional[GaiaDB] = None, convert_time_columns: bool = True) -> ExoDB:
|
|
107
|
+
ExoDB.preprocess_dataset(exo_dataset)
|
|
108
|
+
ExoDB.compute_bounds(exo_dataset)
|
|
109
|
+
|
|
110
|
+
# It's useful to disable parsing Time columns if we need them as Quantities,
|
|
111
|
+
# for example to copy units to another qtable.
|
|
112
|
+
if convert_time_columns:
|
|
113
|
+
ExoDB.convert_time_columns(exo_dataset)
|
|
114
|
+
|
|
115
|
+
if gaia_db:
|
|
116
|
+
ExoDB.impute_stellar_parameters(exo_dataset, gaia_db.view)
|
|
117
|
+
return ExoDB(exo_dataset)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _create_star_system_db(reduced_exo_dataset: QTable) -> StarSystemDB:
|
|
121
|
+
# Now it's safe to parse Time columns
|
|
122
|
+
ExoDB.convert_time_columns(reduced_exo_dataset)
|
|
123
|
+
reduced_exo_dataset = StarSystemDB.preprocess_dataset(reduced_exo_dataset)
|
|
124
|
+
return StarSystemDB(reduced_exo_dataset)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from exotools.db import TessMetaDB, LightcurveDB
|
|
5
|
+
from exotools.downloaders import LightcurveDownloader
|
|
6
|
+
from exotools.io import BaseStorage
|
|
7
|
+
from exotools.utils.download import DownloadParams
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LightcurveDataset:
|
|
11
|
+
_DATASET_LIGHTCURVES = "lightcurves"
|
|
12
|
+
|
|
13
|
+
def __init__(self, storage: BaseStorage, override_existing: bool = False, verbose: bool = False):
|
|
14
|
+
self._folder_path = storage.root_path / self._DATASET_LIGHTCURVES
|
|
15
|
+
self._downloader = LightcurveDownloader(override_existing=override_existing, verbose=verbose)
|
|
16
|
+
|
|
17
|
+
def download_lightcurves_from_tess_db(self, tess_db: TessMetaDB) -> Optional[LightcurveDB]:
|
|
18
|
+
download_params = [
|
|
19
|
+
DownloadParams(
|
|
20
|
+
url=row["dataURL"],
|
|
21
|
+
download_path=str(self._folder_path / str(row["tic_id"]) / f"{row['obs_id']}.fits"),
|
|
22
|
+
)
|
|
23
|
+
for row in tess_db.view
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
print(f"Downloading {len(download_params)} lightcurves")
|
|
27
|
+
downloaded_paths = self._downloader.download_fits_parallel(download_params)
|
|
28
|
+
print(f"Downloaded {len(downloaded_paths)} lightcurves")
|
|
29
|
+
|
|
30
|
+
return self.load_lightcurve_dataset()
|
|
31
|
+
|
|
32
|
+
def load_lightcurve_dataset(self) -> Optional[LightcurveDB]:
|
|
33
|
+
downloaded_paths = _get_file_paths_in_subfolder(self._folder_path, file_extension="fits")
|
|
34
|
+
if len(downloaded_paths) == 0:
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
dataset = LightcurveDB.path_map_to_qtable(downloaded_paths)
|
|
38
|
+
return LightcurveDB(dataset)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _get_file_paths_in_subfolder(
|
|
42
|
+
parent_path: Path,
|
|
43
|
+
file_extension: Optional[str] = None,
|
|
44
|
+
match_name: Optional[str] = None,
|
|
45
|
+
) -> dict[int, list[Path]]:
|
|
46
|
+
subfolder_dict = {}
|
|
47
|
+
if not file_extension and not match_name:
|
|
48
|
+
raise ValueError("At least one between file_extension and match_name should be given")
|
|
49
|
+
pattern = match_name if match_name else f"*.{file_extension}"
|
|
50
|
+
|
|
51
|
+
# Iterate over each subfolder
|
|
52
|
+
for subfolder in parent_path.iterdir():
|
|
53
|
+
if subfolder.is_dir():
|
|
54
|
+
fits_files = list(subfolder.glob(pattern))
|
|
55
|
+
if fits_files:
|
|
56
|
+
subfolder_dict[int(subfolder.name)] = [Path(file) for file in fits_files]
|
|
57
|
+
|
|
58
|
+
return subfolder_dict
|