Coverage for C: \ Users \ peaco \ OneDrive \ Documents \ GitHub \ mt_metadata \ mt_metadata \ common \ location.py: 100%
40 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-10 00:11 -0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-10 00:11 -0800
1# =====================================================
2# Imports
3# =====================================================
4from typing import Annotated
6from pydantic import AliasChoices, Field, field_validator, ValidationInfo
7from pyproj import CRS
9from mt_metadata.base import MetadataBase
10from mt_metadata.common import Declination, GeographicLocation
11from mt_metadata.utils.location_helpers import validate_position
14# =====================================================
17class BasicLocationNoDatum(MetadataBase):
18 """
19 A partial location class that only includes the latitude, longitude, and elevation.
20 This is used to avoid circular imports.
21 """
23 latitude: Annotated[
24 float | None,
25 Field(
26 default=0.0,
27 description="Latitude of the location.",
28 validation_alias=AliasChoices("latitude", "lat"),
29 json_schema_extra={
30 "units": "degrees",
31 "required": False,
32 "examples": ["12.324"],
33 },
34 ),
35 ]
37 longitude: Annotated[
38 float | None,
39 Field(
40 default=0.0,
41 description="Longitude of the location.",
42 validation_alias=AliasChoices("longitude", "lon", "long"),
43 json_schema_extra={
44 "units": "degrees",
45 "required": False,
46 "examples": ["12.324"],
47 },
48 ),
49 ]
51 elevation: Annotated[
52 float,
53 Field(
54 default=0.0,
55 description="Elevation of the location.",
56 alias=None,
57 json_schema_extra={
58 "units": "meters",
59 "required": False,
60 "examples": ["1234.0"],
61 },
62 ),
63 ]
65 @field_validator("latitude", "longitude", mode="before")
66 @classmethod
67 def validate_position(cls, value, info: ValidationInfo):
68 return validate_position(value, info.field_name)
71class BasicLocation(BasicLocationNoDatum):
72 datum: Annotated[
73 str | int,
74 Field(
75 default="WGS 84",
76 description="Datum of the location values. Usually a well known datum like WGS84.",
77 alias=None,
78 json_schema_extra={
79 "units": None,
80 "required": False,
81 "examples": ["WGS 84"],
82 },
83 ),
84 ]
86 x: Annotated[
87 float,
88 Field(
89 default=0.0,
90 description="relative distance to the center of the station",
91 validation_alias=AliasChoices("x", "easting", "east"),
92 json_schema_extra={
93 "units": "meters",
94 "required": False,
95 "examples": ["10.0"],
96 },
97 ),
98 ]
100 y: Annotated[
101 float,
102 Field(
103 default=0.0,
104 description="relative distance to the center of the station",
105 validation_alias=AliasChoices("y", "north", "northing"),
106 json_schema_extra={
107 "units": "meters",
108 "required": False,
109 "examples": ["10.0"],
110 },
111 ),
112 ]
114 z: Annotated[
115 float,
116 Field(
117 default=0.0,
118 description="relative elevation to the center of the station",
119 alias=None,
120 json_schema_extra={
121 "units": "meters",
122 "required": False,
123 "examples": ["10.0"],
124 },
125 ),
126 ]
128 @field_validator("datum", mode="before")
129 @classmethod
130 def validate_datum(cls, value: str | int) -> str:
131 """
132 Validate the datum value and convert it to the appropriate enum type.
133 """
134 try:
135 datum_crs = CRS.from_user_input(value)
136 return datum_crs.name
137 except Exception:
138 raise ValueError(
139 f"Invalid datum value: {value}. Must be a valid CRS string or identifier."
140 )
143class Location(BasicLocation):
144 """
145 Positional location of a geographic point
146 """
148 latitude_uncertainty: Annotated[
149 float,
150 Field(
151 default=0.0,
152 description="uncertainty in latitude estimation in degrees",
153 alias=None,
154 json_schema_extra={
155 "units": "degrees",
156 "required": False,
157 "examples": ["0.01"],
158 },
159 ),
160 ]
162 longitude_uncertainty: Annotated[
163 float,
164 Field(
165 default=0.0,
166 description="uncertainty in longitude estimation in degrees",
167 alias=None,
168 json_schema_extra={
169 "units": "degrees",
170 "required": False,
171 "examples": ["0.01"],
172 },
173 ),
174 ]
176 elevation_uncertainty: Annotated[
177 float,
178 Field(
179 default=0.0,
180 description="uncertainty in elevation estimation",
181 alias=None,
182 json_schema_extra={
183 "units": "meters",
184 "required": False,
185 "examples": ["0.01"],
186 },
187 ),
188 ]
190 x2: Annotated[
191 float,
192 Field(
193 default=0.0,
194 description="relative distance to the center of the station",
195 validation_alias=AliasChoices("x2", "east", "easting"),
196 json_schema_extra={
197 "units": "meters",
198 "required": False,
199 "examples": ["10.0"],
200 },
201 ),
202 ]
204 y2: Annotated[
205 float,
206 Field(
207 default=0.0,
208 description="relative distance to the center of the station",
209 validation_alias=AliasChoices("y2", "north", "northing"),
210 json_schema_extra={
211 "units": "meters",
212 "required": False,
213 "examples": ["10.0"],
214 },
215 ),
216 ]
218 z2: Annotated[
219 float,
220 Field(
221 default=0.0,
222 description="relative elevation to the center of the station",
223 alias=None,
224 json_schema_extra={
225 "units": "meters",
226 "required": False,
227 "examples": ["10.0"],
228 },
229 ),
230 ]
232 x_uncertainty: Annotated[
233 float,
234 Field(
235 default=0.0,
236 description="uncertainty in longitude estimation in x-direction",
237 alias=None,
238 json_schema_extra={
239 "units": "meters",
240 "required": False,
241 "examples": ["0.01"],
242 },
243 ),
244 ]
246 y_uncertainty: Annotated[
247 float,
248 Field(
249 default=0.0,
250 description="uncertainty in longitude estimation in y-direction",
251 alias=None,
252 json_schema_extra={
253 "units": "meters",
254 "required": False,
255 "examples": ["0.01"],
256 },
257 ),
258 ]
260 z_uncertainty: Annotated[
261 float,
262 Field(
263 default=0.0,
264 description="uncertainty in longitude estimation in z-direction",
265 alias=None,
266 json_schema_extra={
267 "units": "meters",
268 "required": False,
269 "examples": ["0.01"],
270 },
271 ),
272 ]
275class StationLocation(Location):
276 """
277 A class that represents the location of a station. It includes latitude, longitude, elevation,
278 and other related attributes.
279 """
281 declination: Annotated[
282 Declination,
283 Field(
284 default_factory=Declination, # type: ignore
285 description="Declination of the location.",
286 alias=None,
287 json_schema_extra={
288 "units": "degrees",
289 "required": False,
290 "examples": ["Declination(10.0)"],
291 },
292 ),
293 ]
295 geographic_location: Annotated[
296 GeographicLocation,
297 Field(
298 default_factory=GeographicLocation, # type: ignore
299 description="Geographic location of the station.",
300 alias=None,
301 json_schema_extra={
302 "units": None,
303 "required": False,
304 "examples": ["GeographicLocation(latitude=12.34, longitude=56.78)"],
305 },
306 ),
307 ]