arvi 0.2.1__py3-none-any.whl → 0.2.3__py3-none-any.whl
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.
Potentially problematic release.
This version of arvi might be problematic. Click here for more details.
- arvi/__init__.py +10 -20
- arvi/binning.py +2 -1
- arvi/config.py +12 -4
- arvi/dace_wrapper.py +17 -4
- arvi/exofop_wrapper.py +62 -0
- arvi/extra_data.py +11 -7
- arvi/gaia_wrapper.py +8 -2
- arvi/instrument_specific.py +46 -36
- arvi/plots.py +46 -23
- arvi/reports.py +175 -101
- arvi/setup_logger.py +22 -9
- arvi/simbad_wrapper.py +38 -27
- arvi/timeseries.py +77 -16
- arvi/utils.py +3 -1
- {arvi-0.2.1.dist-info → arvi-0.2.3.dist-info}/METADATA +1 -1
- {arvi-0.2.1.dist-info → arvi-0.2.3.dist-info}/RECORD +19 -18
- {arvi-0.2.1.dist-info → arvi-0.2.3.dist-info}/WHEEL +1 -1
- {arvi-0.2.1.dist-info → arvi-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {arvi-0.2.1.dist-info → arvi-0.2.3.dist-info}/top_level.txt +0 -0
arvi/reports.py
CHANGED
|
@@ -2,7 +2,7 @@ from functools import partial
|
|
|
2
2
|
import numpy as np
|
|
3
3
|
from astropy.timeseries import LombScargle
|
|
4
4
|
|
|
5
|
-
from .setup_logger import
|
|
5
|
+
from .setup_logger import setup_logger
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
sine_line = None
|
|
@@ -27,104 +27,178 @@ def sine_picker(event, self, fig, ax, ax1):
|
|
|
27
27
|
fig.canvas.draw_idle()
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
rows.append(['N'] + list(self.NN.values()))
|
|
36
|
-
|
|
37
|
-
if add_ccf_mask:
|
|
38
|
-
row = ['CCF mask']
|
|
39
|
-
for inst in self.instruments:
|
|
40
|
-
row.append(', '.join(np.unique(getattr(self, inst).ccf_mask)))
|
|
41
|
-
rows.append(row)
|
|
42
|
-
|
|
43
|
-
if add_prog_id:
|
|
44
|
-
row = ['prog ID']
|
|
45
|
-
for inst in self.instruments:
|
|
46
|
-
p = ', '.join(np.unique(getattr(self, inst).prog_id))
|
|
47
|
-
row.append(p)
|
|
48
|
-
rows.append(row)
|
|
49
|
-
|
|
50
|
-
pretty_print_table(rows)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def report(self, save=None):
|
|
54
|
-
import matplotlib.pyplot as plt
|
|
55
|
-
import matplotlib.gridspec as gridspec
|
|
56
|
-
from matplotlib.backends.backend_pdf import PdfPages
|
|
57
|
-
|
|
58
|
-
# size = A4
|
|
59
|
-
size = 8.27, 11.69
|
|
60
|
-
fig = plt.figure(figsize=size, constrained_layout=True)
|
|
61
|
-
gs = gridspec.GridSpec(5, 3, figure=fig, height_ratios=[2, 2, 1, 1, 0.1])
|
|
62
|
-
|
|
63
|
-
# first row, all columns
|
|
64
|
-
ax1 = plt.subplot(gs[0, :])
|
|
65
|
-
|
|
66
|
-
title = f'{self.star}'
|
|
67
|
-
ax1.set_title(title, loc='left', fontsize=14)
|
|
68
|
-
# ax1.set_title(r"\href{http://www.google.com}{link}", color='blue',
|
|
69
|
-
# loc='center')
|
|
70
|
-
|
|
71
|
-
if self._did_adjust_means:
|
|
72
|
-
title = '(instrument means subtracted) '
|
|
73
|
-
else:
|
|
74
|
-
title = ''
|
|
75
|
-
title += f'V={self.simbad.V}, {self.simbad.sp_type}'
|
|
76
|
-
ax1.set_title(title, loc='right', fontsize=12)
|
|
77
|
-
|
|
78
|
-
self.plot(ax=ax1, N_in_label=True, tooltips=False, remove_50000=True)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
ax1.legend().remove()
|
|
82
|
-
legend_ax = plt.subplot(gs[1, -1])
|
|
83
|
-
legend_ax.axis('off')
|
|
84
|
-
leg = plt.legend(*ax1.get_legend_handles_labels(),
|
|
85
|
-
prop={'family': 'monospace'})
|
|
86
|
-
legend_ax.add_artist(leg)
|
|
87
|
-
second_legend = f'rms : {self.rms:.2f} {self.units}\n'
|
|
88
|
-
second_legend += f'error: {self.error:.2f} {self.units}'
|
|
89
|
-
legend_ax.legend([],
|
|
90
|
-
title=second_legend,
|
|
91
|
-
loc='lower right', frameon=False,
|
|
92
|
-
prop={'family': 'monospace'})
|
|
93
|
-
|
|
94
|
-
ax2 = plt.subplot(gs[1, :-1])
|
|
95
|
-
self.gls(ax=ax2, picker=True)
|
|
96
|
-
|
|
97
|
-
ax3 = plt.subplot(gs[2, :-1])
|
|
98
|
-
self.plot_fwhm(ax=ax3, tooltips=False, remove_50000=True)
|
|
99
|
-
ax3.legend().remove()
|
|
100
|
-
ax3p = plt.subplot(gs[2, -1])
|
|
101
|
-
self.gls_fwhm(ax=ax3p, picker=False)
|
|
102
|
-
|
|
103
|
-
ax4 = plt.subplot(gs[3, :-1])
|
|
104
|
-
self.plot_bis(ax=ax4, tooltips=False, remove_50000=True)
|
|
105
|
-
ax4.legend().remove()
|
|
106
|
-
ax4p = plt.subplot(gs[3, -1])
|
|
107
|
-
self.gls_bis(ax=ax4p, picker=False)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if save is None:
|
|
111
|
-
fig.canvas.mpl_connect(
|
|
112
|
-
'pick_event',
|
|
113
|
-
partial(sine_picker, self=self, fig=fig, ax=ax2, ax1=ax1))
|
|
114
|
-
|
|
115
|
-
if save is not None:
|
|
116
|
-
if save is True:
|
|
117
|
-
save = f'report_{"".join(self.star.split())}.pdf'
|
|
118
|
-
|
|
119
|
-
if save.endswith('.png'):
|
|
120
|
-
fig.savefig(save)
|
|
30
|
+
class REPORTS:
|
|
31
|
+
def summary(self, add_ccf_mask=True, add_prog_id=False, **kwargs):
|
|
32
|
+
from .utils import pretty_print_table
|
|
33
|
+
if isinstance(self, list):
|
|
34
|
+
selfs = self
|
|
121
35
|
else:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
36
|
+
selfs = [self]
|
|
37
|
+
|
|
38
|
+
rows = []
|
|
39
|
+
for self in selfs:
|
|
40
|
+
rows.append([self.star] + [''] * len(self.instruments) + [''])
|
|
41
|
+
rows.append([''] + self.instruments + ['full'])
|
|
42
|
+
rows.append(['N'] + list(self.NN.values()) + [self.N])
|
|
43
|
+
rows.append(['RV span'] + [np.ptp(s.mvrad).round(3) for s in self] + [np.ptp(self.mvrad).round(3)])
|
|
44
|
+
rows.append(['RV std'] + [s.mvrad.std().round(3) for s in self] + [self.mvrad.std().round(3)])
|
|
45
|
+
rows.append(['eRV mean'] + [s.msvrad.mean().round(3) for s in self] + [self.msvrad.mean().round(3)])
|
|
46
|
+
|
|
47
|
+
if add_ccf_mask:
|
|
48
|
+
if hasattr(self, 'ccf_mask'):
|
|
49
|
+
row = ['CCF mask']
|
|
50
|
+
for inst in self.instruments:
|
|
51
|
+
row.append(', '.join(np.unique(getattr(self, inst).ccf_mask)))
|
|
52
|
+
row.append('')
|
|
53
|
+
rows.append(row)
|
|
54
|
+
|
|
55
|
+
if add_prog_id:
|
|
56
|
+
row = ['prog ID']
|
|
57
|
+
for inst in self.instruments:
|
|
58
|
+
p = ', '.join(np.unique(getattr(self, inst).prog_id))
|
|
59
|
+
row.append(p)
|
|
60
|
+
rows.append(row)
|
|
61
|
+
|
|
62
|
+
return pretty_print_table(rows, **kwargs)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def summary_one_instrument(self):
|
|
66
|
+
from .utils import pretty_print_table
|
|
67
|
+
if isinstance(self, list):
|
|
68
|
+
selfs = self
|
|
69
|
+
else:
|
|
70
|
+
selfs = [self]
|
|
71
|
+
|
|
72
|
+
rows = []
|
|
73
|
+
rows.append(['', 'N', 'Δt', 'RV std', 'median σRV'])
|
|
74
|
+
for self in selfs:
|
|
75
|
+
rows.append([
|
|
76
|
+
self.star,
|
|
77
|
+
self.N,
|
|
78
|
+
int(np.ptp(self.mtime).round(0)),
|
|
79
|
+
np.std(self.mvrad).round(1),
|
|
80
|
+
np.median(self.msvrad).round(1),
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
pretty_print_table(rows)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def summary_stellar(self, show_ra_dec=True, show_pm=True, **kwargs):
|
|
87
|
+
from .utils import pretty_print_table, get_ra_sexagesimal, get_dec_sexagesimal
|
|
88
|
+
if isinstance(self, list):
|
|
89
|
+
selfs = self
|
|
90
|
+
else:
|
|
91
|
+
selfs = [self]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
rows = []
|
|
96
|
+
rows.append(['star'] + [self.star for self in selfs])
|
|
97
|
+
if show_ra_dec:
|
|
98
|
+
rows.append(['RA'] + [get_ra_sexagesimal(self.simbad.ra) for self in selfs])
|
|
99
|
+
rows.append(['DEC'] + [get_dec_sexagesimal(self.simbad.dec) for self in selfs])
|
|
100
|
+
|
|
101
|
+
if show_pm:
|
|
102
|
+
rows.append(['pm ra'] + [(self.gaia or self.simbad).pmra for self in selfs])
|
|
103
|
+
rows.append(['pm dec'] + [(self.gaia or self.simbad).pmdec for self in selfs])
|
|
104
|
+
|
|
105
|
+
rows.append(['π (mas)'] + [(self.gaia or self.simbad).plx for self in selfs])
|
|
106
|
+
#
|
|
107
|
+
rows.append(['B (mag)'] + [self.simbad._B for self in selfs])
|
|
108
|
+
rows.append(['V (mag)'] + [self.simbad._V for self in selfs])
|
|
109
|
+
rows.append(['B-V'] + [self.simbad._B - self.simbad._V for self in selfs])
|
|
110
|
+
rows.append(["log R'HK"] + [np.nanmean(self.rhk).round(2) for self in selfs])
|
|
111
|
+
# rows.append([''] + self.instruments + ['full'])
|
|
112
|
+
# rows.append(['N'] + list(self.NN.values()) + [self.N])
|
|
113
|
+
# rows.append(['RV span'] + [np.ptp(s.mvrad).round(3) for s in self] + [np.ptp(self.mvrad).round(3)])
|
|
114
|
+
# rows.append(['RV std'] + [s.mvrad.std().round(3) for s in self] + [self.mvrad.std().round(3)])
|
|
115
|
+
# rows.append(['eRV mean'] + [s.msvrad.mean().round(3) for s in self] + [self.msvrad.mean().round(3)])
|
|
116
|
+
|
|
117
|
+
return pretty_print_table(rows, **kwargs)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def report(self, save=None):
|
|
123
|
+
import matplotlib.pyplot as plt
|
|
124
|
+
import matplotlib.gridspec as gridspec
|
|
125
|
+
from matplotlib.backends.backend_pdf import PdfPages
|
|
126
|
+
logger = setup_logger()
|
|
127
|
+
|
|
128
|
+
# size = A4
|
|
129
|
+
size = 8.27, 11.69
|
|
130
|
+
fig = plt.figure(figsize=size, constrained_layout=True)
|
|
131
|
+
gs = gridspec.GridSpec(5, 3, figure=fig, height_ratios=[2, 2, 1, 1, 0.1])
|
|
132
|
+
|
|
133
|
+
# first row, all columns
|
|
134
|
+
ax1 = plt.subplot(gs[0, :])
|
|
135
|
+
|
|
136
|
+
title = f'{self.star}'
|
|
137
|
+
ax1.set_title(title, loc='left', fontsize=14)
|
|
138
|
+
# ax1.set_title(r"\href{http://www.google.com}{link}", color='blue',
|
|
139
|
+
# loc='center')
|
|
140
|
+
|
|
141
|
+
if self._did_adjust_means:
|
|
142
|
+
title = '(instrument means subtracted) '
|
|
143
|
+
else:
|
|
144
|
+
title = ''
|
|
145
|
+
title += f'V={self.simbad.V}, {self.simbad.sp_type}'
|
|
146
|
+
ax1.set_title(title, loc='right', fontsize=12)
|
|
147
|
+
|
|
148
|
+
self.plot(ax=ax1, N_in_label=True, tooltips=False, remove_50000=True)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
ax1.legend().remove()
|
|
152
|
+
legend_ax = plt.subplot(gs[1, -1])
|
|
153
|
+
legend_ax.axis('off')
|
|
154
|
+
leg = plt.legend(*ax1.get_legend_handles_labels(),
|
|
155
|
+
prop={'family': 'monospace'})
|
|
156
|
+
legend_ax.add_artist(leg)
|
|
157
|
+
|
|
158
|
+
second_legend = f'rms : {self.rms:.2f} {self.units}'
|
|
159
|
+
second_legend += f'\nerror: {self.error:.2f} {self.units}'
|
|
160
|
+
|
|
161
|
+
second_legend += f'\n\nCCF masks: {np.unique(self.ccf_mask)}'
|
|
162
|
+
|
|
163
|
+
legend_ax.legend([],
|
|
164
|
+
title=second_legend,
|
|
165
|
+
loc='lower right', frameon=False,
|
|
166
|
+
prop={'family': 'monospace'})
|
|
167
|
+
|
|
168
|
+
ax2 = plt.subplot(gs[1, :-1])
|
|
169
|
+
self.gls(ax=ax2, picker=True)
|
|
170
|
+
|
|
171
|
+
ax3 = plt.subplot(gs[2, :-1])
|
|
172
|
+
self.plot_fwhm(ax=ax3, tooltips=False, remove_50000=True)
|
|
173
|
+
ax3.legend().remove()
|
|
174
|
+
ax3p = plt.subplot(gs[2, -1])
|
|
175
|
+
self.gls_fwhm(ax=ax3p, picker=False)
|
|
176
|
+
|
|
177
|
+
ax4 = plt.subplot(gs[3, :-1])
|
|
178
|
+
self.plot_rhk(ax=ax4, tooltips=False, remove_50000=True)
|
|
179
|
+
ax4.legend().remove()
|
|
180
|
+
ax4p = plt.subplot(gs[3, -1])
|
|
181
|
+
self.gls_rhk(ax=ax4p, picker=False)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
if save is None:
|
|
185
|
+
fig.canvas.mpl_connect(
|
|
186
|
+
'pick_event',
|
|
187
|
+
partial(sine_picker, self=self, fig=fig, ax=ax2, ax1=ax1))
|
|
188
|
+
|
|
189
|
+
if save is not None:
|
|
190
|
+
if save is True:
|
|
191
|
+
save = f'report_{"".join(self.star.split())}.pdf'
|
|
192
|
+
|
|
193
|
+
if save.endswith('.png'):
|
|
194
|
+
fig.savefig(save)
|
|
195
|
+
else:
|
|
196
|
+
with PdfPages(save) as pdf:
|
|
197
|
+
#pdf.attach_note('hello', positionRect=[5, 15, 20, 30])
|
|
198
|
+
|
|
199
|
+
if self.verbose:
|
|
200
|
+
logger.info(f'saving to {save}')
|
|
201
|
+
pdf.savefig(fig)
|
|
202
|
+
# os.system(f'evince {save} &')
|
|
203
|
+
|
|
204
|
+
return fig
|
arvi/setup_logger.py
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import sys
|
|
2
|
-
from loguru import logger
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
logger
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
def setup_logger():
|
|
4
|
+
from loguru import logger
|
|
5
|
+
try:
|
|
6
|
+
import marimo as mo
|
|
7
|
+
if mo.running_in_notebook():
|
|
8
|
+
raise NotImplementedError
|
|
9
|
+
except NotImplementedError:
|
|
10
|
+
pass
|
|
11
|
+
except (ImportError, ModuleNotFoundError):
|
|
12
|
+
logger.remove()
|
|
13
|
+
else:
|
|
14
|
+
logger.remove()
|
|
15
|
+
|
|
16
|
+
logger.configure(extra={"indent": ""})
|
|
17
|
+
logger.add(
|
|
18
|
+
sys.stdout,
|
|
19
|
+
colorize=True,
|
|
20
|
+
# format="<green>{time:YYYY-MM-DDTHH:mm:ss}</green> <level>{message}</level>",
|
|
21
|
+
format="{extra[indent]}<level>{message}</level>",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
return logger
|
arvi/simbad_wrapper.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import numpy as np
|
|
3
2
|
import requests
|
|
4
3
|
from dataclasses import dataclass
|
|
5
4
|
|
|
6
|
-
import
|
|
5
|
+
import numpy as np
|
|
7
6
|
|
|
8
7
|
try:
|
|
9
8
|
from uncertainties import ufloat
|
|
@@ -12,7 +11,6 @@ except ImportError:
|
|
|
12
11
|
|
|
13
12
|
from .stellar import EFFECTIVE_TEMPERATURES, teff_to_sptype
|
|
14
13
|
from .translations import translate
|
|
15
|
-
from .setup_logger import logger
|
|
16
14
|
|
|
17
15
|
DATA_PATH = os.path.dirname(__file__)
|
|
18
16
|
DATA_PATH = os.path.join(DATA_PATH, 'data')
|
|
@@ -146,6 +144,7 @@ class simbad:
|
|
|
146
144
|
star (str): The name of the star to query simbad
|
|
147
145
|
"""
|
|
148
146
|
from astropy.coordinates import SkyCoord
|
|
147
|
+
import pysweetcat
|
|
149
148
|
|
|
150
149
|
self.star = translate(star, ngc=True, ic=True)
|
|
151
150
|
|
|
@@ -170,41 +169,52 @@ class simbad:
|
|
|
170
169
|
if _debug:
|
|
171
170
|
print('table1:', table1)
|
|
172
171
|
cols, values = parse_table1(table1)
|
|
172
|
+
except IndexError:
|
|
173
|
+
raise ValueError(f'simbad query for {star} failed') from None
|
|
173
174
|
|
|
175
|
+
try:
|
|
174
176
|
table2 = run_query(query=BV_QUERY.format(star=self.star))
|
|
175
177
|
if _debug:
|
|
176
178
|
print('table2:', table2)
|
|
177
179
|
cols, values = parse_table1(table2, cols, values)
|
|
180
|
+
except IndexError:
|
|
181
|
+
self.B = self.V = np.nan
|
|
178
182
|
|
|
183
|
+
try:
|
|
179
184
|
table3 = run_query(query=IDS_QUERY.format(star=self.star))
|
|
180
185
|
if _debug:
|
|
181
186
|
print('table3:', table3)
|
|
182
187
|
line = table3.splitlines()[2]
|
|
183
188
|
self.ids = line.replace('"', '').replace(' ', ' ').replace(' ', ' ').replace(' ', ' ').split('|')
|
|
189
|
+
except IndexError:
|
|
190
|
+
self.ids = []
|
|
191
|
+
|
|
192
|
+
table4 = run_query(query=FILTERS_QUERY.format(star=self.star))
|
|
193
|
+
if _debug:
|
|
194
|
+
print('table4:\n', table4)
|
|
195
|
+
for row in table4.splitlines()[2:]:
|
|
196
|
+
filter_name, mag, mag_err, bibcode = row.replace('"', '').split('|')
|
|
197
|
+
filter_name = filter_name.strip()
|
|
198
|
+
try:
|
|
199
|
+
setattr(self, '_' + filter_name, ufloat(float(mag), float(mag_err)))
|
|
200
|
+
except ValueError:
|
|
201
|
+
setattr(self, '_' + filter_name, float(mag))
|
|
184
202
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
_bibcode.append(bibcode)
|
|
200
|
-
_teff.append(parse_value(teff))
|
|
201
|
-
_logg.append(parse_value(log_g, prec=log_g_prec))
|
|
202
|
-
_feh.append(parse_value(fe_h, prec=fe_h_prec))
|
|
203
|
-
|
|
204
|
-
self.measurements = Measurements(_teff, _logg, _feh, _bibcode)
|
|
203
|
+
# measurements table
|
|
204
|
+
table5 = run_query(query=MEAS_QUERY.format(star=self.star))
|
|
205
|
+
if _debug:
|
|
206
|
+
print('table5:\n', table5)
|
|
207
|
+
|
|
208
|
+
_teff, _logg, _feh, _bibcode = [], [], [], []
|
|
209
|
+
for row in table5.splitlines()[2:]:
|
|
210
|
+
teff, log_g, log_g_prec, fe_h, fe_h_prec, bibcode = row.replace('"', '').split('|')
|
|
211
|
+
_bibcode.append(bibcode)
|
|
212
|
+
_teff.append(parse_value(teff))
|
|
213
|
+
_logg.append(parse_value(log_g, prec=log_g_prec))
|
|
214
|
+
_feh.append(parse_value(fe_h, prec=fe_h_prec))
|
|
215
|
+
|
|
216
|
+
self.measurements = Measurements(_teff, _logg, _feh, _bibcode)
|
|
205
217
|
|
|
206
|
-
except IndexError:
|
|
207
|
-
raise ValueError(f'simbad query for {star} failed') from None
|
|
208
218
|
|
|
209
219
|
try:
|
|
210
220
|
self.gaia_id = int([i for i in self.ids if 'Gaia DR3' in i][0]
|
|
@@ -245,8 +255,9 @@ class simbad:
|
|
|
245
255
|
|
|
246
256
|
except IndexError:
|
|
247
257
|
if self.sp_type == '':
|
|
248
|
-
|
|
249
|
-
|
|
258
|
+
if len(self.measurements.teff) > 0:
|
|
259
|
+
self.teff = int(np.mean(self.measurements.teff))
|
|
260
|
+
self.sp_type = teff_to_sptype(self.teff)
|
|
250
261
|
elif self.sp_type[:2] in EFFECTIVE_TEMPERATURES:
|
|
251
262
|
self.teff = EFFECTIVE_TEMPERATURES[self.sp_type[:2]]
|
|
252
263
|
|
arvi/timeseries.py
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
3
|
from typing import Union
|
|
4
|
-
from functools import
|
|
4
|
+
from functools import partial, partialmethod
|
|
5
5
|
from glob import glob
|
|
6
6
|
import warnings
|
|
7
7
|
from copy import deepcopy
|
|
8
8
|
from datetime import datetime, timezone
|
|
9
9
|
import numpy as np
|
|
10
10
|
|
|
11
|
-
from .setup_logger import
|
|
11
|
+
from .setup_logger import setup_logger
|
|
12
|
+
logger = setup_logger()
|
|
13
|
+
|
|
12
14
|
from .config import config
|
|
13
15
|
from .translations import translate
|
|
14
16
|
from .dace_wrapper import do_download_filetype, do_symlink_filetype, get_observations, get_arrays
|
|
15
17
|
from .simbad_wrapper import simbad
|
|
16
18
|
from .gaia_wrapper import gaia
|
|
19
|
+
from .exofop_wrapper import exofop
|
|
17
20
|
from .extra_data import get_extra_data
|
|
18
21
|
from .stats import wmean, wrms
|
|
19
22
|
from .binning import bin_ccf_mask, binRV
|
|
20
23
|
from .HZ import getHZ_period
|
|
24
|
+
from .instrument_specific import ISSUES
|
|
25
|
+
from .reports import REPORTS
|
|
21
26
|
from .utils import sanitize_path, strtobool, there_is_internet, timer, chdir
|
|
22
27
|
from .utils import lazy_import
|
|
23
28
|
|
|
@@ -30,8 +35,8 @@ class ExtraFields:
|
|
|
30
35
|
return list(self.__dict__.keys())
|
|
31
36
|
|
|
32
37
|
|
|
33
|
-
@dataclass
|
|
34
|
-
class RV:
|
|
38
|
+
@dataclass(order=False)
|
|
39
|
+
class RV(ISSUES, REPORTS):
|
|
35
40
|
"""
|
|
36
41
|
A class holding RV observations
|
|
37
42
|
|
|
@@ -68,23 +73,29 @@ class RV:
|
|
|
68
73
|
_did_adjust_means: bool = field(init=False, repr=False, default=False)
|
|
69
74
|
_did_simbad_query: bool = field(init=False, repr=False, default=False)
|
|
70
75
|
_did_gaia_query: bool = field(init=False, repr=False, default=False)
|
|
76
|
+
_did_toi_query: bool = field(init=False, repr=False, default=False)
|
|
71
77
|
_raise_on_error: bool = field(init=True, repr=False, default=True)
|
|
78
|
+
__masked_numbers: bool = field(init=False, repr=False, default=False)
|
|
72
79
|
#
|
|
73
80
|
_simbad = None
|
|
74
81
|
_gaia = None
|
|
82
|
+
_toi = None
|
|
75
83
|
|
|
76
84
|
def __repr__(self):
|
|
77
85
|
ni = len(self.instruments)
|
|
78
86
|
if self.N == 0:
|
|
79
87
|
return f"RV(star='{self.star}', N=0)"
|
|
80
88
|
|
|
81
|
-
|
|
89
|
+
if self._child:
|
|
90
|
+
i = ''
|
|
91
|
+
else:
|
|
92
|
+
i = f', {ni} instrument' + ('s' if ni > 1 else '')
|
|
82
93
|
|
|
83
94
|
if self.time.size == self.mtime.size:
|
|
84
|
-
return f"RV(star='{self.star}', N={self.N}
|
|
95
|
+
return f"RV(star='{self.star}', N={self.N}{i})"
|
|
85
96
|
else:
|
|
86
97
|
nmasked = self.N - self.mtime.size
|
|
87
|
-
return f"RV(star='{self.star}', N={self.N}, masked={nmasked}
|
|
98
|
+
return f"RV(star='{self.star}', N={self.N}, masked={nmasked}{i})"
|
|
88
99
|
|
|
89
100
|
@property
|
|
90
101
|
def simbad(self):
|
|
@@ -144,6 +155,26 @@ class RV:
|
|
|
144
155
|
self._did_gaia_query = True
|
|
145
156
|
return self._gaia
|
|
146
157
|
|
|
158
|
+
@property
|
|
159
|
+
def toi(self):
|
|
160
|
+
if self._toi is not None:
|
|
161
|
+
return self._toi
|
|
162
|
+
|
|
163
|
+
if 'TOI' not in self.__star__ or 'TIC' not in self.__star__ or self._child or self._did_toi_query:
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
if self.verbose:
|
|
167
|
+
logger.info('querying ExoFOP...')
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
self._toi = exofop(self.__star__)
|
|
171
|
+
except ValueError:
|
|
172
|
+
if self.verbose:
|
|
173
|
+
logger.error(f'ExoFOP query for {self.__star__} failed')
|
|
174
|
+
|
|
175
|
+
self._did_toi_query = True
|
|
176
|
+
return self._toi
|
|
177
|
+
|
|
147
178
|
def __post_init_special_sun(self):
|
|
148
179
|
import pickle
|
|
149
180
|
from .extra_data import get_sun_data
|
|
@@ -168,7 +199,7 @@ class RV:
|
|
|
168
199
|
import concurrent.futures
|
|
169
200
|
with timer('simbad and gaia queries'):
|
|
170
201
|
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
|
|
171
|
-
executor.map(self.__getattribute__, ('simbad', 'gaia'))
|
|
202
|
+
executor.map(self.__getattribute__, ('simbad', 'gaia', 'toi'))
|
|
172
203
|
|
|
173
204
|
# with timer('simbad query'):
|
|
174
205
|
# self.simbad
|
|
@@ -241,7 +272,6 @@ class RV:
|
|
|
241
272
|
# all other quantities
|
|
242
273
|
self._build_arrays()
|
|
243
274
|
|
|
244
|
-
|
|
245
275
|
if self.load_extra_data:
|
|
246
276
|
if isinstance(self.load_extra_data, str):
|
|
247
277
|
path = self.load_extra_data
|
|
@@ -314,6 +344,16 @@ class RV:
|
|
|
314
344
|
for inst in self.instruments:
|
|
315
345
|
yield getattr(self, inst)
|
|
316
346
|
|
|
347
|
+
@property
|
|
348
|
+
def _masked_numbers(self):
|
|
349
|
+
return self.__masked_numbers
|
|
350
|
+
|
|
351
|
+
@_masked_numbers.setter
|
|
352
|
+
def _masked_numbers(self, value):
|
|
353
|
+
self.__masked_numbers = value
|
|
354
|
+
if not self._child:
|
|
355
|
+
for s in self:
|
|
356
|
+
s._masked_numbers = value
|
|
317
357
|
|
|
318
358
|
def reload(self):
|
|
319
359
|
self._did_secular_acceleration = False
|
|
@@ -335,19 +375,35 @@ class RV:
|
|
|
335
375
|
@property
|
|
336
376
|
def N(self) -> int:
|
|
337
377
|
"""Total number of observations"""
|
|
378
|
+
if self._masked_numbers:
|
|
379
|
+
return self.mtime.size
|
|
338
380
|
return self.time.size
|
|
339
381
|
|
|
340
382
|
@property
|
|
341
383
|
def NN(self):
|
|
342
384
|
""" Total number of observations per instrument """
|
|
385
|
+
if self._child:
|
|
386
|
+
return {self.instruments[0]: self.N}
|
|
343
387
|
return {inst: getattr(self, inst).N for inst in self.instruments}
|
|
344
388
|
|
|
345
389
|
@property
|
|
346
390
|
def N_nights(self) -> int:
|
|
347
391
|
""" Number of individual nights """
|
|
348
|
-
|
|
349
|
-
return
|
|
350
|
-
|
|
392
|
+
def get_nights(t):
|
|
393
|
+
return binRV(t, None, None, binning_bins=True).size - 1
|
|
394
|
+
|
|
395
|
+
if self._masked_numbers:
|
|
396
|
+
if self._child:
|
|
397
|
+
return get_nights(self.mtime)
|
|
398
|
+
else:
|
|
399
|
+
return sum([get_nights(s.mtime) for s in self])
|
|
400
|
+
else:
|
|
401
|
+
if self._child:
|
|
402
|
+
return get_nights(self.time)
|
|
403
|
+
else:
|
|
404
|
+
return sum([get_nights(s.time) for s in self])
|
|
405
|
+
# return binRV(_t, None, None, binning_bins=True).size - 1
|
|
406
|
+
# return sum(list(self.NN.values()))
|
|
351
407
|
|
|
352
408
|
@property
|
|
353
409
|
def NN_nights(self):
|
|
@@ -516,8 +572,8 @@ class RV:
|
|
|
516
572
|
return s
|
|
517
573
|
|
|
518
574
|
@classmethod
|
|
519
|
-
def from_rdb(cls, files, star=None, instrument=None,
|
|
520
|
-
header_skip=2, **kwargs):
|
|
575
|
+
def from_rdb(cls, files, star=None, instrument=None, instrument_suffix=None,
|
|
576
|
+
units='ms', header_skip=2, **kwargs):
|
|
521
577
|
""" Create an RV object from an rdb file or a list of rdb files
|
|
522
578
|
|
|
523
579
|
Args:
|
|
@@ -568,6 +624,9 @@ class RV:
|
|
|
568
624
|
if instruments.size == 1 and len(files) > 1:
|
|
569
625
|
instruments = np.repeat(instruments, len(files))
|
|
570
626
|
|
|
627
|
+
if instrument_suffix is not None:
|
|
628
|
+
instruments = [i + instrument_suffix for i in instruments]
|
|
629
|
+
|
|
571
630
|
factor = 1e3 if units == 'kms' else 1.0
|
|
572
631
|
|
|
573
632
|
s = cls(star, _child=True, **kwargs)
|
|
@@ -744,6 +803,8 @@ class RV:
|
|
|
744
803
|
|
|
745
804
|
s._child = False
|
|
746
805
|
s.instruments = list(map(str, instruments))
|
|
806
|
+
s.filenames = list(map(str, files))
|
|
807
|
+
|
|
747
808
|
s._build_arrays()
|
|
748
809
|
|
|
749
810
|
if kwargs.get('do_adjust_means', False):
|
|
@@ -1188,9 +1249,9 @@ class RV:
|
|
|
1188
1249
|
|
|
1189
1250
|
from .plots import plot, plot_fwhm, plot_bispan, plot_contrast, plot_rhk, plot_berv, plot_quantity
|
|
1190
1251
|
from .plots import gls, gls_fwhm, gls_bispan, gls_rhk, gls_quantity, window_function
|
|
1191
|
-
from .reports import report
|
|
1192
1252
|
|
|
1193
|
-
from .
|
|
1253
|
+
# from .reports import report
|
|
1254
|
+
# from .instrument_specific import known_issues
|
|
1194
1255
|
|
|
1195
1256
|
def change_instrument_name(self, old_name, new_name, strict=False):
|
|
1196
1257
|
""" Change the name of an instrument
|
arvi/utils.py
CHANGED
|
@@ -21,7 +21,7 @@ except ImportError:
|
|
|
21
21
|
tqdm = lambda x, *args, **kwargs: x
|
|
22
22
|
trange = lambda *args, **kwargs: range(*args, **kwargs)
|
|
23
23
|
|
|
24
|
-
from .setup_logger import
|
|
24
|
+
from .setup_logger import setup_logger
|
|
25
25
|
from .config import config
|
|
26
26
|
|
|
27
27
|
|
|
@@ -70,6 +70,8 @@ def all_logging_disabled():
|
|
|
70
70
|
@contextmanager
|
|
71
71
|
def timer(name=None):
|
|
72
72
|
""" A simple context manager to time a block of code """
|
|
73
|
+
logger = setup_logger()
|
|
74
|
+
|
|
73
75
|
if not config.debug:
|
|
74
76
|
yield
|
|
75
77
|
return
|