arvi 0.1.5__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of arvi might be problematic. Click here for more details.

Files changed (41) hide show
  1. {arvi-0.1.5 → arvi-0.1.6}/PKG-INFO +1 -13
  2. {arvi-0.1.5 → arvi-0.1.6}/README.md +1 -13
  3. {arvi-0.1.5 → arvi-0.1.6}/arvi/dace_wrapper.py +9 -1
  4. {arvi-0.1.5 → arvi-0.1.6}/arvi/plots.py +1 -1
  5. {arvi-0.1.5 → arvi-0.1.6}/arvi/timeseries.py +105 -47
  6. {arvi-0.1.5 → arvi-0.1.6}/arvi.egg-info/PKG-INFO +1 -13
  7. {arvi-0.1.5 → arvi-0.1.6}/pyproject.toml +1 -1
  8. {arvi-0.1.5 → arvi-0.1.6}/.github/workflows/docs-gh-pages.yml +0 -0
  9. {arvi-0.1.5 → arvi-0.1.6}/.github/workflows/install.yml +0 -0
  10. {arvi-0.1.5 → arvi-0.1.6}/.github/workflows/python-publish.yml +0 -0
  11. {arvi-0.1.5 → arvi-0.1.6}/.gitignore +0 -0
  12. {arvi-0.1.5 → arvi-0.1.6}/LICENSE +0 -0
  13. {arvi-0.1.5 → arvi-0.1.6}/arvi/__init__.py +0 -0
  14. {arvi-0.1.5 → arvi-0.1.6}/arvi/binning.py +0 -0
  15. {arvi-0.1.5 → arvi-0.1.6}/arvi/config.py +0 -0
  16. {arvi-0.1.5 → arvi-0.1.6}/arvi/data/info.svg +0 -0
  17. {arvi-0.1.5 → arvi-0.1.6}/arvi/data/obs_affected_ADC_issues.dat +0 -0
  18. {arvi-0.1.5 → arvi-0.1.6}/arvi/data/obs_affected_blue_cryostat_issues.dat +0 -0
  19. {arvi-0.1.5 → arvi-0.1.6}/arvi/instrument_specific.py +0 -0
  20. {arvi-0.1.5 → arvi-0.1.6}/arvi/lbl_wrapper.py +0 -0
  21. {arvi-0.1.5 → arvi-0.1.6}/arvi/nasaexo_wrapper.py +0 -0
  22. {arvi-0.1.5 → arvi-0.1.6}/arvi/programs.py +0 -0
  23. {arvi-0.1.5 → arvi-0.1.6}/arvi/reports.py +0 -0
  24. {arvi-0.1.5 → arvi-0.1.6}/arvi/setup_logger.py +0 -0
  25. {arvi-0.1.5 → arvi-0.1.6}/arvi/simbad_wrapper.py +0 -0
  26. {arvi-0.1.5 → arvi-0.1.6}/arvi/stats.py +0 -0
  27. {arvi-0.1.5 → arvi-0.1.6}/arvi/translations.py +0 -0
  28. {arvi-0.1.5 → arvi-0.1.6}/arvi/utils.py +0 -0
  29. {arvi-0.1.5 → arvi-0.1.6}/arvi.egg-info/SOURCES.txt +0 -0
  30. {arvi-0.1.5 → arvi-0.1.6}/arvi.egg-info/dependency_links.txt +0 -0
  31. {arvi-0.1.5 → arvi-0.1.6}/arvi.egg-info/requires.txt +0 -0
  32. {arvi-0.1.5 → arvi-0.1.6}/arvi.egg-info/top_level.txt +0 -0
  33. {arvi-0.1.5 → arvi-0.1.6}/docs/API.md +0 -0
  34. {arvi-0.1.5 → arvi-0.1.6}/docs/detailed.md +0 -0
  35. {arvi-0.1.5 → arvi-0.1.6}/docs/index.md +0 -0
  36. {arvi-0.1.5 → arvi-0.1.6}/docs/logo/detective.png +0 -0
  37. {arvi-0.1.5 → arvi-0.1.6}/docs/logo/logo.png +0 -0
  38. {arvi-0.1.5 → arvi-0.1.6}/mkdocs.yml +0 -0
  39. {arvi-0.1.5 → arvi-0.1.6}/setup.cfg +0 -0
  40. {arvi-0.1.5 → arvi-0.1.6}/setup.py +0 -0
  41. {arvi-0.1.5 → arvi-0.1.6}/tests/test_import_object.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arvi
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: The Automated RV Inspector
5
5
  Author-email: João Faria <joao.faria@unige.ch>
