sdss-almanac 0.2.7__tar.gz → 0.2.9__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.
Files changed (34) hide show
  1. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/PKG-INFO +2 -2
  2. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/pyproject.toml +2 -2
  3. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/__init__.py +1 -1
  4. sdss_almanac-0.2.9/src/almanac/catalog.py +262 -0
  5. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/cli.py +126 -2
  6. sdss_almanac-0.2.9/src/almanac/data_models/metadata.py +247 -0
  7. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/data_models/types.py +29 -0
  8. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/utils.py +15 -4
  9. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/sdss_almanac.egg-info/PKG-INFO +2 -2
  10. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/sdss_almanac.egg-info/SOURCES.txt +2 -0
  11. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/LICENSE.md +0 -0
  12. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/README.md +0 -0
  13. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/setup.cfg +0 -0
  14. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/apogee.py +0 -0
  15. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/config.py +0 -0
  16. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/data_models/__init__.py +0 -0
  17. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/data_models/exposure.py +0 -0
  18. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/data_models/fps.py +0 -0
  19. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/data_models/plate.py +0 -0
  20. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/data_models/utils.py +0 -0
  21. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/database.py +0 -0
  22. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/display.py +0 -0
  23. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/etc/__init__.py +0 -0
  24. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/etc/bad_exposures.csv +0 -0
  25. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/io.py +0 -0
  26. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/logger.py +0 -0
  27. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/qa.py +0 -0
  28. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/stash/data_models.py +0 -0
  29. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/almanac/stash/plugmap_models.py +0 -0
  30. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/sdss_almanac.egg-info/dependency_links.txt +0 -0
  31. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/sdss_almanac.egg-info/entry_points.txt +0 -0
  32. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/sdss_almanac.egg-info/not-zip-safe +0 -0
  33. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/sdss_almanac.egg-info/requires.txt +0 -0
  34. {sdss_almanac-0.2.7 → sdss_almanac-0.2.9}/src/sdss_almanac.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sdss-almanac
3
- Version: 0.2.7
3
+ Version: 0.2.9
4
4
  Summary: Everything we've got
5
5
  Author-email: Andy Casey <andrew.casey@monash.edu>
6
6
  License: BSD 3-Clause License
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.7
17
17
  Classifier: Programming Language :: Python :: 3.8
18
18
  Classifier: Topic :: Documentation :: Sphinx
19
19
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
- Requires-Python: >=3.8
20
+ Requires-Python: >=3.12
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE.md
23
23
  Requires-Dist: numpy
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "sdss-almanac"
7
- version = "0.2.7"
7
+ version = "0.2.9"
8
8
  authors = [
9
9
  { name = "Andy Casey", email = "andrew.casey@monash.edu" }
10
10
  ]
11
11
  description = "Everything we've got"
12
12
  readme = "README.md"
13
- requires-python = ">=3.8"
13
+ requires-python = ">=3.12"
14
14
  license = { text = "BSD 3-Clause License" }
15
15
  keywords = ["astronomy", "software"]
