arvi 0.2.12__py3-none-any.whl → 0.3.2__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.
arvi/__init__.py CHANGED
@@ -17,11 +17,15 @@ def __getattr__(name: str):
17
17
  if not config.fancy_import:
18
18
  raise AttributeError
19
19
 
20
+ if name.startswith('__'):
21
+ return
20
22
  if name in (
21
23
  '_ipython_canary_method_should_not_exist_',
22
24
  '_ipython_display_',
23
25
  '_repr_mimebundle_',
24
- '__wrapped__'
26
+ # '__custom_documentations__',
27
+ # '__wrapped__',
28
+ # '__dataframe__'
25
29
  ):
26
30
  return
27
31
 
arvi/config.py CHANGED
@@ -36,6 +36,8 @@ class config:
36
36
  'fancy_import': True,
37
37
  # use the 'dark_background' matplotlib theme
38
38
  'dark_plots': False,
39
+ # specific colors per instrument
40
+ 'colors_per_instrument': False,
39
41
  # debug
40
42
  'debug': False,
41
43
  }
@@ -43,7 +45,7 @@ class config:
43
45
 
44
46
  __user_config = get_config()
45
47
 
46
- def __getattr__(self, name):
48
+ def __getattr__(self, name: str):
47
49
  if name in ('__custom_documentations__', ):
48
50
  # return {'return_self': 'help!'}
49
51
  return {}
@@ -54,7 +56,6 @@ class config:
54
56
  value = True if value == 'True' else value
55
57
  value = False if value == 'False' else value
56
58
  self.__conf[name] = value
57
-
58
59
  return self.__conf[name]
59
60
  except KeyError:
60
61
  raise KeyError(f"unknown config option '{name}'")
