arvi 0.2.11__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}")
@@ -1657,6 +1678,20 @@ class RV(ISSUES, REPORTS):
1657
1678
  for inst in singles:
1658
1679
  self.remove_instrument(inst, strict=True)
1659
1680
 
1681
+ def remove_more_than_n_per_night(self, n=2):
1682
+ """ Remove whenever there are more than `n` observations per night """
1683
+ ind = np.array([], dtype=int)
1684
+ for s in self:
1685
+ # how many observations per night
1686
+ n_night = (np.abs(s.time[:, None] - s.time[None, :]) < 0.5).sum(axis=0)
1687
+ # indices for this instrument
1688
+ ind_s = np.where(n_night >= n)[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]
1692
+ if len(ind) > 0:
1693
+ self.remove_point(ind)
1694
+
1660
1695
  def remove_prog_id(self, prog_id):
1661
1696
  """ Remove observations from a given program ID """
1662
1697
  from glob import has_magic
@@ -1695,7 +1730,7 @@ class RV(ISSUES, REPORTS):
1695
1730
  ind = np.where(to_remove)[0]
1696
1731
  self.remove_point(ind)
1697
1732
 
1698
- def choose_n_points(self, n: int, seed=None, instrument=None):
1733
+ def choose_n_points(self, n: int, instrument=None, seed=None):
1699
1734
  """ Randomly choose `n` observations and mask out the remaining ones
1700
1735
 
1701
1736
  Args:
@@ -1706,21 +1741,21 @@ class RV(ISSUES, REPORTS):
1706
1741
  instrument (str or list, optional):
1707
1742
  For which instrument to choose points (default is all).
1708
1743
  """
1709
- 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)
1710
1748
  rng = np.random.default_rng(seed=seed)
1711
- for inst in instruments:
1712
- # s = getattr(self, inst)
1713
- mask_for_this_inst = self.obs == self.instruments.index(inst) + 1
1714
- # only choose if there are more than n points
1715
- if self.mask[mask_for_this_inst].sum() > n:
1716
- if self.verbose:
1717
- logger.info(f'selecting {n} points from {inst}')
1718
- # indices of points for this instrument which are not masked already
1719
- available = np.where(self.mask & mask_for_this_inst)[0]
1720
- # choose n randomly
1721
- i = rng.choice(available, size=n, replace=False)
1722
- # mask the others out
1723
- 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
1724
1759
  self._propagate_mask_changes()
1725
1760
 
1726
1761
 
@@ -1924,10 +1959,14 @@ class RV(ISSUES, REPORTS):
1924
1959
  if np.isnan(d[m]).all():
1925
1960
  continue
1926
1961
 
1927
- result = dosigmaclip(d[m], low=sigma, high=sigma)
1962
+ result = dosigmaclip(d[m & self.mask], low=sigma, high=sigma)
1928
1963
  # n = self.vrad[m].size - result.clipped.size
1929
1964
 
1930
- 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)
1931
1970
  n = ind.sum()
1932
1971
 
1933
1972
  if self.verbose and n > 0:
@@ -2020,9 +2059,9 @@ class RV(ISSUES, REPORTS):
2020
2059
 
2021
2060
 
2022
2061
 