16
16
  classifiers = [
@@ -1,4 +1,4 @@
1
- __version__ = "0.2.7"
1
+ __version__ = "0.2.9"
2
2
 
3
3
  from .config import config, get_config_path, ConfigManager
4
4
  from .logger import logger
@@ -0,0 +1,262 @@
1
+ from itertools import batched
2
+ from typing import List
3
+ from peewee import JOIN
4
+
5
+ def query_catalog(sdss_ids: List[int], batch_size: int = 1000):
6
+ """
7
+ Query the SDSS database for photometry and astrometry.
8
+ """
9
+
10
+ sdss_ids = sorted(list(set(sdss_ids).difference({0, -1})))
11
+
12
+ from almanac.database import is_database_available, catalogdb as db
13
+
14
+ for batch in batched(sdss_ids, batch_size):
15
+ q = (
16
+ db
17
+ .SDSS_ID_To_Catalog
18
+ .select(
19
+ db.SDSS_ID_To_Catalog.sdss_id,
20
+ db.SDSS_ID_To_Catalog.catalogid,
21
+ db.SDSS_ID_To_Catalog.version_id,
22
+ db.SDSS_ID_To_Catalog.lead,
23
+ db.SDSS_ID_To_Catalog.allstar_dr17_synspec_rev1,
24
+ db.SDSS_ID_To_Catalog.allwise,
25
+ db.SDSS_ID_To_Catalog.bhm_rm_v0,
26
+ db.SDSS_ID_To_Catalog.bhm_rm_v0_2,
27
+ db.SDSS_ID_To_Catalog.catwise,
28
+ db.SDSS_ID_To_Catalog.catwise2020,
29
+ db.SDSS_ID_To_Catalog.gaia_dr2_source,
30
+ db.SDSS_ID_To_Catalog.gaia_dr3_source,
31
+ db.SDSS_ID_To_Catalog.glimpse,
32
+ db.SDSS_ID_To_Catalog.guvcat,
33
+ db.SDSS_ID_To_Catalog.legacy_survey_dr10,
34
+ db.SDSS_ID_To_Catalog.legacy_survey_dr8,
35
+ db.SDSS_ID_To_Catalog.mangatarget,
36
+ db.SDSS_ID_To_Catalog.marvels_dr11_star,
37
+ db.SDSS_ID_To_Catalog.marvels_dr12_star,
38
+ db.SDSS_ID_To_Catalog.mastar_goodstars,
39
+ db.SDSS_ID_To_Catalog.panstarrs1,
40
+ db.SDSS_ID_To_Catalog.ps1_g18,
41
+ db.SDSS_ID_To_Catalog.sdss_dr13_photoobj,
42
+ db.SDSS_ID_To_Catalog.sdss_dr17_specobj,
43
+ db.SDSS_ID_To_Catalog.skymapper_dr1_1,
44
+ db.SDSS_ID_To_Catalog.skymapper_dr2,
45
+ db.SDSS_ID_To_Catalog.supercosmos,
46
+ db.SDSS_ID_To_Catalog.tic_v8,
47
+ db.SDSS_ID_To_Catalog.twomass_psc,
48
+ db.SDSS_ID_To_Catalog.tycho2,
49
+ db.SDSS_ID_To_Catalog.unwise,
50
+ db.Gaia_DR3.source_id,
51
+ db.Gaia_DR3.solution_id,
52
+ db.Gaia_DR3.designation,
53
+ db.Gaia_DR3.random_index,
54
+ db.Gaia_DR3.ref_epoch,
55
+ db.Gaia_DR3.ra,
56
+ db.Gaia_DR3.ra_error,
57
+ db.Gaia_DR3.dec,
58
+ db.Gaia_DR3.dec_error,
59
+ db.Gaia_DR3.parallax,
60
+ db.Gaia_DR3.parallax_error,
61
+ db.Gaia_DR3.parallax_over_error,
62
+ db.Gaia_DR3.pm,
63
+ db.Gaia_DR3.pmra,
64
+ db.Gaia_DR3.pmra_error,
65
+ db.Gaia_DR3.pmdec,
66
+ db.Gaia_DR3.pmdec_error,
67
+ db.Gaia_DR3.ra_dec_corr,
68
+ db.Gaia_DR3.ra_parallax_corr,
69
+ db.Gaia_DR3.ra_pmra_corr,
70
+ db.Gaia_DR3.ra_pmdec_corr,
71
+ db.Gaia_DR3.dec_parallax_corr,
72
+ db.Gaia_DR3.dec_pmra_corr,
73
+ db.Gaia_DR3.dec_pmdec_corr,
74
+ db.Gaia_DR3.parallax_pmra_corr,
75
+ db.Gaia_DR3.parallax_pmdec_corr,
76
+ db.Gaia_DR3.pmra_pmdec_corr,
77
+ db.Gaia_DR3.astrometric_n_obs_al,
78
+ db.Gaia_DR3.astrometric_n_obs_ac,
79
+ db.Gaia_DR3.astrometric_n_good_obs_al,
80
+ db.Gaia_DR3.astrometric_n_bad_obs_al,
81
+ db.Gaia_DR3.astrometric_gof_al,
82
+ db.Gaia_DR3.astrometric_chi2_al,
83
+ db.Gaia_DR3.astrometric_excess_noise,
84
+ db.Gaia_DR3.astrometric_excess_noise_sig,
85
+ db.Gaia_DR3.astrometric_params_solved,
86
+ db.Gaia_DR3.astrometric_primary_flag,
87
+ db.Gaia_DR3.nu_eff_used_in_astrometry,
88
+ db.Gaia_DR3.pseudocolour,
89
+ db.Gaia_DR3.pseudocolour_error,
90
+ db.Gaia_DR3.ra_pseudocolour_corr,
91
+ db.Gaia_DR3.dec_pseudocolour_corr,
92
+ db.Gaia_DR3.parallax_pseudocolour_corr,
93
+ db.Gaia_DR3.pmra_pseudocolour_corr,
94
+ db.Gaia_DR3.pmdec_pseudocolour_corr,
95
+ db.Gaia_DR3.astrometric_matched_transits,
96
+ db.Gaia_DR3.visibility_periods_used,
97
+ db.Gaia_DR3.astrometric_sigma5d_max,
98
+ db.Gaia_DR3.matched_transits,
99
+ db.Gaia_DR3.new_matched_transits,
100
+ db.Gaia_DR3.matched_transits_removed,
101
+ db.Gaia_DR3.ipd_gof_harmonic_amplitude,
102
+ db.Gaia_DR3.ipd_gof_harmonic_phase,
103
+ db.Gaia_DR3.ipd_frac_multi_peak,
104
+ db.Gaia_DR3.ipd_frac_odd_win,
105
+ db.Gaia_DR3.ruwe,
106
+ db.Gaia_DR3.scan_direction_strength_k1,
107
+ db.Gaia_DR3.scan_direction_strength_k2,
108
+ db.Gaia_DR3.scan_direction_strength_k3,
109
+ db.Gaia_DR3.scan_direction_strength_k4,
110
+ db.Gaia_DR3.scan_direction_mean_k1,
111
+ db.Gaia_DR3.scan_direction_mean_k2,
112
+ db.Gaia_DR3.scan_direction_mean_k3,
113
+ db.Gaia_DR3.scan_direction_mean_k4,
114
+ db.Gaia_DR3.duplicated_source,
115
+ db.Gaia_DR3.phot_g_n_obs,
116
+ db.Gaia_DR3.phot_g_mean_flux,
117
+ db.Gaia_DR3.phot_g_mean_flux_error,
118
+ db.Gaia_DR3.phot_g_mean_flux_over_error,
119
+ db.Gaia_DR3.phot_g_mean_mag,
120
+ db.Gaia_DR3.phot_bp_n_obs,
121
+ db.Gaia_DR3.phot_bp_mean_flux,
122
+ db.Gaia_DR3.phot_bp_mean_flux_error,
123
+ db.Gaia_DR3.phot_bp_mean_flux_over_error,
124
+ db.Gaia_DR3.phot_bp_mean_mag,
125
+ db.Gaia_DR3.phot_rp_n_obs,
126
+ db.Gaia_DR3.phot_rp_mean_flux,
127
+ db.Gaia_DR3.phot_rp_mean_flux_error,
128
+ db.Gaia_DR3.phot_rp_mean_flux_over_error,
129
+ db.Gaia_DR3.phot_rp_mean_mag,
130
+ db.Gaia_DR3.phot_bp_rp_excess_factor,
131
+ db.Gaia_DR3.phot_bp_n_contaminated_transits,
132
+ db.Gaia_DR3.phot_bp_n_blended_transits,
133
+ db.Gaia_DR3.phot_rp_n_contaminated_transits,
134
+ db.Gaia_DR3.phot_rp_n_blended_transits,
135
+ db.Gaia_DR3.phot_proc_mode,
136
+ db.Gaia_DR3.bp_rp,
137
+ db.Gaia_DR3.bp_g,
138
+ db.Gaia_DR3.g_rp,
139
+ db.Gaia_DR3.radial_velocity,
140
+ db.Gaia_DR3.radial_velocity_error,
141
+ db.Gaia_DR3.rv_method_used,
142
+ db.Gaia_DR3.rv_nb_transits,
143
+ db.Gaia_DR3.rv_nb_deblended_transits,
144
+ db.Gaia_DR3.rv_visibility_periods_used,
145
+ db.Gaia_DR3.rv_expected_sig_to_noise,
146
+ db.Gaia_DR3.rv_renormalised_gof,
147
+ db.Gaia_DR3.rv_chisq_pvalue,
148
+ db.Gaia_DR3.rv_time_duration,
149
+ db.Gaia_DR3.rv_amplitude_robust,
150
+ db.Gaia_DR3.rv_template_teff,
151
+ db.Gaia_DR3.rv_template_logg,
152
+ db.Gaia_DR3.rv_template_fe_h,
153
+ db.Gaia_DR3.rv_atm_param_origin,
154
+ db.Gaia_DR3.vbroad,
155
+ db.Gaia_DR3.vbroad_error,
156
+ db.Gaia_DR3.vbroad_nb_transits,
157
+ db.Gaia_DR3.grvs_mag,
158
+ db.Gaia_DR3.grvs_mag_error,
159
+ db.Gaia_DR3.grvs_mag_nb_transits,
160
+ db.Gaia_DR3.rvs_spec_sig_to_noise,
161
+ db.Gaia_DR3.phot_variable_flag,
162
+ db.Gaia_DR3.l,
163
+ db.Gaia_DR3.b,
164
+ db.Gaia_DR3.ecl_lon,
165
+ db.Gaia_DR3.ecl_lat,
166
+ db.Gaia_DR3.in_qso_candidates,
167
+ db.Gaia_DR3.in_galaxy_candidates,
168
+ db.Gaia_DR3.non_single_star,
169
+ db.Gaia_DR3.has_xp_continuous,
170
+ db.Gaia_DR3.has_xp_sampled,
171
+ db.Gaia_DR3.has_rvs,
172
+ db.Gaia_DR3.has_epoch_photometry,
173
+ db.Gaia_DR3.has_epoch_rv,
174
+ db.Gaia_DR3.has_mcmc_gspphot,
175
+ db.Gaia_DR3.has_mcmc_msc,
176
+ db.Gaia_DR3.in_andromeda_survey,
177
+ db.Gaia_DR3.classprob_dsc_combmod_quasar,
178
+ db.Gaia_DR3.classprob_dsc_combmod_galaxy,
179
+ db.Gaia_DR3.classprob_dsc_combmod_star,
180
+ db.Gaia_DR3.teff_gspphot,
181
+ db.Gaia_DR3.teff_gspphot_lower,
182
+ db.Gaia_DR3.teff_gspphot_upper,
183
+ db.Gaia_DR3.logg_gspphot,
184
+ db.Gaia_DR3.logg_gspphot_lower,
185
+ db.Gaia_DR3.logg_gspphot_upper,
186
+ db.Gaia_DR3.mh_gspphot,
187
+ db.Gaia_DR3.mh_gspphot_lower,
188
+ db.Gaia_DR3.mh_gspphot_upper,
189
+ db.Gaia_DR3.distance_gspphot,
190
+ db.Gaia_DR3.distance_gspphot_lower,
191
+ db.Gaia_DR3.distance_gspphot_upper,
192
+ db.Gaia_DR3.azero_gspphot,
193
+ db.Gaia_DR3.azero_gspphot_lower,
194
+ db.Gaia_DR3.azero_gspphot_upper,
195
+ db.Gaia_DR3.ag_gspphot,
196
+ db.Gaia_DR3.ag_gspphot_lower,
197
+ db.Gaia_DR3.ag_gspphot_upper,
198
+ db.Gaia_DR3.ebpminrp_gspphot,
199
+ db.Gaia_DR3.ebpminrp_gspphot_lower,
200
+ db.Gaia_DR3.ebpminrp_gspphot_upper,
201
+ db.Gaia_DR3.libname_gspphot,
202
+ db.TwoMassPSC.designation,
203
+ db.TwoMassPSC.j_m,
204
+ db.TwoMassPSC.j_cmsig,
205
+ db.TwoMassPSC.j_msigcom,
206
+ db.TwoMassPSC.j_snr,
207
+ db.TwoMassPSC.h_m,
208
+ db.TwoMassPSC.h_cmsig,
209
+ db.TwoMassPSC.h_msigcom,
210
+ db.TwoMassPSC.h_snr,
211
+ db.TwoMassPSC.k_m,
212
+ db.TwoMassPSC.k_cmsig,
213
+ db.TwoMassPSC.k_msigcom,
214
+ db.TwoMassPSC.k_snr,
215
+ db.TwoMassPSC.ph_qual,
216
+ db.TwoMassPSC.rd_flg,
217
+ db.TwoMassPSC.bl_flg,
218
+ db.TwoMassPSC.cc_flg,
219
+ db.TwoMassPSC.ndet,
220
+ db.TwoMassPSC.prox,
221
+ db.TwoMassPSC.pxpa,
222
+ db.TwoMassPSC.pxcntr,
223
+ db.TwoMassPSC.gal_contam,
224
+ db.TwoMassPSC.mp_flg,
225
+ db.TwoMassPSC.scan,
226
+ db.TwoMassPSC.glon,
227
+ db.TwoMassPSC.glat,
228
+ db.TwoMassPSC.x_scan,
229
+ db.TwoMassPSC.jdate,
230
+ db.TwoMassPSC.j_psfchi,
231
+ db.TwoMassPSC.h_psfchi,
232
+ db.TwoMassPSC.k_psfchi,
233
+ db.TwoMassPSC.j_m_stdap,
234
+ db.TwoMassPSC.j_msig_stdap,
235
+ db.TwoMassPSC.h_m_stdap,
236
+ db.TwoMassPSC.h_msig_stdap,
237
+ db.TwoMassPSC.k_m_stdap,
238
+ db.TwoMassPSC.k_msig_stdap,
239
+ db.TwoMassPSC.dist_edge_ns,
240
+ db.TwoMassPSC.dist_edge_ew,
241
+ db.TwoMassPSC.dist_edge_flg,
242
+ db.TwoMassPSC.dup_src,
243
+ db.TwoMassPSC.use_src,
244
+ db.TwoMassPSC.a,
245
+ db.TwoMassPSC.dist_opt,
246
+ db.TwoMassPSC.phi_opt,
247
+ db.TwoMassPSC.b_m_opt,
248
+ db.TwoMassPSC.vr_m_opt,
249
+ db.TwoMassPSC.nopt_mchs,
250
+ db.TwoMassPSC.ext_key,
251
+ db.TwoMassPSC.scan_key,
252
+ db.TwoMassPSC.coadd_key,
253
+ db.TwoMassPSC.coadd
254
+ )
255
+ .distinct(db.SDSS_ID_To_Catalog.sdss_id)
256
+ .join(db.Gaia_DR3, join_type=JOIN.LEFT_OUTER)
257
+ .switch(db.SDSS_ID_To_Catalog)
258
+ .join(db.TwoMassPSC, join_type=JOIN.LEFT_OUTER)
259
+ .where(db.SDSS_ID_To_Catalog.sdss_id.in_(tuple(batch)))
260
+ .dicts()
261
+ )
262
+ yield from q.iterator()
@@ -41,7 +41,7 @@ def main(
41
41
 
42
42
  # This keeps the default behaviour as 'query mode' but allows for commands like 'config'.
43
43
  if ctx.invoked_subcommand is not None:
44
- command = dict(config=config, dump=dump)[ctx.invoked_subcommand]
44
+ command = dict(config=config, dump=dump, add=add)[ctx.invoked_subcommand]
45
45
  return ctx.invoke(command, **ctx.params)
46
46
 
47
47
  import h5py as h5
@@ -196,6 +196,122 @@ def main(
196
196
  for item in buffered_critical_logs:
197
197
  logger.critical(item)
198
198
 
199
+ @main.group()
200
+ def add(**kwargs):
201
+ """Add new information to an existing Almanac file."""
202
+ pass
203
+
204
+ @add.command()
205
+ @click.argument("input_path", type=str)
206
+ @click.option("--mjd", default=None, type=int, help="Modified Julian date to query. Use negative values to indicate relative to current MJD")
207
+ @click.option("--mjd-start", default=None, type=int, help="Start of MJD range to query")
208
+ @click.option("--mjd-end", default=None, type=int, help="End of MJD range to query")
209
+ @click.option("--date", default=None, type=str, help="Date to query (e.g., 2024-01-15)")
210
+ @click.option("--date-start", default=None, type=str, help="Start of date range to query")
211
+ @click.option("--date-end", default=None, type=str, help="End of date range to query")
212
+ @click.option("--apo", is_flag=True, help="Query Apache Point Observatory data")
213
+ @click.option("--lco", is_flag=True, help="Query Las Campanas Observatory data")
214
+ def metadata(input_path, mjd, mjd_start, mjd_end, date, date_start, date_end, apo, lco, **kwargs):
215
+ """Add astrometry and photometry to an existing Almanac file."""
216
+
217
+ import numpy as np
218
+ import h5py as h5
219
+ from itertools import product
220
+ from almanac import utils
221
+ from almanac.catalog import query_catalog
222
+ from almanac.data_models.metadata import SourceMetadata
223
+ from tqdm import tqdm
224
+
225
+ observatories = utils.get_observatories(apo, lco)
226
+ mjds, *_ = utils.parse_mjds(
227
+ mjd, mjd_start, mjd_end, date, date_start, date_end, return_nones=True
228
+ )
229
+
230
+ sdss_ids = set()
231
+ with h5.File(input_path, "r") as fp:
232
+ if mjds is None:
233
+ mjds = []
234
+ for obs in observatories:
235
+ mjds.extend(fp[obs])
236
+ mjds = list(set(mjds))
237
+
238
+ for mjd, obs in product(mjds, observatories):
239
+ group = fp.get(f"{obs}/{mjd}/fibers", [])
240
+ for config in group:
241
+ if "source_id" in group[config]:
242
+ continue
243
+ sdss_ids.update(group[config]["sdss_id"][:])
244
+
245
+ v = []
246
+ for row in tqdm(query_catalog(sdss_ids), total=len(sdss_ids)):
247
+ v.append(row)
248
+
249
+
250
+
251
+
252
+ if mjd is None:
253
+ total = sum([len(fp[obs].keys()) for obs in observatories])
254
+ else:
255
+ total = 1 * len(observatories)
256
+
257
+ sdss_ids = dict()
258
+ with tqdm(total=total, desc="Collecting SDSS identifiers") as pb:
259
+ for observatory in observatories:
260
+ if observatory not in fp:
261
+ continue
262
+
263
+ mjds = fp[observatory].keys() if mjd is None else [str(mjd)]
264
+
265
+ for mjd in mjds:
266
+ group = fp[f"{observatory}/{mjd}"]
267
+ if "fibers" not in group:
268
+ continue
269
+
270
+ for config_id in group["fibers"]:
271
+ config_group = group[f"fibers/{config_id}"]
272
+
273
+ if "source_id" in config_group:
274
+ continue
275
+
276
+ dtypes = dict(
277
+ sdss_id=(np.int64, -1),
278
+ source_id=(np.int64, -1),
279
+ ra=(float, np.nan),
280
+ dec=(float, np.nan),
281
+ parallax=(float, np.nan),
282
+ radial_velocity=(float, np.nan),
283
+ radial_velocity_error=(float, np.nan),
284
+ bp_rp=(float, np.nan),
285
+ bp_g=(float, np.nan),
286
+ g_rp=(float, np.nan),
287
+ designation=(None, ""),
288
+ j_m=(float, np.nan),
289
+ h_m=(float, np.nan),
290
+ k_m=(float, np.nan),
291
+ )
292
+
293
+ n = len(config_group["sdss_id"][:])
294
+ metadata = {k: [v[1]] * n for k, v in dtypes.items()}
295
+ for i, row in enumerate(query_catalog(list(config_group["sdss_id"][:]))):
296
+ for key in row.keys():
297
+ metadata[key][i] = row[key]
298
+
299
+ # match to existing sdss_id
300
+ new_id = np.argsort(np.argsort(config_group["sdss_id"][:]))
301
+ indices = np.argsort(metadata["sdss_id"])[new_id]
302
+
303
+ for key, values in metadata.items():
304
+ if key in config_group:
305
+ continue
306
+ dtype, default = dtypes[key]
307
+ values = np.array([v or default for v in values], dtype=dtype)[indices]
308
+ if key == "designation":
309
+ values = list(map(str, values))
310
+ config_group.create_dataset(key, data=values, dtype=dtype)
311
+ print(f"Created {observatory}/{mjd}/fibers/{config_id}/{key}")
312
+ pb.update(1)
313
+
314
+
199
315
  @main.group()
200
316
  def config(**kwargs):
201
317
  """View or update configuration settings."""
@@ -259,11 +375,19 @@ def get(key, **kwargs):
259
375
  click.echo(value)
260
376
 
261
377
 
262
- @config.command
378
+ @config.command(hidden=True)
263
379
  @click.argument("key")
264
380
  @click.argument("value")
265
381
  def update(key, value, **kwargs):
266
382
  """Update a configuration value"""
383
+ click.echo(click.style("Deprecated: use `almanac config set`", fg="yellow"))
384
+ return set(key, value, **kwargs)
385
+
386
+ @config.command
387
+ @click.argument("key")
388
+ @click.argument("value")
389
+ def set(key, value, **kwargs):
390
+ """Set a configuration value"""
267
391
 
268
392
  from almanac import config, get_config_path, ConfigManager
269
393
  from dataclasses import asdict, is_dataclass
@@ -0,0 +1,247 @@
1
+ from pydantic import BaseModel, Field, computed_field, field_validator, model_validator
2
+ from almanac.data_models.types import *
3
+
4
+ class SourceMetadata(BaseModel):
5
+
6
+ # Identifiers
7
+ sdss_id: Int64 = Field(default=-1)
8
+ catalogid: Int64 = Field(default=-1)
9
+ version_id: int = Field(default=-1)
10
+ lead: str = Field(default="")
11
+ allstar_dr17_synspec_rev1: Str = Field(default=-1)
12
+ allwise: Int64 = Field(default=-1)
13
+ bhm_rm_v0: Int64 = Field(default=-1)
14
+ bhm_rm_v0_2: Int64 = Field(default=-1)
15
+ catwise: Str = Field(default=-1)
16
+ catwise2020: Str = Field(default=-1)
17
+ gaia_dr2_source: Int64 = Field(default=-1)
18
+ gaia_dr3_source: Int64 = Field(default=-1)
19
+ glimpse: Int64 = Field(default=-1)
20
+ guvcat: Int64 = Field(default=-1)
21
+ legacy_survey_dr10: Int64 = Field(default=-1)
22
+ legacy_survey_dr8: Int64 = Field(default=-1)
23
+ mangatarget: Str = Field(default=-1)
24
+ marvels_dr11_star: Str = Field(default=-1)
25
+ marvels_dr12_star: Int64 = Field(default=-1)
26
+ mastar_goodstars: Str = Field(default=-1)
27
+ panstarrs1: Int64 = Field(default=-1)
28
+ ps1_g18: Int64 = Field(default=-1)
29
+ sdss_dr13_photoobj: Int64 = Field(default=-1)
30
+ sdss_dr17_specobj: Str = Field(default=-1)
31
+ skymapper_dr1_1: Int64 = Field(default=-1)
32
+ skymapper_dr2: Int64 = Field(default=-1)
33
+ supercosmos: Int64 = Field(default=-1)
34
+ tic_v8: Int64 = Field(default=-1)
35
+ twomass_psc: Int64 = Field(default=-1)
36
+ tycho2: Str = Field(default=-1)
37
+ unwise: Str = Field(default=-1)
38
+
39
+ # Gaia
40
+ source_id: Int = Field(default=-1)
41
+ solution_id: Int = Field(default=-1)
42
+ designation: Str = Field(default=-1)
43
+ random_index: Float = Field(default=-1)
44
+ ref_epoch: Float = Field(default=-1)
45
+ ra: Float = Field(default=-1)
46
+ ra_error: Float = Field(default=-1)
47
+ dec: Float = Field(default=-1)
48
+ dec_error: Float = Field(default=-1)
49
+ parallax: Float = Field(default=-1)
50
+ parallax_error: Float = Field(default=-1)
51
+ parallax_over_error: Float = Field(default=-1)
52
+ pm: Float = Field(default=-1)
53
+ pmra: Float = Field(default=-1)
54
+ pmra_error: Float = Field(default=-1)
55
+ pmdec: Float = Field(default=-1)
56
+ pmdec_error: Float = Field(default=-1)
57
+ ra_dec_corr: Float = Field(default=-1)
58
+ ra_parallax_corr: Float = Field(default=-1)
59
+ ra_pmra_corr: Float = Field(default=-1)
60
+ ra_pmdec_corr: Float = Field(default=-1)
61
+ dec_parallax_corr: Float = Field(default=-1)
62
+ dec_pmra_corr: Float = Field(default=-1)
63
+ dec_pmdec_corr: Float = Field(default=-1)
64
+ parallax_pmra_corr: Float = Field(default=-1)
65
+ parallax_pmdec_corr: Float = Field(default=-1)
66
+ pmra_pmdec_corr: Float = Field(default=-1)
67
+ astrometric_n_obs_al: Int = Field(default=-1)
68
+ astrometric_n_obs_ac: Int = Field(default=-1)
69
+ astrometric_n_good_obs_al: Int = Field(default=-1)
70
+ astrometric_n_bad_obs_al: Int = Field(default=-1)
71
+ astrometric_gof_al: Float = Field(default=-1)
72
+ astrometric_chi2_al: Float = Field(default=-1)
73
+ astrometric_excess_noise: Float = Field(default=-1)
74
+ astrometric_excess_noise_sig: Float = Field(default=-1)
75
+ astrometric_params_solved: Int = Field(default=-1)
76
+ astrometric_primary_flag: Bool = Field(default=-1)
77
+ nu_eff_used_in_astrometry: Float = Field(default=-1)
78
+ pseudocolour: Float = Field(default=-1)
79
+ pseudocolour_error: Float = Field(default=-1)
80
+ ra_pseudocolour_corr: Float = Field(default=-1)
81
+ dec_pseudocolour_corr: Float = Field(default=-1)
82
+ parallax_pseudocolour_corr: Float = Field(default=-1)
83
+ pmra_pseudocolour_corr: Float = Field(default=-1)
84
+ pmdec_pseudocolour_corr: Float = Field(default=-1)
85
+ astrometric_matched_transits: Int = Field(default=-1)
86
+ visibility_periods_used: Int = Field(default=-1)
87
+ astrometric_sigma5d_max: Float = Field(default=-1)
88
+ matched_transits: Int = Field(default=-1)
89
+ new_matched_transits: Int = Field(default=-1)
90
+ matched_transits_removed: Int = Field(default=-1)
91
+ ipd_gof_harmonic_amplitude: Float = Field(default=-1)
92
+ ipd_gof_harmonic_phase: Float = Field(default=-1)
93
+ ipd_frac_multi_peak: Float = Field(default=-1)
94
+ ipd_frac_odd_win: Float = Field(default=-1)
95
+ ruwe: Float = Field(default=-1)
96
+ scan_direction_strength_k1: Float = Field(default=-1)
97
+ scan_direction_strength_k2: Float = Field(default=-1)
98
+ scan_direction_strength_k3: Float = Field(default=-1)
99
+ scan_direction_strength_k4: Float = Field(default=-1)
100
+ scan_direction_mean_k1: Float = Field(default=-1)
101
+ scan_direction_mean_k2: Float = Field(default=-1)
102
+ scan_direction_mean_k3: Float = Field(default=-1)
103
+ scan_direction_mean_k4: Float = Field(default=-1)
104
+ duplicated_source: Bool = Field(default=-1)
105
+ phot_g_n_obs: Int = Field(default=-1)
106
+ phot_g_mean_flux: Float = Field(default=-1)
107
+ phot_g_mean_flux_error: Float = Field(default=-1)
108
+ phot_g_mean_flux_over_error: Float = Field(default=-1)
109
+ phot_g_mean_mag: Float = Field(default=-1)
110
+ phot_bp_n_obs: Int = Field(default=-1)
111
+ phot_bp_mean_flux: Float = Field(default=-1)
112
+ phot_bp_mean_flux_error: Float = Field(default=-1)
113
+ phot_bp_mean_flux_over_error: Float = Field(default=-1)
114
+ phot_bp_mean_mag: Float = Field(default=-1)
115
+ phot_rp_n_obs: Int = Field(default=-1)
116
+ phot_rp_mean_flux: Float = Field(default=-1)
117
+ phot_rp_mean_flux_error: Float = Field(default=-1)
118
+ phot_rp_mean_flux_over_error: Float = Field(default=-1)
119
+ phot_rp_mean_mag: Float = Field(default=-1)
120
+ phot_bp_rp_excess_factor: Float = Field(default=-1)
121
+ phot_bp_n_contaminated_transits: Int = Field(default=-1)
122
+ phot_bp_n_blended_transits: Int = Field(default=-1)
123
+ phot_rp_n_contaminated_transits: Int = Field(default=-1)
124
+ phot_rp_n_blended_transits: Int = Field(default=-1)
125
+ phot_proc_mode: Int = Field(default=-1)
126
+ bp_rp: Float = Field(default=-1)
127
+ bp_g: Float = Field(default=-1)
128
+ g_rp: Float = Field(default=-1)
129
+ radial_velocity: Float = Field(default=-1)
130
+ radial_velocity_error: Float = Field(default=-1)
131
+ rv_method_used: Str = Field(default=-1)
132
+ rv_nb_transits: Int = Field(default=-1)
133
+ rv_nb_deblended_transits: Int = Field(default=-1)
134
+ rv_visibility_periods_used: Int = Field(default=-1)
135
+ rv_expected_sig_to_noise: Float = Field(default=-1)
136
+ rv_renormalised_gof: Float = Field(default=-1)
137
+ rv_chisq_pvalue: Float = Field(default=-1)
138
+ rv_time_duration: Float = Field(default=-1)
139
+ rv_amplitude_robust: Float = Field(default=-1)
140
+ rv_template_teff: Float = Field(default=-1)
141
+ rv_template_logg: Float = Field(default=-1)
142
+ rv_template_fe_h: Float = Field(default=-1)
143
+ rv_atm_param_origin: Str = Field(default=-1)
144
+ vbroad: Float = Field(default=-1)
145
+ vbroad_error: Float = Field(default=-1)
146
+ vbroad_nb_transits: Int = Field(default=-1)
147
+ grvs_mag: Float = Field(default=-1)
148
+ grvs_mag_error: Float = Field(default=-1)
149
+ grvs_mag_nb_transits: Int = Field(default=-1)
150
+ rvs_spec_sig_to_noise: Float = Field(default=-1)
151
+ phot_variable_flag: Str = Field(default=-1)
152
+ l: Float = Field(default=-1)
153
+ b: Float = Field(default=-1)
154
+ ecl_lon: Float = Field(default=-1)
155
+ ecl_lat: Float = Field(default=-1)
156
+ in_qso_candidates: Bool = Field(default=-1)
157
+ in_galaxy_candidates: Bool = Field(default=-1)
158
+ non_single_star: Bool = Field(default=-1)
159
+ has_xp_continuous: Bool = Field(default=-1)
160
+ has_xp_sampled: Bool = Field(default=-1)
161
+ has_rvs: Bool = Field(default=-1)
162
+ has_epoch_photometry: Bool = Field(default=-1)
163
+ has_epoch_rv: Bool = Field(default=-1)
164
+ has_mcmc_gspphot: Bool = Field(default=-1)
165
+ has_mcmc_msc: Bool = Field(default=-1)
166
+ in_andromeda_survey: Bool = Field(default=-1)
167
+ classprob_dsc_combmod_quasar: Float = Field(default=-1)
168
+ classprob_dsc_combmod_galaxy: Float = Field(default=-1)
169
+ classprob_dsc_combmod_star: Float = Field(default=-1)
170
+ teff_gspphot: Float = Field(default=-1)
171
+ teff_gspphot_lower: Float = Field(default=-1)
172
+ teff_gspphot_upper: Float = Field(default=-1)
173
+ logg_gspphot: Float = Field(default=-1)
174
+ logg_gspphot_lower: Float = Field(default=-1)
175
+ logg_gspphot_upper: Float = Field(default=-1)
176
+ mh_gspphot: Float = Field(default=-1)
177
+ mh_gspphot_lower: Float = Field(default=-1)
178
+ mh_gspphot_upper: Float = Field(default=-1)
179
+ distance_gspphot: Float = Field(default=-1)
180
+ distance_gspphot_lower: Float = Field(default=-1)
181
+ distance_gspphot_upper: Float = Field(default=-1)
182
+ azero_gspphot: Float = Field(default=-1)
183
+ azero_gspphot_lower: Float = Field(default=-1)
184
+ azero_gspphot_upper: Float = Field(default=-1)
185
+ ag_gspphot: Float = Field(default=-1)
186
+ ag_gspphot_lower: Float = Field(default=-1)
187
+ ag_gspphot_upper: Float = Field(default=-1)
188
+ ebpminrp_gspphot: Float = Field(default=-1)
189
+ ebpminrp_gspphot_lower: Float = Field(default=-1)
190
+ ebpminrp_gspphot_upper: Float = Field(default=-1)
191
+ libname_gspphot: Str = Field(default=-1)
192
+ j_m: Float = Field(default=-1)
193
+ j_cmsig: Float = Field(default=-1)
194
+ j_msigcom: Float = Field(default=-1)
195
+ j_snr: Float = Field(default=-1)
196
+ h_m: Float = Field(default=-1)
197
+ h_cmsig: Float = Field(default=-1)
198
+ h_msigcom: Float = Field(default=-1)
199
+ h_snr: Float = Field(default=-1)
200
+ k_m: Float = Field(default=-1)
201
+ k_cmsig: Float = Field(default=-1)
202
+ k_msigcom: Float = Field(default=-1)
203
+ k_snr: Float = Field(default=-1)
204
+ ph_qual: Str = Field(default=-1)
205
+ rd_flg: Str = Field(default=-1)
206
+ bl_flg: Str = Field(default=-1)
207
+ cc_flg: Str = Field(default=-1)
208
+ ndet: Int = Field(default=-1)
209
+ prox: Float = Field(default=-1)
210
+ pxpa: Float = Field(default=-1)
211
+ pxcntr: Float = Field(default=-1)
212
+ gal_contam: Int = Field(default=-1)
213
+ mp_flg: Int = Field(default=-1)
214
+ scan: Int = Field(default=-1)
215
+ glon: Float = Field(default=-1)
216
+ glat: Float = Field(default=-1)
217
+ x_scan: Float = Field(default=-1)
218
+ jdate: Float = Field(default=-1)
219
+ j_psfchi: Float = Field(default=-1)
220
+ h_psfchi: Float = Field(default=-1)
221
+ k_psfchi: Float = Field(default=-1)
222
+ j_m_stdap: Float = Field(default=-1)
223
+ j_msig_stdap: Float = Field(default=-1)
224
+ h_m_stdap: Float = Field(default=-1)
225
+ h_msig_stdap: Float = Field(default=-1)
226
+ k_m_stdap: Float = Field(default=-1)
227
+ k_msig_stdap: Float = Field(default=-1)
228
+ dist_edge_ns: Float = Field(default=-1)
229
+ dist_edge_ew: Float = Field(default=-1)
230
+ dist_edge_flg: Str = Field(default=-1)
231
+ dup_src: Int = Field(default=-1)
232
+ use_src: Int = Field(default=-1)
233
+ a: Str = Field(default=-1)
234
+ dist_opt: Float = Field(default=-1)
235
+ phi_opt: Float = Field(default=-1)
236
+ b_m_opt: Float = Field(default=-1)
237
+ vr_m_opt: Float = Field(default=-1)
238
+ nopt_mchs: Int = Field(default=-1)
239
+ ext_key: Int = Field(default=-1)
240
+ scan_key: Int = Field(default=-1)
241
+ coadd_key: Int = Field(default=-1)
242
+ coad: Int = Field(default=-1)
243
+
244
+ class Config:
245
+ validate_by_name = True
246
+ validate_assignment = True
247
+ arbitrary_types_allowed = True
@@ -4,11 +4,40 @@ from typing_extensions import Annotated
4
4
  from pydantic import BeforeValidator
5
5
 
6
6
  def validate_np_int64(v):
7
+ if v is None:
8
+ return np.int64(-1)
7
9
  if not isinstance(v, np.int64):
8
10
  return np.int64(v)
9
11
  return v
10
12
 
13
+ def validate_int(v):
14
+ if v is None:
15
+ return -1
16
+ return int(v)
17
+
18
+ def validate_float(v):
19
+ if v is None:
20
+ return float('nan')
21
+ try:
22
+ return float(v)
23
+ except (ValueError, TypeError):
24
+ return float('nan')
25
+
26
+ def validate_str(v):
27
+ if v is None:
28
+ return ""
29
+ return str(v)
30
+
31
+ def validate_bool(v):
32
+ if v is None:
33
+ return False
34
+ return bool(v)
35
+
11
36
  Int64 = Annotated[np.int64, BeforeValidator(validate_np_int64)]
37
+ Int = Annotated[int, BeforeValidator(validate_int)]
38
+ Float = Annotated[float, BeforeValidator(validate_float)]
39
+ Str = Annotated[str, BeforeValidator(validate_str)]
40
+ Bool = Annotated[bool, BeforeValidator(validate_bool)]
12
41
 
13
42
 
14
43
  Observatory = Literal["apo", "lco"]
@@ -83,9 +83,16 @@ def mjd_to_datetime(mjd: float) -> datetime:
83
83
  """
84
84
  return Time(mjd, format='mjd').datetime
85
85
 
86
- def parse_mjds(mjd: Optional[int], mjd_start: Optional[int], mjd_end: Optional[int],
87
- date: Optional[str], date_start: Optional[str], date_end: Optional[str],
88
- earliest_mjd: int = 0) -> Tuple[Union[int, range, Tuple[int, ...]], int, int]:
86
+ def parse_mjds(
87
+ mjd: Optional[int],
88
+ mjd_start: Optional[int],
89
+ mjd_end: Optional[int],
90
+ date: Optional[str],
91
+ date_start: Optional[str],
92
+ date_end: Optional[str],
93
+ earliest_mjd: int = 0,
94
+ return_nones: bool = False
95
+ ) -> Tuple[Union[int, range, Tuple[int, ...]], int, int]:
89
96
  """Parse MJD and date parameters to determine observation date range.
90
97
 
91
98
  Args:
@@ -96,6 +103,7 @@ def parse_mjds(mjd: Optional[int], mjd_start: Optional[int], mjd_end: Optional[i
96
103
  date_start: Start date string in "YYYY-MM-DD" format
97
104
  date_end: End date string in "YYYY-MM-DD" format
98
105
  earliest_mjd: Earliest allowed MJD value (default: 0)
106
+ return_nones: If True, return None for mjd range if no dates are specified (default: False)
99
107
 
100
108
  Returns:
101
109
  Tuple containing:
@@ -117,7 +125,10 @@ def parse_mjds(mjd: Optional[int], mjd_start: Optional[int], mjd_end: Optional[i
117
125
  "Cannot specify more than one of --mjd, --mjd-start/--mjd-end, --date, --date-start/--date-end"
118
126
  )
119
127
  if n_given == 0:
120
- return ((current_mjd, ), current_mjd, current_mjd)
128
+ if return_nones:
129
+ return (None, None, None)
130
+ else:
131
+ return ((current_mjd, ), current_mjd, current_mjd)
121
132
  if mjd is not None:
122
133
  if mjd < 0:
123
134
  mjd += current_mjd
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sdss-almanac
3
- Version: 0.2.7
3
+ Version: 0.2.9
4
4
  Summary: Everything we've got
5
5
  Author-email: Andy Casey <andrew.casey@monash.edu>
6
6
  License: BSD 3-Clause License
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.7
17
17
  Classifier: Programming Language :: Python :: 3.8
18
18
  Classifier: Topic :: Documentation :: Sphinx
19
19
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
- Requires-Python: >=3.8
20
+ Requires-Python: >=3.12
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE.md
23
23
  Requires-Dist: numpy
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  src/almanac/__init__.py
5
5
  src/almanac/apogee.py
6
+ src/almanac/catalog.py
6
7
  src/almanac/cli.py
7
8
  src/almanac/config.py
8
9
  src/almanac/database.py
@@ -14,6 +15,7 @@ src/almanac/utils.py
14
15
  src/almanac/data_models/__init__.py
15
16
  src/almanac/data_models/exposure.py
16
17
  src/almanac/data_models/fps.py
18
+ src/almanac/data_models/metadata.py
17
19
  src/almanac/data_models/plate.py
18
20
  src/almanac/data_models/types.py
19
21
  src/almanac/data_models/utils.py
File without changes
File without changes
File without changes