Coverage for python/lsst/daf/butler/registry/obscore/default_spatial.py: 94%
39 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-06 01:41 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-06 01:41 -0800
1# This file is part of daf_butler.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
22from __future__ import annotations
24__all__ = ["DefaultSpatialObsCorePlugin"]
26import warnings
27from collections.abc import Mapping
28from typing import TYPE_CHECKING, Any, Optional
30import sqlalchemy
31from lsst.daf.butler import DatasetId
32from lsst.sphgeom import ConvexPolygon, LonLat, Region
34from ...core import ddl
35from ._spatial import RegionTypeWarning, SpatialObsCorePlugin
37if TYPE_CHECKING: 37 ↛ 38line 37 didn't jump to line 38, because the condition on line 37 was never true
38 from ..interfaces import Database
39 from ._records import Record
41# Columns added/filled by this plugin
42_COLUMNS = (
43 ddl.FieldSpec(name="s_ra", dtype=sqlalchemy.Float, doc="Central right ascension, ICRS (deg)"),
44 ddl.FieldSpec(name="s_dec", dtype=sqlalchemy.Float, doc="Central declination, ICRS (deg)"),
45 ddl.FieldSpec(name="s_fov", dtype=sqlalchemy.Float, doc="Diameter (bounds) of the covered region (deg)"),
46 ddl.FieldSpec(
47 name="s_region",
48 dtype=sqlalchemy.String,
49 length=65535,
50 doc="Sky region covered by the data product (expressed in ICRS frame)",
51 ),
52)
55class DefaultSpatialObsCorePlugin(SpatialObsCorePlugin):
56 """Class for a spatial ObsCore plugin which creates standard spatial
57 obscore columns.
58 """
60 def __init__(self, *, name: str, config: Mapping[str, Any]):
61 self._name = name
63 @classmethod
64 def initialize(
65 cls, *, name: str, config: Mapping[str, Any], db: Optional[Database]
66 ) -> SpatialObsCorePlugin:
67 # docstring inherited.
68 return cls(name=name, config=config)
70 def extend_table_spec(self, table_spec: ddl.TableSpec) -> None:
71 # docstring inherited.
72 table_spec.fields.update(_COLUMNS)
74 def make_records(self, dataset_id: DatasetId, region: Optional[Region]) -> Optional[Record]:
75 # docstring inherited.
77 if region is None:
78 return None
80 record: Record = {}
82 # Get spatial parameters from the bounding circle.
83 circle = region.getBoundingCircle()
84 center = LonLat(circle.getCenter())
85 record["s_ra"] = center.getLon().asDegrees()
86 record["s_dec"] = center.getLat().asDegrees()
87 record["s_fov"] = circle.getOpeningAngle().asDegrees() * 2
89 if isinstance(region, ConvexPolygon):
90 poly = ["POLYGON ICRS"]
91 for vertex in region.getVertices():
92 lon_lat = LonLat(vertex)
93 poly += [
94 f"{lon_lat.getLon().asDegrees():.6f}",
95 f"{lon_lat.getLat().asDegrees():.6f}",
96 ]
97 record["s_region"] = " ".join(poly)
98 else:
99 warnings.warn(
100 f"Unexpected region type for obscore dataset {dataset_id}: {type(region)}",
101 category=RegionTypeWarning,
102 )
104 return record