arvi 0.1.13__py3-none-any.whl → 0.1.14__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 +21 -6
- arvi/berv.py +437 -0
- arvi/dace_wrapper.py +1 -1
- arvi/headers.py +47 -0
- arvi/plots.py +1 -0
- arvi/programs.py +4 -2
- arvi/stellar.py +89 -0
- arvi/timeseries.py +104 -37
- arvi/translations.py +2 -0
- {arvi-0.1.13.dist-info → arvi-0.1.14.dist-info}/METADATA +1 -1
- {arvi-0.1.13.dist-info → arvi-0.1.14.dist-info}/RECORD +14 -11
- {arvi-0.1.13.dist-info → arvi-0.1.14.dist-info}/WHEEL +1 -1
- {arvi-0.1.13.dist-info → arvi-0.1.14.dist-info}/LICENSE +0 -0
- {arvi-0.1.13.dist-info → arvi-0.1.14.dist-info}/top_level.txt +0 -0
arvi/__init__.py
CHANGED
|
@@ -2,18 +2,33 @@ __all__ = ['RV']
|
|
|
2
2
|
|
|
3
3
|
from .timeseries import RV
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## OLD
|
|
6
|
+
# # the __getattr__ function is always called twice, so we need this
|
|
7
|
+
# # to only build and return the RV object on the second time
|
|
8
|
+
# _ran_once = False
|
|
6
9
|
|
|
7
10
|
def __getattr__(name: str):
|
|
8
11
|
if name in (
|
|
9
12
|
'_ipython_canary_method_should_not_exist_',
|
|
13
|
+
'_ipython_display_',
|
|
10
14
|
'_repr_mimebundle_',
|
|
11
15
|
'__wrapped__'
|
|
12
16
|
):
|
|
13
17
|
return
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
try:
|
|
20
|
+
globals()[name] = RV(name)
|
|
21
|
+
return globals()[name]
|
|
22
|
+
except ValueError as e:
|
|
23
|
+
raise ImportError(e) from None
|
|
24
|
+
# raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
25
|
+
|
|
26
|
+
## OLD
|
|
27
|
+
# # can't do it any other way :(
|
|
28
|
+
# global _ran_once
|
|
29
|
+
|
|
30
|
+
# if _ran_once:
|
|
31
|
+
# _ran_once = False
|
|
32
|
+
# return RV(name)
|
|
33
|
+
# else:
|
|
34
|
+
# _ran_once = True
|
arvi/berv.py
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import numpy as np
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
|
|
5
|
+
from arvi.headers import get_headers
|
|
6
|
+
from barycorrpy import get_BC_vel
|
|
7
|
+
from astropy.coordinates import SkyCoord
|
|
8
|
+
from astropy.time import Time
|
|
9
|
+
from astropy import units as u
|
|
10
|
+
from astropy import constants as const
|
|
11
|
+
from astropy.timeseries import LombScargle
|
|
12
|
+
from tqdm import tqdm
|
|
13
|
+
|
|
14
|
+
from .setup_logger import logger
|
|
15
|
+
from . import config
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def correct_rvs(self, simple=False, H=None, save_files=False, plot=True):
|
|
19
|
+
"""
|
|
20
|
+
"""
|
|
21
|
+
import pickle
|
|
22
|
+
|
|
23
|
+
if hasattr(self, '_did_correct_berv') and self._did_correct_berv:
|
|
24
|
+
logger.info('Already corrected for the BERV! Not doing anything.')
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
path = os.path.dirname(__file__)
|
|
28
|
+
path = os.path.join(path, 'data')
|
|
29
|
+
pkl = os.path.join(path, 'berv_espresso_sine.pkl')
|
|
30
|
+
berv_espresso = pickle.load(open(pkl, 'rb'))
|
|
31
|
+
|
|
32
|
+
if simple:
|
|
33
|
+
logger.info('Correcting RVs with a previously-fitted sinusoid function')
|
|
34
|
+
_f = berv_espresso['func'].replace('lambda t: ', '')
|
|
35
|
+
logger.info(f': {_f}')
|
|
36
|
+
f = eval(berv_espresso['func'])
|
|
37
|
+
if plot:
|
|
38
|
+
_, ax = self.plot()
|
|
39
|
+
ax.plot(self._tt, f(self._tt) + self.vrad.mean(), 'k')
|
|
40
|
+
_, axgls = self.gls(label='before')
|
|
41
|
+
|
|
42
|
+
self.vrad = self.vrad + f(self.time)
|
|
43
|
+
|
|
44
|
+
if plot:
|
|
45
|
+
self.gls(ax=axgls, label='after')
|
|
46
|
+
|
|
47
|
+
return f(self.time)
|
|
48
|
+
|
|
49
|
+
else:
|
|
50
|
+
logger.info('Correcting RVs with actual difference between BERVs')
|
|
51
|
+
logger.info('(basically, use BERV_barycorrpy for BERV correction)')
|
|
52
|
+
|
|
53
|
+
old_vrad = self.vrad.copy()
|
|
54
|
+
|
|
55
|
+
_, berv = BERV(self, H=H, use_gaia_meassurements=True, plx=self.gaia.plx,
|
|
56
|
+
plot=False, ignore_mask=True)
|
|
57
|
+
|
|
58
|
+
if plot:
|
|
59
|
+
fig, axs = plt.subplots(2, 1, constrained_layout=True, height_ratios=(3, 1), sharex=True)
|
|
60
|
+
_, ax = self.plot(ax=axs[0])
|
|
61
|
+
_, axgls = self.gls(label='before')
|
|
62
|
+
|
|
63
|
+
# undo secular acceleration, if it was done
|
|
64
|
+
_did_secular_acceleration = self._did_secular_acceleration
|
|
65
|
+
self._undo_secular_acceleration()
|
|
66
|
+
|
|
67
|
+
# transform RVs: RV --> RV - BERVpipe + BERVbarycorrpy
|
|
68
|
+
|
|
69
|
+
diff = berv[self.star]['berv_barycorrpy'] - berv[self.star]['berv_pipeline']
|
|
70
|
+
|
|
71
|
+
if save_files:
|
|
72
|
+
i_inst = np.hstack([np.arange(n) for n in self.NN.values()])
|
|
73
|
+
with open(f'{self.star}_berv_correction.rdb', 'w') as rdb:
|
|
74
|
+
rdb.write('# time\n')
|
|
75
|
+
rdb.write('# vrad\n')
|
|
76
|
+
rdb.write('# svrad\n')
|
|
77
|
+
rdb.write('# berv - BERV value from header\n')
|
|
78
|
+
rdb.write('# berv_pipe - BERV from header corrected for 1.55e-8 factor\n')
|
|
79
|
+
rdb.write('# berv_barycorrpy - BERV value from barycorrpy\n')
|
|
80
|
+
rdb.write('# diff - difference between berv_barycorrpy and berv_pipe\n')
|
|
81
|
+
rdb.write('# vrad_berv_corrected = vrad + diff\n')
|
|
82
|
+
rdb.write('# instrument\n')
|
|
83
|
+
rdb.write('# i - index\n')
|
|
84
|
+
rdb.write('# i_inst - index within the instrument\n')
|
|
85
|
+
rdb.write('#\n')
|
|
86
|
+
rdb.write('# --> TO CORRECT vrad, we ** add the diff column **\n')
|
|
87
|
+
rdb.write('# --> the result of this operation is in column vrad_berv_corrected\n')
|
|
88
|
+
rdb.write('# --> vrad_berv_corrected is already corrected for the secular acceleration, vrad is not\n')
|
|
89
|
+
rdb.write('#\n')
|
|
90
|
+
#
|
|
91
|
+
cols = [
|
|
92
|
+
'time', 'vrad', 'svrad',
|
|
93
|
+
'berv', 'berv_pipe', 'berv_barycorrpy', 'diff', 'vrad_berv_corrected',
|
|
94
|
+
'instrument', 'i', 'i_inst'
|
|
95
|
+
]
|
|
96
|
+
rdb.write('# ' + '\t'.join(cols) + '\n')
|
|
97
|
+
for i, t in enumerate(self.time):
|
|
98
|
+
rdb.write(f'{t:11.5f}\t')
|
|
99
|
+
# if _did_secular_acceleration:
|
|
100
|
+
# rdb.write(f'{old_vrad[i]:13.5f}\t')
|
|
101
|
+
# else:
|
|
102
|
+
rdb.write(f'{self.vrad[i]:13.7f}\t')
|
|
103
|
+
rdb.write(f'{self.svrad[i]:13.7f}\t')
|
|
104
|
+
rdb.write(f'{self.berv[i]:15.7f}\t')
|
|
105
|
+
rdb.write(f'{berv[self.star]["berv_pipeline"][i]/1e3:15.7f}\t')
|
|
106
|
+
rdb.write(f'{berv[self.star]["berv_barycorrpy"][i]/1e3:15.7f}\t')
|
|
107
|
+
rdb.write(f'{diff[i]:15.7f}\t')
|
|
108
|
+
rdb.write(f'{self.vrad[i] + diff[i]:13.7f}\t')
|
|
109
|
+
rdb.write(f'{self.instrument_array[i]}\t')
|
|
110
|
+
rdb.write(f'{i}\t')
|
|
111
|
+
rdb.write(f'{i_inst[i]}\t')
|
|
112
|
+
rdb.write('\n')
|
|
113
|
+
|
|
114
|
+
self.add_to_vrad(diff)
|
|
115
|
+
self._did_correct_berv = True
|
|
116
|
+
self._did_secular_acceleration = True # "automatically", by using BERV_barycorrpy
|
|
117
|
+
self._did_secular_acceleration_simbad = False
|
|
118
|
+
self._did_secular_acceleration_epoch = Time('J2016').jd - 24e5
|
|
119
|
+
|
|
120
|
+
# the secular acceleration hadn't been done, but it was introduced by
|
|
121
|
+
# BERV_barycorrpy, so we need to undo it
|
|
122
|
+
if not _did_secular_acceleration:
|
|
123
|
+
self._undo_secular_acceleration()
|
|
124
|
+
|
|
125
|
+
if plot:
|
|
126
|
+
self.plot(ax=axs[0], marker='+', ms=5)
|
|
127
|
+
axs[1].plot(self.time, old_vrad - self.vrad, '.k', label='old RV - new RV')
|
|
128
|
+
ma = np.abs(axs[1].get_ylim()).max()
|
|
129
|
+
axs[1].set(ylim=(-ma, ma), xlabel=axs[0].get_xlabel(), ylabel='RV difference [m/s]')
|
|
130
|
+
self.gls(ax=axgls, label='after')
|
|
131
|
+
|
|
132
|
+
return diff
|
|
133
|
+
|
|
134
|
+
def get_A_and_V_from_lesta(self, username=config.username):
|
|
135
|
+
try:
|
|
136
|
+
import paramiko
|
|
137
|
+
except ImportError:
|
|
138
|
+
raise ImportError("paramiko is not installed. Please install it with 'pip install paramiko'")
|
|
139
|
+
|
|
140
|
+
logs = []
|
|
141
|
+
for f in self.raw_file:
|
|
142
|
+
f = f.replace('espresso/', '/projects/astro/ESPRESSODRS/')
|
|
143
|
+
f = f.replace('nirps/', '/projects/astro/NIRPSDRS/')
|
|
144
|
+
f = f.replace('.fits', '_SCIENCE_FP.log')
|
|
145
|
+
f = f.replace('reduced', 'log')
|
|
146
|
+
f = f.replace('r.ESPRE', 'ESPRESSO')
|
|
147
|
+
logs.append(f)
|
|
148
|
+
|
|
149
|
+
A, V = [], []
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
ssh = paramiko.SSHClient()
|
|
153
|
+
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
154
|
+
ssh.connect("lesta02.astro.unige.ch", username=username, timeout=5)
|
|
155
|
+
except Exception as e:
|
|
156
|
+
if 'getaddrinfo failed' in str(e):
|
|
157
|
+
jump = paramiko.SSHClient()
|
|
158
|
+
jump.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
159
|
+
jump.connect('login01.astro.unige.ch', username=username, timeout=5)
|
|
160
|
+
jump_transport = jump.get_transport()
|
|
161
|
+
jump_channel = jump_transport.open_channel('direct-tcpip', ('10.194.64.162', 22), ('129.194.64.20', 22))
|
|
162
|
+
ssh = paramiko.SSHClient()
|
|
163
|
+
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
164
|
+
ssh.connect('lesta02.astro.unige.ch', username=username, sock=jump_channel)
|
|
165
|
+
else:
|
|
166
|
+
raise e
|
|
167
|
+
|
|
168
|
+
with ssh.open_sftp() as sftp:
|
|
169
|
+
pbar = tqdm(logs, total=len(logs), unit='file', desc='Reading logs')
|
|
170
|
+
for f in pbar:
|
|
171
|
+
with sftp.open(f) as fp:
|
|
172
|
+
pattern1 = 'Sun-Earth'
|
|
173
|
+
pattern2 = "Barycentric Observer's Velocity"
|
|
174
|
+
for line in fp:
|
|
175
|
+
if pattern1 in line:
|
|
176
|
+
value = line.strip().split(':')[-1].replace('\x1b[32m', '').replace('\x1b[0m', '').replace(' ', '')
|
|
177
|
+
A.append(float(value))
|
|
178
|
+
if pattern2 in line:
|
|
179
|
+
value = line.strip().split(':')[-1].replace('\x1b[32m', '').replace('\x1b[0m', '').replace(' ', '')
|
|
180
|
+
V.append(float(value))
|
|
181
|
+
|
|
182
|
+
ssh.close()
|
|
183
|
+
|
|
184
|
+
return np.array(A), np.array(V)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def BERV(self, H=None, use_gaia_meassurements=False, plx=None,
|
|
188
|
+
A=None, V=None, plot=True, ignore_mask=False, verbose=False, dpi=None):
|
|
189
|
+
""" Calculate Barycentric Radial Velocity with barycorr and compare with pipeline
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
H (list, optional):
|
|
193
|
+
List of (CCF/S1D/etc) headers for the target. If None, try to
|
|
194
|
+
download the CCF files to get the headers.
|
|
195
|
+
use_gaia_meassurements (bool, optional):
|
|
196
|
+
Use Gaia coordinates and proper motions instead of those in the headers.
|
|
197
|
+
plx (float, optional):
|
|
198
|
+
Value of stellar parallax [mas] to use in barycorr.
|
|
199
|
+
A (array, optional):
|
|
200
|
+
Earth-Sun distance [AU] for each BJD (found in the pipeline logs).
|
|
201
|
+
V (array, optional):
|
|
202
|
+
Earth's orbital velocity [km/s] for each BJD (found in the pipeline logs).
|
|
203
|
+
plot (bool, optional):
|
|
204
|
+
Plot the results.
|
|
205
|
+
"""
|
|
206
|
+
if H is None:
|
|
207
|
+
H = get_headers(self, check_lesta=False, check_exo2=False, instrument='ESPRE')
|
|
208
|
+
|
|
209
|
+
if len(H) != self.N:
|
|
210
|
+
raise ValueError(f'Expected {self.N} headers (in `H`), got {len(H)}')
|
|
211
|
+
|
|
212
|
+
if 'HARPS' in H[0]['INSTRUME'] or 'NIRPS' in H[0]['INSTRUME']:
|
|
213
|
+
obsname = 'lasilla'
|
|
214
|
+
elif 'ESPRESSO' in H[0]['INSTRUME']:
|
|
215
|
+
obsname = 'paranal'
|
|
216
|
+
else:
|
|
217
|
+
raise ValueError('unknown instrument')
|
|
218
|
+
|
|
219
|
+
bjd = np.array([h['HIERARCH ESO QC BJD'] for h in H])
|
|
220
|
+
bjd -= 24e5
|
|
221
|
+
berv_pipeline = np.array([h['HIERARCH ESO QC BERV'] for h in H])
|
|
222
|
+
|
|
223
|
+
# in the pipeline, the BERV is used to shift wavelenghts with this formula
|
|
224
|
+
# berv_factor = (1 + 1.55e-8) * (1 + BERV/c)
|
|
225
|
+
# The 1.55e-8 factor is an average of some relativistic effects, which are
|
|
226
|
+
# probably already included in the BERV calculated from barycorrpy.
|
|
227
|
+
# Therefore, we compute an "effective" BERV from the pipeline doing
|
|
228
|
+
# (1 + 1.55e-8) * (1 + BERV/c) = 1 + effBERV/c
|
|
229
|
+
# => effBERV = ((1 + 1.55e-8) * (1 + BERV/c) - 1) * c
|
|
230
|
+
|
|
231
|
+
if A is None and V is None:
|
|
232
|
+
if verbose:
|
|
233
|
+
logger.info("Using mean value for Earth-Sun distance and Earth's orbital velocity")
|
|
234
|
+
|
|
235
|
+
if A is None:
|
|
236
|
+
Φobs = const.G * const.M_sun / const.au + const.G * const.M_earth / const.R_earth
|
|
237
|
+
else:
|
|
238
|
+
A = np.atleast_1d(A) * u.km
|
|
239
|
+
Φobs = const.G * const.M_sun / A + const.G * const.M_earth / const.R_earth
|
|
240
|
+
|
|
241
|
+
if V is None:
|
|
242
|
+
V = 29785 *u.m / u.second
|
|
243
|
+
else:
|
|
244
|
+
V = np.atleast_1d(V) * u.km / u.second
|
|
245
|
+
|
|
246
|
+
f = 1 / (1 - Φobs / const.c**2 - V**2 / (2*const.c**2))
|
|
247
|
+
c = const.c.to(u.km / u.second).value
|
|
248
|
+
berv_pipeline = (f * (1 + berv_pipeline/c) - 1) * c
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
tmmean = np.array([h['HIERARCH ESO QC TMMEAN USED'] for h in H])
|
|
252
|
+
mjdobs = np.array([h['MJD-OBS'] for h in H])
|
|
253
|
+
texp = np.array([h['EXPTIME'] for h in H])
|
|
254
|
+
jd = mjdobs + 24e5 + 0.5 + (texp * tmmean)/60/60/24
|
|
255
|
+
|
|
256
|
+
if verbose:
|
|
257
|
+
logger.info(f"Unique exposure times: {np.unique(texp)}")
|
|
258
|
+
|
|
259
|
+
berv = []
|
|
260
|
+
if verbose:
|
|
261
|
+
pbar = enumerate(jd)
|
|
262
|
+
else:
|
|
263
|
+
pbar = tqdm(enumerate(jd), total=len(jd),
|
|
264
|
+
unit='observation', desc='Computing BERV')
|
|
265
|
+
|
|
266
|
+
for i, _jd in pbar:
|
|
267
|
+
if use_gaia_meassurements:
|
|
268
|
+
if not hasattr(self, 'gaia'):
|
|
269
|
+
raise ValueError('No Gaia data available')
|
|
270
|
+
|
|
271
|
+
target = self.gaia.coords
|
|
272
|
+
pmra = self.gaia.pmra
|
|
273
|
+
pmdec = self.gaia.pmdec
|
|
274
|
+
epoch = Time('J2016').jd
|
|
275
|
+
else:
|
|
276
|
+
ra = H[i]['* TARG ALPHA'][0]
|
|
277
|
+
ra = f'{ra:09.2f}'
|
|
278
|
+
ra = ra[:2] + 'h' + ra[2:4] + 'm' + ra[4:] + 's'
|
|
279
|
+
|
|
280
|
+
dec = H[i]['* TARG DELTA'][0]
|
|
281
|
+
if dec < 0:
|
|
282
|
+
dec = f'{dec:010.2f}'
|
|
283
|
+
else:
|
|
284
|
+
dec = f'{dec:09.2f}'
|
|
285
|
+
if dec.startswith('-'):
|
|
286
|
+
dec = dec[:3] + 'd' + dec[3:5] + 'm' + dec[5:] + 's'
|
|
287
|
+
else:
|
|
288
|
+
dec = dec[:2] + 'd' + dec[2:4] + 'm' + dec[4:] + 's'
|
|
289
|
+
|
|
290
|
+
target = SkyCoord(ra, dec)
|
|
291
|
+
pmra = H[i]['* TARG PMA'][0] * 1e3
|
|
292
|
+
pmdec = H[i]['* TARG PMD'][0] * 1e3
|
|
293
|
+
epoch = Time('J2000').jd
|
|
294
|
+
|
|
295
|
+
if verbose:
|
|
296
|
+
logger.info(f'jd: {_jd}')
|
|
297
|
+
logger.info(f'\t ra: {target.ra}')
|
|
298
|
+
logger.info(f'\t dec: {target.dec}')
|
|
299
|
+
logger.info(f'\t pmra: {pmra}')
|
|
300
|
+
logger.info(f'\t pmdec: {pmdec}')
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
px = plx or 0.0
|
|
304
|
+
out = get_BC_vel(_jd, obsname=obsname, rv=0.0, px=px, zmeas=0.0, epoch=epoch,
|
|
305
|
+
ra=target.ra.value, dec=target.dec.value, pmra=pmra, pmdec=pmdec)
|
|
306
|
+
# print(out[1][3])
|
|
307
|
+
berv.append(out[0])
|
|
308
|
+
|
|
309
|
+
berv = np.array(berv).flatten()
|
|
310
|
+
|
|
311
|
+
if ignore_mask: # ignore the system's masked points
|
|
312
|
+
pass
|
|
313
|
+
else: # mask points in the BERV output as well
|
|
314
|
+
bjd = bjd[self.mask]
|
|
315
|
+
berv = berv[self.mask]
|
|
316
|
+
berv_pipeline = berv_pipeline[self.mask]
|
|
317
|
+
|
|
318
|
+
fig = None
|
|
319
|
+
if plot:
|
|
320
|
+
fig, axs = plt.subplots(2, 1, figsize=(8, 6), dpi=dpi, sharex=True,
|
|
321
|
+
constrained_layout=True)
|
|
322
|
+
|
|
323
|
+
axs[0].set_title(f'{self.star}', loc='right')
|
|
324
|
+
axs[0].plot(bjd, berv_pipeline*1e3, '.', label='pipeline', alpha=0.5)
|
|
325
|
+
axs[0].plot(bjd, berv, '.', label='barycorrpy', alpha=0.5)
|
|
326
|
+
axs[0].legend(bbox_to_anchor=(0.0, 1.15), loc=2, borderaxespad=0., ncol=2)
|
|
327
|
+
axs[0].set(xlabel='BJD - 2450000', ylabel='BERV [m/s]')
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
if plx is not None:
|
|
331
|
+
epoch = 55500
|
|
332
|
+
sa = self.secular_acceleration(just_compute=True)
|
|
333
|
+
print('sa:', sa)
|
|
334
|
+
sec_acc = sa.value * (bjd - epoch) / 365.25
|
|
335
|
+
|
|
336
|
+
axs[0].plot(bjd, sec_acc)
|
|
337
|
+
|
|
338
|
+
# fitp = np.polyfit(bjd - epoch, diff, 1)
|
|
339
|
+
# axs[1].plot(bjd, np.polyval(fitp, bjd - epoch))
|
|
340
|
+
# axs[1].plot(bjd, np.mean(diff) + diff - np.polyval(fitp, bjd - epoch), '.')
|
|
341
|
+
|
|
342
|
+
if plx is None:
|
|
343
|
+
diff = berv - berv_pipeline*1e3
|
|
344
|
+
label=r'BERV$_{\rm barycorrpy}$ - BERV$_{\rm pipeline}$'
|
|
345
|
+
else:
|
|
346
|
+
diff = berv + sec_acc - berv_pipeline*1e3
|
|
347
|
+
label=r'BERV$_{\rm barycorrpy}$ (+SA) - BERV$_{\rm pipeline}$'
|
|
348
|
+
|
|
349
|
+
axs[1].plot(bjd, diff, 'k.', label=label)
|
|
350
|
+
axs[1].axhline(np.mean(diff), ls='--', c='k', alpha=0.1)
|
|
351
|
+
|
|
352
|
+
from adjustText import adjust_text
|
|
353
|
+
text = axs[1].text(bjd.max(), diff.min() + 0.1*diff.ptp(),
|
|
354
|
+
f'ptp: {diff.ptp()*1e2:.2f} cm/s',
|
|
355
|
+
ha='right', va='bottom', color='g', alpha=0.8)
|
|
356
|
+
axs[1].plot([bjd[np.argmax(diff)], bjd.max() + 0.05 * bjd.ptp()],
|
|
357
|
+
[np.max(diff), np.max(diff)], 'g--', alpha=0.3)
|
|
358
|
+
axs[1].plot([bjd[np.argmin(diff)], bjd.max() + 0.05 * bjd.ptp()],
|
|
359
|
+
[np.min(diff), np.min(diff)], 'g--', alpha=0.3)
|
|
360
|
+
|
|
361
|
+
ax = axs[1].twinx()
|
|
362
|
+
diff_cms = 1e2*(diff - np.mean(diff))
|
|
363
|
+
ax.plot(bjd, diff_cms, alpha=0)
|
|
364
|
+
ma = np.max(np.abs(ax.get_ylim()))
|
|
365
|
+
ax.set_ylim(-1 - 5*round(ma/5), 1 + 5*round(ma/5))
|
|
366
|
+
ax.set(ylabel='diff - mean(diff) [cm/s]')
|
|
367
|
+
axs[1].set_ylim(np.mean(diff)-ma/100, np.mean(diff)+ma/100)
|
|
368
|
+
|
|
369
|
+
axs[1].legend(bbox_to_anchor=(0.0, 1.15), loc=2, borderaxespad=0.)
|
|
370
|
+
axs[1].set(xlabel='BJD - 2450000', ylabel='diff [m/s]')
|
|
371
|
+
|
|
372
|
+
# adjust_text([text], va='bottom')
|
|
373
|
+
|
|
374
|
+
return fig, {
|
|
375
|
+
self.star: {
|
|
376
|
+
'bjd': bjd,
|
|
377
|
+
'berv_pipeline': berv_pipeline*1e3,
|
|
378
|
+
'berv_barycorrpy': berv
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def plot_BERV_correction(self, H, A, V, berv2=None, berv6=None,
|
|
384
|
+
inset=False, inset_range=(3, 5)):
|
|
385
|
+
fig, axs = plt.subplot_mosaic('ab\ncc\ndd\nee', constrained_layout=True, figsize=(2*3.57, 10))
|
|
386
|
+
|
|
387
|
+
if berv2 is None:
|
|
388
|
+
_, berv2 = BERV(self, H, plot=False)
|
|
389
|
+
if berv6 is None:
|
|
390
|
+
_, berv6 = BERV(self, H, A=A, V=V, plot=False)
|
|
391
|
+
|
|
392
|
+
self.plot(ax=axs['a'], ms=2)
|
|
393
|
+
axs['a'].set_title('original', loc='right')
|
|
394
|
+
self.gls(ax=axs['e'], label='original', color='r', alpha=0.5,
|
|
395
|
+
fill_between=True, samples_per_peak=20)
|
|
396
|
+
|
|
397
|
+
temp_vrad = self.vrad.copy()
|
|
398
|
+
self.vrad[self.mask] = self.vrad[self.mask] - berv2[self.star]['berv_pipeline'].value + berv6[self.star]['berv_pipeline'].value
|
|
399
|
+
|
|
400
|
+
self.plot(ax=axs['b'], ms=2)
|
|
401
|
+
axs['b'].set_title('after correction', loc='right')
|
|
402
|
+
|
|
403
|
+
diff = temp_vrad[self.mask] - self.vrad[self.mask]
|
|
404
|
+
|
|
405
|
+
axs['c'].plot(self.mtime, diff, 'k.')
|
|
406
|
+
axs['c'].set_title('RV difference', loc='right')
|
|
407
|
+
axs['c'].set(xlabel='BJD - 2450000', ylabel='RV diff [m/s]')
|
|
408
|
+
|
|
409
|
+
text = axs['c'].text(self.mtime.max(), diff.min() + 0.1*diff.ptp(),
|
|
410
|
+
f'ptp: {diff.ptp()*1e2:.2f} cm/s',
|
|
411
|
+
ha='right', va='bottom', color='g', alpha=0.8)
|
|
412
|
+
axs['c'].plot([self.mtime[np.argmax(diff)], self.mtime.max() + 0.05 * self.mtime.ptp()],
|
|
413
|
+
[np.max(diff), np.max(diff)], 'g--', alpha=0.3)
|
|
414
|
+
axs['c'].plot([self.mtime[np.argmin(diff)], self.mtime.max() + 0.05 * self.mtime.ptp()],
|
|
415
|
+
[np.min(diff), np.min(diff)], 'g--', alpha=0.3)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
f, p = LombScargle(self.mtime, diff).autopower(maximum_frequency=1.0, samples_per_peak=10)
|
|
419
|
+
axs['d'].semilogx(1/f, p, color='k', alpha=0.8)
|
|
420
|
+
axs['d'].vlines([365.25, 365.25/2], 0, 1, color='k', ls='--', alpha=0.3)
|
|
421
|
+
axs['d'].set(xlabel='Period [days]', ylabel='normalized power', ylim=(0, 1))
|
|
422
|
+
axs['d'].set_title('GLS of RV difference', loc='right')
|
|
423
|
+
|
|
424
|
+
if inset:
|
|
425
|
+
inset = axs['d'].inset_axes(bounds=[0.15, 0.3, 0.3, 0.6])
|
|
426
|
+
m = (1/f > inset_range[0]) & (1/f < inset_range[1])
|
|
427
|
+
inset.plot(1/f[m], p[m], color='k', alpha=0.8)
|
|
428
|
+
inset.set(xlim=inset_range, yticks=[])
|
|
429
|
+
inset.minorticks_on()
|
|
430
|
+
|
|
431
|
+
self.gls(ax=axs['e'], label='after correction', color='g', alpha=1,
|
|
432
|
+
lw=0.8, samples_per_peak=20)
|
|
433
|
+
axs['e'].set(xlabel='Period [days]', ylabel='normalized power')
|
|
434
|
+
axs['e'].sharex(axs['d'])
|
|
435
|
+
|
|
436
|
+
self.vrad = temp_vrad
|
|
437
|
+
return fig
|
arvi/dace_wrapper.py
CHANGED
|
@@ -193,7 +193,7 @@ def get_observations(star, instrument=None, main_id=None, verbose=True):
|
|
|
193
193
|
raise ValueError(msg) from None
|
|
194
194
|
else:
|
|
195
195
|
try:
|
|
196
|
-
result = get_observations_from_instrument(star, instrument, main_id
|
|
196
|
+
result = get_observations_from_instrument(star, instrument, main_id)
|
|
197
197
|
except ValueError:
|
|
198
198
|
msg = f'no {instrument} observations for {star}'
|
|
199
199
|
raise ValueError(msg) from None
|
arvi/headers.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from tqdm import tqdm
|
|
2
|
+
from astropy.io import fits
|
|
3
|
+
import iCCF
|
|
4
|
+
|
|
5
|
+
from . import config
|
|
6
|
+
|
|
7
|
+
def get_headers(self, check_lesta=False, lesta_username=config.username,
|
|
8
|
+
check_exo2=False, instrument=None):
|
|
9
|
+
try:
|
|
10
|
+
import paramiko
|
|
11
|
+
except ImportError:
|
|
12
|
+
raise ImportError("paramiko is not installed. Please install it with 'pip install paramiko'")
|
|
13
|
+
|
|
14
|
+
H = []
|
|
15
|
+
|
|
16
|
+
if check_lesta:
|
|
17
|
+
with paramiko.SSHClient() as ssh:
|
|
18
|
+
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
19
|
+
ssh.connect("lesta02.astro.unige.ch", username=lesta_username)
|
|
20
|
+
sftp = ssh.open_sftp()
|
|
21
|
+
|
|
22
|
+
pbar = tqdm(self.raw_file, total=len(self.raw_file), unit='file', desc='Reading headers')
|
|
23
|
+
for f in pbar:
|
|
24
|
+
f = f.replace('espresso/', '/projects/astro/ESPRESSODRS/')
|
|
25
|
+
f = f.replace('nirps/', '/projects/astro/NIRPSDRS/')
|
|
26
|
+
f = f.replace('.fits', '_CCF_A.fits')#.replace(':', r'\:')
|
|
27
|
+
with sftp.open(f) as fp:
|
|
28
|
+
header = fits.getheader(fp)
|
|
29
|
+
H.append(header)
|
|
30
|
+
|
|
31
|
+
if len(H) == 0 and check_exo2:
|
|
32
|
+
raise NotImplementedError('getting headers from exo2 not yet implemented')
|
|
33
|
+
|
|
34
|
+
if len(H) == 0:
|
|
35
|
+
self.download_ccf()
|
|
36
|
+
if instrument is None:
|
|
37
|
+
I = iCCF.from_file(f'{self.star}_downloads/*CCF_A.fits')
|
|
38
|
+
else:
|
|
39
|
+
I = iCCF.from_file(f'{self.star}_downloads/r.{instrument}.*CCF_A.fits',
|
|
40
|
+
guess_instrument='HARPS' not in instrument)
|
|
41
|
+
H = [i.HDU[0].header for i in I]
|
|
42
|
+
|
|
43
|
+
# sort by BJD
|
|
44
|
+
H = sorted(H, key=lambda x: x['HIERARCH ESO QC BJD'])
|
|
45
|
+
|
|
46
|
+
return H
|
|
47
|
+
|
arvi/plots.py
CHANGED
arvi/programs.py
CHANGED
|
@@ -20,12 +20,14 @@ def get_star(star, instrument=None):
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class LazyRV:
|
|
23
|
-
def __init__(self, stars: list, instrument: str = None
|
|
23
|
+
def __init__(self, stars: list, instrument: str = None,
|
|
24
|
+
_parallel_limit=10):
|
|
24
25
|
self.stars = stars
|
|
25
26
|
if isinstance(self.stars, str):
|
|
26
27
|
self.stars = [self.stars]
|
|
27
28
|
self.instrument = instrument
|
|
28
29
|
self._saved = None
|
|
30
|
+
self._parallel_limit = _parallel_limit
|
|
29
31
|
|
|
30
32
|
@property
|
|
31
33
|
def N(self):
|
|
@@ -35,7 +37,7 @@ class LazyRV:
|
|
|
35
37
|
return f"RV({self.N} stars)"
|
|
36
38
|
|
|
37
39
|
def _get(self):
|
|
38
|
-
if self.N >
|
|
40
|
+
if self.N > self._parallel_limit:
|
|
39
41
|
# logger.info('Querying DACE...')
|
|
40
42
|
_get_star = partial(get_star, instrument=self.instrument)
|
|
41
43
|
with multiprocessing.Pool() as pool:
|
arvi/stellar.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
class prot_age_result:
|
|
4
|
+
prot_n84: float
|
|
5
|
+
prot_n84_err: float
|
|
6
|
+
prot_m08: float
|
|
7
|
+
prot_m08_err: float
|
|
8
|
+
age_m08: float
|
|
9
|
+
age_m08_err: float
|
|
10
|
+
def __init__(self):
|
|
11
|
+
pass
|
|
12
|
+
def __repr__(self):
|
|
13
|
+
s = f'{self.prot_n84=:.2f} ± {self.prot_n84_err:.2f}, '
|
|
14
|
+
s += f'{self.prot_m08=:.2f} ± {self.prot_m08_err:.2f}, '
|
|
15
|
+
s += f'{self.age_m08=:.2f} ± {self.age_m08_err:.2f}'
|
|
16
|
+
return s.replace('self.', '')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def calc_prot_age(self, bv=None):
|
|
20
|
+
"""
|
|
21
|
+
Calculate rotation period and age from logR'HK activity level, based on the
|
|
22
|
+
empirical relations of Noyes et al. (1984) and Mamajek & Hillenbrand (2008).
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
self (`arvi.RV`):
|
|
26
|
+
RV object
|
|
27
|
+
bv (float, optional):
|
|
28
|
+
B-V colour. If None, use value from Simbad
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
An object with the following attributes:
|
|
32
|
+
|
|
33
|
+
prot_n84 (float, array):
|
|
34
|
+
Chromospheric rotational period via Noyes et al. (1984)
|
|
35
|
+
prot_n84_err (float, array):
|
|
36
|
+
Error on 'prot_n84'
|
|
37
|
+
prot_m08 (float, array):
|
|
38
|
+
Chromospheric rotational period via Mamajek & Hillenbrand (2008)
|
|
39
|
+
prot_m08_err (float, array):
|
|
40
|
+
Error on 'prot_m08'
|
|
41
|
+
age_m08 (float, array):
|
|
42
|
+
Gyrochronology age via Mamajek & Hillenbrand (2008)
|
|
43
|
+
age_m08_err (float, array):
|
|
44
|
+
Error on 'age_m08'
|
|
45
|
+
|
|
46
|
+
Range of logR'HK-Prot relation: -5.5 < logR'HK < -4.3
|
|
47
|
+
Range of Mamajek & Hillenbrand (2008) relation for ages: 0.5 < B-V < 0.9
|
|
48
|
+
"""
|
|
49
|
+
log_rhk = np.nanmean(self.rhk[self.mask])
|
|
50
|
+
if bv is None:
|
|
51
|
+
bv = self.simbad.B - self.simbad.V
|
|
52
|
+
|
|
53
|
+
# Calculate chromospheric Prot:
|
|
54
|
+
if np.any(log_rhk < -4.3) & np.any(log_rhk > -5.5):
|
|
55
|
+
if bv < 1:
|
|
56
|
+
tau = 1.362 - 0.166*(1-bv) + 0.025*(1-bv)**2 - 5.323*(1-bv)**3
|
|
57
|
+
else:
|
|
58
|
+
tau = 1.362 - 0.14*(1-bv)
|
|
59
|
+
|
|
60
|
+
prot_n84 = 0.324 - 0.400*(5 + log_rhk) - 0.283*(5 + log_rhk)**2 - 1.325*(5 + log_rhk)**3 + tau
|
|
61
|
+
prot_n84 = 10**prot_n84
|
|
62
|
+
prot_n84_err = np.log(10)*0.08*prot_n84
|
|
63
|
+
|
|
64
|
+
prot_m08 = (0.808 - 2.966*(log_rhk + 4.52))*10**tau
|
|
65
|
+
prot_m08_err = 4.4*bv*1.7 - 1.7
|
|
66
|
+
else:
|
|
67
|
+
prot_n84 = np.nan
|
|
68
|
+
prot_n84_err = np.nan
|
|
69
|
+
prot_m08 = np.nan
|
|
70
|
+
prot_m08_err = np.nan
|
|
71
|
+
|
|
72
|
+
# Calculate gyrochronology age:
|
|
73
|
+
if np.any(prot_m08 > 0.0) & (bv > 0.50) & (bv < 0.9):
|
|
74
|
+
age_m08 = 1e-3*(prot_m08/0.407/(bv - 0.495)**0.325)**(1./0.566)
|
|
75
|
+
#age_m08_err = 0.05*np.log(10)*age_m08
|
|
76
|
+
age_m08_err = 0.2 * age_m08 * np.log(10) # using 0.2 dex typical error from paper
|
|
77
|
+
else:
|
|
78
|
+
age_m08 = np.nan
|
|
79
|
+
age_m08_err = np.nan
|
|
80
|
+
|
|
81
|
+
r = prot_age_result()
|
|
82
|
+
r.prot_n84 = prot_n84
|
|
83
|
+
r.prot_n84_err = prot_n84_err
|
|
84
|
+
r.prot_m08 = prot_m08
|
|
85
|
+
r.prot_m08_err = prot_m08_err
|
|
86
|
+
r.age_m08 = age_m08
|
|
87
|
+
r.age_m08_err = age_m08_err
|
|
88
|
+
return r
|
|
89
|
+
# return prot_n84, prot_n84_err, prot_m08, prot_m08_err, age_m08, age_m08_err
|
arvi/timeseries.py
CHANGED
|
@@ -11,7 +11,7 @@ import numpy as np
|
|
|
11
11
|
from astropy import units
|
|
12
12
|
|
|
13
13
|
from .setup_logger import logger
|
|
14
|
-
from .
|
|
14
|
+
from . import config
|
|
15
15
|
from .translations import translate
|
|
16
16
|
from .dace_wrapper import do_download_filetype, do_symlink_filetype, get_observations, get_arrays
|
|
17
17
|
from .simbad_wrapper import simbad
|
|
@@ -23,6 +23,9 @@ from .HZ import getHZ_period
|
|
|
23
23
|
from .utils import strtobool, there_is_internet, timer
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
class ExtraFields:
|
|
27
|
+
pass
|
|
28
|
+
|
|
26
29
|
@dataclass
|
|
27
30
|
class RV:
|
|
28
31
|
"""
|
|
@@ -71,7 +74,7 @@ class RV:
|
|
|
71
74
|
self.__star__ = translate(self.star)
|
|
72
75
|
|
|
73
76
|
if not self._child:
|
|
74
|
-
if check_internet and not there_is_internet():
|
|
77
|
+
if config.check_internet and not there_is_internet():
|
|
75
78
|
raise ConnectionError('There is no internet connection?')
|
|
76
79
|
|
|
77
80
|
# complicated way to query Simbad with self.__star__ or, if that
|
|
@@ -103,9 +106,9 @@ class RV:
|
|
|
103
106
|
logger.info(f'querying DACE for {self.__star__}...')
|
|
104
107
|
try:
|
|
105
108
|
with timer():
|
|
109
|
+
mid = self.simbad.main_id if hasattr(self, 'simbad') else None
|
|
106
110
|
self.dace_result = get_observations(self.__star__, self.instrument,
|
|
107
|
-
main_id=self.
|
|
108
|
-
verbose=self.verbose)
|
|
111
|
+
main_id=mid, verbose=self.verbose)
|
|
109
112
|
except ValueError as e:
|
|
110
113
|
# querying DACE failed, should we raise an error?
|
|
111
114
|
if self._raise_on_error:
|
|
@@ -218,6 +221,7 @@ class RV:
|
|
|
218
221
|
self._did_secular_acceleration = False
|
|
219
222
|
self._did_sigma_clip = False
|
|
220
223
|
self._did_adjust_means = False
|
|
224
|
+
self._did_correct_berv = False
|
|
221
225
|
self.__post_init__()
|
|
222
226
|
|
|
223
227
|
def snapshot(self):
|
|
@@ -382,6 +386,7 @@ class RV:
|
|
|
382
386
|
s.mask = kwargs.get('mask', np.full_like(s.time, True, dtype=bool))
|
|
383
387
|
|
|
384
388
|
s.instruments = [inst]
|
|
389
|
+
s._quantities = np.array([])
|
|
385
390
|
|
|
386
391
|
return s
|
|
387
392
|
|
|
@@ -443,6 +448,13 @@ class RV:
|
|
|
443
448
|
|
|
444
449
|
s = cls(star, _child=True, **kwargs)
|
|
445
450
|
|
|
451
|
+
def find_column(data, names):
|
|
452
|
+
has_col = np.array([name in data.dtype.fields for name in names])
|
|
453
|
+
if any(has_col):
|
|
454
|
+
col = np.where(has_col)[0][0]
|
|
455
|
+
return data[names[col]]
|
|
456
|
+
return False
|
|
457
|
+
|
|
446
458
|
for i, (f, instrument) in enumerate(zip(files, instruments)):
|
|
447
459
|
data = np.loadtxt(f, skiprows=2, usecols=range(3), unpack=True)
|
|
448
460
|
_s = cls(star, _child=True, **kwargs)
|
|
@@ -471,10 +483,11 @@ class RV:
|
|
|
471
483
|
else:
|
|
472
484
|
data = np.array([], dtype=np.dtype([]))
|
|
473
485
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
486
|
+
# try to find FWHM and uncertainty
|
|
487
|
+
if (v := find_column(data, ['fwhm'])) is not False: # walrus !!
|
|
488
|
+
_s.fwhm = v
|
|
489
|
+
if (sv := find_column(data, ['sfwhm', 'fwhm_err', 'sig_fwhm'])) is not False:
|
|
490
|
+
_s.fwhm_err = sv
|
|
478
491
|
else:
|
|
479
492
|
_s.fwhm_err = 2 * _s.svrad
|
|
480
493
|
else:
|
|
@@ -484,12 +497,11 @@ class RV:
|
|
|
484
497
|
_quantities.append('fwhm')
|
|
485
498
|
_quantities.append('fwhm_err')
|
|
486
499
|
|
|
487
|
-
if 'rhk'
|
|
488
|
-
_s.rhk =
|
|
500
|
+
if (v := find_column(data, ['rhk'])) is not False:
|
|
501
|
+
_s.rhk = v
|
|
489
502
|
_s.rhk_err = np.full_like(time, np.nan)
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
_s.rhk_err = data[possible_name]
|
|
503
|
+
if (sv := find_column(data, ['srhk', 'rhk_err', 'sig_rhk'])) is not False:
|
|
504
|
+
_s.rhk_err = sv
|
|
493
505
|
else:
|
|
494
506
|
_s.rhk = np.zeros_like(time)
|
|
495
507
|
_s.rhk_err = np.full_like(time, np.nan)
|
|
@@ -516,6 +528,12 @@ class RV:
|
|
|
516
528
|
setattr(_s, q, np.full(time.size, True))
|
|
517
529
|
_quantities.append(q)
|
|
518
530
|
|
|
531
|
+
_s.extra_fields = ExtraFields()
|
|
532
|
+
for field in data.dtype.names:
|
|
533
|
+
if field not in _quantities:
|
|
534
|
+
setattr(_s.extra_fields, field, data[field])
|
|
535
|
+
# _quantities.append(field)
|
|
536
|
+
|
|
519
537
|
#! end hack
|
|
520
538
|
|
|
521
539
|
_s.mask = np.ones_like(time, dtype=bool)
|
|
@@ -543,31 +561,75 @@ class RV:
|
|
|
543
561
|
logger.error('iCCF is not installed. Please install it with `pip install iCCF`')
|
|
544
562
|
return
|
|
545
563
|
|
|
564
|
+
verbose = kwargs.get('verbose', True)
|
|
565
|
+
|
|
546
566
|
if isinstance(files, str):
|
|
547
567
|
files = [files]
|
|
548
568
|
|
|
549
|
-
|
|
569
|
+
CCFs = iCCF.from_file(files)
|
|
570
|
+
|
|
571
|
+
if not isinstance(CCFs, list):
|
|
572
|
+
CCFs = [CCFs]
|
|
550
573
|
|
|
551
|
-
objects = np.unique([i.HDU[0].header['OBJECT'].replace(' ', '') for i in
|
|
574
|
+
objects = np.unique([i.HDU[0].header['OBJECT'].replace(' ', '') for i in CCFs])
|
|
552
575
|
if objects.size != 1:
|
|
553
576
|
logger.warning(f'found {objects.size} different stars in the CCF files, '
|
|
554
577
|
'choosing the first one')
|
|
555
578
|
star = objects[0]
|
|
556
579
|
|
|
557
580
|
s = cls(star, _child=True)
|
|
581
|
+
instruments = list(np.unique([i.instrument for i in CCFs]))
|
|
558
582
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
583
|
+
for instrument in instruments:
|
|
584
|
+
# time, RVs, uncertainties
|
|
585
|
+
time = np.array([i.bjd for i in CCFs])
|
|
586
|
+
vrad = np.array([i.RV*1e3 for i in CCFs])
|
|
587
|
+
svrad = np.array([i.RVerror*1e3 for i in CCFs])
|
|
588
|
+
_s = RV.from_arrays(star, time, vrad, svrad, inst=instrument)
|
|
563
589
|
|
|
564
|
-
|
|
565
|
-
s.fwhm_err = np.array([i.FWHMerror*1e3 for i in I])
|
|
590
|
+
_quantities = []
|
|
566
591
|
|
|
567
|
-
|
|
568
|
-
|
|
592
|
+
_s.fwhm = np.array([i.FWHM*1e3 for i in CCFs])
|
|
593
|
+
_s.fwhm_err = np.array([i.FWHMerror*1e3 for i in CCFs])
|
|
594
|
+
|
|
595
|
+
_quantities.append('fwhm')
|
|
596
|
+
_quantities.append('fwhm_err')
|
|
597
|
+
|
|
598
|
+
_s.contrast = np.array([i.contrast for i in CCFs])
|
|
599
|
+
_s.contrast_err = np.array([i.contrast_error for i in CCFs])
|
|
600
|
+
|
|
601
|
+
_quantities.append('contrast')
|
|
602
|
+
_quantities.append('contrast_err')
|
|
603
|
+
|
|
604
|
+
_s.texp = np.array([i.HDU[0].header['EXPTIME'] for i in CCFs])
|
|
605
|
+
_quantities.append('texp')
|
|
606
|
+
|
|
607
|
+
_s.date_night = np.array([
|
|
608
|
+
i.HDU[0].header['DATE-OBS'].split('T')[0] for i in CCFs
|
|
609
|
+
])
|
|
610
|
+
_quantities.append('date_night')
|
|
611
|
+
|
|
612
|
+
_s.mask = np.full_like(_s.time, True, dtype=bool)
|
|
569
613
|
|
|
570
|
-
|
|
614
|
+
_s.drs_qc = np.array([i.HDU[0].header['HIERARCH ESO QC SCIRED CHECK'] for i in CCFs], dtype=bool)
|
|
615
|
+
# mask out drs_qc = False
|
|
616
|
+
if not _s.drs_qc.all():
|
|
617
|
+
n = (~ _s.drs_qc).sum()
|
|
618
|
+
if verbose:
|
|
619
|
+
logger.warning(f'masking {n} points where DRS QC failed for {instrument}')
|
|
620
|
+
_s.mask &= _s.drs_qc
|
|
621
|
+
print(_s.mask)
|
|
622
|
+
|
|
623
|
+
_s._quantities = np.array(_quantities)
|
|
624
|
+
setattr(s, instrument, _s)
|
|
625
|
+
|
|
626
|
+
s._child = False
|
|
627
|
+
s.instruments = instruments
|
|
628
|
+
s._build_arrays()
|
|
629
|
+
|
|
630
|
+
if instruments == ['ESPRESSO']:
|
|
631
|
+
from .instrument_specific import divide_ESPRESSO
|
|
632
|
+
divide_ESPRESSO(s)
|
|
571
633
|
|
|
572
634
|
return s
|
|
573
635
|
|
|
@@ -610,7 +672,6 @@ class RV:
|
|
|
610
672
|
logger.info(f'available: {self.instruments}')
|
|
611
673
|
return
|
|
612
674
|
|
|
613
|
-
|
|
614
675
|
def _build_arrays(self):
|
|
615
676
|
""" build all concatenated arrays of `self` from each of the `.inst`s """
|
|
616
677
|
if self._child:
|
|
@@ -653,7 +714,6 @@ class RV:
|
|
|
653
714
|
)
|
|
654
715
|
setattr(self, q, arr)
|
|
655
716
|
|
|
656
|
-
|
|
657
717
|
def download_ccf(self, instrument=None, index=None, limit=None,
|
|
658
718
|
directory=None, symlink=False, **kwargs):
|
|
659
719
|
""" Download CCFs from DACE
|
|
@@ -828,7 +888,7 @@ class RV:
|
|
|
828
888
|
if self.verbose:
|
|
829
889
|
logger.info(f"Removed observations from '{instrument}'")
|
|
830
890
|
|
|
831
|
-
if return_self:
|
|
891
|
+
if config.return_self:
|
|
832
892
|
return self
|
|
833
893
|
|
|
834
894
|
def remove_condition(self, condition):
|
|
@@ -856,7 +916,7 @@ class RV:
|
|
|
856
916
|
index = np.atleast_1d(index)
|
|
857
917
|
try:
|
|
858
918
|
instrument_index = self.obs[index]
|
|
859
|
-
|
|
919
|
+
np.array(self.instruments)[instrument_index - 1]
|
|
860
920
|
except IndexError:
|
|
861
921
|
logger.errors(f'index {index} is out of bounds for N={self.N}')
|
|
862
922
|
return
|
|
@@ -869,7 +929,7 @@ class RV:
|
|
|
869
929
|
# for i, inst in zip(index, instrument):
|
|
870
930
|
# index_in_instrument = i - (self.obs < instrument_index).sum()
|
|
871
931
|
# getattr(self, inst).mask[index_in_instrument] = False
|
|
872
|
-
if return_self:
|
|
932
|
+
if config.return_self:
|
|
873
933
|
return self
|
|
874
934
|
|
|
875
935
|
def remove_non_public(self):
|
|
@@ -932,7 +992,7 @@ class RV:
|
|
|
932
992
|
instruments = self._check_instrument(instrument)
|
|
933
993
|
rng = np.random.default_rng(seed=seed)
|
|
934
994
|
for inst in instruments:
|
|
935
|
-
s = getattr(self, inst)
|
|
995
|
+
# s = getattr(self, inst)
|
|
936
996
|
mask_for_this_inst = self.obs == self.instruments.index(inst) + 1
|
|
937
997
|
# only choose if there are more than n points
|
|
938
998
|
if self.mask[mask_for_this_inst].sum() > n:
|
|
@@ -1037,13 +1097,18 @@ class RV:
|
|
|
1037
1097
|
self.vrad = self.vrad - sa * (self.time - epoch) / 365.25
|
|
1038
1098
|
else:
|
|
1039
1099
|
for inst in self.instruments:
|
|
1100
|
+
s = getattr(self, inst)
|
|
1101
|
+
|
|
1102
|
+
# if RVs come from a publication, don't remove the secular
|
|
1103
|
+
# acceleration
|
|
1104
|
+
if np.all(s.pub_reference != ''):
|
|
1105
|
+
continue
|
|
1106
|
+
|
|
1040
1107
|
if 'HIRES' in inst: # never remove it from HIRES...
|
|
1041
1108
|
continue
|
|
1042
1109
|
if 'NIRPS' in inst: # never remove it from NIRPS...
|
|
1043
1110
|
continue
|
|
1044
1111
|
|
|
1045
|
-
s = getattr(self, inst)
|
|
1046
|
-
|
|
1047
1112
|
if hasattr(s, '_did_secular_acceleration') and s._did_secular_acceleration:
|
|
1048
1113
|
continue
|
|
1049
1114
|
|
|
@@ -1055,7 +1120,7 @@ class RV:
|
|
|
1055
1120
|
self._did_secular_acceleration_epoch = epoch
|
|
1056
1121
|
self._did_secular_acceleration_simbad = force_simbad
|
|
1057
1122
|
|
|
1058
|
-
if return_self:
|
|
1123
|
+
if config.return_self:
|
|
1059
1124
|
return self
|
|
1060
1125
|
|
|
1061
1126
|
def _undo_secular_acceleration(self):
|
|
@@ -1111,7 +1176,7 @@ class RV:
|
|
|
1111
1176
|
# # if insts.size == 1: # of the same instrument?
|
|
1112
1177
|
# if self.verbose:
|
|
1113
1178
|
# logger.warning(f'would remove all observations from {insts[0]}, skipping')
|
|
1114
|
-
# if return_self:
|
|
1179
|
+
# if config.return_self:
|
|
1115
1180
|
# return self
|
|
1116
1181
|
# continue
|
|
1117
1182
|
|
|
@@ -1123,7 +1188,7 @@ class RV:
|
|
|
1123
1188
|
self._did_adjust_means = False
|
|
1124
1189
|
self.adjust_means()
|
|
1125
1190
|
|
|
1126
|
-
if return_self:
|
|
1191
|
+
if config.return_self:
|
|
1127
1192
|
return self
|
|
1128
1193
|
|
|
1129
1194
|
def clip_maxerror(self, maxerror:float):
|
|
@@ -1145,7 +1210,7 @@ class RV:
|
|
|
1145
1210
|
logger.warning(f'clip_maxerror ({maxerror} {self.units}) removed {n} point' + s)
|
|
1146
1211
|
|
|
1147
1212
|
self._propagate_mask_changes()
|
|
1148
|
-
if return_self:
|
|
1213
|
+
if config.return_self:
|
|
1149
1214
|
return self
|
|
1150
1215
|
|
|
1151
1216
|
def bin(self):
|
|
@@ -1309,7 +1374,7 @@ class RV:
|
|
|
1309
1374
|
|
|
1310
1375
|
self._build_arrays()
|
|
1311
1376
|
self._did_adjust_means = True
|
|
1312
|
-
if return_self:
|
|
1377
|
+
if config.return_self:
|
|
1313
1378
|
return self
|
|
1314
1379
|
|
|
1315
1380
|
def add_to_vrad(self, values):
|
|
@@ -1546,6 +1611,8 @@ class RV:
|
|
|
1546
1611
|
|
|
1547
1612
|
|
|
1548
1613
|
#
|
|
1614
|
+
from .stellar import calc_prot_age
|
|
1615
|
+
|
|
1549
1616
|
@property
|
|
1550
1617
|
def HZ(self):
|
|
1551
1618
|
if not hasattr(self, 'star_mass'):
|
arvi/translations.py
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
arvi/HZ.py,sha256=u7rguhlILRBW-LOczlY3dkIB4LM8p8W7Xfg4FnNaYG0,2850
|
|
2
|
-
arvi/__init__.py,sha256=
|
|
2
|
+
arvi/__init__.py,sha256=stLL3UtXmR1jpNEoMyVohjvkCatunz1w5ZK0ApmWuYQ,814
|
|
3
3
|
arvi/ariadne_wrapper.py,sha256=jv8Wl35LfHl1UH1EklbvxHcQHqaEDhRGNogSYjFt7Y4,2141
|
|
4
|
+
arvi/berv.py,sha256=5avwcmc2nkYH1KDo-z4eMPsS1ElNvold2DWkziV13gE,17633
|
|
4
5
|
arvi/binning.py,sha256=jJ_resqSvfI-2BT0cnGPFckTIei_k2Mk95oZyE5b5zQ,15250
|
|
5
6
|
arvi/config.py,sha256=wyj6FTxN7QOZj8LaHAe_ZdPKVfrNfobNNOHRNLH-S7Q,339
|
|
6
|
-
arvi/dace_wrapper.py,sha256=
|
|
7
|
+
arvi/dace_wrapper.py,sha256=HmsyThieljcjorSSZgmGTZPGBqNrm9QoPwjoR_GpVKo,17025
|
|
7
8
|
arvi/extra_data.py,sha256=WEEaYeLh52Zdv0uyHO72Ys5MWS3naTAP4wJV2BJ1mbk,2551
|
|
8
9
|
arvi/gaia_wrapper.py,sha256=YxqqlWkLAKBY7AGHfDpNbkOLYWK0lt0L5GZenn0FfxM,3555
|
|
10
|
+
arvi/headers.py,sha256=uvdJebw1M5YkGjE3vJJwYBOnLikib75uuZE9FXB5JJM,1673
|
|
9
11
|
arvi/instrument_specific.py,sha256=fhkvR5jJzpJH7XbT8Fbzkaz6tGeoFYugkJCIAJgSR7o,4746
|
|
10
12
|
arvi/lbl_wrapper.py,sha256=_ViGVkpakvuBR_xhu9XJRV5EKHpj5Go6jBZGJZMIS2Y,11850
|
|
11
13
|
arvi/nasaexo_wrapper.py,sha256=mWt7eHgSZe4MBKCmUvMPTyUPGuiwGTqKugNBvmjOg9s,7306
|
|
12
|
-
arvi/plots.py,sha256=
|
|
13
|
-
arvi/programs.py,sha256=
|
|
14
|
+
arvi/plots.py,sha256=53_rHVh7SeyBylM91PP6mNr7WTGmIoRnR8JfKJPdu7E,25594
|
|
15
|
+
arvi/programs.py,sha256=C0Fbldjf-QEZYYJp5wBKP3h7zraD0O2mJC7Su967STg,4607
|
|
14
16
|
arvi/reports.py,sha256=yrdajC-zz5_kH1Ucc6cU70DK-5dpG0Xyeru-EITKpNo,3355
|
|
15
17
|
arvi/setup_logger.py,sha256=pBzaRTn0hntozjbaRVx0JIbWGuENkvYUApa6uB-FsRo,279
|
|
16
18
|
arvi/simbad_wrapper.py,sha256=fwO0NbMvxAW3RyC58FPkLjXqLs9OkRyK0sYcb0ZVBQA,5571
|
|
17
19
|
arvi/spectra.py,sha256=pTAWSW4vk96DWRQ-6l5mNJHUhiAyaPR-QDjZdOT6Ak0,7489
|
|
18
20
|
arvi/stats.py,sha256=MQiyLvdiAFxIC29uajTy8kuxD-b2Y6mraL4AfWkRJkM,2576
|
|
19
|
-
arvi/
|
|
20
|
-
arvi/
|
|
21
|
+
arvi/stellar.py,sha256=MdO1_-ZXHnMHbkG-a5LvrnYeULy6MCAnWMKPvR4NZxQ,2954
|
|
22
|
+
arvi/timeseries.py,sha256=sdm9l_LHItZHDAVI6r_wsQwkrfbuMX46q3Wqs0y-KGA,60787
|
|
23
|
+
arvi/translations.py,sha256=SUIrJHt3JZdL_GQh3OJyg2Gm3X5ut86w5zW8hZpxHe0,498
|
|
21
24
|
arvi/utils.py,sha256=nuIOuUdysMesWF9ute4v-kbeo6DylWjWW-SJhCsHn9I,4078
|
|
22
25
|
arvi/data/info.svg,sha256=0IMI6W-eFoTD8acnury79WJJakpBwLa4qKS4JWpsXiI,489
|
|
23
26
|
arvi/data/obs_affected_ADC_issues.dat,sha256=tn93uOL0eCTYhireqp1wG-_c3CbxPA7C-Rf-pejVY8M,10853
|
|
@@ -25,8 +28,8 @@ arvi/data/obs_affected_blue_cryostat_issues.dat,sha256=z4AK17xfz8tGTDv1FjRvQFnio
|
|
|
25
28
|
arvi/data/extra/HD86226_PFS1.rdb,sha256=vfAozbrKHM_j8dYkCBJsuHyD01KEM1asghe2KInwVao,3475
|
|
26
29
|
arvi/data/extra/HD86226_PFS2.rdb,sha256=F2P7dB6gVyzCglUjNheB0hIHVClC5RmARrGwbrY1cfo,4114
|
|
27
30
|
arvi/data/extra/metadata.json,sha256=C69hIw6CohyES6BI9vDWjxwSz7N4VOYX0PCgjXtYFmU,178
|
|
28
|
-
arvi-0.1.
|
|
29
|
-
arvi-0.1.
|
|
30
|
-
arvi-0.1.
|
|
31
|
-
arvi-0.1.
|
|
32
|
-
arvi-0.1.
|
|
31
|
+
arvi-0.1.14.dist-info/LICENSE,sha256=6JfQgl7SpM55t0EHMFNMnNh-AdkpGW25MwMiTnhdWQg,1068
|
|
32
|
+
arvi-0.1.14.dist-info/METADATA,sha256=duTaG6amS-M9iVUNvfo2RFwnA_fz1gY1ysUB2N_yCaE,1306
|
|
33
|
+
arvi-0.1.14.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
|
|
34
|
+
arvi-0.1.14.dist-info/top_level.txt,sha256=4EeiKDVLD45ztuflTGfQ3TU8GVjJg5Y95xS5XjI-utU,5
|
|
35
|
+
arvi-0.1.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|