sdss-almanac 0.2.4__tar.gz → 0.2.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.
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/PKG-INFO +1 -1
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/pyproject.toml +1 -1
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/__init__.py +1 -1
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/data_models/exposure.py +19 -11
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/data_models/types.py +4 -2
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/data_models/utils.py +26 -3
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/sdss_almanac.egg-info/PKG-INFO +1 -1
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/LICENSE.md +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/README.md +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/setup.cfg +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/apogee.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/cli.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/config.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/data_models/__init__.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/data_models/fps.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/data_models/plate.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/database.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/display.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/etc/__init__.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/etc/bad_exposures.csv +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/io.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/logger.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/qa.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/stash/data_models.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/stash/plugmap_models.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/almanac/utils.py +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/sdss_almanac.egg-info/SOURCES.txt +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/sdss_almanac.egg-info/dependency_links.txt +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/sdss_almanac.egg-info/entry_points.txt +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/sdss_almanac.egg-info/not-zip-safe +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/sdss_almanac.egg-info/requires.txt +0 -0
- {sdss_almanac-0.2.4 → sdss_almanac-0.2.6}/src/sdss_almanac.egg-info/top_level.txt +0 -0
@@ -121,7 +121,7 @@ class Exposure(BaseModel):
|
|
121
121
|
|
122
122
|
@field_validator('lamp_quartz', 'lamp_thar', 'lamp_une', mode="before")
|
123
123
|
def validate_lamps(cls, v):
|
124
|
-
return {'F': 0, 'T': 1}.get(str(v).strip().upper(), -1)
|
124
|
+
return {'F': 0, 'T': 1, '0': 0, '1': 1}.get(str(v).strip().upper(), -1)
|
125
125
|
|
126
126
|
@model_validator(mode="after")
|
127
127
|
def check_fields(self):
|
@@ -299,7 +299,6 @@ class Exposure(BaseModel):
|
|
299
299
|
@cached_property
|
300
300
|
def targets(self) -> Tuple[Union[FPSTarget, PlateTarget]]:
|
301
301
|
if self._targets is None:
|
302
|
-
|
303
302
|
if (
|
304
303
|
(self.image_type == "object")
|
305
304
|
& (
|
@@ -309,9 +308,18 @@ class Exposure(BaseModel):
|
|
309
308
|
):
|
310
309
|
if self.fps:
|
311
310
|
factory = FPSTarget
|
312
|
-
|
313
|
-
keep = (
|
314
|
-
|
311
|
+
rows = self.fiber_map
|
312
|
+
keep = (rows["fiberType"] == "APOGEE") & (rows["fiberId"] > 0)
|
313
|
+
rows = rows[keep]
|
314
|
+
missing = set(range(1, 301)) - set(rows["fiberId"])
|
315
|
+
for fiber_id in missing:
|
316
|
+
rows.add_row({
|
317
|
+
"fiberId": fiber_id,
|
318
|
+
"racat": np.nan,
|
319
|
+
"deccat": np.nan,
|
320
|
+
"category": "unplugged",
|
321
|
+
})
|
322
|
+
rows.sort("fiberId")
|
315
323
|
else:
|
316
324
|
factory = PlateTarget
|
317
325
|
bad_exposure_notes = (
|
@@ -320,16 +328,16 @@ class Exposure(BaseModel):
|
|
320
328
|
.get("notes", None)
|
321
329
|
)
|
322
330
|
if bad_exposure_notes == "missing_plug_map_file":
|
323
|
-
|
331
|
+
rows = []
|
324
332
|
else:
|
325
|
-
|
326
|
-
if
|
333
|
+
rows = match_planned_to_plugged(self.plate_hole_map, self.plug_map)
|
334
|
+
if rows:
|
327
335
|
# Plugged MJD is necessary to understand where the fiber mapping
|
328
336
|
# went wrong in early plate era.
|
329
|
-
|
330
|
-
|
337
|
+
rows["plugged_mjd"] = self.plugged_mjd
|
338
|
+
rows["observatory"] = self.observatory
|
331
339
|
|
332
|
-
self._targets = tuple([factory(**r) for r in
|
340
|
+
self._targets = tuple([factory(**r) for r in rows])
|
333
341
|
else:
|
334
342
|
self._targets = tuple()
|
335
343
|
return self._targets
|
@@ -33,7 +33,8 @@ Category = Literal[
|
|
33
33
|
"sky_boss",
|
34
34
|
"standard_apogee",
|
35
35
|
"standard_boss",
|
36
|
-
"open_fiber"
|
36
|
+
"open_fiber",
|
37
|
+
"unplugged",
|
37
38
|
]
|
38
39
|
|
39
40
|
HoleType = Literal[
|
@@ -56,7 +57,8 @@ HoleType = Literal[
|
|
56
57
|
"apogee_south",
|
57
58
|
"bosshalf",
|
58
59
|
"boss_shared",
|
59
|
-
"fps"
|
60
|
+
"fps",
|
61
|
+
"unplugged",
|
60
62
|
]
|
61
63
|
|
62
64
|
ObjType = Literal[
|
@@ -17,16 +17,33 @@ def sanitise_twomass_designation(v):
|
|
17
17
|
return ""
|
18
18
|
return v
|
19
19
|
|
20
|
-
def match_planned_to_plugged(planned, plugged, tol=1e-5):
|
21
20
|
|
21
|
+
def match_planned_to_plugged(planned, plugged, tol=1e-5, enforce_300=True):
|
22
|
+
|
23
|
+
unplugged_dict = {
|
24
|
+
"holeType": "unplugged",
|
25
|
+
"holetype": "unplugged",
|
26
|
+
"targettype": "unplugged",
|
27
|
+
"ra": np.nan,
|
28
|
+
"dec": np.nan,
|
29
|
+
"objType": "na",
|
30
|
+
}
|
22
31
|
is_apogee = (
|
23
32
|
(planned["holetype"] == "APOGEE")
|
24
33
|
| (planned["holetype"] == "APOGEE_SHARED")
|
25
34
|
| (planned["holetype"] == "APOGEE_SOUTH")
|
26
35
|
)
|
27
|
-
if not any(is_apogee):
|
36
|
+
if not np.any(is_apogee) and not enforce_300:
|
28
37
|
return []
|
29
38
|
|
39
|
+
elif not np.any(is_apogee):
|
40
|
+
rows = []
|
41
|
+
for i in range(1, 301):
|
42
|
+
unplugged_dict["fiberId"] = i
|
43
|
+
rows.append(unplugged_dict.copy())
|
44
|
+
|
45
|
+
return Table(rows=rows)
|
46
|
+
|
30
47
|
planned = planned[is_apogee]
|
31
48
|
plugged = plugged[plugged["spectrographId"] == 2]
|
32
49
|
|
@@ -50,7 +67,7 @@ def match_planned_to_plugged(planned, plugged, tol=1e-5):
|
|
50
67
|
has_match = (n_matches_to_plugged_holes == 1)
|
51
68
|
planned_hole_indices = np.argmin(dist[:, has_match], axis=0)
|
52
69
|
|
53
|
-
|
70
|
+
rows = hstack(
|
54
71
|
[
|
55
72
|
plugged[has_match],
|
56
73
|
planned[planned_hole_indices]
|
@@ -59,6 +76,12 @@ def match_planned_to_plugged(planned, plugged, tol=1e-5):
|
|
59
76
|
uniq_col_name="{table_name}{col_name}",
|
60
77
|
table_names=("", "planned_")
|
61
78
|
)
|
79
|
+
if enforce_300 and len(rows) != 300:
|
80
|
+
for fiber_id in (set(range(1, 301)) - set(rows["fiberId"])):
|
81
|
+
rows.add_row({"fiberId": fiber_id, **unplugged_dict })
|
82
|
+
rows.sort("fiberId")
|
83
|
+
|
84
|
+
return rows
|
62
85
|
|
63
86
|
|
64
87
|
def get_headers(path, head=20_000):
|
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
|