arvi 0.0.2__py3-none-any.whl → 0.0.3__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
@@ -1,30 +1,13 @@
1
- __version__ = '0.0.2'
1
+ __version__ = '0.0.3'
2
2
  __all__ = []
3
3
 
4
4
  from .timeseries import RV
5
5
 
6
6
  _ran_once = False
7
+
7
8
  def __getattr__(name: str):
8
- global _ran_once
9
+ global _ran_once # can't do it any other way :(
9
10
  if _ran_once:
10
11
  return RV(name)
11
12
  else:
12
13
  _ran_once = True
13
-
14
-
15
- # from importlib import import_module
16
-
17
- # HACK_IMPORTS = True
18
-
19
- # if HACK_IMPORTS:
20
- # timeseries = import_module('.timeseries', 'arvi')
21
- # class FakeModule(object):
22
- # def __getattribute__(self, name):
23
- # print(name)
24
- # r = RV(name)
25
- # return r
26
- # # first, load (some) subpackages
27
- # # then, replace the 'arvi' module to allow for dynamic imports
28
- # # of the type "from arvi import HD1"
29
- # import sys
30
- # sys.modules['arvi'] = FakeModule()
arvi/dace_wrapper.py CHANGED
@@ -1,7 +1,17 @@
1
+ import os
2
+ import tarfile
1
3
  import numpy as np
2
- from dace_query.spectroscopy import Spectroscopy
4
+ from dace_query import DaceClass
5
+ from dace_query.spectroscopy import SpectroscopyClass, Spectroscopy as default_Spectroscopy
3
6
  from .setup_logger import logger
4
7
 
8
+ def load_spectroscopy():
9
+ if 'DACERC' in os.environ:
10
+ dace = DaceClass(dace_rc_config_path=os.environ['DACERC'])
11
+ return SpectroscopyClass(dace_instance=dace)
12
+ # elif os.path.exists(os.path.expanduser('~/.dacerc')):
13
+ return default_Spectroscopy
14
+
5
15
 
6
16
  def get_arrays(result, latest_pipeline=True):
7
17
  arrays = []
@@ -25,11 +35,22 @@ def get_arrays(result, latest_pipeline=True):
25
35
 
26
36
 
27
37
  def get_observations(star, save_rdb=False, verbose=True):
38
+ Spectroscopy = load_spectroscopy()
28
39
  result = Spectroscopy.get_timeseries(target=star,
29
40
  sorted_by_instrument=True,
30
41
  output_format='numpy')
31
42
  instruments = list(result.keys())
32
43
 
44
+ # sort pipelines, being extra careful with HARPS pipeline names
45
+ # (i.e. ensure that 3.0.0 > 3.5)
46
+ class sorter:
47
+ def __call__(self, x):
48
+ return '0.3.5' if x == '3.5' else x
49
+
50
+ for inst in instruments:
51
+ result[inst] = dict(sorted(result[inst].items(),
52
+ key=sorter(), reverse=True))
53
+
33
54
  if verbose:
34
55
  logger.info('RVs available from')
35
56
  with logger.contextualize(indent=' '):
@@ -44,5 +65,28 @@ def get_observations(star, save_rdb=False, verbose=True):
44
65
  return result
45
66
 
46
67
 
47
- def save_rdb(data, columns):
48
- pass
68
+ def do_download_ccf(raw_files, output_directory, verbose=True):
69
+ raw_files = np.atleast_1d(raw_files)
70
+ if not os.path.isdir(output_directory):
71
+ os.makedirs(output_directory)
72
+ if verbose:
73
+ logger.info(f"Downloading {len(raw_files)} CCFs into '{output_directory}'...")
74
+
75
+ Spectroscopy = load_spectroscopy()
76
+
77
+ from .utils import all_logging_disabled, stdout_disabled
78
+ with stdout_disabled(), all_logging_disabled():
79
+ Spectroscopy.download_files(raw_files[:2],
80
+ file_type='ccf',
81
+ output_directory=output_directory)
82
+
83
+ if verbose:
84
+ logger.info('Extracting .fits files')
85
+
86
+ file = os.path.join(output_directory, 'spectroscopy_download.tar.gz')
87
+ tar = tarfile.open(file, "r")
88
+ for member in tar.getmembers():
89
+ if member.isreg(): # skip if the TarInfo is not a file
90
+ member.name = os.path.basename(member.name) # remove the path
91
+ tar.extract(member, output_directory)
92
+ os.remove(file)
arvi/simbad_wrapper.py CHANGED
@@ -1,6 +1,8 @@
1
1
  from dataclasses import dataclass, field
