arvi 0.1.12__tar.gz → 0.1.15__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.
Potentially problematic release.
This version of arvi might be problematic. Click here for more details.
- {arvi-0.1.12 → arvi-0.1.15}/.github/workflows/install.yml +2 -2
- {arvi-0.1.12 → arvi-0.1.15}/.github/workflows/python-publish.yml +3 -2
- {arvi-0.1.12 → arvi-0.1.15}/PKG-INFO +1 -3
- {arvi-0.1.12 → arvi-0.1.15}/arvi/HZ.py +0 -1
- arvi-0.1.15/arvi/__init__.py +34 -0
- arvi-0.1.15/arvi/berv.py +437 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/binning.py +14 -8
- {arvi-0.1.12 → arvi-0.1.15}/arvi/config.py +7 -1
- {arvi-0.1.12 → arvi-0.1.15}/arvi/dace_wrapper.py +165 -11
- {arvi-0.1.12 → arvi-0.1.15}/arvi/data/obs_affected_ADC_issues.dat +4 -1
- {arvi-0.1.12 → arvi-0.1.15}/arvi/gaia_wrapper.py +10 -6
- arvi-0.1.15/arvi/headers.py +47 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/instrument_specific.py +59 -3
- {arvi-0.1.12 → arvi-0.1.15}/arvi/nasaexo_wrapper.py +1 -1
- arvi-0.1.15/arvi/plots.py +776 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/programs.py +4 -2
- {arvi-0.1.12 → arvi-0.1.15}/arvi/reports.py +4 -3
- {arvi-0.1.12 → arvi-0.1.15}/arvi/simbad_wrapper.py +8 -4
- arvi-0.1.15/arvi/spectra.py +208 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/stats.py +2 -3
- arvi-0.1.15/arvi/stellar.py +89 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/timeseries.py +233 -66
- {arvi-0.1.12 → arvi-0.1.15}/arvi/translations.py +2 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/utils.py +34 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi.egg-info/PKG-INFO +1 -3
- {arvi-0.1.12 → arvi-0.1.15}/arvi.egg-info/SOURCES.txt +4 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi.egg-info/requires.txt +0 -2
- {arvi-0.1.12 → arvi-0.1.15}/pyproject.toml +1 -3
- {arvi-0.1.12 → arvi-0.1.15}/tests/test_import_object.py +1 -1
- arvi-0.1.12/arvi/__init__.py +0 -19
- arvi-0.1.12/arvi/plots.py +0 -509
- {arvi-0.1.12 → arvi-0.1.15}/.github/workflows/docs-gh-pages.yml +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/.gitignore +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/LICENSE +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/README.md +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/ariadne_wrapper.py +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/data/extra/HD86226_PFS1.rdb +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/data/extra/HD86226_PFS2.rdb +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/data/extra/metadata.json +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/data/info.svg +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/data/obs_affected_blue_cryostat_issues.dat +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/extra_data.py +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/lbl_wrapper.py +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi/setup_logger.py +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi.egg-info/dependency_links.txt +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/arvi.egg-info/top_level.txt +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/docs/API.md +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/docs/detailed.md +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/docs/index.md +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/docs/logo/detective.png +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/docs/logo/logo.png +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/mkdocs.yml +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/setup.cfg +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/setup.py +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/tests/test_binning.py +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/tests/test_simbad.py +0 -0
- {arvi-0.1.12 → arvi-0.1.15}/tests/test_stats.py +0 -0
|
@@ -19,9 +19,9 @@ jobs:
|
|
|
19
19
|
python-version: ["3.8", "3.9", "3.10", "3.11"]
|
|
20
20
|
|
|
21
21
|
steps:
|
|
22
|
-
- uses: actions/checkout@
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
23
|
- name: Set up Python ${{ matrix.python-version }}
|
|
24
|
-
uses: actions/setup-python@
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
25
|
with:
|
|
26
26
|
python-version: ${{ matrix.python-version }}
|
|
27
27
|
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
name: Upload Python Package
|
|
10
10
|
|
|
11
11
|
on:
|
|
12
|
+
workflow_dispatch:
|
|
12
13
|
release:
|
|
13
14
|
types: [published]
|
|
14
15
|
|
|
@@ -21,9 +22,9 @@ jobs:
|
|
|
21
22
|
runs-on: ubuntu-latest
|
|
22
23
|
|
|
23
24
|
steps:
|
|
24
|
-
- uses: actions/checkout@
|
|
25
|
+
- uses: actions/checkout@v4
|
|
25
26
|
- name: Set up Python
|
|
26
|
-
uses: actions/setup-python@
|
|
27
|
+
uses: actions/setup-python@v5
|
|
27
28
|
with:
|
|
28
29
|
python-version: '3.x'
|
|
29
30
|
- name: Install dependencies
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: arvi
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.15
|
|
4
4
|
Summary: The Automated RV Inspector
|
|
5
5
|
Author-email: João Faria <joao.faria@unige.ch>
|
|
6
6
|
License: MIT
|
|
@@ -14,11 +14,9 @@ Requires-Dist: mock; python_version < "3.3"
|
|
|
14
14
|
Requires-Dist: numpy
|
|
15
15
|
Requires-Dist: scipy
|
|
16
16
|
Requires-Dist: matplotlib
|
|
17
|
-
Requires-Dist: mplcursors
|
|
18
17
|
Requires-Dist: astropy
|
|
19
18
|
Requires-Dist: dace-query
|
|
20
19
|
Requires-Dist: loguru
|
|
21
|
-
Requires-Dist: mpldatacursor
|
|
22
20
|
Requires-Dist: tqdm
|
|
23
21
|
Requires-Dist: pySWEETCat
|
|
24
22
|
Requires-Dist: kepmodel
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
__all__ = ['RV']
|
|
2
|
+
|
|
3
|
+
from .timeseries import RV
|
|
4
|
+
|
|
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
|
|
9
|
+
|
|
10
|
+
def __getattr__(name: str):
|
|
11
|
+
if name in (
|
|
12
|
+
'_ipython_canary_method_should_not_exist_',
|
|
13
|
+
'_ipython_display_',
|
|
14
|
+
'_repr_mimebundle_',
|
|
15
|
+
'__wrapped__'
|
|
16
|
+
):
|
|
17
|
+
return
|
|
18
|
+
|
|
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-0.1.15/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
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
-
from numpy.testing import suppress_warnings
|
|
3
2
|
|
|
4
3
|
from .setup_logger import logger
|
|
5
4
|
|
|
@@ -35,6 +34,7 @@ def binned_statistic(x, values, statistic='mean', bins=10, range=None,
|
|
|
35
34
|
|
|
36
35
|
def binned_statistic_dd(sample, values, statistic='mean', bins=10, range=None,
|
|
37
36
|
expand_binnumbers=False, weights=None):
|
|
37
|
+
from numpy.testing import suppress_warnings
|
|
38
38
|
known_stats = [
|
|
39
39
|
'mean', 'median', 'count', 'sum', 'std', 'min', 'max', 'ptp'
|
|
40
40
|
]
|
|
@@ -211,13 +211,13 @@ def binned_statistic_dd(sample, values, statistic='mean', bins=10, range=None,
|
|
|
211
211
|
return result, edges, binnumbers
|
|
212
212
|
|
|
213
213
|
|
|
214
|
-
# put back the documentation
|
|
215
|
-
from scipy.stats import binned_statistic as old_binned_statistic,\
|
|
216
|
-
|
|
217
|
-
doc1 = old_binned_statistic.__doc__
|
|
218
|
-
doc2 = old_binned_statistic_dd.__doc__
|
|
219
|
-
binned_statistic.__doc__ = doc1
|
|
220
|
-
binned_statistic_dd.__doc__ = doc2
|
|
214
|
+
# # put back the documentation
|
|
215
|
+
# from scipy.stats import binned_statistic as old_binned_statistic,\
|
|
216
|
+
# binned_statistic_dd as old_binned_statistic_dd
|
|
217
|
+
# doc1 = old_binned_statistic.__doc__
|
|
218
|
+
# doc2 = old_binned_statistic_dd.__doc__
|
|
219
|
+
# binned_statistic.__doc__ = doc1
|
|
220
|
+
# binned_statistic_dd.__doc__ = doc2
|
|
221
221
|
|
|
222
222
|
###############################################################################
|
|
223
223
|
|
|
@@ -338,6 +338,9 @@ def binRV(time, rv, err=None, stat='wmean', tstat='wmean', estat='addquad',
|
|
|
338
338
|
if (err is not None) and (stat == 'wmean'):
|
|
339
339
|
stat = wmean # default is weighted mean
|
|
340
340
|
|
|
341
|
+
if (err is None) and (stat == 'wmean'):
|
|
342
|
+
stat = 'mean'
|
|
343
|
+
|
|
341
344
|
brv = binned_statistic(time, rv, statistic=stat, bins=bins, range=None,
|
|
342
345
|
weights=err)
|
|
343
346
|
|
|
@@ -345,6 +348,9 @@ def binRV(time, rv, err=None, stat='wmean', tstat='wmean', estat='addquad',
|
|
|
345
348
|
if (err is not None) and (tstat == 'wmean'):
|
|
346
349
|
tstat = wmean # default is weighted mean
|
|
347
350
|
|
|
351
|
+
if (err is None) and (tstat == 'wmean'):
|
|
352
|
+
tstat = 'mean'
|
|
353
|
+
|
|
348
354
|
times = binned_statistic(time, time, statistic=tstat, bins=bins,
|
|
349
355
|
range=None, weights=err)
|
|
350
356
|
# if there are errors, bin them too
|
|
@@ -5,4 +5,10 @@ return_self = False
|
|
|
5
5
|
check_internet = False
|
|
6
6
|
|
|
7
7
|
# make all DACE requests without using a .dacerc file
|
|
8
|
-
request_as_public = False
|
|
8
|
+
request_as_public = False
|
|
9
|
+
|
|
10
|
+
# whether to adjust instrument means before gls by default
|
|
11
|
+
adjust_means_gls = True
|
|
12
|
+
|
|
13
|
+
# debug
|
|
14
|
+
debug = False
|