anemoi-datasets 0.5.25__py3-none-any.whl → 0.5.27__py3-none-any.whl
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.
- anemoi/datasets/__init__.py +1 -2
- anemoi/datasets/_version.py +16 -3
- anemoi/datasets/commands/check.py +1 -1
- anemoi/datasets/commands/copy.py +1 -2
- anemoi/datasets/commands/create.py +1 -1
- anemoi/datasets/commands/grib-index.py +1 -1
- anemoi/datasets/commands/inspect.py +27 -35
- anemoi/datasets/commands/validate.py +59 -0
- anemoi/datasets/compute/recentre.py +3 -6
- anemoi/datasets/create/__init__.py +22 -25
- anemoi/datasets/create/check.py +10 -12
- anemoi/datasets/create/chunks.py +1 -2
- anemoi/datasets/create/config.py +3 -6
- anemoi/datasets/create/filter.py +21 -24
- anemoi/datasets/create/input/__init__.py +1 -2
- anemoi/datasets/create/input/action.py +3 -5
- anemoi/datasets/create/input/concat.py +5 -8
- anemoi/datasets/create/input/context.py +3 -6
- anemoi/datasets/create/input/data_sources.py +5 -8
- anemoi/datasets/create/input/empty.py +1 -2
- anemoi/datasets/create/input/filter.py +2 -3
- anemoi/datasets/create/input/function.py +1 -2
- anemoi/datasets/create/input/join.py +4 -5
- anemoi/datasets/create/input/misc.py +4 -6
- anemoi/datasets/create/input/repeated_dates.py +13 -18
- anemoi/datasets/create/input/result.py +29 -33
- anemoi/datasets/create/input/step.py +6 -24
- anemoi/datasets/create/input/template.py +3 -4
- anemoi/datasets/create/input/trace.py +1 -1
- anemoi/datasets/create/patch.py +1 -2
- anemoi/datasets/create/persistent.py +3 -5
- anemoi/datasets/create/size.py +1 -3
- anemoi/datasets/create/sources/accumulations.py +47 -52
- anemoi/datasets/create/sources/accumulations2.py +4 -8
- anemoi/datasets/create/sources/constants.py +1 -3
- anemoi/datasets/create/sources/empty.py +1 -2
- anemoi/datasets/create/sources/fdb.py +133 -0
- anemoi/datasets/create/sources/forcings.py +1 -2
- anemoi/datasets/create/sources/grib.py +6 -10
- anemoi/datasets/create/sources/grib_index.py +13 -15
- anemoi/datasets/create/sources/hindcasts.py +2 -5
- anemoi/datasets/create/sources/legacy.py +1 -1
- anemoi/datasets/create/sources/mars.py +17 -21
- anemoi/datasets/create/sources/netcdf.py +1 -2
- anemoi/datasets/create/sources/opendap.py +1 -3
- anemoi/datasets/create/sources/patterns.py +4 -6
- anemoi/datasets/create/sources/planetary_computer.py +44 -0
- anemoi/datasets/create/sources/recentre.py +8 -11
- anemoi/datasets/create/sources/source.py +3 -6
- anemoi/datasets/create/sources/tendencies.py +2 -5
- anemoi/datasets/create/sources/xarray.py +4 -6
- anemoi/datasets/create/sources/xarray_support/__init__.py +15 -32
- anemoi/datasets/create/sources/xarray_support/coordinates.py +16 -12
- anemoi/datasets/create/sources/xarray_support/field.py +17 -16
- anemoi/datasets/create/sources/xarray_support/fieldlist.py +11 -15
- anemoi/datasets/create/sources/xarray_support/flavour.py +83 -45
- anemoi/datasets/create/sources/xarray_support/grid.py +15 -9
- anemoi/datasets/create/sources/xarray_support/metadata.py +19 -128
- anemoi/datasets/create/sources/xarray_support/patch.py +47 -6
- anemoi/datasets/create/sources/xarray_support/time.py +10 -13
- anemoi/datasets/create/sources/xarray_support/variable.py +27 -23
- anemoi/datasets/create/sources/xarray_zarr.py +1 -2
- anemoi/datasets/create/sources/zenodo.py +3 -5
- anemoi/datasets/create/statistics/__init__.py +3 -6
- anemoi/datasets/create/testing.py +2 -74
- anemoi/datasets/create/typing.py +1 -2
- anemoi/datasets/create/utils.py +1 -2
- anemoi/datasets/create/zarr.py +7 -2
- anemoi/datasets/data/__init__.py +15 -6
- anemoi/datasets/data/complement.py +52 -23
- anemoi/datasets/data/concat.py +5 -8
- anemoi/datasets/data/dataset.py +42 -47
- anemoi/datasets/data/debug.py +7 -9
- anemoi/datasets/data/ensemble.py +4 -6
- anemoi/datasets/data/fill_missing.py +7 -10
- anemoi/datasets/data/forwards.py +30 -28
- anemoi/datasets/data/grids.py +12 -16
- anemoi/datasets/data/indexing.py +9 -12
- anemoi/datasets/data/interpolate.py +7 -15
- anemoi/datasets/data/join.py +8 -12
- anemoi/datasets/data/masked.py +6 -11
- anemoi/datasets/data/merge.py +5 -9
- anemoi/datasets/data/misc.py +41 -45
- anemoi/datasets/data/missing.py +11 -16
- anemoi/datasets/data/observations/__init__.py +8 -14
- anemoi/datasets/data/padded.py +3 -5
- anemoi/datasets/data/records/backends/__init__.py +2 -2
- anemoi/datasets/data/rescale.py +5 -12
- anemoi/datasets/data/select.py +13 -16
- anemoi/datasets/data/statistics.py +4 -7
- anemoi/datasets/data/stores.py +23 -77
- anemoi/datasets/data/subset.py +8 -11
- anemoi/datasets/data/unchecked.py +7 -11
- anemoi/datasets/data/xy.py +25 -21
- anemoi/datasets/dates/__init__.py +13 -18
- anemoi/datasets/dates/groups.py +7 -10
- anemoi/datasets/grids.py +11 -12
- anemoi/datasets/testing.py +93 -7
- anemoi/datasets/validate.py +598 -0
- {anemoi_datasets-0.5.25.dist-info → anemoi_datasets-0.5.27.dist-info}/METADATA +5 -4
- anemoi_datasets-0.5.27.dist-info/RECORD +134 -0
- anemoi/datasets/create/filters/__init__.py +0 -33
- anemoi/datasets/create/filters/empty.py +0 -37
- anemoi/datasets/create/filters/legacy.py +0 -93
- anemoi/datasets/create/filters/noop.py +0 -37
- anemoi/datasets/create/filters/orog_to_z.py +0 -58
- anemoi/datasets/create/filters/pressure_level_relative_humidity_to_specific_humidity.py +0 -83
- anemoi/datasets/create/filters/pressure_level_specific_humidity_to_relative_humidity.py +0 -84
- anemoi/datasets/create/filters/rename.py +0 -205
- anemoi/datasets/create/filters/rotate_winds.py +0 -105
- anemoi/datasets/create/filters/single_level_dewpoint_to_relative_humidity.py +0 -78
- anemoi/datasets/create/filters/single_level_relative_humidity_to_dewpoint.py +0 -84
- anemoi/datasets/create/filters/single_level_relative_humidity_to_specific_humidity.py +0 -163
- anemoi/datasets/create/filters/single_level_specific_humidity_to_relative_humidity.py +0 -451
- anemoi/datasets/create/filters/speeddir_to_uv.py +0 -95
- anemoi/datasets/create/filters/sum.py +0 -68
- anemoi/datasets/create/filters/transform.py +0 -51
- anemoi/datasets/create/filters/unrotate_winds.py +0 -105
- anemoi/datasets/create/filters/uv_to_speeddir.py +0 -94
- anemoi/datasets/create/filters/wz_to_w.py +0 -98
- anemoi/datasets/utils/__init__.py +0 -8
- anemoi_datasets-0.5.25.dist-info/RECORD +0 -150
- {anemoi_datasets-0.5.25.dist-info → anemoi_datasets-0.5.27.dist-info}/WHEEL +0 -0
- {anemoi_datasets-0.5.25.dist-info → anemoi_datasets-0.5.27.dist-info}/entry_points.txt +0 -0
- {anemoi_datasets-0.5.25.dist-info → anemoi_datasets-0.5.27.dist-info}/licenses/LICENSE +0 -0
- {anemoi_datasets-0.5.25.dist-info → anemoi_datasets-0.5.27.dist-info}/top_level.txt +0 -0
|
@@ -11,11 +11,8 @@
|
|
|
11
11
|
import logging
|
|
12
12
|
from abc import ABC
|
|
13
13
|
from abc import abstractmethod
|
|
14
|
+
from collections.abc import Hashable
|
|
14
15
|
from typing import Any
|
|
15
|
-
from typing import Dict
|
|
16
|
-
from typing import Hashable
|
|
17
|
-
from typing import Optional
|
|
18
|
-
from typing import Tuple
|
|
19
16
|
|
|
20
17
|
import xarray as xr
|
|
21
18
|
from anemoi.utils.config import DotDict
|
|
@@ -26,6 +23,7 @@ from .coordinates import EnsembleCoordinate
|
|
|
26
23
|
from .coordinates import LatitudeCoordinate
|
|
27
24
|
from .coordinates import LevelCoordinate
|
|
28
25
|
from .coordinates import LongitudeCoordinate
|
|
26
|
+
from .coordinates import PointCoordinate
|
|
29
27
|
from .coordinates import ScalarCoordinate
|
|
30
28
|
from .coordinates import StepCoordinate
|
|
31
29
|
from .coordinates import TimeCoordinate
|
|
@@ -60,11 +58,11 @@ class CoordinateGuesser(ABC):
|
|
|
60
58
|
The dataset to guess coordinates from.
|
|
61
59
|
"""
|
|
62
60
|
self.ds = ds
|
|
63
|
-
self._coordinate_cache:
|
|
64
|
-
self._grid_cache:
|
|
61
|
+
self._coordinate_cache: dict[Hashable, Coordinate] = {}
|
|
62
|
+
self._grid_cache: dict[Hashable, Grid] = {}
|
|
65
63
|
|
|
66
64
|
@classmethod
|
|
67
|
-
def from_flavour(cls, ds: xr.Dataset, flavour:
|
|
65
|
+
def from_flavour(cls, ds: xr.Dataset, flavour: dict[str, Any] | None) -> "CoordinateGuesser":
|
|
68
66
|
"""Creates a CoordinateGuesser from a flavour.
|
|
69
67
|
|
|
70
68
|
Parameters
|
|
@@ -132,7 +130,11 @@ class CoordinateGuesser(ABC):
|
|
|
132
130
|
units=units,
|
|
133
131
|
)
|
|
134
132
|
|
|
135
|
-
d:
|
|
133
|
+
d: Coordinate | None = None
|
|
134
|
+
|
|
135
|
+
d = self._is_point(coordinate, attributes)
|
|
136
|
+
if d is not None:
|
|
137
|
+
return d
|
|
136
138
|
|
|
137
139
|
d = self._is_longitude(coordinate, attributes)
|
|
138
140
|
if d is not None:
|
|
@@ -209,7 +211,7 @@ class CoordinateGuesser(ABC):
|
|
|
209
211
|
|
|
210
212
|
raise NotImplementedError(f"Cannot establish grid {coordinates}")
|
|
211
213
|
|
|
212
|
-
def _check_dims(self, variable: Any, x_or_lon: Any, y_or_lat: Any) ->
|
|
214
|
+
def _check_dims(self, variable: Any, x_or_lon: Any, y_or_lat: Any) -> tuple[Any, bool]:
|
|
213
215
|
"""Checks the dimensions of the variable against the coordinates.
|
|
214
216
|
|
|
215
217
|
Parameters
|
|
@@ -308,9 +310,9 @@ class CoordinateGuesser(ABC):
|
|
|
308
310
|
return self._grid_cache[(x.name, y.name, dim_vars)]
|
|
309
311
|
|
|
310
312
|
grid_mapping = variable.attrs.get("grid_mapping", None)
|
|
311
|
-
if grid_mapping is not None:
|
|
312
|
-
|
|
313
|
-
|
|
313
|
+
# if grid_mapping is not None:
|
|
314
|
+
# print(f"grid_mapping: {grid_mapping}")
|
|
315
|
+
# print(self.ds[grid_mapping])
|
|
314
316
|
|
|
315
317
|
if grid_mapping is None:
|
|
316
318
|
LOG.warning(f"No 'grid_mapping' attribute provided for '{variable.name}'")
|
|
@@ -357,7 +359,7 @@ class CoordinateGuesser(ABC):
|
|
|
357
359
|
grid_mapping = self.ds.attrs["crs"]
|
|
358
360
|
LOG.warning(f"Using CRS {grid_mapping} from global attributes")
|
|
359
361
|
|
|
360
|
-
grid:
|
|
362
|
+
grid: Grid | None = None
|
|
361
363
|
if grid_mapping is not None:
|
|
362
364
|
|
|
363
365
|
grid_mapping = dict(self.ds[grid_mapping].attrs)
|
|
@@ -375,7 +377,7 @@ class CoordinateGuesser(ABC):
|
|
|
375
377
|
raise NotImplementedError(f"Unstructured grid {x.name} {y.name}")
|
|
376
378
|
|
|
377
379
|
@abstractmethod
|
|
378
|
-
def _is_longitude(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
380
|
+
def _is_longitude(self, c: xr.DataArray, attributes: CoordinateAttributes) -> LongitudeCoordinate | None:
|
|
379
381
|
"""Checks if the coordinate is a longitude.
|
|
380
382
|
|
|
381
383
|
Parameters
|
|
@@ -393,7 +395,11 @@ class CoordinateGuesser(ABC):
|
|
|
393
395
|
pass
|
|
394
396
|
|
|
395
397
|
@abstractmethod
|
|
396
|
-
def
|
|
398
|
+
def _is_point(self, c: xr.DataArray, attributes: CoordinateAttributes) -> PointCoordinate | None:
|
|
399
|
+
pass
|
|
400
|
+
|
|
401
|
+
@abstractmethod
|
|
402
|
+
def _is_latitude(self, c: xr.DataArray, attributes: CoordinateAttributes) -> LatitudeCoordinate | None:
|
|
397
403
|
"""Checks if the coordinate is a latitude.
|
|
398
404
|
|
|
399
405
|
Parameters
|
|
@@ -411,7 +417,7 @@ class CoordinateGuesser(ABC):
|
|
|
411
417
|
pass
|
|
412
418
|
|
|
413
419
|
@abstractmethod
|
|
414
|
-
def _is_x(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
420
|
+
def _is_x(self, c: xr.DataArray, attributes: CoordinateAttributes) -> XCoordinate | None:
|
|
415
421
|
"""Checks if the coordinate is an x coordinate.
|
|
416
422
|
|
|
417
423
|
Parameters
|
|
@@ -429,7 +435,7 @@ class CoordinateGuesser(ABC):
|
|
|
429
435
|
pass
|
|
430
436
|
|
|
431
437
|
@abstractmethod
|
|
432
|
-
def _is_y(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
438
|
+
def _is_y(self, c: xr.DataArray, attributes: CoordinateAttributes) -> YCoordinate | None:
|
|
433
439
|
"""Checks if the coordinate is a y coordinate.
|
|
434
440
|
|
|
435
441
|
Parameters
|
|
@@ -447,7 +453,7 @@ class CoordinateGuesser(ABC):
|
|
|
447
453
|
pass
|
|
448
454
|
|
|
449
455
|
@abstractmethod
|
|
450
|
-
def _is_time(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
456
|
+
def _is_time(self, c: xr.DataArray, attributes: CoordinateAttributes) -> TimeCoordinate | None:
|
|
451
457
|
"""Checks if the coordinate is a time coordinate.
|
|
452
458
|
|
|
453
459
|
Parameters
|
|
@@ -465,7 +471,7 @@ class CoordinateGuesser(ABC):
|
|
|
465
471
|
pass
|
|
466
472
|
|
|
467
473
|
@abstractmethod
|
|
468
|
-
def _is_date(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
474
|
+
def _is_date(self, c: xr.DataArray, attributes: CoordinateAttributes) -> DateCoordinate | None:
|
|
469
475
|
"""Checks if the coordinate is a date coordinate.
|
|
470
476
|
|
|
471
477
|
Parameters
|
|
@@ -483,7 +489,7 @@ class CoordinateGuesser(ABC):
|
|
|
483
489
|
pass
|
|
484
490
|
|
|
485
491
|
@abstractmethod
|
|
486
|
-
def _is_step(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
492
|
+
def _is_step(self, c: xr.DataArray, attributes: CoordinateAttributes) -> StepCoordinate | None:
|
|
487
493
|
"""Checks if the coordinate is a step coordinate.
|
|
488
494
|
|
|
489
495
|
Parameters
|
|
@@ -501,7 +507,7 @@ class CoordinateGuesser(ABC):
|
|
|
501
507
|
pass
|
|
502
508
|
|
|
503
509
|
@abstractmethod
|
|
504
|
-
def _is_level(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
510
|
+
def _is_level(self, c: xr.DataArray, attributes: CoordinateAttributes) -> LevelCoordinate | None:
|
|
505
511
|
"""Checks if the coordinate is a level coordinate.
|
|
506
512
|
|
|
507
513
|
Parameters
|
|
@@ -519,7 +525,7 @@ class CoordinateGuesser(ABC):
|
|
|
519
525
|
pass
|
|
520
526
|
|
|
521
527
|
@abstractmethod
|
|
522
|
-
def _is_number(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
528
|
+
def _is_number(self, c: xr.DataArray, attributes: CoordinateAttributes) -> EnsembleCoordinate | None:
|
|
523
529
|
"""Checks if the coordinate is an ensemble coordinate.
|
|
524
530
|
|
|
525
531
|
Parameters
|
|
@@ -550,7 +556,16 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
550
556
|
"""
|
|
551
557
|
super().__init__(ds)
|
|
552
558
|
|
|
553
|
-
def
|
|
559
|
+
def _is_point(self, c: xr.DataArray, attributes: CoordinateAttributes) -> PointCoordinate | None:
|
|
560
|
+
if attributes.standard_name in ["cell", "station", "poi", "point"]:
|
|
561
|
+
return PointCoordinate(c)
|
|
562
|
+
|
|
563
|
+
if attributes.name in ["cell", "station", "poi", "point"]: # WeatherBench
|
|
564
|
+
return PointCoordinate(c)
|
|
565
|
+
|
|
566
|
+
return None
|
|
567
|
+
|
|
568
|
+
def _is_longitude(self, c: xr.DataArray, attributes: CoordinateAttributes) -> LongitudeCoordinate | None:
|
|
554
569
|
"""Checks if the coordinate is a longitude.
|
|
555
570
|
|
|
556
571
|
Parameters
|
|
@@ -579,7 +594,7 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
579
594
|
|
|
580
595
|
return None
|
|
581
596
|
|
|
582
|
-
def _is_latitude(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
597
|
+
def _is_latitude(self, c: xr.DataArray, attributes: CoordinateAttributes) -> LatitudeCoordinate | None:
|
|
583
598
|
"""Checks if the coordinate is a latitude.
|
|
584
599
|
|
|
585
600
|
Parameters
|
|
@@ -608,7 +623,7 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
608
623
|
|
|
609
624
|
return None
|
|
610
625
|
|
|
611
|
-
def _is_x(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
626
|
+
def _is_x(self, c: xr.DataArray, attributes: CoordinateAttributes) -> XCoordinate | None:
|
|
612
627
|
"""Checks if the coordinate is an x coordinate.
|
|
613
628
|
|
|
614
629
|
Parameters
|
|
@@ -631,7 +646,7 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
631
646
|
|
|
632
647
|
return None
|
|
633
648
|
|
|
634
|
-
def _is_y(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
649
|
+
def _is_y(self, c: xr.DataArray, attributes: CoordinateAttributes) -> YCoordinate | None:
|
|
635
650
|
"""Checks if the coordinate is a y coordinate.
|
|
636
651
|
|
|
637
652
|
Parameters
|
|
@@ -654,7 +669,7 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
654
669
|
|
|
655
670
|
return None
|
|
656
671
|
|
|
657
|
-
def _is_time(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
672
|
+
def _is_time(self, c: xr.DataArray, attributes: CoordinateAttributes) -> TimeCoordinate | None:
|
|
658
673
|
"""Checks if the coordinate is a time coordinate.
|
|
659
674
|
|
|
660
675
|
Parameters
|
|
@@ -677,7 +692,7 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
677
692
|
|
|
678
693
|
return None
|
|
679
694
|
|
|
680
|
-
def _is_date(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
695
|
+
def _is_date(self, c: xr.DataArray, attributes: CoordinateAttributes) -> DateCoordinate | None:
|
|
681
696
|
"""Checks if the coordinate is a date coordinate.
|
|
682
697
|
|
|
683
698
|
Parameters
|
|
@@ -700,7 +715,7 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
700
715
|
|
|
701
716
|
return None
|
|
702
717
|
|
|
703
|
-
def _is_step(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
718
|
+
def _is_step(self, c: xr.DataArray, attributes: CoordinateAttributes) -> StepCoordinate | None:
|
|
704
719
|
"""Checks if the coordinate is a step coordinate.
|
|
705
720
|
|
|
706
721
|
Parameters
|
|
@@ -726,7 +741,7 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
726
741
|
|
|
727
742
|
return None
|
|
728
743
|
|
|
729
|
-
def _is_level(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
744
|
+
def _is_level(self, c: xr.DataArray, attributes: CoordinateAttributes) -> LevelCoordinate | None:
|
|
730
745
|
"""Checks if the coordinate is a level coordinate.
|
|
731
746
|
|
|
732
747
|
Parameters
|
|
@@ -744,12 +759,18 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
744
759
|
if attributes.standard_name == "atmosphere_hybrid_sigma_pressure_coordinate":
|
|
745
760
|
return LevelCoordinate(c, "ml")
|
|
746
761
|
|
|
762
|
+
if attributes.standard_name == "model_level_number":
|
|
763
|
+
return LevelCoordinate(c, "ml")
|
|
764
|
+
|
|
747
765
|
if attributes.long_name == "height" and attributes.units == "m":
|
|
748
766
|
return LevelCoordinate(c, "height")
|
|
749
767
|
|
|
750
768
|
if attributes.standard_name == "air_pressure" and attributes.units == "hPa":
|
|
751
769
|
return LevelCoordinate(c, "pl")
|
|
752
770
|
|
|
771
|
+
if attributes.long_name == "pressure" and attributes.units in ["hPa", "Pa"]:
|
|
772
|
+
return LevelCoordinate(c, "pl")
|
|
773
|
+
|
|
753
774
|
if attributes.name == "level":
|
|
754
775
|
return LevelCoordinate(c, "pl")
|
|
755
776
|
|
|
@@ -759,12 +780,9 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
759
780
|
if attributes.standard_name == "depth":
|
|
760
781
|
return LevelCoordinate(c, "depth")
|
|
761
782
|
|
|
762
|
-
if attributes.name == "vertical" and attributes.units == "hPa":
|
|
763
|
-
return LevelCoordinate(c, "pl")
|
|
764
|
-
|
|
765
783
|
return None
|
|
766
784
|
|
|
767
|
-
def _is_number(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
785
|
+
def _is_number(self, c: xr.DataArray, attributes: CoordinateAttributes) -> EnsembleCoordinate | None:
|
|
768
786
|
"""Checks if the coordinate is an ensemble coordinate.
|
|
769
787
|
|
|
770
788
|
Parameters
|
|
@@ -788,7 +806,7 @@ class DefaultCoordinateGuesser(CoordinateGuesser):
|
|
|
788
806
|
class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
789
807
|
"""Implementation of CoordinateGuesser that uses a flavour for guessing."""
|
|
790
808
|
|
|
791
|
-
def __init__(self, ds: xr.Dataset, flavour:
|
|
809
|
+
def __init__(self, ds: xr.Dataset, flavour: dict[str, Any]) -> None:
|
|
792
810
|
"""Initializes the FlavourCoordinateGuesser.
|
|
793
811
|
|
|
794
812
|
Parameters
|
|
@@ -801,7 +819,7 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
801
819
|
super().__init__(ds)
|
|
802
820
|
self.flavour = flavour
|
|
803
821
|
|
|
804
|
-
def _match(self, c: xr.DataArray, key: str, attributes: CoordinateAttributes) ->
|
|
822
|
+
def _match(self, c: xr.DataArray, key: str, attributes: CoordinateAttributes) -> dict[str, Any] | None:
|
|
805
823
|
"""Matches the coordinate against the flavour rules.
|
|
806
824
|
|
|
807
825
|
Parameters
|
|
@@ -836,7 +854,7 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
836
854
|
|
|
837
855
|
return None
|
|
838
856
|
|
|
839
|
-
def _is_longitude(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
857
|
+
def _is_longitude(self, c: xr.DataArray, attributes: CoordinateAttributes) -> LongitudeCoordinate | None:
|
|
840
858
|
"""Checks if the coordinate is a longitude using the flavour rules.
|
|
841
859
|
|
|
842
860
|
Parameters
|
|
@@ -856,7 +874,7 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
856
874
|
|
|
857
875
|
return None
|
|
858
876
|
|
|
859
|
-
def _is_latitude(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
877
|
+
def _is_latitude(self, c: xr.DataArray, attributes: CoordinateAttributes) -> LatitudeCoordinate | None:
|
|
860
878
|
"""Checks if the coordinate is a latitude using the flavour rules.
|
|
861
879
|
|
|
862
880
|
Parameters
|
|
@@ -876,7 +894,7 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
876
894
|
|
|
877
895
|
return None
|
|
878
896
|
|
|
879
|
-
def _is_x(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
897
|
+
def _is_x(self, c: xr.DataArray, attributes: CoordinateAttributes) -> XCoordinate | None:
|
|
880
898
|
"""Checks if the coordinate is an x coordinate using the flavour rules.
|
|
881
899
|
|
|
882
900
|
Parameters
|
|
@@ -896,7 +914,7 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
896
914
|
|
|
897
915
|
return None
|
|
898
916
|
|
|
899
|
-
def _is_y(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
917
|
+
def _is_y(self, c: xr.DataArray, attributes: CoordinateAttributes) -> YCoordinate | None:
|
|
900
918
|
"""Checks if the coordinate is a y coordinate using the flavour rules.
|
|
901
919
|
|
|
902
920
|
Parameters
|
|
@@ -916,7 +934,7 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
916
934
|
|
|
917
935
|
return None
|
|
918
936
|
|
|
919
|
-
def _is_time(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
937
|
+
def _is_time(self, c: xr.DataArray, attributes: CoordinateAttributes) -> TimeCoordinate | None:
|
|
920
938
|
"""Checks if the coordinate is a time coordinate using the flavour rules.
|
|
921
939
|
|
|
922
940
|
Parameters
|
|
@@ -936,7 +954,7 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
936
954
|
|
|
937
955
|
return None
|
|
938
956
|
|
|
939
|
-
def _is_step(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
957
|
+
def _is_step(self, c: xr.DataArray, attributes: CoordinateAttributes) -> StepCoordinate | None:
|
|
940
958
|
"""Checks if the coordinate is a step coordinate using the flavour rules.
|
|
941
959
|
|
|
942
960
|
Parameters
|
|
@@ -956,7 +974,7 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
956
974
|
|
|
957
975
|
return None
|
|
958
976
|
|
|
959
|
-
def _is_date(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
977
|
+
def _is_date(self, c: xr.DataArray, attributes: CoordinateAttributes) -> DateCoordinate | None:
|
|
960
978
|
"""Checks if the coordinate is a date coordinate using the flavour rules.
|
|
961
979
|
|
|
962
980
|
Parameters
|
|
@@ -976,7 +994,7 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
976
994
|
|
|
977
995
|
return None
|
|
978
996
|
|
|
979
|
-
def _is_level(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
997
|
+
def _is_level(self, c: xr.DataArray, attributes: CoordinateAttributes) -> LevelCoordinate | None:
|
|
980
998
|
"""Checks if the coordinate is a level coordinate using the flavour rules.
|
|
981
999
|
|
|
982
1000
|
Parameters
|
|
@@ -1021,7 +1039,7 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
1021
1039
|
|
|
1022
1040
|
raise NotImplementedError(f"levtype for {c=}")
|
|
1023
1041
|
|
|
1024
|
-
def _is_number(self, c: xr.DataArray, attributes: CoordinateAttributes) ->
|
|
1042
|
+
def _is_number(self, c: xr.DataArray, attributes: CoordinateAttributes) -> EnsembleCoordinate | None:
|
|
1025
1043
|
"""Checks if the coordinate is an ensemble coordinate using the flavour rules.
|
|
1026
1044
|
|
|
1027
1045
|
Parameters
|
|
@@ -1040,3 +1058,23 @@ class FlavourCoordinateGuesser(CoordinateGuesser):
|
|
|
1040
1058
|
return EnsembleCoordinate(c)
|
|
1041
1059
|
|
|
1042
1060
|
return None
|
|
1061
|
+
|
|
1062
|
+
def _is_point(self, c: xr.DataArray, attributes: CoordinateAttributes) -> PointCoordinate | None:
|
|
1063
|
+
"""Checks if the coordinate is a point coordinate using the flavour rules.
|
|
1064
|
+
|
|
1065
|
+
Parameters
|
|
1066
|
+
----------
|
|
1067
|
+
c : xr.DataArray
|
|
1068
|
+
The coordinate to check.
|
|
1069
|
+
attributes : CoordinateAttributes
|
|
1070
|
+
The attributes of the coordinate.
|
|
1071
|
+
|
|
1072
|
+
Returns
|
|
1073
|
+
-------
|
|
1074
|
+
Optional[PointCoordinate]
|
|
1075
|
+
The StepCoorPointCoordinateinate if matched, else None.
|
|
1076
|
+
"""
|
|
1077
|
+
if self._match(c, "point", attributes):
|
|
1078
|
+
return PointCoordinate(c)
|
|
1079
|
+
|
|
1080
|
+
return None
|
|
@@ -13,7 +13,6 @@ from abc import ABC
|
|
|
13
13
|
from abc import abstractmethod
|
|
14
14
|
from functools import cached_property
|
|
15
15
|
from typing import Any
|
|
16
|
-
from typing import Tuple
|
|
17
16
|
|
|
18
17
|
import numpy as np
|
|
19
18
|
|
|
@@ -38,7 +37,7 @@ class Grid(ABC):
|
|
|
38
37
|
|
|
39
38
|
@property
|
|
40
39
|
@abstractmethod
|
|
41
|
-
def grid_points(self) ->
|
|
40
|
+
def grid_points(self) -> tuple[Any, Any]:
|
|
42
41
|
"""Get the grid points."""
|
|
43
42
|
pass
|
|
44
43
|
|
|
@@ -85,7 +84,7 @@ class MeshedGrid(LatLonGrid):
|
|
|
85
84
|
"""Grid class for meshed latitude and longitude coordinates."""
|
|
86
85
|
|
|
87
86
|
@cached_property
|
|
88
|
-
def grid_points(self) ->
|
|
87
|
+
def grid_points(self) -> tuple[Any, Any]:
|
|
89
88
|
"""Get the grid points for the meshed grid."""
|
|
90
89
|
|
|
91
90
|
if self.variable_dims == (self.lon.variable.name, self.lat.variable.name):
|
|
@@ -128,7 +127,7 @@ class UnstructuredGrid(LatLonGrid):
|
|
|
128
127
|
assert set(self.variable_dims) == set(self.grid_dims), (self.variable_dims, self.grid_dims)
|
|
129
128
|
|
|
130
129
|
@cached_property
|
|
131
|
-
def grid_points(self) ->
|
|
130
|
+
def grid_points(self) -> tuple[Any, Any]:
|
|
132
131
|
"""Get the grid points for the unstructured grid."""
|
|
133
132
|
assert 1 <= len(self.variable_dims) <= 2
|
|
134
133
|
|
|
@@ -191,7 +190,7 @@ class MeshProjectionGrid(ProjectionGrid):
|
|
|
191
190
|
"""Grid class for meshed projected coordinates."""
|
|
192
191
|
|
|
193
192
|
@cached_property
|
|
194
|
-
def grid_points(self) ->
|
|
193
|
+
def grid_points(self) -> tuple[Any, Any]:
|
|
195
194
|
"""Get the grid points for the mesh projection grid."""
|
|
196
195
|
transformer = self.transformer()
|
|
197
196
|
xv, yv = np.meshgrid(self.x.variable.values, self.y.variable.values) # , indexing="ij")
|
|
@@ -199,10 +198,17 @@ class MeshProjectionGrid(ProjectionGrid):
|
|
|
199
198
|
return lat.flatten(), lon.flatten()
|
|
200
199
|
|
|
201
200
|
|
|
202
|
-
class UnstructuredProjectionGrid(
|
|
201
|
+
class UnstructuredProjectionGrid(ProjectionGrid):
|
|
203
202
|
"""Grid class for unstructured projected coordinates."""
|
|
204
203
|
|
|
205
204
|
@cached_property
|
|
206
|
-
def grid_points(self) ->
|
|
207
|
-
"""Get the grid points for the unstructured
|
|
208
|
-
|
|
205
|
+
def grid_points(self) -> tuple[Any, Any]:
|
|
206
|
+
"""Get the grid points for the unstructured grid."""
|
|
207
|
+
if self.projection == "epsg:4326":
|
|
208
|
+
# WGS84, no transformation needed
|
|
209
|
+
return self.y.variable.values.flatten(), self.x.variable.values.flatten()
|
|
210
|
+
transformer = self.transformer()
|
|
211
|
+
xv, yv = np.meshgrid(self.x.variable.values, self.y.variable.values) # , indexing="ij")
|
|
212
|
+
lon, lat = transformer.transform(xv, yv)
|
|
213
|
+
|
|
214
|
+
return lat.flatten(), lon.flatten()
|