2
2
  import requests
3
3
 
4
+ from astropy.coordinates import SkyCoord
5
+
4
6
  QUERY = """
5
7
  SELECT basic.OID,
6
8
  RA,
@@ -58,6 +60,7 @@ class simbad:
58
60
  Attributes:
59
61
  ra (float): right ascension
60
62
  dec (float): declination
63
+ coords (SkyCoord): coordinates as a SkyCoord object
61
64
  main_id (str): main identifier
62
65
  plx_value (float): parallax
63
66
  rvz_radvel (float): radial velocity
@@ -72,15 +75,18 @@ class simbad:
72
75
  star (str): The name of the star to query simbad
73
76
  """
74
77
  self.star = star
75
- table1 = run_query(query=QUERY.format(star=star))
76
- cols, values = parse_table(table1)
78
+ try:
79
+ table1 = run_query(query=QUERY.format(star=star))
80
+ cols, values = parse_table(table1)
77
81
 
78
- table2 = run_query(query=BV_QUERY.format(star=star))
79
- cols, values = parse_table(table2, cols, values)
82
+ table2 = run_query(query=BV_QUERY.format(star=star))
83
+ cols, values = parse_table(table2, cols, values)
80
84
 
81
- table3 = run_query(query=IDS_QUERY.format(star=star))
82
- line = table3.splitlines()[2]
83
- self.ids = line.replace('"', '').replace(' ', ' ').split('|')
85
+ table3 = run_query(query=IDS_QUERY.format(star=star))
86
+ line = table3.splitlines()[2]
87
+ self.ids = line.replace('"', '').replace(' ', ' ').split('|')
88
+ except IndexError:
89
+ raise ValueError(f'simbad query for {star} failed')
84
90
 
85
91
  for col, val in zip(cols, values):
86
92
  try:
@@ -88,6 +94,9 @@ class simbad:
88
94
  except ValueError:
89
95
  setattr(self, col, val)
90
96
 
97
+ self.coords = SkyCoord(self.ra, self.dec, unit='deg')
98
+
99
+
91
100
  def __repr__(self):
92
101
  V = self.V
93
102
  sp_type = self.sp_type
arvi/timeseries.py CHANGED
@@ -1,11 +1,12 @@
1
1
  from dataclasses import dataclass, field
2
+ from typing import Union
2
3
  from functools import partial
3
4
  from datetime import datetime, timezone
4
5
  import numpy as np
5
6
 
6
7
  from .setup_logger import logger
7
8
  from .translations import translate
8
- from .dace_wrapper import get_observations, get_arrays
9
+ from .dace_wrapper import get_observations, get_arrays, do_download_ccf
9
10
  from .simbad_wrapper import simbad
10
11
  from .stats import wmean, wrms
11
12
 
@@ -29,6 +30,7 @@ class RV:
29
30
  N: int = field(init=False, repr=True)
30
31
  verbose: bool = field(init=True, repr=False, default=True)
31
32
  do_sigma_clip: bool = field(init=True, repr=False, default=True)
33
+ do_maxerror: Union[bool, float] = field(init=True, repr=False, default=100)
32
34
  do_adjust_means: bool = field(init=True, repr=False, default=True)
33
35
  #
34
36
  _child: bool = field(init=True, repr=False, default=False)
@@ -37,7 +39,10 @@ class RV:
37
39
 
38
40
  def __post_init__(self):
39
41
  self.__star__ = translate(self.star)
40
- self.simbad = simbad(self.__star__)
42
+ try:
43
+ self.simbad = simbad(self.__star__)
44
+ except ValueError as e:
45
+ logger.error(e.msg)
41
46
 
42
47
  if not self._child:
43
48
  if self.verbose:
@@ -71,11 +76,16 @@ class RV:
71
76
  # all other quantities
72
77
  self._build_arrays()
73
78
 
