Source code for pymt.framework.bmi_ugrid

from collections import OrderedDict

import numpy as np
import xarray as xr

from landlab.graph import (StructuredQuadGraph,
                           UniformRectilinearGraph,
                           RectilinearGraph)

COORDINATE_NAMES = ["z", "y", "x"]
INDEX_NAMES = ["k", "j", "i"]


[docs]def index_names(rank): return ["node_" + ind for ind in INDEX_NAMES[-rank:]]
[docs]def coordinate_names(rank): return ["node_" + d for d in COORDINATE_NAMES[-rank:]]
class _Base(xr.Dataset): __slots__ = "bmi", "grid_id", "grid_type", "ndim", "metadata" def __init__(self, bmi, grid_id): self.bmi = bmi self.grid_id = grid_id self.grid_type = bmi.grid_type(grid_id) self.ndim = bmi.grid_ndim(grid_id) self.metadata = OrderedDict() super(_Base, self).__init__() def set_mesh(self): self.update({"mesh": xr.DataArray(data=self.grid_id, attrs=self.metadata)}) def set_shape(self, shape): self.update({"node_shape": xr.DataArray(data=shape, dims=("rank",))}) def set_spacing(self, spacing): self.update({"node_spacing": xr.DataArray(data=spacing, dims=("rank",))}) def set_origin(self, origin): self.update({"node_origin": xr.DataArray(data=origin, dims=("rank",))}) def get_nodes(self): nodes = [] for dim_name in COORDINATE_NAMES[: -(self.ndim + 1) : -1]: data = getattr(self.bmi, "grid_" + dim_name)(self.grid_id) nodes.insert(0, data) return tuple(nodes) def set_nodes(self): coords = {} for dim_name in COORDINATE_NAMES[: -(self.ndim + 1) : -1]: data = getattr(self.bmi, "grid_" + dim_name)(self.grid_id) coord = xr.DataArray( data=data, dims=("node",), attrs={"standard_name": dim_name, "units": "m"}, ) coords["node_" + dim_name] = coord self.update(coords) def set_nodes_rectilinear(self, grid_coords): coords_at_node = np.meshgrid(*grid_coords, indexing="ij") coords = {} for axis, dim_name in enumerate(COORDINATE_NAMES[-self.ndim :]): coord = xr.DataArray( data=coords_at_node[axis].reshape(-1), dims=("node",), attrs={"standard_name": dim_name, "units": "m"}, ) coords["node_" + dim_name] = coord self.update(coords) def set_connectivity(self, data=None): if data is None: data = self.bmi.grid_face_nodes(self.grid_id) face_node_connectivity = xr.DataArray( data=data, dims=("vertex",), attrs={"standard_name": "Face-node connectivity"}, ) self.update({"face_node_connectivity": face_node_connectivity}) def set_offset(self, data=None): if data is None: data = self.bmi.grid_face_node_offset(self.grid_id) face_node_offset = xr.DataArray( data=data, dims=("face",), attrs={"standard_name": "Offset to face-node connectivity"}, ) self.update({"face_node_offset": face_node_offset}) class Scalar(_Base): __slots__ = () def __init__(self, *args): super(Scalar, self).__init__(*args) if self.ndim != 0: raise ValueError("scalar must be rank 0") self.metadata = OrderedDict( [ ("cf_role", "grid_topology"), ("long_name", "scalar value"), ("topology_dimension", self.ndim), ("type", self.grid_type), ] ) self.set_mesh() class Vector(_Base): __slots__ = () def __init__(self, *args): super(Vector, self).__init__(*args) if self.ndim != 1: raise ValueError("vector must be rank 1") self.metadata = OrderedDict( [ ("cf_role", "grid_topology"), ("long_name", "vector value"), ("topology_dimension", self.ndim), ("type", self.grid_type), ] ) self.set_mesh() class Points(_Base): __slots__ = () def __init__(self, *args): super(Points, self).__init__(*args) self.metadata = OrderedDict( [ ("cf_role", "mesh_topology"), ("long_name", "Topology data of 2D unstructured points"), ("topology_dimension", self.ndim), ("node_coordinates", "node_x node_y"), ("type", self.grid_type), ] ) self.set_mesh() self.set_nodes() class Unstructured(_Base): __slots__ = () def __init__(self, *args): super(Unstructured, self).__init__(*args) self.metadata = OrderedDict( [ ("cf_role", "mesh_topology"), ("long_name", "Topology data of 2D unstructured points"), ("topology_dimension", self.ndim), ("node_coordinates", "node_x node_y"), ("type", self.grid_type), ] ) self.set_mesh() self.set_nodes() self.set_connectivity() self.set_offset() class StructuredQuadrilateral(_Base): __slots__ = () def __init__(self, *args): super(StructuredQuadrilateral, self).__init__(*args) if self.ndim < 1 or self.ndim > 3: raise ValueError("structured_quadrilateral grid must be rank 1, 2, or 3") shape = self.bmi.grid_shape(self.grid_id) self.metadata = OrderedDict( [ ("cf_role", "grid_topology"), ( "long_name", "Topology data of {}D structured quadrilateral".format(self.ndim), ), ("topology_dimension", self.ndim), ("node_coordinates", " ".join(coordinate_names(self.ndim))), ("node_dimensions", " ".join(index_names(self.ndim))), ("type", self.grid_type), ] ) self.set_mesh() self.set_shape(shape) nodes = self.get_nodes() self.set_nodes() graph = StructuredQuadGraph(nodes, shape=tuple(shape)) self.set_connectivity(data=graph.nodes_at_patch.reshape((-1,))) self.set_offset( data=np.arange(1, graph.number_of_patches + 1, dtype=np.int32) * 4 ) class Rectilinear(_Base): __slots__ = () def __init__(self, *args): super(Rectilinear, self).__init__(*args) if self.ndim < 1 or self.ndim > 3: raise ValueError("rectilinear grid must be rank 1, 2, or 3") shape = self.bmi.grid_shape(self.grid_id) self.metadata = OrderedDict( [ ("cf_role", "grid_topology"), ( "long_name", "Topology data of {}D structured quadrilateral".format(self.ndim), ), ("topology_dimension", self.ndim), ("node_coordinates", " ".join(coordinate_names(self.ndim))), ("node_dimensions", " ".join(index_names(self.ndim))), ("type", self.grid_type), ] ) self.set_mesh() self.set_shape(shape) nodes = self.get_nodes() self.set_nodes_rectilinear(nodes) graph = RectilinearGraph(nodes) self.set_connectivity(data=graph.nodes_at_patch.reshape((-1,))) self.set_offset( data=np.arange(1, graph.number_of_patches + 1, dtype=np.int32) * 4 ) class UniformRectilinear(_Base): __slots__ = () def __init__(self, *args): super(UniformRectilinear, self).__init__(*args) if self.ndim < 1 or self.ndim > 3: raise ValueError("uniform_rectangular grid must be rank 1, 2, or 3") shape = self.bmi.grid_shape(self.grid_id) spacing = self.bmi.grid_spacing(self.grid_id) origin = self.bmi.grid_origin(self.grid_id) self.metadata = OrderedDict( [ ("cf_role", "grid_topology"), ( "long_name", "Topology data of {}D structured quadrilateral".format(self.ndim), ), ("topology_dimension", self.ndim), ("node_coordinates", " ".join(coordinate_names(self.ndim))), ("node_dimensions", " ".join(index_names(self.ndim))), ("node_spacing", "node_spacing"), ("node_origin", "node_origin"), ("type", self.grid_type), ] ) self.set_mesh() self.set_shape(shape) self.set_spacing(spacing) self.set_origin(origin) grid_coords = [] for dim in range(self.ndim): grid_coords.append( np.arange(shape[dim], dtype=float) * spacing[dim] + origin[dim] ) self.set_nodes_rectilinear(grid_coords) graph = UniformRectilinearGraph(shape, spacing=spacing, origin=origin) self.set_connectivity(data=graph.nodes_at_patch.reshape((-1,))) self.set_offset( data=np.arange(1, graph.number_of_patches + 1, dtype=np.int32) * 4 )
[docs]def dataset_from_bmi_grid(bmi, grid_id): grid_type = bmi.grid_type(grid_id) if grid_type == "points": grid = Points(bmi, grid_id) elif grid_type == "uniform_rectilinear": grid = UniformRectilinear(bmi, grid_id) elif grid_type == "structured_quadrilateral": grid = StructuredQuadrilateral(bmi, grid_id) elif grid_type == "scalar": grid = Scalar(bmi, grid_id) elif grid_type.startswith("unstructured"): grid = Unstructured(bmi, grid_id) elif grid_type == "vector": grid = Vector(bmi, grid_id) elif grid_type == "rectilinear": grid = Rectilinear(bmi, grid_id) else: raise ValueError("grid type not understood ({gtype})".format(gtype=grid_type)) return grid