2023
- def bin(self):
2062
+ def bin(self, daily=False):
2024
2063
  """
2025
- Nightly bin the observations.
2064
+ Bin the observations, nightly by default.
2026
2065
 
2027
2066
  !!! Warning
2028
2067
  This creates and returns a new object and does not modify self.
@@ -2033,6 +2072,8 @@ class RV(ISSUES, REPORTS):
2033
2072
  # store original object
2034
2073
  snew._unbinned = deepcopy(self)
2035
2074
 
2075
+ time_offset = 0.5 if daily else 0.0
2076
+
2036
2077
  all_bad_quantities = []
2037
2078
 
2038
2079
  for inst in snew.instruments:
@@ -2046,7 +2087,8 @@ class RV(ISSUES, REPORTS):
2046
2087
  if s.mtime.size == 0:
2047
2088
  continue
2048
2089
 
2049
- 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
2050
2092
  s.vrad = vb
2051
2093
  s.svrad = svb
2052
2094
 
@@ -2057,14 +2099,14 @@ class RV(ISSUES, REPORTS):
2057
2099
 
2058
2100
  # treat date_night specially, basically doing a group-by
2059
2101
  if q == 'date_night':
2060
- inds = binRV(s.mtime, None, None, binning_indices=True)
2102
+ inds = binRV(s.mtime + time_offset, None, None, binning_indices=True)
2061
2103
  setattr(s, q, Q[s.mask][inds])
2062
2104
  continue
2063
2105
 
2064
2106
  # treat ccf_mask specially, doing a 'unique' bin
2065
2107
  if q == 'ccf_mask':
2066
2108
  ccf_mask = getattr(s, q)[s.mask]
2067
- setattr(s, q, bin_ccf_mask(s.mtime, ccf_mask))
2109
+ setattr(s, q, bin_ccf_mask(s.mtime + time_offset, ccf_mask))
2068
2110
  continue
2069
2111
 
2070
2112
  if Q.dtype != np.float64:
@@ -2079,12 +2121,14 @@ class RV(ISSUES, REPORTS):
2079
2121
  elif q + '_err' in s._quantities:
2080
2122
  Qerr = getattr(s, q + '_err')
2081
2123
  if (Qerr == 0.0).all(): # if all errors are NaN, don't use them
2082
- _, 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')
2083
2126
  else:
2084
2127
  if (Qerr <= 0.0).any(): # if any error is <= 0, set it to NaN
2085
2128
  Qerr[Qerr <= 0.0] = np.nan
2086
2129
 
2087
- _, 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)
2088
2132
  setattr(s, q + '_err', eb)
2089
2133
 
2090
2134
  setattr(s, q, yb)
@@ -2093,7 +2137,7 @@ class RV(ISSUES, REPORTS):
2093
2137
  with warnings.catch_warnings():
2094
2138
  warnings.filterwarnings('ignore', category=RuntimeWarning)
2095
2139
  try:
2096
- _, yb = binRV(s.mtime, Q[s.mask],
2140
+ _, yb = binRV(s.mtime + time_offset, Q[s.mask],
2097
2141
  stat=np.nanmean, tstat=np.nanmean)
2098
2142
  setattr(s, q, yb)
2099
2143
  except TypeError:
@@ -2395,7 +2439,7 @@ class RV(ISSUES, REPORTS):
2395
2439
  if new_units not in possible:
2396
2440
  msg = f"new_units must be one of 'm/s', 'km/s', 'ms', 'kms', got '{new_units}'"
2397
2441
  raise ValueError(msg)
2398
-
2442
+
2399
2443
  new_units = possible[new_units]
2400
2444
  if new_units == self.units:
2401
2445
  return
@@ -2403,11 +2447,14 @@ class RV(ISSUES, REPORTS):
2403
2447
  if self.verbose:
2404
2448
  logger.info(f"changing units from {self.units} to {new_units}")
2405
2449
 
2406
- if new_units == 'm/s' and self.units == 'km/s':
2450
+ if new_units == 'm/s' and self.units in ('km/s', 'kms'):
2407
2451
  factor = 1e3
2408
- elif new_units == 'km/s' and self.units == 'm/s':
2452
+ elif new_units == 'km/s' and self.units in ('m/s', 'ms'):
2409
2453
  factor = 1e-3
2410
-
2454
+ else:
2455
+ logger.warning(f"no known conversion from {self.units} to {new_units}")
2456
+ return
2457
+
2411
2458
  for inst in self.instruments:
2412
2459
  s = getattr(self, inst)
2413
2460
  s.vrad *= factor
@@ -2469,6 +2516,10 @@ class RV(ISSUES, REPORTS):
2469
2516
  by_last_observation (bool, optional):
2470
2517
  Sort by last observation date
2471
2518
  """
2519
+ if self.N == 0:
2520
+ if self.verbose:
2521
+ logger.warning("no observations to sort")
2522
+ return
2472
2523
  if by_last_observation:
2473
2524
  by_first_observation = False
2474
2525
  if by_first_observation:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arvi
3
- Version: 0.2.11
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=suXPLmFlNbnFbfixXufNMwqwZWz-FwKdckJ1x2PtrXQ,104664
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.11.dist-info/licenses/LICENSE,sha256=6JfQgl7SpM55t0EHMFNMnNh-AdkpGW25MwMiTnhdWQg,1068
36
- arvi-0.2.11.dist-info/METADATA,sha256=G2yojj2vhNVuEPtoY81O3aWPvgMMxNw5ax4_40zVhb8,1933
37
- arvi-0.2.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
- arvi-0.2.11.dist-info/top_level.txt,sha256=4EeiKDVLD45ztuflTGfQ3TU8GVjJg5Y95xS5XjI-utU,5
39
- arvi-0.2.11.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