exoclock 1.0.0__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.
Files changed (38) hide show
  1. exoclock-1.0.0/MANIFEST.in +12 -0
  2. exoclock-1.0.0/PKG-INFO +17 -0
  3. exoclock-1.0.0/README.md +12 -0
  4. exoclock-1.0.0/exoclock/__author__.txt +1 -0
  5. exoclock-1.0.0/exoclock/__author_email__.txt +1 -0
  6. exoclock-1.0.0/exoclock/__databases__.pickle +0 -0
  7. exoclock-1.0.0/exoclock/__databases_setup__.py +182 -0
  8. exoclock-1.0.0/exoclock/__description__.txt +1 -0
  9. exoclock-1.0.0/exoclock/__init__.py +20 -0
  10. exoclock-1.0.0/exoclock/__url__.txt +1 -0
  11. exoclock-1.0.0/exoclock/__version__.txt +1 -0
  12. exoclock-1.0.0/exoclock/catalogues/__init__.py +0 -0
  13. exoclock-1.0.0/exoclock/catalogues/catalogues.py +121 -0
  14. exoclock-1.0.0/exoclock/catalogues/simbad.py +152 -0
  15. exoclock-1.0.0/exoclock/databases.py +206 -0
  16. exoclock-1.0.0/exoclock/errors.py +19 -0
  17. exoclock-1.0.0/exoclock/processes/__init__.py +0 -0
  18. exoclock-1.0.0/exoclock/processes/files.py +75 -0
  19. exoclock-1.0.0/exoclock/spacetime/__init__.py +0 -0
  20. exoclock-1.0.0/exoclock/spacetime/angles.py +286 -0
  21. exoclock-1.0.0/exoclock/spacetime/moments.py +598 -0
  22. exoclock-1.0.0/exoclock/spacetime/observatories.py +314 -0
  23. exoclock-1.0.0/exoclock/spacetime/targets.py +136 -0
  24. exoclock-1.0.0/exoclock.egg-info/PKG-INFO +17 -0
  25. exoclock-1.0.0/exoclock.egg-info/SOURCES.txt +36 -0
  26. exoclock-1.0.0/exoclock.egg-info/dependency_links.txt +1 -0
  27. exoclock-1.0.0/exoclock.egg-info/not-zip-safe +1 -0
  28. exoclock-1.0.0/exoclock.egg-info/requires.txt +6 -0
  29. exoclock-1.0.0/exoclock.egg-info/top_level.txt +1 -0
  30. exoclock-1.0.0/requirements.txt +6 -0
  31. exoclock-1.0.0/setup.cfg +4 -0
  32. exoclock-1.0.0/setup.py +42 -0
  33. exoclock-1.0.0/tests/test_catalogues.py +57 -0
  34. exoclock-1.0.0/tests/test_spacetime_angles.py +94 -0
  35. exoclock-1.0.0/tests/test_spacetime_moments.py +144 -0
  36. exoclock-1.0.0/tests/test_spacetime_observatories.py +68 -0
  37. exoclock-1.0.0/tests/test_specetime_targets.py +94 -0
  38. exoclock-1.0.0/tests/test_tools.py +24 -0