arvi/dace_wrapper.py CHANGED
@@ -229,61 +229,95 @@ def get_observations_from_instrument(star, instrument, user=None, main_id=None,
229
229
  mask3 = mask2 & (result['ins_mode'] == ins_mode)
230
230
  _nan = np.full(mask3.sum(), np.nan)
231
231
 
232
- r[str(inst)][str(pipe)][str(ins_mode)] = {
233
- 'texp': result['texp'][mask3],
234
- 'bispan': result['spectro_ccf_bispan'][mask3],
235
- 'bispan_err': result['spectro_ccf_bispan_err'][mask3],
236
- 'drift_noise': result['spectro_cal_drift_noise'][mask3],
237
- 'rjd': result['obj_date_bjd'][mask3],
238
- 'cal_therror': _nan,
239
- 'fwhm': result['spectro_ccf_fwhm'][mask3],
240
- 'fwhm_err': result['spectro_ccf_fwhm_err'][mask3],
241
- 'rv': result['spectro_ccf_rv'][mask3],
242
- 'rv_err': result['spectro_ccf_rv_err'][mask3],
243
- 'berv': result['spectro_cal_berv'][mask3],
244
- 'ccf_noise': np.sqrt(
245
- np.square(result['spectro_ccf_rv_err'][mask3]) - np.square(result['spectro_cal_drift_noise'][mask3])
246
- ),
247
- 'rhk': result['spectro_analysis_rhk'][mask3],
248
- 'rhk_err': result['spectro_analysis_rhk_err'][mask3],
249
- 'contrast': result['spectro_ccf_contrast'][mask3],
250
- 'contrast_err': result['spectro_ccf_contrast_err'][mask3],
251
- 'cal_thfile': result['spectro_cal_thfile'][mask3],
252
- 'spectroFluxSn50': result['spectro_flux_sn50'][mask3],
253
- 'protm08': result['spectro_analysis_protm08'][mask3],
254
- 'protm08_err': result['spectro_analysis_protm08_err'][mask3],
255
- 'caindex': result['spectro_analysis_ca'][mask3],
256
- 'caindex_err': result['spectro_analysis_ca_err'][mask3],
257
- 'pub_reference': result['pub_ref'][mask3],
258
- 'drs_qc': result['spectro_drs_qc'][mask3],
259
- 'haindex': result['spectro_analysis_halpha'][mask3],
260
- 'haindex_err': result['spectro_analysis_halpha_err'][mask3],
261
- 'protn84': result['spectro_analysis_protn84'][mask3],
262
- 'protn84_err': result['spectro_analysis_protn84_err'][mask3],
263
- 'naindex': result['spectro_analysis_na'][mask3],
264
- 'naindex_err': result['spectro_analysis_na_err'][mask3],
265
- 'snca2': _nan,
266
- 'mask': result['spectro_ccf_mask'][mask3],
267
- 'public': result['public'][mask3],
268
- 'spectroFluxSn20': result['spectro_flux_sn20'][mask3],
269
- 'sindex': result['spectro_analysis_smw'][mask3],
270
- 'sindex_err': result['spectro_analysis_smw_err'][mask3],
271
- 'drift_used': _nan,
272
- 'ccf_asym': result['spectro_ccf_asym'][mask3],
273
- 'ccf_asym_err': result['spectro_ccf_asym_err'][mask3],
274
- 'date_night': result['date_night'][mask3],
275
- 'raw_file': result['file_rootpath'][mask3],
276
- 'prog_id': result['prog_id'][mask3],
277
- 'th_ar': result['th_ar'][mask3],
278
- 'th_ar1': result['th_ar1'][mask3],
279
- 'th_ar2': result['th_ar2'][mask3],
232
+ translations = {
233
+ 'obj_date_bjd': 'rjd',
234
+ 'spectro_drs_qc': 'drs_qc',
235
+ 'spectro_cal_berv_mx': 'bervmax',
236
+ 'pub_ref': 'pub_reference',
237
+ 'file_rootpath': 'raw_file',
238
+ 'spectro_ccf_asym': 'ccf_asym',
239
+ 'spectro_ccf_asym_err': 'ccf_asym_err',
280
240
  }
241
+ new_result = {}
242
+ for key in result.keys():
243
+ if key in translations:
244
+ new_key = translations[key]
245
+ else:
246
+ new_key = key
247
+ new_key = new_key.replace('spectro_ccf_', '')
248
+ new_key = new_key.replace('spectro_cal_', '')
249
+ new_key = new_key.replace('spectro_analysis_', '')
250
+ new_result[new_key] = result[key][mask3]
251
+
252
+ new_result['ccf_noise'] = np.sqrt(
253
+ np.square(result['spectro_ccf_rv_err'][mask3]) - np.square(result['spectro_cal_drift_noise'][mask3])
254
+ )
255
+
256
+ r[str(inst)][str(pipe)][str(ins_mode)] = new_result
257
+
258
+ # r[str(inst)][str(pipe)][str(ins_mode)] = {
259
+ # 'texp': result['texp'][mask3],
260
+ # 'bispan': result['spectro_ccf_bispan'][mask3],
261
+ # 'bispan_err': result['spectro_ccf_bispan_err'][mask3],
262
+ # 'drift_noise': result['spectro_cal_drift_noise'][mask3],
263
+ # 'rjd': result['obj_date_bjd'][mask3],
264
+ # 'cal_therror': _nan,
265
+ # 'fwhm': result['spectro_ccf_fwhm'][mask3],
266
+ # 'fwhm_err': result['spectro_ccf_fwhm_err'][mask3],
267
+ # 'rv': result['spectro_ccf_rv'][mask3],
268
+ # 'rv_err': result['spectro_ccf_rv_err'][mask3],
269
+ # 'berv': result['spectro_cal_berv'][mask3],
270
+ # 'ccf_noise': np.sqrt(
271
+ # np.square(result['spectro_ccf_rv_err'][mask3]) - np.square(result['spectro_cal_drift_noise'][mask3])
272
+ # ),
273
+ # 'rhk': result['spectro_analysis_rhk'][mask3],
274
+ # 'rhk_err': result['spectro_analysis_rhk_err'][mask3],
275
+ # 'contrast': result['spectro_ccf_contrast'][mask3],
276
+ # 'contrast_err': result['spectro_ccf_contrast_err'][mask3],
277
+ # 'cal_thfile': result['spectro_cal_thfile'][mask3],
278
+ # 'spectroFluxSn50': result['spectro_flux_sn50'][mask3],
279
+ # 'protm08': result['spectro_analysis_protm08'][mask3],
280
+ # 'protm08_err': result['spectro_analysis_protm08_err'][mask3],
281
+ # 'caindex': result['spectro_analysis_ca'][mask3],
282
+ # 'caindex_err': result['spectro_analysis_ca_err'][mask3],
283
+ # 'pub_reference': result['pub_ref'][mask3],
284
+ # 'drs_qc': result['spectro_drs_qc'][mask3],
285
+ # 'haindex': result['spectro_analysis_halpha'][mask3],
286
+ # 'haindex_err': result['spectro_analysis_halpha_err'][mask3],
287
+ # 'protn84': result['spectro_analysis_protn84'][mask3],
288
+ # 'protn84_err': result['spectro_analysis_protn84_err'][mask3],
289
+ # 'naindex': result['spectro_analysis_na'][mask3],
290
+ # 'naindex_err': result['spectro_analysis_na_err'][mask3],
291
+ # 'snca2': _nan,
292
+ # 'mask': result['spectro_ccf_mask'][mask3],
293
+ # 'public': result['public'][mask3],
294
+ # 'spectroFluxSn20': result['spectro_flux_sn20'][mask3],
295
+ # 'sindex': result['spectro_analysis_smw'][mask3],
296
+ # 'sindex_err': result['spectro_analysis_smw_err'][mask3],
297
+ # 'drift_used': _nan,
298
+ # 'ccf_asym': result['spectro_ccf_asym'][mask3],
299
+ # 'ccf_asym_err': result['spectro_ccf_asym_err'][mask3],
300
+ # 'date_night': result['date_night'][mask3],
301
+ # 'raw_file': result['file_rootpath'][mask3],
302
+ # 'prog_id': result['prog_id'][mask3],
303
+ # 'th_ar': result['th_ar'][mask3],
304
+ # 'th_ar1': result['th_ar1'][mask3],
305
+ # 'th_ar2': result['th_ar2'][mask3],
306
+ # }
281
307
 
282
308
  # print(r.keys())
283
309
  # print([r[k].keys() for k in r.keys()])
284
310
  # print([r[k1][k2].keys() for k1 in r.keys() for k2 in r[k1].keys()])
285
311
  return r
286
312
 
313
+ def _warn_harpsn(instrument):
314
+ if 'HARPSN' in instrument or 'HARPS-N' in instrument:
315
+ logger = setup_logger()
316
+ logger.warning(f'Did you mean "HARPN" instead of "{instrument}"?')
317
+ return True
318
+ return False
319
+
320
+
287
321
  def get_observations(star, instrument=None, user=None, main_id=None, verbose=True):
288
322
  logger = setup_logger()
289
323
  if instrument is None:
@@ -305,6 +339,7 @@ def get_observations(star, instrument=None, user=None, main_id=None, verbose=Tru
305
339
  result = get_observations_from_instrument(star, instrument, user, main_id, verbose)
306
340
  except ValueError:
307
341
  msg = f'no {instrument} observations for {star}'
342
+ _warn_harpsn(instrument)
308
343
  raise ValueError(msg) from None
309
344
 
310
345
  # defaultdict --> dict
@@ -384,6 +419,8 @@ def get_observations(star, instrument=None, user=None, main_id=None, verbose=Tru
384
419
  def custom_key(val, strip_EGGS=False):
385
420
  if strip_EGGS:
386
421
  val = val.replace('-EGGS', '').replace(' EGGS', '')
422
+ if val in ('3.3', '3.4', '3.5', '3.6', '3.7', '3.8'):
423
+ val = '0.' + val
387
424
  key = 0
388
425
  key -= 1 if '3.5' in val else 0
389
426
  key -= 1 if 'EGGS' in val else 0
@@ -408,9 +445,10 @@ def get_observations(star, instrument=None, user=None, main_id=None, verbose=Tru
408
445
  logger.info('RVs available from')
409
446
  with logger.contextualize(indent=' '):
410
447
  _inst = ''
411
- for inst in instruments:
448
+ max_len_inst = max([len(inst) for inst in instruments])
449
+ for inst in sorted(instruments):
412
450
  pipelines = list(new_result[inst].keys())
413
- max_len = max([len(pipe) for pipe in pipelines])
451
+ max_len_pipe = max([len(pipe) for pipe in pipelines])
414
452
  for pipe in pipelines:
415
453
  last_pipe = pipe == pipelines[-1]
416
454
  modes = list(new_result[inst][pipe].keys())
@@ -418,11 +456,11 @@ def get_observations(star, instrument=None, user=None, main_id=None, verbose=Tru
418
456
  N = len(new_result[inst][pipe][mode]['rjd'])
419
457
  # LOG
420
458
  if inst == _inst and last_pipe:
421
- logger.info(f'{" ":>12s} └ {pipe:{max_len}s} - {mode} ({N} observations)')
459
+ logger.info(f'{" ":>{max_len_inst}s} └ {pipe:{max_len_pipe}s} - {mode} ({N} observations)')
422
460
  elif inst == _inst:
423
- logger.info(f'{" ":>12s} ├ {pipe:{max_len}s} - {mode} ({N} observations)')
461
+ logger.info(f'{" ":>{max_len_inst}s} ├ {pipe:{max_len_pipe}s} - {mode} ({N} observations)')
424
462
  else:
425
- logger.info(f'{inst:>12s} ├ {pipe:{max_len}s} - {mode} ({N} observations)')
463
+ logger.info(f'{inst:>{max_len_inst}s} ├ {pipe:{max_len_pipe}s} - {mode} ({N} observations)')
426
464
  _inst = inst
427
465
 
428
466
  return new_result
arvi/gaia_wrapper.py CHANGED
@@ -9,7 +9,8 @@ DATA_PATH = os.path.join(DATA_PATH, 'data')
9
9
  QUERY = """
10
10
  SELECT TOP 20 gaia_source.designation, gaia_source.source_id,
11
11
  gaia_source.ra, gaia_source.dec,
12
- gaia_source.parallax, gaia_source.pmra, gaia_source.pmdec,
12
+ gaia_source.parallax, gaia_source.parallax_error,
13
+ gaia_source.pmra, gaia_source.pmdec,
13
14
  gaia_source.ruwe, gaia_source.phot_g_mean_mag, gaia_source.bp_rp,
14
15
  gaia_source.radial_velocity, gaia_source.radial_velocity_error
15
16
  FROM gaiadr3.gaia_source
@@ -27,7 +28,8 @@ CONTAINS(
27
28
  QUERY_ID = """
28
29
  SELECT TOP 20 gaia_source.designation, gaia_source.source_id,
29
30
  gaia_source.ra, gaia_source.dec,
30
- gaia_source.parallax, gaia_source.pmra, gaia_source.pmdec,
31
+ gaia_source.parallax, gaia_source.parallax_error,
32
+ gaia_source.pmra, gaia_source.pmdec,
31
33
  gaia_source.ruwe, gaia_source.phot_g_mean_mag, gaia_source.bp_rp,
32
34
  gaia_source.radial_velocity, gaia_source.radial_velocity_error
33
35
  FROM gaiadr3.gaia_source
@@ -120,6 +122,7 @@ class gaia:
120
122
  self.pmdec = float(results['pmdec'])
121
123
  self.coords = SkyCoord(self.ra, self.dec, unit='deg')
122
124
  self.plx = float(results['parallax'])
125
+ self.plx_err = float(results['parallax_error'])
123
126
  try:
124
127
  self.radial_velocity = float(results['radial_velocity'])
125
128
  except ValueError:
@@ -131,5 +134,12 @@ class gaia:
131
134
 
132
135
  return
133
136
 
137
+ def distance(self):
138
+ """ Calculate the distance to the star as 1 / parallax [pc] """
139
+ from astropy import units as u
140
+ d = (self.plx * u.mas).to(u.parsec,
141
+ equivalencies=u.equivalencies.parallax())
142
+ return d
143
+
134
144
  def __repr__(self):
135
145
  return f'{self.star} (DR3 id={self.dr3_id})'
arvi/kima_wrapper.py CHANGED
@@ -1,19 +1,8 @@
1
1
  import os
2
- import numpy as np
2
+ import ast
3
3
 
4
4
  from .setup_logger import setup_logger
5
5
 
6
- try:
7
- import kima
8
- from kima.pykima.utils import chdir
9
- from kima import distributions
10
- from kima import RVData, HGPMdata
11
- from kima import RVmodel, GPmodel, RVHGPMmodel
12
- kima_available = True
13
- except ImportError:
14
- kima_available = False
15
-
16
-
17
6
  def try_to_guess_prior(model, prior):
18
7
  if 'jitter' in prior:
19
8
  return 'Jprior'
@@ -23,8 +12,14 @@ def try_to_guess_prior(model, prior):
23
12
 
24
13
 
25
14
  def run_kima(self, run=False, load=False, run_directory=None,
26
- model=RVmodel, priors={}, **kwargs):
27
- if not kima_available:
15
+ model='RVmodel', priors={}, **kwargs):
16
+ try:
17
+ import kima
18
+ from kima.pykima.utils import chdir
19
+ from kima import distributions
20
+ from kima import RVData, HGPMdata
21
+ from kima import RVmodel, GPmodel, RVHGPMmodel
22
+ except ImportError:
28
23
  raise ImportError('kima not available, please install with `pip install kima`')
29
24
 
30
25
  logger = setup_logger()
@@ -57,7 +52,7 @@ def run_kima(self, run=False, load=False, run_directory=None,
57
52
  model.trend = kwargs.pop('trend', False)
58
53
  model.degree = kwargs.pop('degree', 0)
59
54
 
60
- if isinstance(model, RVmodel):
55
+ if isinstance(model, (RVmodel, RVHGPMmodel)):
61
56
  model.studentt = kwargs.pop('studentt', False)
62
57
 
63
58
  if isinstance(model, GPmodel):
@@ -81,6 +76,16 @@ def run_kima(self, run=False, load=False, run_directory=None,
81
76
  model.pm_dec_bary_prior = priors.pop('pm_dec_bary_prior',
82
77
  distributions.Gaussian(pm_data.pm_dec_hg, pm_data.sig_hg_dec))
83
78
 
79
+ KO = kwargs.pop('known_object', False)
80
+ if KO:
81
+ if isinstance(KO, int) and KO is not True:
82
+ model.set_known_object(KO)
83
+ else:
84
+ try:
85
+ model.set_known_object(kwargs.pop('n_known_object'))
86
+ except KeyError:
87
+ msg = 'if `known_object` is True, specify `n_known_object` or pass `known_object` as an integer'
88
+ raise ValueError(msg) from None
84
89
 
85
90
  for k, v in priors.items():
86
91
  try:
@@ -99,21 +104,27 @@ def run_kima(self, run=False, load=False, run_directory=None,
99
104
  if run_directory is None:
100
105
  run_directory = os.getcwd()
101
106
 
102
- if run:
103
- # TODO: use signature of kima.run to pop the correct kwargs
104
- # model_name = model.__class__.__name__
105
- # model_name = f'kima.{model_name}.{model_name}'
106
- # signature, defaults = [sig for sig in kima.run.__nb_signature__ if model_name in sig[0]]
107
+ diagnostic = kwargs.pop('diagnostic', False)
107
108
 
109
+ if run:
110
+ model_name = model.__class__.__name__
111
+ model_name = f'kima.{model_name}.{model_name}'
112
+ signature, _, defaults = [sig for sig in kima._run_really.__nb_signature__ if model_name in sig[0]][0]
113
+ signature = signature.replace('\\', '')
114
+ args = ast.parse(signature + ':\n pass').body[0].args
115
+ defaults = {arg.arg: d for arg, d in zip(args.args[1:], defaults)}
116
+ defaults.update(kwargs)
108
117
  with chdir(run_directory):
109
- kima.run(model, **kwargs)
118
+ kima.run(model, **defaults)
110
119
 
111
120
  if isinstance(model, RVHGPMmodel):
112
121
  data = (data, pm_data)
113
122
 
114
123
  if load:
115
124
  with chdir(run_directory):
116
- res = kima.load_results(model)
125
+ res = kima.load_results(model, diagnostic=diagnostic)
126
+
127
+ res.star = self.star
117
128
  return data, model, res
118
129
 
119
130
  return data, model
arvi/plots.py CHANGED
@@ -587,6 +587,32 @@ def plot_xy(self, x, y, ax=None, instrument=None, show_legend=True, **kwargs):
587
587
  return fig, ax
588
588
 
589
589
 
590
+ def plot_several(obj, axs=None, **kwargs):
591
+ try:
592
+ from grid_strategy.strategies import SquareStrategy
593
+ except ImportError:
594
+ raise ImportError("Please install 'grid-strategy' to use this function")
595
+ if axs is None:
596
+ if isinstance(obj, (list, tuple)):
597
+ n = len(obj)
598
+ GS = SquareStrategy().get_grid(n)
599
+ fig = plt.gcf()
600
+ fig.set_size_inches(8, 6)
601
+ axs = [fig.add_subplot(gs) for gs in GS]
602
+ else:
603
+ raise NotImplementedError('`obj` should be a list or tuple')
604
+ else:
605
+ assert isinstance(axs, (list, tuple))
606
+ assert len(axs) == len(obj), 'Number of axes does not match number of objects'
607
+
608
+ kwargs.setdefault('show_legend', False)
609
+ kwargs.setdefault('show_title', True)
610
+
611
+ for ax, s in zip(axs, obj):
612
+ s.plot(ax=ax, **kwargs)
613
+ ax.set(xlabel='', ylabel='')
614
+
615
+
590
616
  # @plot_fast
591
617
  def gls(self, ax=None, label=None, instrument=None,
592
618
  fap=True, fap_method='baluev', adjust_means=config.adjust_means_gls,
arvi/programs.py CHANGED
@@ -23,6 +23,7 @@ def get_star(star, instrument=None, verbose=False, **kwargs):
23
23
 
24
24
 
25
25
  class LazyRV:
26
+ """ A lazy wrapper around `RV` """
26
27
  def __init__(self, stars: list, instrument: str = None,
27
28
  _parallel_limit=10, _parallel_workers=8):
28
29
  self.stars = stars
@@ -60,25 +61,6 @@ class LazyRV:
60
61
 
61
62
  return result
62
63
 
63
- # # use a with statement to ensure threads are cleaned up promptly
64
- # with concurrent.futures.ThreadPoolExecutor(max_workers=8) as pool:
65
- # star_to_RV = {
66
- # pool.submit(get_star, star, self.instrument): star
67
- # for star in self.stars
68
- # }
69
- # logger.info('Querying DACE...')
70
- # pbar = tqdm(concurrent.futures.as_completed(star_to_RV),
71
- # total=self.N, unit='star')
72
- # for future in pbar:
73
- # star = star_to_RV[future]
74
- # pbar.set_description(star)
75
- # try:
76
- # result.append(future.result())
77
- # except ValueError:
78
- # print(f'{star} generated an exception')
79
- # result.append(None)
80
- # return result
81
-
82
64
  def reload(self, **kwargs):
83
65
  self._saved = self._get(**kwargs)
84
66
  return self._saved
@@ -92,12 +74,24 @@ class LazyRV:
92
74
  return self._saved
93
75
 
94
76
  @lru_cache(maxsize=10)
95
- def __getitem__(self, index):
96
- star = self.stars[index]
77
+ def __getitem__(self, index_or_name):
78
+ if isinstance(index_or_name, str):
79
+ index = self.stars.index(index_or_name)
80
+ else:
81
+ index = index_or_name
82
+
97
83
  if self._saved is not None:
98
84
  return self._saved[index]
85
+
86
+ star = self.stars[index]
99
87
  return get_star(star, self.instrument, verbose=True)
100
88
 
89
+ def plot(self, split=20, **kwargs):
90
+ from .plots import plot_several
91
+ from itertools import batched
92
+ S = list(batched(self.__call__(), split))
93
+ for s in S:
94
+ plot_several(s, **kwargs)
101
95
 
102
96
  # sorted by spectral type
103
97
  WG1_stars = [
arvi/setup_logger.py CHANGED
@@ -2,17 +2,17 @@ import sys
2
2
 
3
3
  def setup_logger():
4
4
  from loguru import logger
5
- try:
6
- import marimo as mo
7
- if mo.running_in_notebook():
8
- raise NotImplementedError
9
- except (NotImplementedError, AttributeError):
10
- pass
11
- except (ImportError, ModuleNotFoundError):
12
- logger.remove()
13
- else:
14
- logger.remove()
15
-
5
+ # try:
6
+ # import marimo as mo
7
+ # if mo.running_in_notebook():
8
+ # return logger
9
+ # raise NotImplementedError
10
+ # except (NotImplementedError, AttributeError):
11
+ # pass
12
+ # except (ImportError, ModuleNotFoundError):
13
+ # logger.remove()
14
+ # else:
15
+ logger.remove()
16
16
  logger.configure(extra={"indent": ""})
17
17
  logger.add(
18
18
  sys.stdout,
arvi/simbad_wrapper.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import os
2
+ from urllib.error import URLError
2
3
  import requests
3
4
  from dataclasses import dataclass
4
5
  from functools import partial
@@ -64,6 +65,12 @@ JOIN ident ON oidref = oid
64
65
  WHERE id = '{star}';
65
66
  """
66
67
 
68
+ OTYPE_QUERY = """
69
+ SELECT otype FROM basic
70
+ JOIN ident ON oidref = oid
71
+ WHERE id = '{star}';
72
+ """
73
+
67
74
  HD_GJ_HIP_QUERY = """
68
75
  SELECT id2.id
69
76
  FROM ident AS id1 JOIN ident AS id2 USING(oidref)
@@ -204,11 +211,19 @@ class simbad:
204
211
  try:
205
212
  table2 = run_query(query=BV_QUERY.format(star=self.star))
206
213
  if _debug:
207
- print('table2:', table2)
214
+ print('table2:\n', table2)
208
215
  cols, values = parse_table1(table2, cols, values)
209
216
  except IndexError:
210
217
  self.B = self.V = np.nan
211
218
 
219
+ try:
220
+ table21 = run_query(query=OTYPE_QUERY.format(star=self.star))
221
+ if _debug:
222
+ print('table21:\n', table21)
223
+ cols, values = parse_table1(table21, cols, values)
224
+ except IndexError:
225
+ self.otype = None
226
+
212
227
  try:
213
228
  table3 = run_query(query=IDS_QUERY.format(star=self.star))
214
229
  if _debug:
@@ -228,6 +243,14 @@ class simbad:
228
243
  setattr(self, '_' + filter_name, ufloat(float(mag), float(mag_err)))
229
244
  except ValueError:
230
245
  setattr(self, '_' + filter_name, float(mag))
246
+
247
+ # substitute missing V magnitude
248
+ if filter_name == 'V' and values[cols.index('V')] == '':
249
+ values[cols.index('V')] = mag
250
+ # substitute missing B magnitude
251
+ if filter_name == 'B' and values[cols.index('B')] == '':
252
+ values[cols.index('B')] = mag
253
+
231
254
 
232
255
  # measurements table
233
256
  table5 = run_query(query=MEAS_QUERY.format(star=self.star))
@@ -258,6 +281,8 @@ class simbad:
258
281
  try:
259
282
  setattr(self, col, float(val))
260
283
  except ValueError:
284
+ if val == '':
285
+ val = None
261
286
  setattr(self, col, val)
262
287
 
263
288
  self.coords = SkyCoord(self.ra, self.dec, unit='deg')
@@ -281,12 +306,17 @@ class simbad:
281
306
  else:
282
307
  self.teff = data['teff']
283
308
  self.sweetcat = data
284
-
309
+ except URLError:
310
+ pass
285
311
  except IndexError:
286
- if self.sp_type == '':
312
+ if self.sp_type in (None, ''):
287
313
  if len(self.measurements.teff) > 0:
288
- self.teff = int(np.mean(self.measurements.teff))
289
- self.sp_type = teff_to_sptype(self.teff)
314
+ try:
315
+ self.teff = int(np.mean(self.measurements.teff))
316
+ self.sp_type = teff_to_sptype(self.teff)
317
+ except ValueError:
318
+ self.teff = np.nan
319
+ self.sp_type = ''
290
320
  elif self.sp_type[:2] in EFFECTIVE_TEMPERATURES:
291
321
  self.teff = EFFECTIVE_TEMPERATURES[self.sp_type[:2]]
292
322
 
arvi/sophie_wrapper.py CHANGED
@@ -13,7 +13,7 @@ URL_HEADER = "http://atlas.obs-hp.fr/sophie/sophie.cgi?n=sophiecc&c=i&z=fd&a=t&o
13
13
  def extract_keyword(keyword, text, raise_error=True):
14
14
  for line in text.splitlines():
15
15
  if keyword in line:
16
- value = re.findall(fr'{keyword}\s+([\'\w\d.]+)', line)[0]
16
+ value = re.findall(fr'{keyword}\s+([-\'\w\d.]+)', line)[0]
17
17
  value = value.replace("'", "")
18
18
  try:
19
19
  return float(value)
arvi/stats.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from functools import partial
2
2
  import numpy as np
3
- from scipy.stats import norm
3
+
4
4
 
5
5
  def wmean(a, e):
6
6
  """Weighted mean of array `a`, with uncertainties given by `e`.
@@ -69,7 +69,7 @@ weighted_median = partial(weighted_quantiles_interpolate, quantiles=0.5)
69
69
 
70
70
 
71
71
 
72
- def sigmaclip_median(a, low=4.0, high=4.0, k=1/norm.ppf(3/4)):
72
+ def sigmaclip_median(a, low=4.0, high=4.0, k=None):
73
73
  """
74
74
  Same as scipy.stats.sigmaclip but using the median and median absolute
75
75
  deviation instead of the mean and standard deviation.
@@ -91,8 +91,12 @@ def sigmaclip_median(a, low=4.0, high=4.0, k=1/norm.ppf(3/4)):
91
91
  - `lower`: Lower clipping limit
92
92
  - `upper`: Upper clipping limit
93
93
  """
94
- from scipy.stats import median_abs_deviation
94
+ from scipy.stats import median_abs_deviation, norm
95
95
  from scipy.stats._stats_py import SigmaclipResult
96
+
97
+ if k is None:
98
+ k = 1 / norm.ppf(3 / 4)
99
+
96
100
  c = np.asarray(a).ravel()
97
101
  delta = 1
98
102
  while delta:
arvi/timeseries.py CHANGED
@@ -145,6 +145,7 @@ class RV(ISSUES, REPORTS):
145
145
  if self.verbose:
146
146
  logger.info('querying Simbad...')
147
147
 
148
+ # TODO: removing the 'A' might not be a good idea
148
149
  # complicated way to query Simbad with self.__star__ or, if that
149
150
  # fails, try after removing a trailing 'A'
150
151
  for target in set([self.__star__, self.__star__.replace('A', '')]):
@@ -590,9 +591,12 @@ class RV(ISSUES, REPORTS):
590
591
  """ Total time span of the (masked) observations """
591
592
  return np.ptp(self.mtime)
592
593
 
593
- def _index_from_instrument_index(self, index, instrument):
594
+ def _index_from_instrument_index(self, index, instrument, masked=True):
594
595
  ind = np.where(self.instrument_array == instrument)[0]
595
- return ind[getattr(self, instrument).mask][index]
596
+ if masked:
597
+ return ind[getattr(self, instrument).mask][index]
598
+ else:
599
+ return ind[index]
596
600
 
597
601
  # @property
598
602
  def _tt(self, f=20) -> np.ndarray:
@@ -651,7 +655,11 @@ class RV(ISSUES, REPORTS):
651
655
  return s
652
656
 
653
657
  @classmethod
654
- def from_arrays(cls, star, time, vrad, svrad, inst, **kwargs):
658
+ def from_arrays(cls, star, time, vrad, svrad, instrument:str, **kwargs):
659
+ if 'inst' in kwargs:
660
+ logger.warning('`inst` is deprecated. Use `instrument` instead.')
661
+ instrument = kwargs.pop('inst')
662
+
655
663
  s = cls(star, _child=True)
656
664
  time, vrad, svrad = map(np.atleast_1d, (time, vrad, svrad))
657
665
 
@@ -673,8 +681,12 @@ class RV(ISSUES, REPORTS):
673
681
  for k, v in kwargs.items():
674
682
  setattr(s, k, np.atleast_1d(v))
675
683
 
676
- s.instruments = [inst]
677
684
  s._quantities = np.array(list(kwargs.keys()))
685
+ _instrument = instrument.replace(' ', '_').replace('-', '_')
686
+ s.instruments = [_instrument]
687
+
688
+ setattr(s, _instrument, deepcopy(s))
689
+ s._child = False
678
690
 
679
691
  return s
680
692
 
@@ -1039,7 +1051,7 @@ class RV(ISSUES, REPORTS):
1039
1051
  time = np.array([i.bjd for i in CCFs])
1040
1052
  vrad = np.array([i.RV*1e3 for i in CCFs])
1041
1053
  svrad = np.array([i.RVerror*1e3 for i in CCFs])
1042
- _s = RV.from_arrays(star, time, vrad, svrad, inst=instrument)
1054
+ _s = RV.from_arrays(star, time, vrad, svrad, instrument=instrument)
1043
1055
 
1044
1056
  _quantities = []
1045
1057
 
@@ -1066,9 +1078,13 @@ class RV(ISSUES, REPORTS):
1066
1078
  _s.texp = np.array([i.HDU[0].header['EXPTIME'] for i in CCFs])
1067
1079
  _quantities.append('texp')
1068
1080
 
1069
- _s.berv = np.array([i.HDU[0].header['HIERARCH ESO QC BERV'] for i in CCFs])
1081
+ try:
1082
+ _s.berv = np.array([i.HDU[0].header['HIERARCH ESO QC BERV'] for i in CCFs])
1083
+ except KeyError:
1084
+ _s.berv = np.full_like(time, np.nan)
1070
1085
  _quantities.append('berv')
1071
1086
 
1087
+
1072
1088
  _s.date_night = np.array([
1073
1089
  i.HDU[0].header['DATE-OBS'].split('T')[0] for i in CCFs
1074
1090
  ])
@@ -1567,6 +1583,11 @@ class RV(ISSUES, REPORTS):
1567
1583
  condition (ndarray):
1568
1584
  Boolean array of the same length as the observations
1569
1585
  """
1586
+ condition = np.asarray(condition, dtype=bool)
1587
+ if not np.any(condition):
1588
+ if self.verbose:
1589
+ logger.info('no points to remove')
1590
+ return
1570
1591
  if self.verbose:
1571
1592
  inst = np.unique(self.instrument_array[condition])
1572
1593
  logger.info(f"Removing {condition.sum()} points from instruments {inst}")
@@ -1661,9 +1682,13 @@ class RV(ISSUES, REPORTS):
1661
1682
  """ Remove whenever there are more than `n` observations per night """
1662
1683
  ind = np.array([], dtype=int)
1663
1684
  for s in self:
1685
+ # how many observations per night
1664
1686
  n_night = (np.abs(s.time[:, None] - s.time[None, :]) < 0.5).sum(axis=0)
1687
+ # indices for this instrument
1665
1688
  ind_s = np.where(n_night >= n)[0]
1666
- ind = np.r_[ind, self._index_from_instrument_index(ind_s, s.instruments[0])]
1689
+ # translate to indices in self
1690
+ ind_self = self._index_from_instrument_index(ind_s, s.instruments[0], masked=False)
1691
+ ind = np.r_[ind, ind_self]
1667
1692
  if len(ind) > 0:
1668
1693
  self.remove_point(ind)
1669
1694
 
@@ -1705,7 +1730,7 @@ class RV(ISSUES, REPORTS):
1705
1730
  ind = np.where(to_remove)[0]
1706
1731
  self.remove_point(ind)
1707
1732
 
1708
- def choose_n_points(self, n: int, seed=None, instrument=None):
1733
+ def choose_n_points(self, n: int, instrument=None, seed=None):
1709
1734
  """ Randomly choose `n` observations and mask out the remaining ones
1710
1735
 
1711
1736
  Args:
@@ -1716,21 +1741,21 @@ class RV(ISSUES, REPORTS):
1716
1741
  instrument (str or list, optional):
1717
1742
  For which instrument to choose points (default is all).
1718
1743
  """
1719
- instruments = self._check_instrument(instrument)
1744
+ if not self._check_instrument(instrument):
1745
+ return
1746
+ # instruments = self._check_instrument(instrument)
1747
+ mask_for_this_inst = self._instrument_mask(instrument)
1720
1748
  rng = np.random.default_rng(seed=seed)
1721
- for inst in instruments:
1722
- # s = getattr(self, inst)
1723
- mask_for_this_inst = self.obs == self.instruments.index(inst) + 1
1724
- # only choose if there are more than n points
1725
- if self.mask[mask_for_this_inst].sum() > n:
1726
- if self.verbose:
1727
- logger.info(f'selecting {n} points from {inst}')
1728
- # indices of points for this instrument which are not masked already
1729
- available = np.where(self.mask & mask_for_this_inst)[0]
1730
- # choose n randomly
1731
- i = rng.choice(available, size=n, replace=False)
1732
- # mask the others out
1733
- self.mask[np.setdiff1d(available, i)] = False
1749
+ # only choose if there are more than n points
1750
+ if self.mask[mask_for_this_inst].sum() > n:
1751
+ if self.verbose:
1752
+ logger.info(f'selecting {n} points from {instrument}')
1753
+ # indices of points for this instrument which are not masked already
1754
+ available = np.where(self.mask & mask_for_this_inst)[0]
1755
+ # choose n randomly
1756
+ i = rng.choice(available, size=n, replace=False)
1757
+ # mask the others out
1758
+ self.mask[np.setdiff1d(available, i)] = False
1734
1759
  self._propagate_mask_changes()
1735
1760
 
1736
1761
 
@@ -1937,7 +1962,11 @@ class RV(ISSUES, REPORTS):
1937
1962
  result = dosigmaclip(d[m & self.mask], low=sigma, high=sigma)
1938
1963
  # n = self.vrad[m].size - result.clipped.size
1939
1964
 
1940
- ind = m & self.mask & ((d < result.lower) | (d > result.upper))
1965
+ # NOTE: result.lower and result.upper are updated values, calculated
1966
+ # *after* the last point has been removed. So the previous solution
1967
+ # getting points outside the range [result.lower, result.upper] is
1968
+ # not correct and we need to use result.clipped instead.
1969
+ ind = m & self.mask & ~np.isin(d, result.clipped)
1941
1970
  n = ind.sum()
1942
1971
 
1943
1972
  if self.verbose and n > 0:
@@ -2030,9 +2059,9 @@ class RV(ISSUES, REPORTS):
2030
2059
 
2031
2060
 
2032
2061
 
2033
- def bin(self):
2062
+ def bin(self, daily=False):
2034
2063
  """
2035
- Nightly bin the observations.
2064
+ Bin the observations, nightly by default.
2036
2065
 
2037
2066
  !!! Warning
2038
2067
  This creates and returns a new object and does not modify self.
@@ -2043,6 +2072,8 @@ class RV(ISSUES, REPORTS):
2043
2072
  # store original object
2044
2073
  snew._unbinned = deepcopy(self)
2045
2074
 
2075
+ time_offset = 0.5 if daily else 0.0
2076
+
2046
2077
  all_bad_quantities = []
2047
2078
 
2048
2079
  for inst in snew.instruments:
@@ -2056,7 +2087,8 @@ class RV(ISSUES, REPORTS):
2056
2087
  if s.mtime.size == 0:
2057
2088
  continue
2058
2089
 
2059
- tb, vb, svb = binRV(s.mtime, s.mvrad, s.msvrad)
2090
+ tb, vb, svb = binRV(s.mtime + time_offset, s.mvrad, s.msvrad)
2091
+ tb -= time_offset
2060
2092
  s.vrad = vb
2061
2093
  s.svrad = svb
2062
2094
 
@@ -2067,14 +2099,14 @@ class RV(ISSUES, REPORTS):
2067
2099
 
2068
2100
  # treat date_night specially, basically doing a group-by
2069
2101
  if q == 'date_night':
2070
- inds = binRV(s.mtime, None, None, binning_indices=True)
2102
+ inds = binRV(s.mtime + time_offset, None, None, binning_indices=True)
2071
2103
  setattr(s, q, Q[s.mask][inds])
2072
2104
  continue
2073
2105
 
2074
2106
  # treat ccf_mask specially, doing a 'unique' bin
2075
2107
  if q == 'ccf_mask':
2076
2108
  ccf_mask = getattr(s, q)[s.mask]
2077
- setattr(s, q, bin_ccf_mask(s.mtime, ccf_mask))
2109
+ setattr(s, q, bin_ccf_mask(s.mtime + time_offset, ccf_mask))
2078
2110
  continue
2079
2111
 
2080
2112
  if Q.dtype != np.float64:
@@ -2089,12 +2121,14 @@ class RV(ISSUES, REPORTS):
2089
2121
  elif q + '_err' in s._quantities:
2090
2122
  Qerr = getattr(s, q + '_err')
2091
2123
  if (Qerr == 0.0).all(): # if all errors are NaN, don't use them
2092
- _, yb = binRV(s.mtime, Q[s.mask], stat='mean', tstat='mean')
2124
+ _, yb = binRV(s.mtime + time_offset, Q[s.mask],
2125
+ stat='mean', tstat='mean')
2093
2126
  else:
2094
2127
  if (Qerr <= 0.0).any(): # if any error is <= 0, set it to NaN
2095
2128
  Qerr[Qerr <= 0.0] = np.nan
2096
2129
 
2097
- _, yb, eb = binRV(s.mtime, Q[s.mask], Qerr[s.mask], remove_nans=False)
2130
+ _, yb, eb = binRV(s.mtime + time_offset, Q[s.mask], Qerr[s.mask],
2131
+ remove_nans=False)
2098
2132
  setattr(s, q + '_err', eb)
2099
2133
 
2100
2134
  setattr(s, q, yb)
@@ -2103,7 +2137,7 @@ class RV(ISSUES, REPORTS):
2103
2137
  with warnings.catch_warnings():
2104
2138
  warnings.filterwarnings('ignore', category=RuntimeWarning)
2105
2139
  try:
2106
- _, yb = binRV(s.mtime, Q[s.mask],
2140
+ _, yb = binRV(s.mtime + time_offset, Q[s.mask],
2107
2141
  stat=np.nanmean, tstat=np.nanmean)
2108
2142
  setattr(s, q, yb)
2109
2143
  except TypeError:
@@ -2405,7 +2439,7 @@ class RV(ISSUES, REPORTS):
2405
2439
  if new_units not in possible:
2406
2440
  msg = f"new_units must be one of 'm/s', 'km/s', 'ms', 'kms', got '{new_units}'"
2407
2441
  raise ValueError(msg)
2408
-
2442
+
2409
2443
  new_units = possible[new_units]
2410
2444
  if new_units == self.units:
2411
2445
  return
@@ -2413,11 +2447,14 @@ class RV(ISSUES, REPORTS):
2413
2447
  if self.verbose:
2414
2448
  logger.info(f"changing units from {self.units} to {new_units}")
2415
2449
 
2416
- if new_units == 'm/s' and self.units == 'km/s':
2450
+ if new_units == 'm/s' and self.units in ('km/s', 'kms'):
2417
2451
  factor = 1e3
2418
- elif new_units == 'km/s' and self.units == 'm/s':
2452
+ elif new_units == 'km/s' and self.units in ('m/s', 'ms'):
2419
2453
  factor = 1e-3
2420
-
2454
+ else:
2455
+ logger.warning(f"no known conversion from {self.units} to {new_units}")
2456
+ return
2457
+
2421
2458
  for inst in self.instruments:
2422
2459
  s = getattr(self, inst)
2423
2460
  s.vrad *= factor
@@ -2479,6 +2516,10 @@ class RV(ISSUES, REPORTS):
2479
2516
  by_last_observation (bool, optional):
2480
2517
  Sort by last observation date
2481
2518
  """
2519
+ if self.N == 0:
2520
+ if self.verbose:
2521
+ logger.warning("no observations to sort")
2522
+ return
2482
2523
  if by_last_observation:
2483
2524
  by_first_observation = False
2484
2525
  if by_first_observation:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arvi
3
- Version: 0.2.12
3
+ Version: 0.3.2
4
4
  Summary: The Automated RV Inspector
5
5
  Author-email: João Faria <joao.faria@unige.ch>
6
6
  License: MIT
@@ -1,29 +1,29 @@
1
1
  arvi/HZ.py,sha256=u7rguhlILRBW-LOczlY3dkIB4LM8p8W7Xfg4FnNaYG0,2850
2
- arvi/__init__.py,sha256=8IeHbu8LR1H3MxVi9aJHNpBU6SDbmzj9FZGKsiF0AKE,740
2
+ arvi/__init__.py,sha256=XpHKf-hlJvZvjnhGia_0DAoL0OHagtR7zknIJwIx_UY,853
3
3
  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=NK9y9bUrdyWCbh79LkcRABHG-n5MtlETMHMvLj1z-OM,15437
6
- arvi/config.py,sha256=JkHSwF-EEqwwbcc8thGgbFc9udDZPjQH-9XFjqDepBY,2337
7
- arvi/dace_wrapper.py,sha256=i3aIRKSc2MylEzM5WbbU-BnuLbz8JlG1ez6sK_vvQH0,26125
6
+ arvi/config.py,sha256=DbOhDKGbNoKVWMd965wY6gAfYf0TdbjR5_WIlHvilcA,2422
7
+ arvi/dace_wrapper.py,sha256=-FHY9xc2Oyf7b_qzbZWy0RtQmLvm770yJeWVV8_8Zwc,27893
8
8
  arvi/exofop_wrapper.py,sha256=8S7UEcrBAgANIweMV0-CvaWaVTPgGVo8vQQk_KRa0nU,2414
9
9
  arvi/extra_data.py,sha256=Xi65pI5kkzqlMmHGl9xFoumtH699611pJJ5PV-a_IfU,3397
10
- arvi/gaia_wrapper.py,sha256=HTuigIduin3raWfSC7QYuQxDk2dEXYH_4egRkzzg7Xw,4379
10
+ arvi/gaia_wrapper.py,sha256=JiD0BRix7wD3LXcnaAxWyRkC2M91pVJ2P9DhtzrBavM,4793
11
11
  arvi/headers.py,sha256=uvdJebw1M5YkGjE3vJJwYBOnLikib75uuZE9FXB5JJM,1673
12
12
  arvi/instrument_specific.py,sha256=94oMb6UeH6tp7H8YXnXHpxEhIz2evz0iYsT_HrNOCTo,12105
13
13
  arvi/kepmodel_wrapper.py,sha256=mmHudetAZ4cBxKDwzQzgUydzkjhomCWw5VVuyiKfXq8,10288
14
- arvi/kima_wrapper.py,sha256=GrAZWkDCg8ukhW41M1VTadSbab0GBa6BIzjtAtvjk58,3891
14
+ arvi/kima_wrapper.py,sha256=T_NjUcbhwPh4gKW4uS2Bki1xKNvZ2LApcYfoJVrkbz8,4541
15
15
  arvi/lbl_wrapper.py,sha256=_ViGVkpakvuBR_xhu9XJRV5EKHpj5Go6jBZGJZMIS2Y,11850
16
16
  arvi/nasaexo_wrapper.py,sha256=ZKY3IUClqsJuysxDv0Gu51EnzMX7101zQb7UQy_urhI,7431
17
- arvi/plots.py,sha256=U4VUNyIx4h_rEFd7ZWgBcawUcIGcURES0A4VXIBKp3U,35240
18
- arvi/programs.py,sha256=M8o8hXr6W22dMiIX3Nxz4pgb8lsJXApDlq7HStyTfqs,9047
17
+ arvi/plots.py,sha256=7u-EqZRYod1arakelhNwNZ_EJwxYDcplxn9KgcS33aQ,36131
18
+ arvi/programs.py,sha256=2gTvHcJPEmmf4hXQcHvG487PXe__qsS-S-L_Ip6tgNM,8622
19
19
  arvi/reports.py,sha256=a38EZNhyGoSSzJh63wBQCAt3_xhqbpVGcDOXaZWTLXs,11127
20
- arvi/setup_logger.py,sha256=dHzO2gPjw6CaKWpYZd2f83z09tmxgi--qpp7k1jROjI,615
21
- arvi/simbad_wrapper.py,sha256=uZc8mcfNijXsQi29LReRTabZb2hRPhYdLsDLMgq1OEI,9927
22
- arvi/sophie_wrapper.py,sha256=KUeWccXud5_Lrx72S1HSemHIZRdjd2oLvqyofwsL0QQ,3440
20
+ arvi/setup_logger.py,sha256=bRZ0CdYM406IoIKyaLurqGLxq-sQrHry8nSSiZGoMBw,656
21
+ arvi/simbad_wrapper.py,sha256=ID43g5mlORx5pOsk3cMX2dGkKktrFBbzxhzEHeZ-0mw,10937
22
+ arvi/sophie_wrapper.py,sha256=SUNGeOhS8FSlHsF9PTK3QIx8EUbEvmGlyIfogwjhtSc,3441
23
23
  arvi/spectra.py,sha256=ebF1ocodTastLx0CyqLSpE8EZNDXBF8riyfxMr3L6H0,7491
24
- arvi/stats.py,sha256=gvMkKzP83AV8_Oi71JHmA8QH8Y1z1viYykV9ELVDqZI,3547
24
+ arvi/stats.py,sha256=oV1ouTV_c5bx-akTCXh6WKhoit9LpGHUw0xhR7RF0kY,3566
25
25
  arvi/stellar.py,sha256=GQ7yweuBRnfkJ0M5eWjvLd8uvGq_by81PbXfidBvWis,4918
26
- arvi/timeseries.py,sha256=K33MmNG_xyAfr5Jw5lR_Yq0JJjCwEGPreaeMMoQoE9M,105145
26
+ arvi/timeseries.py,sha256=shQxIjbsWS3l2x5dh9VWk61bTbmZvQmMIvXjMHPDPDI,106826
27
27
  arvi/translations.py,sha256=PUSrn4zvYO2MqGzUxlFGwev_tBkgJaJrIYs6NKHzbWo,951
28
28
  arvi/utils.py,sha256=MuAgjyXr297Sm_T6QmB1riVUktyT9ud1qngGMgKlXMc,10863
29
29
  arvi/data/info.svg,sha256=0IMI6W-eFoTD8acnury79WJJakpBwLa4qKS4JWpsXiI,489
@@ -32,8 +32,8 @@ arvi/data/obs_affected_blue_cryostat_issues.dat,sha256=z4AK17xfz8tGTDv1FjRvQFnio
32
32
  arvi/data/extra/HD86226_PFS1.rdb,sha256=vfAozbrKHM_j8dYkCBJsuHyD01KEM1asghe2KInwVao,3475
33
33
  arvi/data/extra/HD86226_PFS2.rdb,sha256=F2P7dB6gVyzCglUjNheB0hIHVClC5RmARrGwbrY1cfo,4114
34
34
  arvi/data/extra/metadata.json,sha256=C69hIw6CohyES6BI9vDWjxwSz7N4VOYX0PCgjXtYFmU,178
35
- arvi-0.2.12.dist-info/licenses/LICENSE,sha256=6JfQgl7SpM55t0EHMFNMnNh-AdkpGW25MwMiTnhdWQg,1068
36
- arvi-0.2.12.dist-info/METADATA,sha256=w1LdRdx-VwxhRgcIik-9at_k49xkJQQasIrGu1qtwc4,1933
37
- arvi-0.2.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
- arvi-0.2.12.dist-info/top_level.txt,sha256=4EeiKDVLD45ztuflTGfQ3TU8GVjJg5Y95xS5XjI-utU,5
39
- arvi-0.2.12.dist-info/RECORD,,
35
+ arvi-0.3.2.dist-info/licenses/LICENSE,sha256=6JfQgl7SpM55t0EHMFNMnNh-AdkpGW25MwMiTnhdWQg,1068
36
+ arvi-0.3.2.dist-info/METADATA,sha256=FmP8zMlErd55jcJNCbH_KSG5ergHedbcpwQOBpCOwZw,1932
37
+ arvi-0.3.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
38
+ arvi-0.3.2.dist-info/top_level.txt,sha256=4EeiKDVLD45ztuflTGfQ3TU8GVjJg5Y95xS5XjI-utU,5
39
+ arvi-0.3.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5