74
- if self.do_sigma_clip:
75
- self.sigmaclip()
79
+ # do clip_maxerror, sigmaclip, adjust_means
80
+ if not self._child:
81
+ if self.do_maxerror:
82
+ self.clip_maxerror(self.do_maxerror)
83
+
84
+ if self.do_sigma_clip:
85
+ self.sigmaclip()
76
86
 
77
- if self.do_adjust_means:
78
- self.adjust_means()
87
+ if self.do_adjust_means:
88
+ self.adjust_means()
79
89
 
80
90
 
81
91
  def reload(self):
@@ -171,6 +181,21 @@ class RV:
171
181
  )
172
182
  setattr(self, q, arr)
173
183
 
184
+
185
+ def download_ccf(self, instrument=None):
186
+ directory = f'{self.star}_downloads'
187
+ if instrument is None:
188
+ files = [file for file in self.raw_file if file.endswith('.fits')]
189
+ else:
190
+ if instrument not in self.instruments:
191
+ logger.error(f"No data from instrument '{instrument}'")
192
+ logger.info(f'available: {self.instruments}')
193
+ return
194
+ files = getattr(self, instrument).raw_file
195
+
196
+ do_download_ccf(files, directory)
197
+
198
+
174
199
  from .plots import plot, plot_fwhm, plot_bis
175
200
  from .plots import gls, gls_fwhm, gls_bis
176
201
  from .reports import report
@@ -237,12 +262,19 @@ class RV:
237
262
  self.mask[~ind] = False
238
263
  self._propagate_mask_changes()
239
264
 
240
- def sigmaclip_errors(self, maxerror:float, plot=False):
265
+ def clip_maxerror(self, maxerror:float, plot=False):
241
266
  """ Mask out points with RV error larger than `maxerror` """
242
267
  if self._child:
243
268
  return
244
269
  self.maxerror = maxerror
245
- self.mask[self.svrad > maxerror] = False
270
+ above = self.svrad > maxerror
271
+ n = above.sum()
272
+ self.mask[above] = False
273
+
274
+ if self.verbose and above.sum() > 0:
275
+ s = 's' if (n == 0 or n > 1) else ''
276
+ logger.warning(f'clip_maxerror removed {n} point' + s)
277
+
246
278
  self._propagate_mask_changes()
247
279
 
248
280
  def adjust_means(self, just_rv=False):
@@ -258,13 +290,19 @@ class RV:
258
290
  logger.info(f'subtracted weighted average from {inst:10s}: ({s.rv_mean:.3f} {self.units})')
259
291
  if just_rv:
260
292
  continue
261
- for other in others:
293
+ log_msg = 'same for '
294
+ for i, other in enumerate(others):
262
295
  y, ye = getattr(s, other), getattr(s, other + '_err')
263
296
  m = wmean(y, ye)
264
297
  setattr(s, f'{other}_mean', m)
265
298
  setattr(s, other, getattr(s, other) - m)
266
- if self.verbose:
267
- logger.info(f'same for {other}')
299
+ log_msg += other
300
+ if i < len(others) - 1:
301
+ log_msg += ', '
302
+
303
+ if self.verbose:
304
+ logger.info(log_msg)
305
+
268
306
  self._build_arrays()
269
307
  self._did_adjust_means = True
270
308
 
arvi/utils.py ADDED
@@ -0,0 +1,32 @@
1
+ import os
2
+ from contextlib import contextmanager
3
+ from mock import patch
4
+ import logging
5
+
6
+
7
+ @contextmanager
8
+ def stdout_disabled():
9
+ devnull = open(os.devnull, 'w')
10
+ with patch('sys.stdout', devnull):
11
+ yield
12
+
13
+
14
+ @contextmanager
15
+ def all_logging_disabled():
16
+ """
17
+ A context manager that will prevent any logging messages triggered during
18
+ the body from being processed.
19
+ """
20
+ # two kind-of hacks here:
21
+ # * can't get the highest logging level in effect => delegate to the user
22
+ # * can't get the current module-level override => use an undocumented
23
+ # (but non-private!) interface
24
+
25
+ previous_level = logging.root.manager.disable
26
+
27
+ logging.disable(logging.CRITICAL)
28
+
29
+ try:
30
+ yield
31
+ finally:
32
+ logging.disable(previous_level)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arvi
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: The Automated RV Inspector
5
5
  Author-email: João Faria <joao.faria@astro.up.pt>
6
6
  License: MIT