6
6
  License: MIT
@@ -29,18 +29,6 @@ Requires-Dist: kepmodel
29
29
 
30
30
 
31
31
 
32
- ## Goals
33
-
34
- - _Fast_:
35
- all `arvi` operations must be completed in under **1 second**
36
-
37
- - _Reproducible_:
38
- **everyone** must be able to use `arvi`
39
-
40
- - _Accurate_:
41
- `arvi` must always provide the **correct result**
42
-
43
-
44
32
  #### Actions
45
33
 
46
34
  [![Deploy docs](https://github.com/j-faria/arvi/actions/workflows/docs-gh-pages.yml/badge.svg)](https://github.com/j-faria/arvi/actions/workflows/docs-gh-pages.yml)
@@ -4,20 +4,8 @@
4
4
 
5
5
 
6
6
 
7
- ## Goals
8
-
9
- - _Fast_:
10
- all `arvi` operations must be completed in under **1 second**
11
-
12
- - _Reproducible_:
13
- **everyone** must be able to use `arvi`
14
-
15
- - _Accurate_:
16
- `arvi` must always provide the **correct result**
17
-
18
-
19
7
  #### Actions
20
8
 
21
9
  [![Deploy docs](https://github.com/j-faria/arvi/actions/workflows/docs-gh-pages.yml/badge.svg)](https://github.com/j-faria/arvi/actions/workflows/docs-gh-pages.yml)
22
10
  [![Install-Test](https://github.com/j-faria/arvi/actions/workflows/install.yml/badge.svg)](https://github.com/j-faria/arvi/actions/workflows/install.yml)
23
- [![Upload Python Package](https://github.com/j-faria/arvi/actions/workflows/python-publish.yml/badge.svg)](https://github.com/j-faria/arvi/actions/workflows/python-publish.yml)
11
+ [![Upload Python Package](https://github.com/j-faria/arvi/actions/workflows/python-publish.yml/badge.svg)](https://github.com/j-faria/arvi/actions/workflows/python-publish.yml)
@@ -152,14 +152,22 @@ def get_observations(star, instrument=None, save_rdb=False, verbose=True):
152
152
 
153
153
  def check_existing(output_directory, files, type):
154
154
  existing = [
155
- f.partition('_')[0] for f in os.listdir(output_directory)
155
+ f.partition('.fits')[0] for f in os.listdir(output_directory)
156
156
  if type in f
157
157
  ]
158
+ if os.name == 'nt': # on Windows, be careful with ':' in filename
159
+ import re
160
+ existing = [re.sub(r'T(\d+)_(\d+)_(\d+)', r'T\1:\2:\3', f) for f in existing]
161
+
162
+ # remove type of file (e.g. _CCF_A)
163
+ existing = [f.partition('_')[0] for f in existing]
164
+
158
165
  missing = []
159
166
  for file in files:
160
167
  if any(other in file for other in existing):
161
168
  continue
162
169
  missing.append(file)
170
+
163
171
  return np.array(missing)
164
172
 
165
173
  def download(files, type, output_directory):
@@ -272,7 +272,7 @@ def gls(self, ax=None, label=None, fap=True, picker=True, instrument=None, **kwa
272
272
  y = self.vrad[self.mask]
273
273
  e = self.svrad[self.mask]
274
274
 
275
- gls = LombScargle(t, y, e)
275
+ self._gls = gls = LombScargle(t, y, e)
276
276
  freq, power = gls.autopower(maximum_frequency=1.0, samples_per_peak=10)
277
277
  ax.semilogx(1/freq, power, picker=picker, label=label, **kwargs)
278
278
 
@@ -294,9 +294,9 @@ class RV:
294
294
  star, timestamp = file.replace('.pkl', '').split('_')
295
295
  else:
296
296
  try:
297
- file = sorted(glob(f'{star}*.pkl'))[-1]
297
+ file = sorted(glob(f'{star}_*.pkl'))[-1]
298
298
  except IndexError:
299
- raise ValueError(f'cannot find any file matching {star}*.pkl')
299
+ raise ValueError(f'cannot find any file matching {star}_*.pkl')
300
300
  star, timestamp = file.replace('.pkl', '').split('_')
301
301
 
302
302
  dt = datetime.fromtimestamp(float(timestamp))
@@ -314,7 +314,7 @@ class RV:
314
314
  logger.info(f'assuming star is {star_[0]}')
315
315
  star = star_[0]
316
316
 
317
- instruments = np.unique([os.path.splitext(f)[0].split('_')[1] for f in files])
317
+ instruments = np.array([os.path.splitext(f)[0].split('_')[1] for f in files])
318
318
  logger.info(f'assuming instruments: {instruments}')
319
319
 
320
320
  if instruments.size == 1 and len(files) > 1:
@@ -508,18 +508,19 @@ class RV:
508
508
  extracted_files = do_download_s2d(files[:limit], directory)
509
509
 
510
510
 
511
- from .plots import plot, plot_fwhm, plot_bis, plot_rhk
511
+ from .plots import plot, plot_fwhm, plot_bis, plot_rhk, plot_quantity
512
512
  from .plots import gls, gls_fwhm, gls_bis, gls_rhk
513
513
  from .reports import report
514
514
 
515
515
  from .instrument_specific import known_issues
516
516
 
517
517
 
518
- def remove_instrument(self, instrument):
518
+ def remove_instrument(self, instrument, strict=False):
519
519
  """ Remove all observations from one instrument
520
520
 
521
521
  Args:
522
522
  instrument (str): The instrument for which to remove observations.
523
+ strict (bool): Whether to match `instrument` exactly
523
524
 
524
525
  Note:
525
526
  A common name can be used to remove observations for several subsets
@@ -538,34 +539,37 @@ class RV:
538
539
 
539
540
  will remove observations from the specific subset.
540
541
  """
541
- if instrument not in self.instruments:
542
+ instruments = self._check_instrument(instrument, strict)
543
+
544
+ if instruments is None:
542
545
  logger.error(f"No data from instrument '{instrument}'")
543
546
  logger.info(f'available: {self.instruments}')
544
547
  return
545
548
 
546
- ind = self.instruments.index(instrument) + 1
547
- remove = np.where(self.obs == ind)
548
- self.obs = np.delete(self.obs, remove)
549
- self.obs[self.obs > ind] -= 1
550
- #
551
- self.time = np.delete(self.time, remove)
552
- self.vrad = np.delete(self.vrad, remove)
553
- self.svrad = np.delete(self.svrad, remove)
554
- #
555
- self.mask = np.delete(self.mask, remove)
556
- #
557
- # all other quantities
558
- for q in self._quantities:
559
- if q not in ('rjd', 'rv', 'rv_err'):
560
- new = np.delete(getattr(self, q), remove)
561
- setattr(self, q, new)
562
- #
563
- self.instruments.remove(instrument)
564
- #
565
- delattr(self, instrument)
549
+ for instrument in instruments:
550
+ ind = self.instruments.index(instrument) + 1
551
+ remove = np.where(self.obs == ind)
552
+ self.obs = np.delete(self.obs, remove)
553
+ self.obs[self.obs > ind] -= 1
554
+ #
555
+ self.time = np.delete(self.time, remove)
556
+ self.vrad = np.delete(self.vrad, remove)
557
+ self.svrad = np.delete(self.svrad, remove)
558
+ #
559
+ self.mask = np.delete(self.mask, remove)
560
+ #
561
+ # all other quantities
562
+ for q in self._quantities:
563
+ if q not in ('rjd', 'rv', 'rv_err'):
564
+ new = np.delete(getattr(self, q), remove)
565
+ setattr(self, q, new)
566
+ #
567
+ self.instruments.remove(instrument)
568
+ #
569
+ delattr(self, instrument)
566
570
 
567
- if self.verbose:
568
- logger.info(f"Removed observations from '{instrument}'")
571
+ if self.verbose:
572
+ logger.info(f"Removed observations from '{instrument}'")
569
573
 
570
574
  if return_self:
571
575
  return self
@@ -610,6 +614,30 @@ class RV:
610
614
  if getattr(self, inst).mtime.size == 1:
611
615
  self.remove_instrument(inst)
612
616
 
617
+ def remove_prog_id(self, prog_id):
618
+ from glob import has_magic
619
+ if has_magic(prog_id):
620
+ from fnmatch import filter
621
+ matching = np.unique(filter(self.prog_id, prog_id))
622
+ mask = np.full_like(self.time, False, dtype=bool)
623
+ for m in matching:
624
+ mask |= np.isin(self.prog_id, m)
625
+ ind = np.where(mask)[0]
626
+ self.remove_point(ind)
627
+ else:
628
+ if prog_id in self.prog_id:
629
+ ind = np.where(self.prog_id == prog_id)[0]
630
+ self.remove_point(ind)
631
+ else:
632
+ if self.verbose:
633
+ logger.warning(f'no observations for prog_id "{prog_id}"')
634
+
635
+
636
+ def remove_after_bjd(self, bjd):
637
+ if (self.time > bjd).any():
638
+ ind = np.where(self.time > bjd)[0]
639
+ self.remove_point(ind)
640
+
613
641
 
614
642
  def _propagate_mask_changes(self):
615
643
  """ link self.mask with each self.`instrument`.mask """
@@ -763,31 +791,38 @@ class RV:
763
791
  bad_quantities = []
764
792
 
765
793
  for q in s._quantities:
794
+ Q = getattr(s, q)
795
+
766
796
  # treat date_night specially, basically doing a group-by
767
797
  if q == 'date_night':
768
798
  inds = binRV(s.mtime, None, None, binning_indices=True)
769
- setattr(s, q, getattr(s, q)[s.mask][inds])
799
+ setattr(s, q, Q[s.mask][inds])
770
800
  continue
771
801
 
772
- if getattr(s, q).dtype != np.float64:
802
+ if Q.dtype != np.float64:
773
803
  bad_quantities.append(q)
774
804
  all_bad_quantities.append(q)
775
805
  continue
776
806
 
777
- if np.isnan(getattr(s, q)).all():
807
+ if np.isnan(Q).all():
778
808
  yb = np.full_like(tb, np.nan)
779
809
  setattr(s, q, yb)
810
+
780
811
  elif q + '_err' in s._quantities:
781
- _, yb, eb = binRV(s.mtime,
782
- getattr(s, q)[s.mask],
783
- getattr(s, q + '_err')[s.mask])
812
+ Qerr = getattr(s, q + '_err')
813
+ if (Qerr == 0.0).all():
814
+ _, yb = binRV(s.mtime, Q[s.mask], stat='mean', tstat='mean')
815
+ else:
816
+ _, yb, eb = binRV(s.mtime, Q[s.mask], Qerr[s.mask])
817
+ setattr(s, q + '_err', eb)
818
+
784
819
  setattr(s, q, yb)
785
- setattr(s, q + '_err', eb)
820
+
786
821
  elif not q.endswith('_err'):
787
822
  with warnings.catch_warnings():
788
823
  warnings.filterwarnings('ignore', category=RuntimeWarning)
789
824
  try:
790
- _, yb = binRV(s.mtime, getattr(s, q)[s.mask],
825
+ _, yb = binRV(s.mtime, Q[s.mask],
791
826
  stat=np.nanmean, tstat=np.nanmean)
792
827
  setattr(s, q, yb)
793
828
  except TypeError:
@@ -820,13 +855,26 @@ class RV:
820
855
  return np.nanmean(z, axis=0)
821
856
 
822
857
  def subtract_mean(self):
823
- meanRV = self.mvrad.mean()
858
+ """ Subtract (single) mean RV from all instruments """
859
+ self._meanRV = meanRV = self.mvrad.mean()
824
860
  for inst in self.instruments:
825
861
  s = getattr(self, inst)
826
862
  s.vrad -= meanRV
827
863
  self._build_arrays()
828
864
 
865
+ def _add_back_mean(self):
866
+ """ Add the (single) mean RV removed by self.subtract_mean() """
867
+ if not hasattr(self, '_meanRV'):
868
+ logger.warning("no mean RV stored, run 'self.subtract_mean()'")
869
+ return
870
+
871
+ for inst in self.instruments:
872
+ s = getattr(self, inst)
873
+ s.vrad += self._meanRV
874
+ self._build_arrays()
875
+
829
876
  def adjust_means(self, just_rv=False):
877
+ """ Subtract individual mean RVs from each instrument """
830
878
  if self._child or self._did_adjust_means:
831
879
  return
832
880
 
@@ -877,9 +925,14 @@ class RV:
877
925
  changed = False
878
926
  for inst in self.instruments:
879
927
  s = getattr(self, inst)
880
- if np.abs(s.mvrad.mean()) < s.mvrad.ptp():
881
- s.vrad += self.simbad.rvz_radvel * 1e3
882
- changed = True
928
+ if s.mask.any():
929
+ if np.abs(s.mvrad.mean()) < s.mvrad.ptp():
930
+ s.vrad += self.simbad.rvz_radvel * 1e3
931
+ changed = True
932
+ else: # all observations are masked, use non-masked arrays
933
+ if np.abs(s.vrad.mean()) < s.vrad.ptp():
934
+ s.vrad += self.simbad.rvz_radvel * 1e3
935
+ changed = True
883
936
  if changed:
884
937
  self._build_arrays()
885
938
 
@@ -913,6 +966,11 @@ class RV:
913
966
  """
914
967
  star_name = self.star.replace(' ', '')
915
968
 
969
+ if directory is None:
970
+ directory = '.'
971
+ else:
972
+ os.makedirs(directory, exist_ok=True)
973
+
916
974
  files = []
917
975
 
918
976
  for inst in self.instruments:
@@ -920,15 +978,11 @@ class RV:
920
978
  if instrument not in inst:
921
979
  continue
922
980
 
923
- file = f'{star_name}_{inst}.rdb'
924
- files.append(file)
925
-
926
- if directory is not None:
927
- os.makedirs(directory, exist_ok=True)
928
- file = os.path.join(directory, file)
929
-
930
981
  _s = getattr(self, inst)
931
982
 
983
+ if not _s.mask.any(): # all observations are masked, don't save
984
+ continue
985
+
932
986
  if full:
933
987
  d = np.c_[
934
988
  _s.mtime, _s.mvrad, _s.msvrad,
@@ -941,6 +995,10 @@ class RV:
941
995
  d = np.c_[_s.mtime, _s.mvrad, _s.msvrad]
942
996
  header = 'bjd\tvrad\tsvrad\n---\t----\t-----'
943
997
 
998
+ file = f'{star_name}_{inst}.rdb'
999
+ files.append(file)
1000
+ file = os.path.join(directory, file)
1001
+
944
1002
  np.savetxt(file, d, fmt='%9.5f', header=header, delimiter='\t', comments='')
945
1003
 
946
1004
  if self.verbose:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arvi
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: The Automated RV Inspector
5
5
  Author-email: João Faria <joao.faria@unige.ch>
6
6
  License: MIT
@@ -29,18 +29,6 @@ Requires-Dist: kepmodel
29
29
 
30
30
 
31
31
 
32
- ## Goals
33
-
34
- - _Fast_:
35
- all `arvi` operations must be completed in under **1 second**
36
-
37
- - _Reproducible_:
38
- **everyone** must be able to use `arvi`
39
-
40
- - _Accurate_:
41
- `arvi` must always provide the **correct result**
42
-
43
-
44
32
  #### Actions
45
33
 
46
34
  [![Deploy docs](https://github.com/j-faria/arvi/actions/workflows/docs-gh-pages.yml/badge.svg)](https://github.com/j-faria/arvi/actions/workflows/docs-gh-pages.yml)
@@ -8,7 +8,7 @@ authors = [
8
8
  {name = "João Faria", email = "joao.faria@unige.ch"},
9
9
  ]
10
10
  description = "The Automated RV Inspector"
11
- version = "0.1.5"
11
+ version = "0.1.6"
12
12
  readme = {file = "README.md", content-type = "text/markdown"}
13
13
  requires-python = ">=3.8"
14
14
  keywords = ["RV", "exoplanets"]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes