Source code for ascat.grids.grid_registry

# Copyright (c) 2025, TU Wien
# All rights reserved.

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#    * Redistributions of source code must retain the above copyright notice,
#      this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in the
#      documentation and/or other materials provided with the distribution.
#    * Neither the name of TU Wien, Department of Geodesy and Geoinformation
#      nor the names of its contributors may be used to endorse or promote
#      products derived from this software without specific prior written
#      permission.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL TU WIEN DEPARTMENT OF GEODESY AND
# GEOINFORMATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from enum import Enum
from pathlib import Path
from typing import Dict, Type, Any, Tuple

from fibgrid.realization import FibGrid
from pygeogrids.netcdf import load_grid


[docs] class GridType(Enum): FIBGRID = "fibgrid" NAMED = "named"
[docs] class SingletonArgs(type): _instances: Dict[Tuple[Type, Tuple, frozenset], Any] = {} def __call__(cls, *args, **kwargs): key = (cls, args, frozenset(kwargs.items())) if key not in cls._instances: cls._instances[key] = super().__call__(*args, **kwargs) return cls._instances[key]
[docs] class GridSingleton(metaclass=SingletonArgs): __slots__ = ['grid'] def __init__(self, grid_class: Type, *args): self.grid = grid_class(*args)
[docs] class NamedFileGridRegistry: _grids: Dict[str, str] = {}
[docs] @classmethod def register(cls, grid_name: str, grid_path: str) -> None: """Register a named grid with its file path.""" cls._grids[grid_name] = Path(grid_path)
[docs] @classmethod def get(cls, grid_name: str) -> str: """Retrieve the file path for a registered grid.""" if grid_name not in cls._grids: raise KeyError(f"Grid '{grid_name}' is not registered.") return cls._grids[grid_name]
[docs] class NamedFileGrid: def __new__(cls, grid_name: str): grid_path = NamedFileGridRegistry.get(grid_name) return load_grid(grid_path)
[docs] class GridRegistry: _registry = { "fibgrid": FibGrid, "named": NamedFileGrid, }
[docs] def register( self, grid_type_name: str, grid_class: type, ): """ Register a grid class with a name for later retrieval. e.g. `register("fibgrid", FibGrid)` or `register("named", NamedFileGrid)` """ if grid_type_name in self._registry: return self._registry[grid_type_name] = grid_class
[docs] def get(self, grid_name): """ Retrieve a grid instance based on its name. The grid name can be a simple name (e.g. "fibgrid") or a more complex name with parameters (e.g. "fibgrid_0.1"). The latter will be split into the grid type and its parameters. Parameters ---------- grid_name (str): The name of the grid to retrieve. """ parts = grid_name.split("_") if len(parts) >= 2 and parts[0] == "fibgrid": grid_type = "fibgrid" grid_spacing = float(parts[1]) args = (grid_spacing,) elif len(parts) == 1: grid_type = "named" args = (grid_name,) else: grid_type = parts[0] args = tuple(parts[1:]) grid_class = self._registry.get(grid_type) if grid_class is None: raise KeyError(f"Grid {grid_name} is not registered.") return GridSingleton(grid_class, *args).grid