@@ -0,0 +1,15 @@
1
+ arvi/__init__.py,sha256=d4UTdSj3oRwFvO1a_m5uz_fqEVFR9U-afio38MNuESU,241
2
+ arvi/dace_wrapper.py,sha256=0zId_2uti-_UOkCZHJnRvajO5EMNgwNfc5AgV-LjSPQ,3340
3
+ arvi/plots.py,sha256=uOruz1xhlx7nNjIEtLTX6gs_iya2Yds71eIYoYt2LVw,6925
4
+ arvi/reports.py,sha256=FtalLbmBHOSHQ3RldImUZTHPc3cc3Z3W5r3d-31FIo8,3261
5
+ arvi/setup_logger.py,sha256=nvnd2PtXYnpYMGleTeqAKFe-TnC6SjNlTZ-EmiewLyY,278
6
+ arvi/simbad_wrapper.py,sha256=7XnuM7Kq5kK4EchHjh-uyRoTWm6kCx0sx7Ak0eDaALo,3023
7
+ arvi/stats.py,sha256=OIlXisf_kuUhfDRhvCirmJ2e-YSIJnoBjdFOXaYd0bQ,868
8
+ arvi/timeseries.py,sha256=tWKAn5tCQpI1YaCE_breyQ_dXAsj0X06jox4nH9ES5E,11159
9
+ arvi/translations.py,sha256=eyUJei8wlsyBecTz8E_ntpP35-Mre2Tzm_mUMMGaZWY,150
10
+ arvi/utils.py,sha256=OPb6rXafv7b8vRRTEg9zQAQnhi3lRLICF62R8Fhy43A,788
11
+ arvi-0.0.3.dist-info/LICENSE,sha256=6JfQgl7SpM55t0EHMFNMnNh-AdkpGW25MwMiTnhdWQg,1068
12
+ arvi-0.0.3.dist-info/METADATA,sha256=01PYughU6O-f6cwMA_6elKUMallpnN5uaxN6k8xgeys,827
13
+ arvi-0.0.3.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
14
+ arvi-0.0.3.dist-info/top_level.txt,sha256=4EeiKDVLD45ztuflTGfQ3TU8GVjJg5Y95xS5XjI-utU,5
15
+ arvi-0.0.3.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- arvi/__init__.py,sha256=rEegmfeT2Xy3gBLpx7_MZOHUcbo_Mg_4aPlD_QsGzaI,708
2
- arvi/dace_wrapper.py,sha256=N3-cdj8YrryZFA4Tztrb3cJ-2MKgWjLV0rJ6bue8bQQ,1567
3
- arvi/plots.py,sha256=uOruz1xhlx7nNjIEtLTX6gs_iya2Yds71eIYoYt2LVw,6925
4
- arvi/reports.py,sha256=FtalLbmBHOSHQ3RldImUZTHPc3cc3Z3W5r3d-31FIo8,3261
5
- arvi/setup_logger.py,sha256=nvnd2PtXYnpYMGleTeqAKFe-TnC6SjNlTZ-EmiewLyY,278
6
- arvi/simbad_wrapper.py,sha256=oCcyoWPtkP2RntUNZ3Y0pPFk1hK2nawRlYHCpTRETaE,2725
7
- arvi/stats.py,sha256=OIlXisf_kuUhfDRhvCirmJ2e-YSIJnoBjdFOXaYd0bQ,868
8
- arvi/timeseries.py,sha256=KHTUHEgp7m_ZQYGufntn-pHwFqzVhAlqFWuFolsWUEM,9893
9
- arvi/translations.py,sha256=eyUJei8wlsyBecTz8E_ntpP35-Mre2Tzm_mUMMGaZWY,150
10
- arvi-0.0.2.dist-info/LICENSE,sha256=6JfQgl7SpM55t0EHMFNMnNh-AdkpGW25MwMiTnhdWQg,1068
11
- arvi-0.0.2.dist-info/METADATA,sha256=U7NMIBTxucQP3aY7siFcaR04dXGfxthu3HEI40bi7xI,827
12
- arvi-0.0.2.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
13
- arvi-0.0.2.dist-info/top_level.txt,sha256=4EeiKDVLD45ztuflTGfQ3TU8GVjJg5Y95xS5XjI-utU,5
14
- arvi-0.0.2.dist-info/RECORD,,
File without changes
File without changes