Source code for dtcc_model.geometry.grid
# Copyright(C) 2023 Anders Logg
# Licensed under the MIT License
from dataclasses import dataclass
from typing import Union
import numpy as np
from .geometry import Geometry, Bounds
from dtcc_model import proto
[docs]
@dataclass
class Grid(Geometry):
"""Represents a structured quadrilateral grid in 2D.
Attributes
----------
width : int
Number of cells in the x-direction (horizontal).
height : int
Number of cells in the y-direction (vertical).
"""
width: int = 0
height: int = 0
[docs]
def __str__(self):
return (
f"DTCC Grid on {self.bounds.bndstr} with {self.width} x {self.height} cells"
)
[docs]
def calculate_bounds(self):
self._bounds = Bounds(xmin=0, ymin=0, xmax=self.width, ymax=self.height)
return self._bounds
@property
def xstep(self) -> int:
"""Return the distance between adjacent grid points in the x-direction.
Returns
-------
int
The distance between adjacent grid points in the x-direction.
"""
return self.bounds.width / self.width
@property
def ystep(self) -> int:
"""Return the distance between adjacent grid points in the y-direction.
Returns
-------
int
The distance between adjacent grid points in the y-direction.
"""
return self.bounds.height / self.height
@property
def num_vertices(self) -> int:
"""Return the total number of vertices in the grid.
Returns
-------
int
The total number of vertices in the grid, including boundary vertices.
"""
return (self.width + 1) * (self.height + 1)
@property
def num_cells(self) -> int:
"""Return the total number of cells in the grid.
Returns
-------
int
The total number of cells in the grid.
"""
return self.width * self.height
[docs]
def coordinates(self):
"""Return the coordinates of the grid points.
Returns
-------
np.ndarray
An array of shape (num_vertices, 2) containing the coordinates of the grid points.
"""
x = np.linspace(self.bounds.xmin, self.bounds.xmax, self.width + 1)
y = np.linspace(self.bounds.ymin, self.bounds.ymax, self.height + 1)
X, Y = np.meshgrid(x, y)
return np.vstack([X.ravel(), Y.ravel()]).T
[docs]
def to_proto(self) -> proto.Geometry:
"""Return a protobuf representation of the Grid.
Returns
-------
proto.Geometry
A protobuf representation of the Grid as a Geometry.
"""
# Handle Geometry fields
pb = Geometry.to_proto(self)
# Handle specific fields
_pb = proto.Grid()
_pb.width = self.width
_pb.height = self.height
pb.grid.CopyFrom(_pb)
return pb
[docs]
def from_proto(self, pb: Union[proto.Geometry, bytes]):
"""Initialize Grid from a protobuf representation.
Parameters
----------
pb: Union[proto.Geometry, bytes]
The protobuf message or its serialized bytes representation.
"""
# Handle byte representation
if isinstance(pb, bytes):
pb = proto.Geometry.FromString(pb)
# Handle Geometry fields
Geometry.from_proto(self, pb)
# Handle specific fields
_pb = pb.grid
self.width = _pb.width
self.height = _pb.height
[docs]
@dataclass
class VolumeGrid(Geometry):
"""Represents a structured hexahedral grid in 3D.
Attributes
----------
width : int
Number of cells in the x-direction.
height : int
Number of cells in the y-direction.
depth : int
Number of cells in the z-direction.
"""
width: int = 0
height: int = 0
depth: int = 0
[docs]
def __str__(self):
return f"DTCC VolumeGrid on {self.bounds.bndstr} with {self.width} x {self.height} x {self.depth} cells"
[docs]
def calculate_bounds(self):
self._bounds = Bounds(
xmin=0, ymin=0, zmin=0, xmax=self.width, ymax=self.height, zmax=self.depth
)
return self._bounds
@property
def xstep(self) -> int:
"""Return the distance between adjacent grid points in the x-direction.
Returns
-------
int
The distance between adjacent grid points in the x-direction.
"""
return self.bounds.width / self.width
@property
def ystep(self) -> int:
"""Return the distance between adjacent grid points in the y-direction.
Returns
-------
int
The distance between adjacent grid points in the y-direction.
"""
return self.bounds.height / self.height
@property
def zstep(self) -> int:
"""Return the distance between adjacent grid points in the z-direction.
Returns
-------
int
The distance between adjacent grid points in the z-direction.
"""
return self.bounds.depth / self.depth
@property
def num_vertices(self) -> int:
"""Return the total number of vertices in the grid.
Returns
-------
int
The total number of vertices in the grid, including boundary vertices.
"""
return (self.width + 1) * (self.height + 1) * (self.depth + 1)
@property
def num_cells(self) -> int:
"""Return the total number of cells in the grid.
Returns
-------
int
The total number of cells in the grid.
"""
return self.width * self.height * self.depth
[docs]
def coordinates(self):
"""Return the coordinates of the grid points.
Returns
-------
np.ndarray
An array of shape (num_vertices, 3) containing the coordinates of the grid points.
"""
x = np.linspace(self.bounds.xmin, self.bounds.xmax, self.width + 1)
y = np.linspace(self.bounds.ymin, self.bounds.ymax, self.height + 1)
z = np.linspace(self.bounds.zmin, self.bounds.zmax, self.depth + 1)
X, Y, Z = np.meshgrid(x, y, z)
return np.vstack([X.ravel(), Y.ravel(), Z.ravel()]).T
[docs]
def to_proto(self) -> proto.Geometry:
"""Return a protobuf representation of the VolumeGrid.
Returns
-------
proto.Geometry
A protobuf representation of the VolumeGrid as a Geometry.
"""
# Handle Geometry fields
pb = Geometry.to_proto(self)
# Handle specific fields
_pb = proto.VolumeGrid()
_pb.width = self.width
_pb.height = self.height
_pb.depth = self.depth
pb.volume_grid.CopyFrom(_pb)
return pb
[docs]
def from_proto(self, pb: Union[proto.Geometry, bytes]):
"""Initialize VolumeGrid from a protobuf representation.
Parameters
----------
pb: Union[proto.Geometry, bytes]
The protobuf message or its serialized bytes representation.
"""
# Handle byte representation
if isinstance(pb, bytes):
pb = proto.Geometry.FromString(pb)
# Handle Geometry fields
Geometry.from_proto(self, pb)
# Handle specific fields
_pb = pb.volume_grid
self.width = _pb.width
self.height = _pb.height
self.depth = _pb.depth