arvi 0.1.24__py3-none-any.whl → 0.1.26__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/dace_wrapper.py CHANGED
@@ -70,7 +70,6 @@ def get_arrays(result, latest_pipeline=True, ESPRESSO_mode='HR11', NIRPS_mode='H
70
70
  if verbose and npipe > 1:
71
71
  logger.info(f'selecting latest pipeline ({pipelines[0]}) for {inst}')
72
72
 
73
-
74
73
  for pipe in pipelines:
75
74
  modes = [m for m in result[inst][pipe].keys()]
76
75
 
@@ -85,28 +84,21 @@ def get_arrays(result, latest_pipeline=True, ESPRESSO_mode='HR11', NIRPS_mode='H
85
84
  if verbose:
86
85
  logger.warning(f'no observations for requested NIRPS mode ({NIRPS_mode})')
87
86
 
88
- # HARPS15 observations should not be separated by 'mode' if some are
89
- # done together with NIRPS
90
- if 'HARPS15' in inst:
87
+ # HARPS observations should not be separated by 'mode' if some are
88
+ # done together with NIRPS, but should be separated by 'EGGS' mode
89
+ if 'HARPS' in inst:
90
+ m0 = modes[0]
91
+ data = {
92
+ k: np.concatenate([result[inst][pipe][m][k] for m in modes])
93
+ for k in result[inst][pipe][m0].keys()
94
+ }
91
95
  if 'HARPS+NIRPS' in modes:
92
- m0 = modes[0]
93
- data = {
94
- k: np.concatenate([result[inst][pipe][m][k] for m in modes])
95
- for k in result[inst][pipe][m0].keys()
96
- }
97
- arrays.append(
98
- ((str(inst), str(pipe), str(m0)), data)
99
- )
100
- if 'EGGS+NIRPS' in modes:
101
- m0 = modes[0]
102
- data = {
103
- k: np.concatenate([result[inst][pipe][m][k] for m in modes])
104
- for k in result[inst][pipe][m0].keys()
105
- }
106
- arrays.append(
107
- ((str(inst + '_EGGS'), str(pipe), str(m0)), data)
108
- )
109
- continue
96
+ arrays.append( ((str(inst), str(pipe), str(m0)), data) )
97
+ continue
98
+
99
+ if 'EGGS+NIRPS' in modes or 'EGGS' in modes:
100
+ arrays.append( ((str(inst + '_EGGS'), str(pipe), str(m0)), data) )
101
+ continue
110
102
 
111
103
  for mode in modes:
112
104
  if 'rjd' not in result[inst][pipe][mode]:
arvi/extra_data.py CHANGED
@@ -10,7 +10,8 @@ refs = {
10
10
  'HD86226': 'Teske et al. 2020 (AJ, 160, 2)'
11
11
  }
12
12
 
13
- def get_extra_data(star, instrument=None, path=None, verbose=True):
13
+ def get_extra_data(star, instrument=None, path=None, verbose=True,
14
+ check_for_kms=True):
14
15
  if path is None:
15
16
  path = os.path.dirname(__file__)
16
17
  path = os.path.join(path, 'data', 'extra')
@@ -18,7 +19,7 @@ def get_extra_data(star, instrument=None, path=None, verbose=True):
18
19
  metadata = json.load(open(os.path.join(path, 'metadata.json'), 'r'))
19
20
  # print(metadata)
20
21
 
21
- files = glob(os.path.join(path, star + '*'))
22
+ files = glob(os.path.join(path, star.replace(' ', '') + '*.rdb'))
22
23
  files = [f for f in files if os.path.isfile(f)]
23
24
  files = [f for f in files if not os.path.basename(f).endswith('.zip')]
24
25
 
@@ -57,9 +58,24 @@ def get_extra_data(star, instrument=None, path=None, verbose=True):
57
58
  if 'corrected_for_secular_acceleration' in metadata[file_basename]:
58
59
  did_sa[i] = metadata[file_basename]['corrected_for_secular_acceleration']
59
60
 
60
- s = timeseries.RV.from_rdb(files[0], star=star, instrument=instruments[0], units=units[0])
61
- for file, instrument, unit in zip(files[1:], instruments[1:], units[1:]):
62
- s = s + timeseries.RV.from_rdb(file, star=star, instrument=instrument, units=unit)
61
+ with logger.contextualize(indent=' '):
62
+ s = timeseries.RV.from_rdb(files[0], star=star, instrument=instruments[0], units=units[0])
63
+ if check_for_kms and s.svrad.min() < 0.01:
64
+ units[0] = 'kms'
65
+ s = timeseries.RV.from_rdb(files[0], star=star, instrument=instruments[0], units=units[0])
66
+ if verbose:
67
+ logger.info(f'{instruments[0]:>12s} ├ ({s.N} observations)')
68
+
69
+ for file, instrument, unit in zip(files[1:], instruments[1:], units[1:]):
70
+ _s = timeseries.RV.from_rdb(file, star=star, instrument=instrument, units=unit)
71
+ if check_for_kms and _s.svrad.min() < 0.01:
72
+ unit = 'kms'
73
+ _s = timeseries.RV.from_rdb(file, star=star, instrument=instrument, units=unit)
74
+ if verbose:
75
+ logger.info(f'{instrument:>12s} ├ ({_s.N} observations)')
76
+
77
+ s = s + _s
78
+
63
79
 
64
80
  for i, (inst, ref, inst_did_sa) in enumerate(zip(s.instruments, reference, did_sa)):
65
81
  _s = getattr(s, inst)
arvi/gaia_wrapper.py CHANGED
@@ -31,6 +31,7 @@ gaia_source.source_id = {id}
31
31
 
32
32
  translate = {
33
33
  'Proxima': '5853498713190525696',
34
+ 'GJ699': '4472832130942575872',
34
35
  'LS II +14 13': '4318465066420528000',
35
36
  }
36
37
 
@@ -81,7 +82,7 @@ class gaia:
81
82
  pmra = simbad.pmra
82
83
  pmdec = simbad.pmdec
83
84
  rv = simbad.rvz_radvel
84
- args = dict(ra=ra, dec=dec, plx=plx, pmra=pmra, pmdec=pmdec, rv=rv)
85
+ args = dict(ra=ra, dec=dec, plx=plx, pmra=pmra, pmdec=pmdec, rv=rv)
85
86
 
86
87
  try:
87
88
  if star in translate:
arvi/plots.py CHANGED
@@ -6,7 +6,7 @@ import numpy as np
6
6
  from astropy.timeseries import LombScargle
7
7
 
8
8
  from .setup_logger import logger
9
- from . import config
9
+ from .config import config
10
10
  from .stats import wmean
11
11
 
12
12
  from .utils import lazy_import
@@ -123,8 +123,12 @@ def clickable_legend(fig, ax, leg):
123
123
  h = handles[labels.index(artist.get_text())]
124
124
  alpha_text = {None:0.2, 1.0: 0.2, 0.2:1.0}[artist.get_alpha()]
125
125
  alpha_point = {None: 0.0, 1.0: 0.0, 0.2: 1.0}[artist.get_alpha()]
126
- h[0].set_alpha(alpha_point)
127
- h[2][0].set_alpha(alpha_point)
126
+ try:
127
+ h[0].set_alpha(alpha_point)
128
+ h[2][0].set_alpha(alpha_point)
129
+ except TypeError:
130
+ h.set_alpha(alpha_point)
131
+
128
132
  artist.set_alpha(alpha_text)
129
133
  fig.canvas.draw()
130
134
  except ValueError:
@@ -488,14 +492,15 @@ def plot_quantity(self, quantity, ax=None, show_masked=False, instrument=None,
488
492
 
489
493
 
490
494
  plot_fwhm = partialmethod(plot_quantity, quantity='fwhm')
491
- plot_bis = partialmethod(plot_quantity, quantity='bispan')
495
+ plot_bispan = partialmethod(plot_quantity, quantity='bispan')
492
496
  plot_contrast = partialmethod(plot_quantity, quantity='contrast')
493
497
  plot_rhk = partialmethod(plot_quantity, quantity='rhk')
494
498
  plot_berv = partialmethod(plot_quantity, quantity='berv')
495
499
 
496
500
 
497
501
  @plot_fast
498
- def gls(self, ax=None, label=None, fap=True, instrument=None, adjust_means=config.adjust_means_gls,
502
+ def gls(self, ax=None, label=None, fap=True, instrument=None,
503
+ adjust_means=config.adjust_means_gls,
499
504
  picker=True, **kwargs):
500
505
  """
501
506
  Calculate and plot the Generalised Lomb-Scargle periodogram of the radial
@@ -711,7 +716,7 @@ def gls_quantity(self, quantity, ax=None, fap=True, instrument=None,
711
716
 
712
717
 
713
718
  gls_fwhm = partialmethod(gls_quantity, quantity='fwhm')
714
- gls_bis = partialmethod(gls_quantity, quantity='bispan')
719
+ gls_bispan = partialmethod(gls_quantity, quantity='bispan')
715
720
  gls_rhk = partialmethod(gls_quantity, quantity='rhk')
716
721
 
717
722
 
arvi/timeseries.py CHANGED
@@ -25,7 +25,10 @@ units = lazy_import('astropy.units')
25
25
  # from astropy import units
26
26
 
27
27
  class ExtraFields:
28
- pass
28
+ @property
29
+ def fields(self):
30
+ return list(self.__dict__.keys())
31
+
29
32
 
30
33
  @dataclass
31
34
  class RV:
@@ -70,13 +73,17 @@ class RV:
70
73
  _gaia = None
71
74
 
72
75
  def __repr__(self):
76
+ ni = len(self.instruments)
73
77
  if self.N == 0:
74
78
  return f"RV(star='{self.star}', N=0)"
79
+
80
+ i = f'{ni} instrument' + ('s' if ni > 1 else '')
81
+
75
82
  if self.time.size == self.mtime.size:
76
- return f"RV(star='{self.star}', N={self.N})"
83
+ return f"RV(star='{self.star}', N={self.N}, {i})"
77
84
  else:
78
85
  nmasked = self.N - self.mtime.size
79
- return f"RV(star='{self.star}', N={self.N}, masked={nmasked})"
86
+ return f"RV(star='{self.star}', N={self.N}, masked={nmasked}, {i})"
80
87
 
81
88
  @property
82
89
  def simbad(self):
@@ -272,11 +279,20 @@ class RV:
272
279
  # if not isinstance(other, self.__class__):
273
280
  # raise TypeError('unsupported operand type(s) for +: '
274
281
  # f"'{self.__class__.__name__}' and '{other.__class__.__name__}'")
282
+ if other is None:
283
+ if inplace:
284
+ return
285
+ else:
286
+ return deepcopy(self)
275
287
 
276
288
  if np.isin(self.instruments, other.instruments).any():
277
289
  logger.error('the two objects share instrument(s), cannot add them')
278
290
  return
279
291
 
292
+ if self._did_adjust_means or other._did_adjust_means:
293
+ self.adjust_means()
294
+ other.adjust_means()
295
+
280
296
  if inplace:
281
297
  #? could it be as simple as this?
282
298
  for i in other.instruments:
@@ -511,18 +527,33 @@ class RV:
511
527
  Examples:
512
528
  s = RV.from_rdb('star_HARPS.rdb')
513
529
  """
530
+ from glob import glob
531
+ from os.path import splitext, basename
532
+
533
+ verbose = kwargs.pop('verbose', True)
534
+
514
535
  if isinstance(files, str):
515
- files = [files]
536
+ if '*' in files:
537
+ files = glob(files)
538
+ else:
539
+ files = [files]
540
+
541
+ if len(files) == 0:
542
+ if verbose:
543
+ logger.error('no files found')
544
+ return
516
545
 
517
546
  if star is None:
518
- star_ = np.unique([os.path.splitext(os.path.basename(f))[0].split('_')[0] for f in files])
547
+ star_ = np.unique([splitext(basename(f))[0].split('_')[0] for f in files])
519
548
  if star_.size == 1:
520
- logger.info(f'assuming star is {star_[0]}')
521
- star = star_[0]
549
+ star = star_[0].replace('-', '_')
550
+ if verbose:
551
+ logger.info(f'assuming star is {star}')
522
552
 
523
553
  if instrument is None:
524
- instruments = np.array([os.path.splitext(f)[0].split('_')[1] for f in files])
525
- logger.info(f'assuming instruments: {instruments}')
554
+ instruments = np.array([splitext(basename(f))[0].split('_')[1] for f in files])
555
+ if verbose:
556
+ logger.info(f'assuming instruments: {instruments}')
526
557
  else:
527
558
  instruments = np.atleast_1d(instrument)
528
559
 
@@ -537,11 +568,14 @@ class RV:
537
568
  has_col = np.array([name in data.dtype.fields for name in names])
538
569
  if any(has_col):
539
570
  col = np.where(has_col)[0][0]
540
- return data[names[col]]
571
+ return np.atleast_1d(data[names[col]])
541
572
  return False
542
573
 
543
574
  for i, (f, instrument) in enumerate(zip(files, instruments)):
544
575
  data = np.loadtxt(f, skiprows=2, usecols=range(3), unpack=True)
576
+ if data.ndim == 1:
577
+ data = data.reshape(-1, 1)
578
+
545
579
  _s = cls(star, _child=True, **kwargs)
546
580
  time = data[0]
547
581
  _s.time = time
@@ -559,14 +593,20 @@ class RV:
559
593
  names = header.split()
560
594
 
561
595
  if len(names) > 3:
562
- if f.endswith('.rdb'):
563
- kw = dict(skip_header=2, dtype=None, encoding=None)
564
- else:
565
- kw = dict(skip_header=0, comments='--', names=True, dtype=None, encoding=None)
596
+ # if f.endswith('.rdb'):
597
+ # kw = dict(skip_header=2, dtype=None, encoding=None)
598
+ # else:
599
+ comments = '#'
600
+ kw = dict(skip_header=2, comments=comments,
601
+ names=names, dtype=None, encoding=None)
566
602
  if '\t' in header:
567
603
  data = np.genfromtxt(f, **kw, delimiter='\t')
568
604
  else:
569
605
  data = np.genfromtxt(f, **kw)
606
+
607
+ # if data.ndim in (0, 1):
608
+ # data = data.reshape(-1, 1)
609
+
570
610
  if len(names) == len(data.dtype.names):
571
611
  data.dtype.names = names
572
612
  else:
@@ -580,19 +620,20 @@ class RV:
580
620
  else:
581
621
  _s.fwhm_err = 2 * _s.svrad
582
622
  else:
583
- _s.fwhm = np.zeros_like(time)
623
+ _s.fwhm = np.full_like(time, np.nan)
584
624
  _s.fwhm_err = np.full_like(time, np.nan)
585
625
 
586
626
  _quantities.append('fwhm')
587
627
  _quantities.append('fwhm_err')
588
628
 
629
+ # try to find R'HK and uncertainty
589
630
  if (v := find_column(data, ['rhk'])) is not False:
590
631
  _s.rhk = v
591
632
  _s.rhk_err = np.full_like(time, np.nan)
592
633
  if (sv := find_column(data, ['srhk', 'rhk_err', 'sig_rhk'])) is not False:
593
634
  _s.rhk_err = sv
594
635
  else:
595
- _s.rhk = np.zeros_like(time)
636
+ _s.rhk = np.full_like(time, np.nan)
596
637
  _s.rhk_err = np.full_like(time, np.nan)
597
638
 
598
639
  _quantities.append('rhk')
@@ -636,8 +677,9 @@ class RV:
636
677
 
637
678
  _s.extra_fields = ExtraFields()
638
679
  for name in data.dtype.names:
639
- if name not in _quantities:
640
- name_ = name.replace(' ', '_')
680
+ # don't repeat some quantities
681
+ if name not in _quantities + ['bjd', 'rjd', 'vrad', 'svrad']:
682
+ name_ = name.replace(' ', '_').replace('-', '_')
641
683
  setattr(_s.extra_fields, name_, data[name])
642
684
  # _quantities.append(field)
643
685
 
@@ -744,8 +786,8 @@ class RV:
744
786
  return s
745
787
 
746
788
  @classmethod
747
- @lru_cache(maxsize=60)
748
- def from_KOBE_file(cls, star, **kwargs):
789
+ # @lru_cache(maxsize=60)
790
+ def from_KOBE_file(cls, star, directory='.', force_download=False, **kwargs):
749
791
  assert 'KOBE' in star, f'{star} is not a KOBE star?'
750
792
  import requests
751
793
  from requests.auth import HTTPBasicAuth
@@ -766,7 +808,14 @@ class RV:
766
808
  local_targz_file = os.path.join(get_data_path(), 'KOBE_fitsfiles.tar.gz')
767
809
  fits_file = f'{star}_RVs.fits'
768
810
 
769
- if os.path.exists(local_targz_file) and os.path.getmtime(local_targz_file) > pytime() - 60*60*2:
811
+ local_exists = os.path.exists(local_targz_file)
812
+ local_recent = os.path.getmtime(local_targz_file) > pytime() - 60*60*2
813
+
814
+ if os.path.exists(os.path.join(directory, fits_file)):
815
+ logger.info(f'found file "{fits_file}" in "{directory}"')
816
+ hdul = fits.open(fits_file)
817
+
818
+ elif local_exists and local_recent and not force_download:
770
819
  tar = tarfile.open(local_targz_file)
771
820
 
772
821
  if fits_file not in tar.getnames():
@@ -778,6 +827,7 @@ class RV:
778
827
  else:
779
828
  resp = requests.get(f'https://kobe.caha.es/internal/fitsfiles/{fits_file}',
780
829
  auth=HTTPBasicAuth('kobeteam', config.kobe_password))
830
+ logger.info(f'found file "{fits_file}" on server')
781
831
 
782
832
  if resp.status_code != 200:
783
833
  # something went wrong, try to extract the file by downloading the
@@ -983,13 +1033,18 @@ class RV:
983
1033
 
984
1034
  if load:
985
1035
  try:
986
- from os.path import basename, join
1036
+ from os.path import basename, join, exists
987
1037
  from .utils import sanitize_path
988
1038
  import iCCF
989
1039
  downloaded = [
990
1040
  sanitize_path(join(directory, basename(f).replace('.fits', '_CCF_A.fits')))
991
1041
  for f in files[:limit]
992
1042
  ]
1043
+ downloaded = [
1044
+ skysub
1045
+ if exists(skysub := f.replace('CCF_A.fits', 'CCF_SKYSUB_A.fits')) else f
1046
+ for f in downloaded
1047
+ ]
993
1048
  if self.verbose:
994
1049
  logger.info('loading the CCF(s) into `.CCF` attribute')
995
1050
 
@@ -1063,12 +1118,45 @@ class RV:
1063
1118
  do_download_filetype('S2D', files[:limit], directory, verbose=self.verbose, **kwargs)
1064
1119
 
1065
1120
 
1066
- from .plots import plot, plot_fwhm, plot_bis, plot_rhk, plot_berv, plot_quantity
1067
- from .plots import gls, gls_fwhm, gls_bis, gls_rhk, window_function
1121
+ from .plots import plot, plot_fwhm, plot_bispan, plot_contrast, plot_rhk, plot_berv, plot_quantity
1122
+ from .plots import gls, gls_fwhm, gls_bispan, gls_rhk, gls_quantity, window_function
1068
1123
  from .reports import report
1069
1124
 
1070
1125
  from .instrument_specific import known_issues
1071
1126
 
1127
+ def change_instrument_name(self, old_name, new_name, strict=False):
1128
+ """ Change the name of an instrument
1129
+
1130
+ Args:
1131
+ old_name (str):
1132
+ The old name of the instrument
1133
+ new_name (str):
1134
+ The new name of the instrument, or postfix if `strict` is False
1135
+ strict (bool):
1136
+ Whether to match (each) `instrument` exactly
1137
+ """
1138
+ if new_name == '':
1139
+ if self.verbose:
1140
+ logger.error('new name cannot be empty string')
1141
+ return
1142
+
1143
+ instruments = self._check_instrument(old_name, strict, log=True)
1144
+ if instruments is not None:
1145
+ several = len(instruments) >= 2
1146
+ for instrument in instruments:
1147
+ if several:
1148
+ new_name_instrument = f'{instrument}_{new_name}'
1149
+ else:
1150
+ new_name_instrument = new_name
1151
+ if self.verbose:
1152
+ logger.info(f'Renaming {instrument} to {new_name_instrument}')
1153
+
1154
+ setattr(self, new_name_instrument, getattr(self, instrument))
1155
+ delattr(self, instrument)
1156
+ self.instruments[self.instruments.index(instrument)] = new_name_instrument
1157
+
1158
+ self._build_arrays()
1159
+
1072
1160
 
1073
1161
  def remove_instrument(self, instrument, strict=False):
1074
1162
  """ Remove all observations from one instrument
@@ -1697,8 +1785,52 @@ class RV:
1697
1785
  if config.return_self:
1698
1786
  return self
1699
1787
 
1788
+ def detrend(self, degree=1):
1789
+ """ Detrend the RVs of all instruments """
1790
+ instrument_indices = np.unique_inverse(self.instrument_array).inverse_indices
1791
+ def fun(p, t, degree, ninstruments, just_model=False, index=None):
1792
+ polyp, offsets = p[:degree], p[-ninstruments:]
1793
+ polyp = np.r_[polyp, 0.0]
1794
+ if index is None:
1795
+ model = offsets[instrument_indices] + np.polyval(polyp, t)
1796
+ else:
1797
+ model = offsets[index] + np.polyval(polyp, t)
1798
+ if just_model:
1799
+ return model
1800
+ return self.mvrad - model
1801
+ coef = np.polyfit(self.mtime, self.mvrad, degree)
1802
+ x0 = np.append(coef, [0.0] * (len(self.instruments) - 1))
1803
+ print(x0)
1804
+ fun(x0, self.mtime, degree, len(self.instruments))
1805
+ from scipy.optimize import leastsq
1806
+ xbest, _ = leastsq(fun, x0, args=(self.mtime, degree, len(self.instruments)))
1807
+
1808
+ fig, ax = self.plot()
1809
+ ax.remove()
1810
+ ax = fig.add_subplot(2, 1, 1)
1811
+ self.plot(ax=ax)
1812
+ for i, inst in enumerate(self.instruments):
1813
+ s = getattr(self, inst)
1814
+ ax.plot(s.time, fun(xbest, s.time, degree, len(self.instruments), just_model=True, index=i),
1815
+ color=f'C{i}')
1816
+ ax.set_title('original', loc='left', fontsize=10)
1817
+ ax.set_title(f'coefficients: {xbest[:degree]}', loc='right', fontsize=10)
1818
+
1819
+ self.add_to_vrad(-fun(xbest, self.time, degree, len(self.instruments), just_model=True))
1820
+ ax = fig.add_subplot(2, 1, 2)
1821
+ self.plot(ax=ax)
1822
+ ax.set_title('detrended', loc='left', fontsize=10)
1823
+
1824
+ # axs[0].plot(self.time, fun(xbest, self.time, degree, len(self.instruments), just_model=True))
1825
+ # axs[1].errorbar(self.mtime, fun(xbest, self.mtime, degree, len(self.instruments)), self.msvrad, fmt='o')
1826
+
1827
+ return
1828
+
1829
+
1830
+
1831
+
1700
1832
  def add_to_vrad(self, values):
1701
- """ Add a value of array of values to the RVs of all instruments """
1833
+ """ Add a value or array of values to the RVs of all instruments """
1702
1834
  values = np.atleast_1d(values)
1703
1835
  if values.size == 1:
1704
1836
  values = np.full_like(self.vrad, values)
@@ -1723,7 +1855,7 @@ class RV:
1723
1855
 
1724
1856
  def add_to_quantity(self, quantity, values):
1725
1857
  """
1726
- Add a value of array of values to the given quantity of all instruments
1858
+ Add a value or array of values to the given quantity of all instruments
1727
1859
  """
1728
1860
  if not hasattr(self, quantity):
1729
1861
  logger.error(f"cannot find '{quantity}' attribute")
@@ -1742,6 +1874,75 @@ class RV:
1742
1874
  setattr(s, quantity, getattr(s, quantity) + values[mask])
1743
1875
  self._build_arrays()
1744
1876
 
1877
+ def replace_vrad(self, values):
1878
+ """ Replace the RVs of all instruments with a value or array of values """
1879
+ values = np.atleast_1d(values)
1880
+ if values.size == 1:
1881
+ values = np.full_like(self.vrad, values)
1882
+
1883
+ masked = False
1884
+ if values.size != self.vrad.size:
1885
+ if values.size == self.mvrad.size:
1886
+ logger.warning('adding to masked RVs only')
1887
+ masked = True
1888
+ else:
1889
+ raise ValueError(f"incompatible sizes: len(values) must equal self.N, got {values.size} != {self.vrad.size}")
1890
+
1891
+ for inst in self.instruments:
1892
+ s = getattr(self, inst)
1893
+ if masked:
1894
+ mask = self.instrument_array[self.mask] == inst
1895
+ s.vrad[s.mask] = values[mask]
1896
+ else:
1897
+ mask = self.instrument_array == inst
1898
+ s.vrad = values[mask]
1899
+ self._build_arrays()
1900
+
1901
+ def replace_svrad(self, values):
1902
+ """ Replace the RV uncertainties of all instruments with a value or array of values """
1903
+ values = np.atleast_1d(values)
1904
+ if values.size == 1:
1905
+ values = np.full_like(self.svrad, values)
1906
+
1907
+ masked = False
1908
+ if values.size != self.svrad.size:
1909
+ if values.size == self.msvrad.size:
1910
+ logger.warning('adding to masked RV uncertainties only')
1911
+ masked = True
1912
+ else:
1913
+ raise ValueError(f"incompatible sizes: len(values) must equal self.N, got {values.size} != {self.svrad.size}")
1914
+
1915
+ for inst in self.instruments:
1916
+ s = getattr(self, inst)
1917
+ if masked:
1918
+ mask = self.instrument_array[self.mask] == inst
1919
+ s.svrad[s.mask] = values[mask]
1920
+ else:
1921
+ mask = self.instrument_array == inst
1922
+ s.svrad = values[mask]
1923
+ self._build_arrays()
1924
+
1925
+ def replace_quantity(self, quantity, values):
1926
+ """ Replace the given quantity of all instruments by a value or array of values """
1927
+ if not hasattr(self, quantity):
1928
+ logger.error(f"cannot find '{quantity}' attribute")
1929
+ return
1930
+ q = getattr(self, quantity)
1931
+
1932
+ values = np.atleast_1d(values)
1933
+ if values.size == 1:
1934
+ values = np.full_like(q, values)
1935
+ if values.size != q.size:
1936
+ raise ValueError(f"incompatible sizes: len(values) must equal self.N, got {values.size} != {q.size}")
1937
+
1938
+ for inst in self.instruments:
1939
+ s = getattr(self, inst)
1940
+ mask = self.instrument_array == inst
1941
+ setattr(s, quantity, values[mask])
1942
+ self._build_arrays()
1943
+
1944
+
1945
+
1745
1946
  def change_units(self, new_units):
1746
1947
  possible = {'m/s': 'm/s', 'km/s': 'km/s', 'ms': 'm/s', 'kms': 'km/s'}
1747
1948
  if new_units not in possible:
@@ -1809,20 +2010,18 @@ class RV:
1809
2010
  """ Sort instruments by first or last observation date.
1810
2011
 
1811
2012
  Args:
1812
- by_first_observation (bool, optional):
2013
+ by_first_observation (bool, optional, default=True):
1813
2014
  Sort by first observation date.
1814
- by_last_observation (bool, optional):
1815
- Sort by last observation data.
2015
+ by_last_observation (bool, optional, default=False):
2016
+ Sort by last observation date.
1816
2017
  """
1817
2018
  if by_last_observation:
1818
2019
  by_first_observation = False
1819
2020
  if by_first_observation:
1820
- fun = lambda i: getattr(self, i).time.min()
1821
- self.instruments = sorted(self.instruments, key=fun)
2021
+ self.instruments = sorted(self.instruments, key=lambda i: getattr(self, i).time.min())
1822
2022
  self._build_arrays()
1823
2023
  if by_last_observation:
1824
- fun = lambda i: getattr(self, i).time.max()
1825
- self.instruments = sorted(self.instruments, key=fun)
2024
+ self.instruments = sorted(self.instruments, key=lambda i: getattr(self, i).time.max())
1826
2025
  self._build_arrays()
1827
2026
 
1828
2027
 
@@ -1841,7 +2040,7 @@ class RV:
1841
2040
  Postfix to add to the filenames ([star]_[instrument]_[postfix].rdb).
1842
2041
  save_nans (bool, optional)
1843
2042
  Whether to save NaN values in the indicators, if they exist. If
1844
- False, the full observation is not saved.
2043
+ False, the full observation which contains NaN values is not saved.
1845
2044
  """
1846
2045
  star_name = self.star.replace(' ', '')
1847
2046
 
@@ -1864,7 +2063,7 @@ class RV:
1864
2063
 
1865
2064
  if full:
1866
2065
  if save_masked:
1867
- d = np.c_[
2066
+ arrays = [
1868
2067
  _s.time, _s.vrad, _s.svrad,
1869
2068
  _s.fwhm, _s.fwhm_err,
1870
2069
  _s.bispan, _s.bispan_err,
@@ -1873,7 +2072,7 @@ class RV:
1873
2072
  _s.berv,
1874
2073
  ]
1875
2074
  else:
1876
- d = np.c_[
2075
+ arrays = [
1877
2076
  _s.mtime, _s.mvrad, _s.msvrad,
1878
2077
  _s.fwhm[_s.mask], _s.fwhm_err[_s.mask],
1879
2078
  _s.bispan[_s.mask], _s.bispan_err[_s.mask],
@@ -1882,12 +2081,13 @@ class RV:
1882
2081
  _s.berv[_s.mask],
1883
2082
  ]
1884
2083
  if not save_nans:
1885
- if np.isnan(d).any():
1886
- # remove observations where any of the indicators are # NaN
1887
- nan_mask = np.isnan(d[:, 3:]).any(axis=1)
1888
- d = d[~nan_mask]
1889
- if self.verbose:
1890
- logger.warning(f'masking {nan_mask.sum()} observations with NaN in indicators')
2084
+ raise NotImplementedError
2085
+ # if np.isnan(d).any():
2086
+ # # remove observations where any of the indicators are # NaN
2087
+ # nan_mask = np.isnan(d[:, 3:]).any(axis=1)
2088
+ # d = d[~nan_mask]
2089
+ # if self.verbose:
2090
+ # logger.warning(f'masking {nan_mask.sum()} observations with NaN in indicators')
1891
2091
 
1892
2092
  header = '\t'.join(['bjd', 'vrad', 'svrad',
1893
2093
  'fwhm', 'sig_fwhm',
@@ -1901,9 +2101,11 @@ class RV:
1901
2101
 
1902
2102
  else:
1903
2103
  if save_masked:
1904
- d = np.c_[_s.time, _s.vrad, _s.svrad]
2104
+ arrays = [_s.time, _s.vrad, _s.svrad]
1905
2105
  else:
1906
- d = np.c_[_s.mtime, _s.mvrad, _s.msvrad]
2106
+ arrays = [_s.mtime, _s.mvrad, _s.msvrad]
2107
+
2108
+ # d = np.stack(arrays, axis=1)
1907
2109
  header = 'bjd\tvrad\tsvrad\n---\t----\t-----'
1908
2110
 
1909
2111
  file = f'{star_name}_{inst}.rdb'
@@ -1913,7 +2115,17 @@ class RV:
1913
2115
  files.append(file)
1914
2116
  file = os.path.join(directory, file)
1915
2117
 
1916
- np.savetxt(file, d, fmt='%9.5f', header=header, delimiter='\t', comments='')
2118
+ N = len(arrays[0])
2119
+ with open(file, 'w') as f:
2120
+ f.write(header + '\n')
2121
+ for i in range(N):
2122
+ for j, a in enumerate(arrays):
2123
+ f.write(str(a[i]))
2124
+ if j < len(arrays) - 1:
2125
+ f.write('\t')
2126
+ f.write('\n')
2127
+
2128
+ # np.savetxt(file, d, header=header, delimiter='\t', comments='', fmt='%f')
1917
2129
 
1918
2130
  if self.verbose:
1919
2131
  logger.info(f'saving to {file}')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arvi
3
- Version: 0.1.24
3
+ Version: 0.1.26
4
4
  Summary: The Automated RV Inspector
5
5
  Author-email: João Faria <joao.faria@unige.ch>
6
6
  License: MIT
@@ -10,6 +10,7 @@ Classifier: Programming Language :: Python :: 3
10
10
  Requires-Python: >=3.8
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
+ Requires-Dist: mock; python_version < "3.3"
13
14
  Requires-Dist: numpy
14
15
  Requires-Dist: scipy
15
16
  Requires-Dist: matplotlib
@@ -19,7 +20,6 @@ Requires-Dist: loguru
19
20
  Requires-Dist: tqdm
20
21
  Requires-Dist: pySWEETCat
21
22
  Requires-Dist: kepmodel
22
- Requires-Dist: mock; python_version < "3.3"
23
23
 
24
24
  <p align="center">
25
25
  <img width = "140" src="https://github.com/j-faria/arvi/blob/main/docs/logo/logo.png?raw=true"/>
@@ -4,15 +4,15 @@ arvi/ariadne_wrapper.py,sha256=YvilopJa9T4NwPcj3Nah_U8smSeSAU5-HYZMb_GJ-BQ,2232
4
4
  arvi/berv.py,sha256=eKnpuPC1w45UrUEyFRbs9F9j3bXz3kxYzNXbnRgvFQM,17596
5
5
  arvi/binning.py,sha256=jbemJ-bM3aqoOsqMo_OhWt_co-JAQ0nhdG_GpTsrRsw,15403
6
6
  arvi/config.py,sha256=W-v8NNhRd_PROu0wCMilXmOhYcju4xbUalugd5u7SRU,1881
7
- arvi/dace_wrapper.py,sha256=CUHKN5m7KULM1sES5x0GXx8HQgJE7XdwwWv6_zAYhb4,21324
8
- arvi/extra_data.py,sha256=WEEaYeLh52Zdv0uyHO72Ys5MWS3naTAP4wJV2BJ1mbk,2551
9
- arvi/gaia_wrapper.py,sha256=icm3LJjG9pjP47_bM30NFyocUQO3X3SHS5yQ-Dwcr5w,4653
7
+ arvi/dace_wrapper.py,sha256=YArI7acfkktiy5GWfKMXHoRRe7O1tKpL18LfzygqPCQ,21071
8
+ arvi/extra_data.py,sha256=cpJGMle0ZqY_dtrmbbMQcyU48PkNjfzUgQ-qY-2XTj8,3249
9
+ arvi/gaia_wrapper.py,sha256=Ox-zWSXX_rxzieP-Nr2FERcQgOZWxv7FhBkFhGu2ROU,4680
10
10
  arvi/headers.py,sha256=uvdJebw1M5YkGjE3vJJwYBOnLikib75uuZE9FXB5JJM,1673
11
11
  arvi/instrument_specific.py,sha256=-pbm2Vk3iK_1K7nDa1avlJOKHBcXllwILI4lQn-Ze-A,7761
12
12
  arvi/kima_wrapper.py,sha256=BvNTVqzM4lMNhLCyBFVh3T84hHfGKAFpgiYiOi4lh0g,2731
13
13
  arvi/lbl_wrapper.py,sha256=_ViGVkpakvuBR_xhu9XJRV5EKHpj5Go6jBZGJZMIS2Y,11850
14
14
  arvi/nasaexo_wrapper.py,sha256=mWt7eHgSZe4MBKCmUvMPTyUPGuiwGTqKugNBvmjOg9s,7306
15
- arvi/plots.py,sha256=WUm-sqN0aZTNXvE1kYpvmHTW9QPWqSCpKhNjwaqxjEk,29628
15
+ arvi/plots.py,sha256=ys3M_zU701ubz-hEcE8Jpp4fG9D4yoZE7o7q1qW_-nA,29758
16
16
  arvi/programs.py,sha256=BW7xBNKLei7NVLLW3_lsVskwzkaIoNRiHK2jn9Tn2ZM,8879
17
17
  arvi/reports.py,sha256=ayPdZ4HZO9iCDdnADQ18gQPJh79o-1UYG7TYkvm9Lrc,4051
18
18
  arvi/setup_logger.py,sha256=pBzaRTn0hntozjbaRVx0JIbWGuENkvYUApa6uB-FsRo,279
@@ -20,7 +20,7 @@ arvi/simbad_wrapper.py,sha256=iAAwEMcr1Hgu6lnDctmaCC1TLPCB8yAfHG0wxh9K9C8,5791
20
20
  arvi/spectra.py,sha256=ebF1ocodTastLx0CyqLSpE8EZNDXBF8riyfxMr3L6H0,7491
21
21
  arvi/stats.py,sha256=ilzzGL9ew-SyVa9eEdrYCpD3DliOAwhoNUg9LIlHjzU,2583
22
22
  arvi/stellar.py,sha256=veuL_y9kJvvApU_jqYQqP3EkcRnQffTc8Us6iT5UrFI,3790
23
- arvi/timeseries.py,sha256=NdmSSYeDdS-cYBXPt8NCeKS1jLdv8LP6Zh561KRGfZc,77328
23
+ arvi/timeseries.py,sha256=w9DxFeuzaxI8r_WMziMMxKDZK2KmC8jlgbpcX8bmKpQ,85531
24
24
  arvi/translations.py,sha256=PUSrn4zvYO2MqGzUxlFGwev_tBkgJaJrIYs6NKHzbWo,951
25
25
  arvi/utils.py,sha256=LImV8iPjG8ZKjPCT9lp25_pDb-51ZZk42Hc8bzZt7M0,6568
26
26
  arvi/data/info.svg,sha256=0IMI6W-eFoTD8acnury79WJJakpBwLa4qKS4JWpsXiI,489
@@ -29,8 +29,8 @@ arvi/data/obs_affected_blue_cryostat_issues.dat,sha256=z4AK17xfz8tGTDv1FjRvQFnio
29
29
  arvi/data/extra/HD86226_PFS1.rdb,sha256=vfAozbrKHM_j8dYkCBJsuHyD01KEM1asghe2KInwVao,3475
30
30
  arvi/data/extra/HD86226_PFS2.rdb,sha256=F2P7dB6gVyzCglUjNheB0hIHVClC5RmARrGwbrY1cfo,4114
31
31
  arvi/data/extra/metadata.json,sha256=C69hIw6CohyES6BI9vDWjxwSz7N4VOYX0PCgjXtYFmU,178
32
- arvi-0.1.24.dist-info/LICENSE,sha256=6JfQgl7SpM55t0EHMFNMnNh-AdkpGW25MwMiTnhdWQg,1068
33
- arvi-0.1.24.dist-info/METADATA,sha256=ijGk4XpvyZZ1IxV0_6iFuJkjZI4wtWW6A4kuCZE-gSA,1852
34
- arvi-0.1.24.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
35
- arvi-0.1.24.dist-info/top_level.txt,sha256=4EeiKDVLD45ztuflTGfQ3TU8GVjJg5Y95xS5XjI-utU,5
36
- arvi-0.1.24.dist-info/RECORD,,
32
+ arvi-0.1.26.dist-info/LICENSE,sha256=6JfQgl7SpM55t0EHMFNMnNh-AdkpGW25MwMiTnhdWQg,1068
33
+ arvi-0.1.26.dist-info/METADATA,sha256=vfc7Kqv4a87W9NQcEV3q1AmOrQTvwOWVK1wNYgxy24A,1852
34
+ arvi-0.1.26.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
35
+ arvi-0.1.26.dist-info/top_level.txt,sha256=4EeiKDVLD45ztuflTGfQ3TU8GVjJg5Y95xS5XjI-utU,5
36
+ arvi-0.1.26.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.5.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
File without changes