@@ -0,0 +1,12 @@
1
+ include exoclock/catalogues/*
2
+ include exoclock/processes/*
3
+ include exoclock/spacetime/*
4
+ include exoclock/__author__.txt
5
+ include exoclock/__author_email__.txt
6
+ include exoclock/__databases__.pickle
7
+ include exoclock/__description__.txt
8
+ include exoclock/__url__.txt
9
+ include exoclock/__version__.txt
10
+ include README.md
11
+ include LICENSE
12
+ include requirements.txt
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.1
2
+ Name: exoclock
3
+ Version: 1.0.0
4
+ Summary: A python package for programmatic interaction with the ExoClock project archives.
5
+ Home-page: https://github.com/atsiaras/exoclock
6
+ Author: Angelos Tsiaras
7
+ Author-email: aggelostsiaras@gmail.com
8
+ License: MIT
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
14
+ Classifier: Operating System :: MacOS :: MacOS X
15
+ Classifier: Programming Language :: Python :: 3.8
16
+
17
+ Visit https://github.com/atsiaras/exoclock for more details.
@@ -0,0 +1,12 @@
1
+ [![Build Python 3.8](https://github.com/atsiaras/exoclock/actions/workflows/build-python-3.8.yml/badge.svg)](https://github.com/atsiaras/exoclock/actions/workflows/build-python-3.8.yml)
2
+ [![Build Python 3.9](https://github.com/atsiaras/exoclock/actions/workflows/build-python-3.9.yml/badge.svg)](https://github.com/atsiaras/exoclock/actions/workflows/build-python-3.9.yml)
3
+ [![Build Python 3.10](https://github.com/atsiaras/exoclock/actions/workflows/build-python-3.10.yml/badge.svg)](https://github.com/atsiaras/exoclock/actions/workflows/build-python-3.10.yml)
4
+ [![Build Python 3.11](https://github.com/atsiaras/exoclock/actions/workflows/build-python-3.11.yml/badge.svg)](https://github.com/atsiaras/exoclock/actions/workflows/build-python-3.11.yml)
5
+ [![Build Python 3.12](https://github.com/atsiaras/exoclock/actions/workflows/build-python-3.12.yml/badge.svg)](https://github.com/atsiaras/exoclock/actions/workflows/build-python-3.12.yml)
6
+
7
+ [![codecov](https://codecov.io/gh/atsiaras/exoclock/graph/badge.svg?token=L514113T7U)](https://codecov.io/gh/atsiaras/exoclock)
8
+
9
+ # exoclock
10
+ A python package to connect with the [ExoClock Project](https://www.exoclock.space) ([Kokori et al. 2022](https://link.springer.com/article/10.1007/s10686-020-09696-3)).
11
+
12
+ <img src="https://www.exoclock.space/static/logo.png" width="25%">
@@ -0,0 +1 @@
1
+ Angelos Tsiaras
@@ -0,0 +1 @@
1
+ aggelostsiaras@gmail.com
@@ -0,0 +1,182 @@
1
+
2
+ import os
3
+ import time
4
+ import shutil
5
+
6
+ from .processes.files import open_dict, download
7
+
8
+ try:
9
+ import zipfile
10
+ download_zip = True
11
+ except:
12
+ download_zip = False
13
+
14
+
15
+ def _setup_database(package_data, database_name):
16
+
17
+ print('exoclock: Checking {0} database...'.format(database_name))
18
+
19
+ # define paths
20
+
21
+ database_directory_path = os.path.join(package_data.databases_directory_path, database_name)
22
+ database_file_path = os.path.join(package_data.databases_directory_path, database_name + '.pickle')
23
+ database_link_file_path = os.path.join(package_data.databases_directory_path, database_name + '_link.txt')
24
+ database_file_path_new = os.path.join(package_data.databases_directory_path, database_name + '_new.pickle')
25
+ database_file_path_old = os.path.join(package_data.databases_directory_path, database_name + '_old.pickle')
26
+ last_update_file_path = os.path.join(package_data.databases_directory_path, '{0}_last_update.txt'.format(database_name))
27
+
28
+ # define paths
29
+
30
+ # check if everything exists, if not reset database
31
+
32
+ if not os.path.isdir(database_directory_path) or not os.path.isfile(database_file_path) or not os.path.isfile(database_link_file_path):
33
+
34
+ try:
35
+ shutil.rmtree(database_directory_path)
36
+ except:
37
+ pass
38
+
39
+ try:
40
+ os.remove(database_file_path)
41
+ except:
42
+ pass
43
+
44
+ try:
45
+ os.remove(database_file_path_old)
46
+ except:
47
+ pass
48
+
49
+ try:
50
+ os.remove(database_file_path_new)
51
+ except:
52
+ pass
53
+
54
+ try:
55
+ os.remove(database_link_file_path)
56
+ except:
57
+ pass
58
+
59
+ try:
60
+ os.remove(last_update_file_path)
61
+ except:
62
+ pass
63
+
64
+ os.mkdir(database_directory_path)
65
+
66
+
67
+ print(package_data.databases[package_data.version][database_name], database_file_path)
68
+
69
+ if not download(package_data.databases[package_data.version][database_name], database_file_path):
70
+ print('\n{0} features cannot be used.'.format(database_name))
71
+ return False
72
+ else:
73
+ shutil.copy(database_file_path, database_file_path_old)
74
+ w = open(database_link_file_path, 'w')
75
+ w.write(package_data.databases[package_data.version][database_name])
76
+ w.close()
77
+
78
+ try:
79
+ new_database = open_dict(database_file_path)
80
+ download(new_database['zipfile'], database_directory_path + '.zip')
81
+ new_database = zipfile.ZipFile(database_directory_path + '.zip', 'r')
82
+ here = os.path.abspath('.')
83
+ os.chdir(package_data.databases_directory_path)
84
+ new_database.extractall()
85
+ os.chdir(here)
86
+ os.remove(database_directory_path + '.zip')
87
+ except:
88
+ pass
89
+
90
+ # check if everything exists, if not reset database
91
+
92
+ # download database if there is an update
93
+
94
+ if package_data.databases[package_data.version][database_name] != open(database_link_file_path).read():
95
+
96
+ if not download(package_data.databases[package_data.version][database_name], database_file_path_new):
97
+ pass
98
+ else:
99
+ shutil.move(database_file_path, database_file_path_old)
100
+ shutil.move(database_file_path_new, database_file_path)
101
+
102
+ w = open(database_link_file_path, 'w')
103
+ w.write(package_data.databases[package_data.version][database_name])
104
+ w.close()
105
+
106
+ # download database if there is an update
107
+
108
+ # check all files in database, remove files that need to be updated
109
+
110
+ current_database = open_dict(database_file_path_old)
111
+ new_database = open_dict(database_file_path)
112
+
113
+ for dbx_file in current_database['files']:
114
+
115
+ if dbx_file not in new_database['files']:
116
+ try:
117
+ os.remove(os.path.join(package_data.databases_directory_path,
118
+ new_database['files'][dbx_file]['local_path']))
119
+ except:
120
+ pass
121
+ elif new_database['files'][dbx_file]['link'] != current_database['files'][dbx_file]['link']:
122
+ try:
123
+ os.remove(os.path.join(package_data.databases_directory_path,
124
+ new_database['files'][dbx_file]['local_path']))
125
+ except:
126
+ pass
127
+
128
+ # check for updates, remove files that need to be updated
129
+
130
+ # download missing files
131
+
132
+ final_check = True
133
+
134
+ for dbx_file in new_database['files']:
135
+ if not os.path.isfile(os.path.join(package_data.databases_directory_path,
136
+ new_database['files'][dbx_file]['local_path'])):
137
+ try:
138
+ os.remove(last_update_file_path)
139
+ except:
140
+ pass
141
+ if not download(new_database['files'][dbx_file]['link'],
142
+ os.path.join(package_data.databases_directory_path,
143
+ new_database['files'][dbx_file]['local_path'])):
144
+ final_check = False
145
+
146
+ # download missing files
147
+
148
+ # update files from external links
149
+
150
+ frequency = new_database['frequency']
151
+ if frequency:
152
+
153
+ try:
154
+ last_update_date = int(open(last_update_file_path).read())
155
+ except:
156
+ last_update_date = 0
157
+
158
+ today = int(time.strftime('%y%m%d'))
159
+
160
+ if today >= last_update_date + frequency:
161
+
162
+ for dbx_file in new_database['files']:
163
+ if 'external_link' in new_database['files'][dbx_file]:
164
+ print('\tUpdating: ', dbx_file)
165
+ if not download(new_database['files'][dbx_file]['external_link'],
166
+ os.path.join(package_data.databases_directory_path,
167
+ new_database['files'][dbx_file]['local_path'])):
168
+ final_check = False
169
+
170
+ w = open(last_update_file_path, 'w')
171
+ w.write(time.strftime('%y%m%d'))
172
+ w.close()
173
+
174
+ # update files from external links
175
+
176
+ if not final_check:
177
+ print('\n{0} features cannot be used.'.format(database_name))
178
+ return False
179
+ else:
180
+ if current_database != new_database:
181
+ shutil.copy(database_file_path, database_file_path_old)
182
+ return database_directory_path
@@ -0,0 +1 @@
1
+ A python package for programmatic interaction with the ExoClock project archives.
@@ -0,0 +1,20 @@
1
+ import os
2
+
3
+ __version__ = open(os.path.join(os.path.abspath(os.path.dirname(__file__)), '__version__.txt')).read()
4
+ __author__ = open(os.path.join(os.path.abspath(os.path.dirname(__file__)), '__author__.txt')).read()
5
+ __author_email__ = open(os.path.join(os.path.abspath(os.path.dirname(__file__)), '__author_email__.txt')).read()
6
+ __description__ = open(os.path.join(os.path.abspath(os.path.dirname(__file__)), '__description__.txt')).read()
7
+ __url__ = open(os.path.join(os.path.abspath(os.path.dirname(__file__)), '__url__.txt')).read()
8
+
9
+ from .catalogues.catalogues import *
10
+ from .catalogues.simbad import *
11
+
12
+ from .spacetime.angles import *
13
+ from .spacetime.moments import *
14
+ from .spacetime.observatories import *
15
+ from .spacetime.targets import *
16
+
17
+ from .processes.files import *
18
+
19
+ from .errors import *
20
+ from .databases import *
@@ -0,0 +1 @@
1
+ https://github.com/atsiaras/exoclock
@@ -0,0 +1 @@
1
+ 1.0.0
File without changes
@@ -0,0 +1,121 @@
1
+
2
+ __all__ = ['get_planet', 'get_system', 'get_all_planets', 'locate_planet', 'locate_system', 'get_all_planets']
3
+
4
+ import numpy as np
5
+
6
+
7
+ from .simbad import simbad_search_by_name
8
+
9
+ from ..spacetime.angles import *
10
+ from ..spacetime.angles import _request_angle, _reformat_or_request_angle
11
+ from ..spacetime.targets import *
12
+ from ..databases import exoclock_data
13
+ from ..errors import *
14
+
15
+
16
+ def _flat_name(name):
17
+
18
+ flat_name_list = [
19
+ [' ', ''],
20
+ ['-', ''],
21
+ ['cancri', 'cnc'],
22
+ ['hatp10', 'wasp11'],
23
+ ['wasp40', 'hatp27'],
24
+ ['wasp51', 'hatp30'],
25
+ ['wasp86', 'kelt12'],
26
+ ['kelt22', 'wasp173'],
27
+ ]
28
+
29
+ name = name.lower()
30
+
31
+ for char in flat_name_list:
32
+ name = name.replace(char[0], char[1])
33
+
34
+ return name
35
+
36
+
37
+ def _search_by_planet(name):
38
+
39
+ planets = exoclock_data.ecc()['planets']
40
+
41
+ name_or = name
42
+
43
+ if name in planets:
44
+ return name
45
+
46
+ else:
47
+ for i in planets:
48
+ if _flat_name(i) == _flat_name(name):
49
+ return str(i)
50
+ elif (_flat_name(i)[-1] == _flat_name(name)[-1] and _flat_name(i)[:-2] == _flat_name(name)[:-1] and
51
+ _flat_name(i)[-2] in ['a', 'b', 'n']):
52
+ return str(i)
53
+
54
+ raise ExoClockInputError('No planet {0} found in the catalogue.'.format(name_or))
55
+
56
+
57
+ def get_all_planets():
58
+
59
+ return list(exoclock_data.ecc()['planets'].keys())
60
+
61
+
62
+ def get_planet(name):
63
+
64
+ name = _search_by_planet(name)
65
+
66
+ planet_data = exoclock_data.ecc()['planets'][name]
67
+ star_data = exoclock_data.ecc()['stars'][planet_data['star']]
68
+ star_data['ra_deg'] = Hours(star_data['ra']).deg()
69
+ star_data['dec_deg'] = Degrees(star_data['dec']).deg_coord()
70
+
71
+ return {'name': name, 'planet': planet_data, 'star': star_data}
72
+
73
+
74
+ def get_system(star_name):
75
+
76
+ target = simbad_search_by_name(star_name)
77
+ if not target:
78
+ return []
79
+
80
+ test = list(set(target.all_names).intersection(list(exoclock_data.ecc()['hosts'])))
81
+
82
+ if len(test) == 0:
83
+ return []
84
+
85
+ planets = exoclock_data.ecc()['hosts'][test[0]]
86
+
87
+ return [get_planet(planet) for planet in planets]
88
+
89
+
90
+ def locate_planet(ra, dec, radius=Degrees(0.02), observation_time=None, observation_type=None):
91
+
92
+ _request_angle(ra)
93
+ _request_angle(dec)
94
+ _request_angle(radius)
95
+
96
+ pointing = FixedTarget(ra, dec)
97
+
98
+ test_planets = []
99
+
100
+ for test_planet_name in get_all_planets():
101
+ test_planet = get_planet(test_planet_name)
102
+ test_planet = FixedTarget(Degrees(test_planet['star']['ra_deg']), Degrees(test_planet['star']['dec_deg']))
103
+ test_planets.append([pointing.distance_on_sphere(test_planet).deg(), test_planet_name])
104
+
105
+ test_planets.sort()
106
+
107
+ if test_planets[0][0] < radius.deg():
108
+ return get_planet(test_planets[0][1])
109
+ else:
110
+ raise ExoClockLibraryError('Planet could not be located')
111
+
112
+
113
+ def locate_system(ra, dec, radius=0.02):
114
+
115
+ return get_system(locate_planet(ra, dec, radius)['star']['simbad_id'])
116
+
117
+
118
+ def get_all_planets():
119
+ return list(exoclock_data.ecc()['planets'].keys())
120
+
121
+
@@ -0,0 +1,152 @@
1
+ __all__ = ['simbad_search_by_name', 'simbad_search_by_coordinates']
2
+
3
+ import time
4
+ import requests
5
+ import warnings
6
+
7
+ from astroquery.simbad import Simbad
8
+
9
+ from ..spacetime.angles import *
10
+ from ..spacetime.angles import _request_angle, _reformat_or_request_angle
11
+ from ..spacetime.targets import *
12
+ from ..databases import exoclock_data
13
+ from ..errors import *
14
+
15
+ Simbad = Simbad()
16
+ Simbad.add_votable_fields('ids')
17
+
18
+
19
+ def _flat_name(name):
20
+
21
+ flat_name_list = [
22
+ [' ', ''],
23
+ ['-', ''],
24
+ ['cancri', 'cnc'],
25
+ ['hatp10', 'wasp11'],
26
+ ['wasp40', 'hatp27'],
27
+ ['wasp51', 'hatp30'],
28
+ ['wasp86', 'kelt12'],
29
+ ['kelt22', 'wasp173'],
30
+ ]
31
+
32
+ name = name.lower()
33
+
34
+ for char in flat_name_list:
35
+ name = name.replace(char[0], char[1])
36
+
37
+ return name
38
+
39
+
40
+ def _fix_simbad_name(input):
41
+
42
+ try:
43
+ input = input.decode("utf-8")
44
+ except:
45
+ pass
46
+
47
+ while ' ' in input:
48
+ input = input.replace(' ', ' ')
49
+
50
+ return input
51
+
52
+
53
+ def _fix_simbad_coordinates(input):
54
+
55
+ input = str(input).replace(' ', ':')
56
+
57
+ if len(input.split(':')) == 1:
58
+ input += ':00:00'
59
+ elif len(input.split(':')) == 2:
60
+ input += ':00'
61
+
62
+ return input
63
+
64
+
65
+ def simbad_search_by_name(star_name, max_trials=10):
66
+
67
+ try:
68
+ star = exoclock_data.ecc()['stars'][exoclock_data.ecc()['flats'][_flat_name(star_name)]]
69
+
70
+ return FixedTarget(
71
+ Hours(star['ra']),
72
+ Degrees(star['dec']),
73
+ star['simbad_id'],
74
+ [star['simbad_id']]
75
+ )
76
+
77
+ except KeyError:
78
+ pass
79
+
80
+ star_name = star_name.replace('HD-', 'HD ')
81
+ star_name = star_name.replace('HR-', 'HR ')
82
+ star_name = star_name.replace('2MASS-', '2MASS ')
83
+ star_name = star_name.replace('GJ-', 'GJ ')
84
+ star_name = star_name.replace('HIP-', 'HIP ')
85
+ star_name = star_name.replace('LHS-', 'LHS ')
86
+ star_name = star_name.replace('TYC-', 'TYC ')
87
+ star_name = star_name.replace('KIC-', 'KIC ')
88
+ star_name = star_name.replace('ADS-', 'ADS ')
89
+ star_name = star_name.replace('GSC-', 'GSC ')
90
+ star_name = star_name.replace('UCAC4-', 'UCAC4 ')
91
+
92
+ if 'BD' in star_name:
93
+ star_name = star_name[:3] + star_name[3:].replace('-', ' ')
94
+
95
+ result = None
96
+ connected = False
97
+ trials = 0
98
+ while not connected and trials < max_trials:
99
+ try:
100
+ with warnings.catch_warnings():
101
+ warnings.filterwarnings("ignore")
102
+ result = Simbad.query_object(star_name)
103
+ connected = True
104
+ time.sleep(0.1)
105
+ except requests.ConnectionError:
106
+ trials += 1
107
+
108
+ if result and len(result) > 0:
109
+
110
+ return FixedTarget(
111
+ Hours(_fix_simbad_coordinates(result[0]['RA'])),
112
+ Degrees(_fix_simbad_coordinates(result[0]['DEC'])),
113
+ _fix_simbad_name(result[0]['MAIN_ID']),
114
+ [_fix_simbad_name(ff) for ff in result[0]['IDS'].split('|')]
115
+ )
116
+ else:
117
+ print('No matches found or connection is down.')
118
+ return None
119
+
120
+
121
+ def simbad_search_by_coordinates(ra, dec, radius=Degrees(0.02), max_trials=10):
122
+
123
+ _request_angle(ra)
124
+ _request_angle(dec)
125
+ _request_angle(radius)
126
+
127
+ target = FixedTarget(ra, dec)
128
+
129
+ result = None
130
+ connected = False
131
+ trials = 0
132
+ while not connected and trials < max_trials:
133
+ try:
134
+ with warnings.catch_warnings():
135
+ warnings.filterwarnings("ignore")
136
+ result = Simbad.query_region("{0}d {1}d".format(target.ra.deg(), target.dec.deg()),
137
+ radius='{0}d'.format(radius.deg()))
138
+ connected = True
139
+ time.sleep(0.1)
140
+ except requests.ConnectionError:
141
+ trials += 1
142
+
143
+ if result and len(result) > 0:
144
+ return FixedTarget(
145
+ Hours(_fix_simbad_coordinates(result[0]['RA'])),
146
+ Degrees(_fix_simbad_coordinates(result[0]['DEC'])),
147
+ _fix_simbad_name(result[0]['MAIN_ID']),
148
+ [_fix_simbad_name(ff) for ff in result[0]['IDS'].split('|')]
149
+ )
150
+ else:
151
+ print('No matches found or connection is down.')
152
+ return None