arvi 0.1.12__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/HZ.py +0 -1
- arvi/__init__.py +21 -6
- arvi/berv.py +437 -0
- arvi/binning.py +3 -2
- arvi/config.py +7 -1
- arvi/dace_wrapper.py +165 -11
- arvi/data/obs_affected_ADC_issues.dat +4 -1
- arvi/gaia_wrapper.py +9 -5
- arvi/headers.py +47 -0
- arvi/instrument_specific.py +59 -3
- arvi/nasaexo_wrapper.py +1 -1
- arvi/plots.py +228 -28
- arvi/programs.py +4 -2
- arvi/simbad_wrapper.py +5 -2
- arvi/spectra.py +208 -0
- arvi/stellar.py +89 -0
- arvi/timeseries.py +233 -66
- arvi/translations.py +2 -0
- arvi/utils.py +21 -0
- {arvi-0.1.12.dist-info → arvi-0.1.14.dist-info}/METADATA +1 -1
- arvi-0.1.14.dist-info/RECORD +35 -0
- {arvi-0.1.12.dist-info → arvi-0.1.14.dist-info}/WHEEL +1 -1
- arvi-0.1.12.dist-info/RECORD +0 -31
- {arvi-0.1.12.dist-info → arvi-0.1.14.dist-info}/LICENSE +0 -0
- {arvi-0.1.12.dist-info → arvi-0.1.14.dist-info}/top_level.txt +0 -0
arvi/timeseries.py
CHANGED
|
@@ -11,18 +11,21 @@ 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
|
-
from .dace_wrapper import do_download_filetype, get_observations, get_arrays
|
|
16
|
+
from .dace_wrapper import do_download_filetype, do_symlink_filetype, get_observations, get_arrays
|
|
17
17
|
from .simbad_wrapper import simbad
|
|
18
18
|
from .gaia_wrapper import gaia
|
|
19
19
|
from .extra_data import get_extra_data
|
|
20
20
|
from .stats import wmean, wrms
|
|
21
21
|
from .binning import bin_ccf_mask, binRV
|
|
22
22
|
from .HZ import getHZ_period
|
|
23
|
-
from .utils import strtobool, there_is_internet
|
|
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
|
|
@@ -102,8 +105,10 @@ class RV:
|
|
|
102
105
|
if self.verbose:
|
|
103
106
|
logger.info(f'querying DACE for {self.__star__}...')
|
|
104
107
|
try:
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
with timer():
|
|
109
|
+
mid = self.simbad.main_id if hasattr(self, 'simbad') else None
|
|
110
|
+
self.dace_result = get_observations(self.__star__, self.instrument,
|
|
111
|
+
main_id=mid, verbose=self.verbose)
|
|
107
112
|
except ValueError as e:
|
|
108
113
|
# querying DACE failed, should we raise an error?
|
|
109
114
|
if self._raise_on_error:
|
|
@@ -216,6 +221,7 @@ class RV:
|
|
|
216
221
|
self._did_secular_acceleration = False
|
|
217
222
|
self._did_sigma_clip = False
|
|
218
223
|
self._did_adjust_means = False
|
|
224
|
+
self._did_correct_berv = False
|
|
219
225
|
self.__post_init__()
|
|
220
226
|
|
|
221
227
|
def snapshot(self):
|
|
@@ -257,6 +263,10 @@ class RV:
|
|
|
257
263
|
table += ' | '.join(map(str, self.NN.values())) + '\n'
|
|
258
264
|
return table
|
|
259
265
|
|
|
266
|
+
@property
|
|
267
|
+
def point(self):
|
|
268
|
+
return [(t.round(4), v.round(4), sv.round(4)) for t, v, sv in zip(self.time, self.vrad, self.svrad)]
|
|
269
|
+
|
|
260
270
|
@property
|
|
261
271
|
def mtime(self) -> np.ndarray:
|
|
262
272
|
""" Masked array of times """
|
|
@@ -376,6 +386,7 @@ class RV:
|
|
|
376
386
|
s.mask = kwargs.get('mask', np.full_like(s.time, True, dtype=bool))
|
|
377
387
|
|
|
378
388
|
s.instruments = [inst]
|
|
389
|
+
s._quantities = np.array([])
|
|
379
390
|
|
|
380
391
|
return s
|
|
381
392
|
|
|
@@ -437,6 +448,13 @@ class RV:
|
|
|
437
448
|
|
|
438
449
|
s = cls(star, _child=True, **kwargs)
|
|
439
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
|
+
|
|
440
458
|
for i, (f, instrument) in enumerate(zip(files, instruments)):
|
|
441
459
|
data = np.loadtxt(f, skiprows=2, usecols=range(3), unpack=True)
|
|
442
460
|
_s = cls(star, _child=True, **kwargs)
|
|
@@ -465,10 +483,11 @@ class RV:
|
|
|
465
483
|
else:
|
|
466
484
|
data = np.array([], dtype=np.dtype([]))
|
|
467
485
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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
|
|
472
491
|
else:
|
|
473
492
|
_s.fwhm_err = 2 * _s.svrad
|
|
474
493
|
else:
|
|
@@ -478,12 +497,11 @@ class RV:
|
|
|
478
497
|
_quantities.append('fwhm')
|
|
479
498
|
_quantities.append('fwhm_err')
|
|
480
499
|
|
|
481
|
-
if 'rhk'
|
|
482
|
-
_s.rhk =
|
|
500
|
+
if (v := find_column(data, ['rhk'])) is not False:
|
|
501
|
+
_s.rhk = v
|
|
483
502
|
_s.rhk_err = np.full_like(time, np.nan)
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
_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
|
|
487
505
|
else:
|
|
488
506
|
_s.rhk = np.zeros_like(time)
|
|
489
507
|
_s.rhk_err = np.full_like(time, np.nan)
|
|
@@ -510,6 +528,12 @@ class RV:
|
|
|
510
528
|
setattr(_s, q, np.full(time.size, True))
|
|
511
529
|
_quantities.append(q)
|
|
512
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
|
+
|
|
513
537
|
#! end hack
|
|
514
538
|
|
|
515
539
|
_s.mask = np.ones_like(time, dtype=bool)
|
|
@@ -537,36 +561,80 @@ class RV:
|
|
|
537
561
|
logger.error('iCCF is not installed. Please install it with `pip install iCCF`')
|
|
538
562
|
return
|
|
539
563
|
|
|
564
|
+
verbose = kwargs.get('verbose', True)
|
|
565
|
+
|
|
540
566
|
if isinstance(files, str):
|
|
541
567
|
files = [files]
|
|
542
568
|
|
|
543
|
-
|
|
569
|
+
CCFs = iCCF.from_file(files)
|
|
570
|
+
|
|
571
|
+
if not isinstance(CCFs, list):
|
|
572
|
+
CCFs = [CCFs]
|
|
544
573
|
|
|
545
|
-
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])
|
|
546
575
|
if objects.size != 1:
|
|
547
576
|
logger.warning(f'found {objects.size} different stars in the CCF files, '
|
|
548
577
|
'choosing the first one')
|
|
549
578
|
star = objects[0]
|
|
550
579
|
|
|
551
580
|
s = cls(star, _child=True)
|
|
581
|
+
instruments = list(np.unique([i.instrument for i in CCFs]))
|
|
552
582
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
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)
|
|
557
589
|
|
|
558
|
-
|
|
559
|
-
s.fwhm_err = np.array([i.FWHMerror*1e3 for i in I])
|
|
590
|
+
_quantities = []
|
|
560
591
|
|
|
561
|
-
|
|
562
|
-
|
|
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')
|
|
563
603
|
|
|
564
|
-
|
|
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)
|
|
613
|
+
|
|
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)
|
|
565
633
|
|
|
566
634
|
return s
|
|
567
635
|
|
|
568
636
|
|
|
569
|
-
def _check_instrument(self, instrument, strict=False):# -> list | None:
|
|
637
|
+
def _check_instrument(self, instrument, strict=False, log=False):# -> list | None:
|
|
570
638
|
"""
|
|
571
639
|
Check if there are observations from `instrument`.
|
|
572
640
|
|
|
@@ -599,6 +667,10 @@ class RV:
|
|
|
599
667
|
if any([instrument in inst for inst in self.instruments]):
|
|
600
668
|
return [inst for inst in self.instruments if instrument in inst]
|
|
601
669
|
|
|
670
|
+
if log:
|
|
671
|
+
logger.error(f"No data from instrument '{instrument}'")
|
|
672
|
+
logger.info(f'available: {self.instruments}')
|
|
673
|
+
return
|
|
602
674
|
|
|
603
675
|
def _build_arrays(self):
|
|
604
676
|
""" build all concatenated arrays of `self` from each of the `.inst`s """
|
|
@@ -642,8 +714,8 @@ class RV:
|
|
|
642
714
|
)
|
|
643
715
|
setattr(self, q, arr)
|
|
644
716
|
|
|
645
|
-
|
|
646
|
-
|
|
717
|
+
def download_ccf(self, instrument=None, index=None, limit=None,
|
|
718
|
+
directory=None, symlink=False, **kwargs):
|
|
647
719
|
""" Download CCFs from DACE
|
|
648
720
|
|
|
649
721
|
Args:
|
|
@@ -671,9 +743,15 @@ class RV:
|
|
|
671
743
|
# remove empty strings
|
|
672
744
|
files = list(filter(None, files))
|
|
673
745
|
|
|
674
|
-
|
|
746
|
+
if symlink:
|
|
747
|
+
if 'top_level' not in kwargs:
|
|
748
|
+
logger.warning('may need to provide `top_level` in kwargs to find file')
|
|
749
|
+
do_symlink_filetype('CCF', files[:limit], directory, **kwargs)
|
|
750
|
+
else:
|
|
751
|
+
do_download_filetype('CCF', files[:limit], directory, verbose=self.verbose, **kwargs)
|
|
675
752
|
|
|
676
|
-
def download_s1d(self, instrument=None, index=None, limit=None,
|
|
753
|
+
def download_s1d(self, instrument=None, index=None, limit=None,
|
|
754
|
+
directory=None, symlink=False, **kwargs):
|
|
677
755
|
""" Download S1Ds from DACE
|
|
678
756
|
|
|
679
757
|
Args:
|
|
@@ -701,9 +779,15 @@ class RV:
|
|
|
701
779
|
# remove empty strings
|
|
702
780
|
files = list(filter(None, files))
|
|
703
781
|
|
|
704
|
-
|
|
782
|
+
if symlink:
|
|
783
|
+
if 'top_level' not in kwargs:
|
|
784
|
+
logger.warning('may need to provide `top_level` in kwargs to find file')
|
|
785
|
+
do_symlink_filetype('S1D', files[:limit], directory, **kwargs)
|
|
786
|
+
else:
|
|
787
|
+
do_download_filetype('S1D', files[:limit], directory, verbose=self.verbose, **kwargs)
|
|
705
788
|
|
|
706
|
-
def download_s2d(self, instrument=None, index=None, limit=None,
|
|
789
|
+
def download_s2d(self, instrument=None, index=None, limit=None,
|
|
790
|
+
directory=None, symlink=False, **kwargs):
|
|
707
791
|
""" Download S2Ds from DACE
|
|
708
792
|
|
|
709
793
|
Args:
|
|
@@ -731,11 +815,16 @@ class RV:
|
|
|
731
815
|
# remove empty strings
|
|
732
816
|
files = list(filter(None, files))
|
|
733
817
|
|
|
734
|
-
|
|
818
|
+
if symlink:
|
|
819
|
+
if 'top_level' not in kwargs:
|
|
820
|
+
logger.warning('may need to provide `top_level` in kwargs to find file')
|
|
821
|
+
do_symlink_filetype('S2D', files[:limit], directory, **kwargs)
|
|
822
|
+
else:
|
|
823
|
+
do_download_filetype('S2D', files[:limit], directory, verbose=self.verbose, **kwargs)
|
|
735
824
|
|
|
736
825
|
|
|
737
|
-
from .plots import plot, plot_fwhm, plot_bis, plot_rhk, plot_quantity
|
|
738
|
-
from .plots import gls, gls_fwhm, gls_bis, gls_rhk
|
|
826
|
+
from .plots import plot, plot_fwhm, plot_bis, plot_rhk, plot_berv, plot_quantity
|
|
827
|
+
from .plots import gls, gls_fwhm, gls_bis, gls_rhk, window_function
|
|
739
828
|
from .reports import report
|
|
740
829
|
|
|
741
830
|
from .instrument_specific import known_issues
|
|
@@ -799,7 +888,7 @@ class RV:
|
|
|
799
888
|
if self.verbose:
|
|
800
889
|
logger.info(f"Removed observations from '{instrument}'")
|
|
801
890
|
|
|
802
|
-
if return_self:
|
|
891
|
+
if config.return_self:
|
|
803
892
|
return self
|
|
804
893
|
|
|
805
894
|
def remove_condition(self, condition):
|
|
@@ -827,7 +916,7 @@ class RV:
|
|
|
827
916
|
index = np.atleast_1d(index)
|
|
828
917
|
try:
|
|
829
918
|
instrument_index = self.obs[index]
|
|
830
|
-
|
|
919
|
+
np.array(self.instruments)[instrument_index - 1]
|
|
831
920
|
except IndexError:
|
|
832
921
|
logger.errors(f'index {index} is out of bounds for N={self.N}')
|
|
833
922
|
return
|
|
@@ -840,7 +929,7 @@ class RV:
|
|
|
840
929
|
# for i, inst in zip(index, instrument):
|
|
841
930
|
# index_in_instrument = i - (self.obs < instrument_index).sum()
|
|
842
931
|
# getattr(self, inst).mask[index_in_instrument] = False
|
|
843
|
-
if return_self:
|
|
932
|
+
if config.return_self:
|
|
844
933
|
return self
|
|
845
934
|
|
|
846
935
|
def remove_non_public(self):
|
|
@@ -903,7 +992,7 @@ class RV:
|
|
|
903
992
|
instruments = self._check_instrument(instrument)
|
|
904
993
|
rng = np.random.default_rng(seed=seed)
|
|
905
994
|
for inst in instruments:
|
|
906
|
-
s = getattr(self, inst)
|
|
995
|
+
# s = getattr(self, inst)
|
|
907
996
|
mask_for_this_inst = self.obs == self.instruments.index(inst) + 1
|
|
908
997
|
# only choose if there are more than n points
|
|
909
998
|
if self.mask[mask_for_this_inst].sum() > n:
|
|
@@ -1008,13 +1097,18 @@ class RV:
|
|
|
1008
1097
|
self.vrad = self.vrad - sa * (self.time - epoch) / 365.25
|
|
1009
1098
|
else:
|
|
1010
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
|
+
|
|
1011
1107
|
if 'HIRES' in inst: # never remove it from HIRES...
|
|
1012
1108
|
continue
|
|
1013
1109
|
if 'NIRPS' in inst: # never remove it from NIRPS...
|
|
1014
1110
|
continue
|
|
1015
1111
|
|
|
1016
|
-
s = getattr(self, inst)
|
|
1017
|
-
|
|
1018
1112
|
if hasattr(s, '_did_secular_acceleration') and s._did_secular_acceleration:
|
|
1019
1113
|
continue
|
|
1020
1114
|
|
|
@@ -1023,8 +1117,37 @@ class RV:
|
|
|
1023
1117
|
self._build_arrays()
|
|
1024
1118
|
|
|
1025
1119
|
self._did_secular_acceleration = True
|
|
1026
|
-
|
|
1120
|
+
self._did_secular_acceleration_epoch = epoch
|
|
1121
|
+
self._did_secular_acceleration_simbad = force_simbad
|
|
1122
|
+
|
|
1123
|
+
if config.return_self:
|
|
1027
1124
|
return self
|
|
1125
|
+
|
|
1126
|
+
def _undo_secular_acceleration(self):
|
|
1127
|
+
if self._did_secular_acceleration:
|
|
1128
|
+
_old_verbose = self.verbose
|
|
1129
|
+
self.verbose = False
|
|
1130
|
+
sa = self.secular_acceleration(just_compute=True,
|
|
1131
|
+
force_simbad=self._did_secular_acceleration_simbad)
|
|
1132
|
+
self.verbose = _old_verbose
|
|
1133
|
+
sa = sa.value
|
|
1134
|
+
|
|
1135
|
+
if self._child:
|
|
1136
|
+
self.vrad = self.vrad + sa * (self.time - self._did_secular_acceleration_epoch) / 365.25
|
|
1137
|
+
else:
|
|
1138
|
+
for inst in self.instruments:
|
|
1139
|
+
if 'HIRES' in inst: # never remove it from HIRES...
|
|
1140
|
+
continue
|
|
1141
|
+
if 'NIRPS' in inst: # never remove it from NIRPS...
|
|
1142
|
+
continue
|
|
1143
|
+
|
|
1144
|
+
s = getattr(self, inst)
|
|
1145
|
+
|
|
1146
|
+
s.vrad = s.vrad + sa * (s.time - self._did_secular_acceleration_epoch) / 365.25
|
|
1147
|
+
|
|
1148
|
+
self._build_arrays()
|
|
1149
|
+
|
|
1150
|
+
self._did_secular_acceleration = False
|
|
1028
1151
|
|
|
1029
1152
|
def sigmaclip(self, sigma=5, instrument=None, strict=True):
|
|
1030
1153
|
""" Sigma-clip RVs (per instrument!) """
|
|
@@ -1053,7 +1176,7 @@ class RV:
|
|
|
1053
1176
|
# # if insts.size == 1: # of the same instrument?
|
|
1054
1177
|
# if self.verbose:
|
|
1055
1178
|
# logger.warning(f'would remove all observations from {insts[0]}, skipping')
|
|
1056
|
-
# if return_self:
|
|
1179
|
+
# if config.return_self:
|
|
1057
1180
|
# return self
|
|
1058
1181
|
# continue
|
|
1059
1182
|
|
|
@@ -1065,7 +1188,7 @@ class RV:
|
|
|
1065
1188
|
self._did_adjust_means = False
|
|
1066
1189
|
self.adjust_means()
|
|
1067
1190
|
|
|
1068
|
-
if return_self:
|
|
1191
|
+
if config.return_self:
|
|
1069
1192
|
return self
|
|
1070
1193
|
|
|
1071
1194
|
def clip_maxerror(self, maxerror:float):
|
|
@@ -1087,7 +1210,7 @@ class RV:
|
|
|
1087
1210
|
logger.warning(f'clip_maxerror ({maxerror} {self.units}) removed {n} point' + s)
|
|
1088
1211
|
|
|
1089
1212
|
self._propagate_mask_changes()
|
|
1090
|
-
if return_self:
|
|
1213
|
+
if config.return_self:
|
|
1091
1214
|
return self
|
|
1092
1215
|
|
|
1093
1216
|
def bin(self):
|
|
@@ -1220,6 +1343,11 @@ class RV:
|
|
|
1220
1343
|
for inst in self.instruments:
|
|
1221
1344
|
s = getattr(self, inst)
|
|
1222
1345
|
|
|
1346
|
+
if s.mtime.size == 0:
|
|
1347
|
+
if self.verbose:
|
|
1348
|
+
logger.info(f'all observations of {inst} are masked')
|
|
1349
|
+
continue
|
|
1350
|
+
|
|
1223
1351
|
if s.N == 1:
|
|
1224
1352
|
if self.verbose:
|
|
1225
1353
|
msg = (f'only 1 observation for {inst}, '
|
|
@@ -1231,28 +1359,37 @@ class RV:
|
|
|
1231
1359
|
|
|
1232
1360
|
s.rv_mean = wmean(s.mvrad, s.msvrad)
|
|
1233
1361
|
s.vrad -= s.rv_mean
|
|
1362
|
+
|
|
1234
1363
|
if self.verbose:
|
|
1235
1364
|
logger.info(f'subtracted weighted average from {inst:10s}: ({s.rv_mean:.3f} {self.units})')
|
|
1365
|
+
|
|
1236
1366
|
if just_rv:
|
|
1237
1367
|
continue
|
|
1238
|
-
|
|
1368
|
+
|
|
1239
1369
|
for i, other in enumerate(others):
|
|
1240
1370
|
y, ye = getattr(s, other), getattr(s, other + '_err')
|
|
1241
1371
|
m = wmean(y[s.mask], ye[s.mask])
|
|
1242
1372
|
setattr(s, f'{other}_mean', m)
|
|
1243
1373
|
setattr(s, other, getattr(s, other) - m)
|
|
1244
|
-
# log_msg += other
|
|
1245
|
-
# if i < len(others) - 1:
|
|
1246
|
-
# log_msg += ', '
|
|
1247
|
-
|
|
1248
|
-
# if self.verbose:
|
|
1249
|
-
# logger.info(log_msg)
|
|
1250
1374
|
|
|
1251
1375
|
self._build_arrays()
|
|
1252
1376
|
self._did_adjust_means = True
|
|
1253
|
-
if return_self:
|
|
1377
|
+
if config.return_self:
|
|
1254
1378
|
return self
|
|
1255
1379
|
|
|
1380
|
+
def add_to_vrad(self, values):
|
|
1381
|
+
""" Add an array of values to the RVs of all instruments """
|
|
1382
|
+
if values.size != self.vrad.size:
|
|
1383
|
+
raise ValueError(f"incompatible sizes: len(values) must equal self.N, got {values.size} != {self.vrad.size}")
|
|
1384
|
+
|
|
1385
|
+
for inst in self.instruments:
|
|
1386
|
+
s = getattr(self, inst)
|
|
1387
|
+
mask = self.instrument_array == inst
|
|
1388
|
+
s.vrad += values[mask]
|
|
1389
|
+
|
|
1390
|
+
self._build_arrays()
|
|
1391
|
+
|
|
1392
|
+
|
|
1256
1393
|
def put_at_systemic_velocity(self):
|
|
1257
1394
|
"""
|
|
1258
1395
|
For instruments in which mean(RV) < ptp(RV), "move" RVs to the systemic
|
|
@@ -1474,6 +1611,8 @@ class RV:
|
|
|
1474
1611
|
|
|
1475
1612
|
|
|
1476
1613
|
#
|
|
1614
|
+
from .stellar import calc_prot_age
|
|
1615
|
+
|
|
1477
1616
|
@property
|
|
1478
1617
|
def HZ(self):
|
|
1479
1618
|
if not hasattr(self, 'star_mass'):
|
|
@@ -1492,22 +1631,50 @@ class RV:
|
|
|
1492
1631
|
return self._planets
|
|
1493
1632
|
|
|
1494
1633
|
|
|
1495
|
-
def fit_sine(t, y, yerr, period='gls', fix_period=False):
|
|
1634
|
+
def fit_sine(t, y, yerr=None, period='gls', fix_period=False):
|
|
1635
|
+
""" Fit a sine curve of the form y = A * sin(2π * t / P + φ) + c
|
|
1636
|
+
|
|
1637
|
+
Args:
|
|
1638
|
+
t (ndarray):
|
|
1639
|
+
Time array
|
|
1640
|
+
y (ndarray):
|
|
1641
|
+
Array of observed values
|
|
1642
|
+
yerr (ndarray, optional):
|
|
1643
|
+
Array of uncertainties. Defaults to None.
|
|
1644
|
+
period (str or float, optional):
|
|
1645
|
+
Initial guess for period or 'gls' to get it from Lomb-Scargle
|
|
1646
|
+
periodogram. Defaults to 'gls'.
|
|
1647
|
+
fix_period (bool, optional):
|
|
1648
|
+
Whether to fix the period. Defaults to False.
|
|
1649
|
+
|
|
1650
|
+
Returns:
|
|
1651
|
+
p (ndarray):
|
|
1652
|
+
Best-fit parameters [A, P, φ, c] or [A, φ, c]
|
|
1653
|
+
f (callable):
|
|
1654
|
+
Function that returns the best-fit sine curve for input times
|
|
1655
|
+
"""
|
|
1496
1656
|
from scipy.optimize import leastsq
|
|
1497
1657
|
if period == 'gls':
|
|
1498
1658
|
from astropy.timeseries import LombScargle
|
|
1499
1659
|
gls = LombScargle(t, y, yerr)
|
|
1500
1660
|
freq, power = gls.autopower()
|
|
1501
1661
|
period = 1 / freq[power.argmax()]
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1662
|
+
else:
|
|
1663
|
+
period = float(period)
|
|
1664
|
+
|
|
1665
|
+
if yerr is None:
|
|
1666
|
+
yerr = np.ones_like(y)
|
|
1667
|
+
|
|
1668
|
+
if fix_period:
|
|
1669
|
+
def sine(t, p):
|
|
1670
|
+
return p[0] * np.sin(2 * np.pi * t / period + p[1]) + p[2]
|
|
1671
|
+
f = lambda p, t, y, ye: (sine(t, p) - y) / ye
|
|
1672
|
+
p0 = [y.ptp(), 0.0, 0.0]
|
|
1673
|
+
else:
|
|
1674
|
+
def sine(t, p):
|
|
1675
|
+
return p[0] * np.sin(2 * np.pi * t / p[1] + p[2]) + p[3]
|
|
1676
|
+
f = lambda p, t, y, ye: (sine(t, p) - y) / ye
|
|
1677
|
+
p0 = [y.ptp(), period, 0.0, 0.0]
|
|
1678
|
+
|
|
1679
|
+
xbest, _ = leastsq(f, p0, args=(t, y, yerr))
|
|
1513
1680
|
return xbest, partial(sine, p=xbest)
|
arvi/translations.py
CHANGED
arvi/utils.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import time
|
|
2
3
|
from contextlib import contextmanager
|
|
3
4
|
try:
|
|
4
5
|
from unittest.mock import patch
|
|
@@ -19,6 +20,9 @@ except ImportError:
|
|
|
19
20
|
tqdm = lambda x, *args, **kwargs: x
|
|
20
21
|
trange = lambda *args, **kwargs: range(*args, **kwargs)
|
|
21
22
|
|
|
23
|
+
from .setup_logger import logger
|
|
24
|
+
from . import config
|
|
25
|
+
|
|
22
26
|
|
|
23
27
|
def create_directory(directory):
|
|
24
28
|
""" Create a directory if it does not exist """
|
|
@@ -61,6 +65,23 @@ def all_logging_disabled():
|
|
|
61
65
|
finally:
|
|
62
66
|
logging.disable(previous_level)
|
|
63
67
|
|
|
68
|
+
|
|
69
|
+
@contextmanager
|
|
70
|
+
def timer():
|
|
71
|
+
""" A simple context manager to time a block of code """
|
|
72
|
+
if not config.debug:
|
|
73
|
+
yield
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
logger.debug(f'starting timer')
|
|
77
|
+
start = time.time()
|
|
78
|
+
try:
|
|
79
|
+
yield
|
|
80
|
+
finally:
|
|
81
|
+
end = time.time()
|
|
82
|
+
logger.debug(f'elapsed time: {end - start:.2f} seconds')
|
|
83
|
+
|
|
84
|
+
|
|
64
85
|
def strtobool(val):
|
|
65
86
|
"""Convert a string representation of truth to true (1) or false (0).
|
|
66
87
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
arvi/HZ.py,sha256=u7rguhlILRBW-LOczlY3dkIB4LM8p8W7Xfg4FnNaYG0,2850
|
|
2
|
+
arvi/__init__.py,sha256=stLL3UtXmR1jpNEoMyVohjvkCatunz1w5ZK0ApmWuYQ,814
|
|
3
|
+
arvi/ariadne_wrapper.py,sha256=jv8Wl35LfHl1UH1EklbvxHcQHqaEDhRGNogSYjFt7Y4,2141
|
|
4
|
+
arvi/berv.py,sha256=5avwcmc2nkYH1KDo-z4eMPsS1ElNvold2DWkziV13gE,17633
|
|
5
|
+
arvi/binning.py,sha256=jJ_resqSvfI-2BT0cnGPFckTIei_k2Mk95oZyE5b5zQ,15250
|
|
6
|
+
arvi/config.py,sha256=wyj6FTxN7QOZj8LaHAe_ZdPKVfrNfobNNOHRNLH-S7Q,339
|
|
7
|
+
arvi/dace_wrapper.py,sha256=HmsyThieljcjorSSZgmGTZPGBqNrm9QoPwjoR_GpVKo,17025
|
|
8
|
+
arvi/extra_data.py,sha256=WEEaYeLh52Zdv0uyHO72Ys5MWS3naTAP4wJV2BJ1mbk,2551
|
|
9
|
+
arvi/gaia_wrapper.py,sha256=YxqqlWkLAKBY7AGHfDpNbkOLYWK0lt0L5GZenn0FfxM,3555
|
|
10
|
+
arvi/headers.py,sha256=uvdJebw1M5YkGjE3vJJwYBOnLikib75uuZE9FXB5JJM,1673
|
|
11
|
+
arvi/instrument_specific.py,sha256=fhkvR5jJzpJH7XbT8Fbzkaz6tGeoFYugkJCIAJgSR7o,4746
|
|
12
|
+
arvi/lbl_wrapper.py,sha256=_ViGVkpakvuBR_xhu9XJRV5EKHpj5Go6jBZGJZMIS2Y,11850
|
|
13
|
+
arvi/nasaexo_wrapper.py,sha256=mWt7eHgSZe4MBKCmUvMPTyUPGuiwGTqKugNBvmjOg9s,7306
|
|
14
|
+
arvi/plots.py,sha256=53_rHVh7SeyBylM91PP6mNr7WTGmIoRnR8JfKJPdu7E,25594
|
|
15
|
+
arvi/programs.py,sha256=C0Fbldjf-QEZYYJp5wBKP3h7zraD0O2mJC7Su967STg,4607
|
|
16
|
+
arvi/reports.py,sha256=yrdajC-zz5_kH1Ucc6cU70DK-5dpG0Xyeru-EITKpNo,3355
|
|
17
|
+
arvi/setup_logger.py,sha256=pBzaRTn0hntozjbaRVx0JIbWGuENkvYUApa6uB-FsRo,279
|
|
18
|
+
arvi/simbad_wrapper.py,sha256=fwO0NbMvxAW3RyC58FPkLjXqLs9OkRyK0sYcb0ZVBQA,5571
|
|
19
|
+
arvi/spectra.py,sha256=pTAWSW4vk96DWRQ-6l5mNJHUhiAyaPR-QDjZdOT6Ak0,7489
|
|
20
|
+
arvi/stats.py,sha256=MQiyLvdiAFxIC29uajTy8kuxD-b2Y6mraL4AfWkRJkM,2576
|
|
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
|
|
24
|
+
arvi/utils.py,sha256=nuIOuUdysMesWF9ute4v-kbeo6DylWjWW-SJhCsHn9I,4078
|
|
25
|
+
arvi/data/info.svg,sha256=0IMI6W-eFoTD8acnury79WJJakpBwLa4qKS4JWpsXiI,489
|
|
26
|
+
arvi/data/obs_affected_ADC_issues.dat,sha256=tn93uOL0eCTYhireqp1wG-_c3CbxPA7C-Rf-pejVY8M,10853
|
|
27
|
+
arvi/data/obs_affected_blue_cryostat_issues.dat,sha256=z4AK17xfz8tGTDv1FjRvQFnio4XA6PNNfDXuicewHk4,1771
|
|
28
|
+
arvi/data/extra/HD86226_PFS1.rdb,sha256=vfAozbrKHM_j8dYkCBJsuHyD01KEM1asghe2KInwVao,3475
|
|
29
|
+
arvi/data/extra/HD86226_PFS2.rdb,sha256=F2P7dB6gVyzCglUjNheB0hIHVClC5RmARrGwbrY1cfo,4114
|
|
30
|
+
arvi/data/extra/metadata.json,sha256=C69hIw6CohyES6BI9vDWjxwSz7N4VOYX0PCgjXtYFmU,178
|
|
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,,
|