Skip to content

Commit

Permalink
Define new error class and update code and tests
Browse files Browse the repository at this point in the history
Define the new `TreeMeshNotFinalizedError` class. Update the properties
to not pass the `is_property` argument to the error method. Update the
tests accordingly.
  • Loading branch information
santisoler committed Feb 25, 2025
1 parent 5688c91 commit e1d144b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 41 deletions.
73 changes: 38 additions & 35 deletions discretize/_extensions/tree_ext.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import scipy.sparse as sp
import numpy as np
from .interputils_cython cimport _bisect_left, _bisect_right

class TreeMeshNotFinalizedError(RuntimeError):
"""Raise when a TreeMesh is not finalized."""


cdef class TreeCell:
"""A class for defining cells within instances of :class:`~discretize.TreeMesh`.
Expand Down Expand Up @@ -1959,7 +1962,7 @@ cdef class _TreeMesh:
(n_cells, dim) numpy.ndarray of float
Gridded cell center locations
"""
self._error_if_not_finalized("cell_centers", is_property=True)
self._error_if_not_finalized("cell_centers")
cdef np.float64_t[:, :] gridCC
cdef np.int64_t ii, ind, dim
if self._cell_centers is None:
Expand All @@ -1985,7 +1988,7 @@ cdef class _TreeMesh:
(n_nodes, dim) numpy.ndarray of float
Gridded non-hanging node locations
"""
self._error_if_not_finalized("nodes", is_property=True)
self._error_if_not_finalized("nodes")
cdef np.float64_t[:, :] gridN
cdef Node *node
cdef np.int64_t ii, ind, dim
Expand Down Expand Up @@ -2014,7 +2017,7 @@ cdef class _TreeMesh:
(n_hanging_nodes, dim) numpy.ndarray of float
Gridded hanging node locations
"""
self._error_if_not_finalized("hanging_nodes", is_property=True)
self._error_if_not_finalized("hanging_nodes")
cdef np.float64_t[:, :] gridN
cdef Node *node
cdef np.int64_t ii, ind, dim
Expand All @@ -2041,7 +2044,7 @@ cdef class _TreeMesh:
(n_boundary_nodes, dim) numpy.ndarray of float
Gridded boundary node locations
"""
self._error_if_not_finalized("boundary_nodes", is_property=True)
self._error_if_not_finalized("boundary_nodes")
nodes = self.nodes
x0, xF = self._xs[0], self._xs[-1]
y0, yF = self._ys[0], self._ys[-1]
Expand Down Expand Up @@ -2073,7 +2076,7 @@ cdef class _TreeMesh:
(n_cells, dim) numpy.ndarray of float
Gridded cell dimensions
"""
self._error_if_not_finalized("h_gridded", is_property=True)
self._error_if_not_finalized("h_gridded")
if self._h_gridded is not None:
return self._h_gridded
cdef np.float64_t[:, :] gridCH
Expand Down Expand Up @@ -2102,7 +2105,7 @@ cdef class _TreeMesh:
(n_edges_x, dim) numpy.ndarray of float
Gridded locations of all non-hanging x-edges
"""
self._error_if_not_finalized("edges_x", is_property=True)
self._error_if_not_finalized("edges_x")
cdef np.float64_t[:, :] gridEx
cdef Edge *edge
cdef np.int64_t ii, ind, dim
Expand Down Expand Up @@ -2130,7 +2133,7 @@ cdef class _TreeMesh:
(n_hanging_edges_x, dim) numpy.ndarray of float
Gridded locations of all hanging x-edges
"""
self._error_if_not_finalized("hanging_edges_x", is_property=True)
self._error_if_not_finalized("hanging_edges_x")
cdef np.float64_t[:, :] gridhEx
cdef Edge *edge
cdef np.int64_t ii, ind, dim
Expand All @@ -2156,7 +2159,7 @@ cdef class _TreeMesh:
(n_edges_y, dim) numpy.ndarray of float
Gridded locations of all non-hanging y-edges
"""
self._error_if_not_finalized("edges_y", is_property=True)
self._error_if_not_finalized("edges_y")
cdef np.float64_t[:, :] gridEy
cdef Edge *edge
cdef np.int64_t ii, ind, dim
Expand Down Expand Up @@ -2184,7 +2187,7 @@ cdef class _TreeMesh:
(n_haning_edges_y, dim) numpy.ndarray of float
Gridded locations of all hanging y-edges
"""
self._error_if_not_finalized("hanging_edges_y", is_property=True)
self._error_if_not_finalized("hanging_edges_y")
cdef np.float64_t[:, :] gridhEy
cdef Edge *edge
cdef np.int64_t ii, ind, dim
Expand All @@ -2210,7 +2213,7 @@ cdef class _TreeMesh:
(n_edges_z, dim) numpy.ndarray of float
Gridded locations of all non-hanging z-edges
"""
self._error_if_not_finalized("edges_z", is_property=True)
self._error_if_not_finalized("edges_z")
cdef np.float64_t[:, :] gridEz
cdef Edge *edge
cdef np.int64_t ii, ind, dim
Expand Down Expand Up @@ -2238,7 +2241,7 @@ cdef class _TreeMesh:
(n_hanging_edges_z, dim) numpy.ndarray of float
Gridded locations of all hanging z-edges
"""
self._error_if_not_finalized("hanging_edges_z", is_property=True)
self._error_if_not_finalized("hanging_edges_z")
cdef np.float64_t[:, :] gridhEz
cdef Edge *edge
cdef np.int64_t ii, ind, dim
Expand Down Expand Up @@ -2266,7 +2269,7 @@ cdef class _TreeMesh:
(n_boundary_edges, dim) numpy.ndarray of float
Gridded boundary edge locations
"""
self._error_if_not_finalized("boundary_edges", is_property=True)
self._error_if_not_finalized("boundary_edges")
edges_x = self.edges_x
edges_y = self.edges_y
x0, xF = self._xs[0], self._xs[-1]
Expand Down Expand Up @@ -2306,7 +2309,7 @@ cdef class _TreeMesh:
(n_faces_x, dim) numpy.ndarray of float
Gridded locations of all non-hanging x-faces
"""
self._error_if_not_finalized("faces_x", is_property=True)
self._error_if_not_finalized("faces_x")
if(self._dim == 2): return self.edges_y

cdef np.float64_t[:, :] gridFx
Expand Down Expand Up @@ -2336,7 +2339,7 @@ cdef class _TreeMesh:
(n_faces_y, dim) numpy.ndarray of float
Gridded locations of all non-hanging y-faces
"""
self._error_if_not_finalized("faces_y", is_property=True)
self._error_if_not_finalized("faces_y")
if(self._dim == 2): return self.edges_x
cdef np.float64_t[:, :] gridFy
cdef Face *face
Expand Down Expand Up @@ -2365,7 +2368,7 @@ cdef class _TreeMesh:
(n_faces_z, dim) numpy.ndarray of float
Gridded locations of all non-hanging z-faces
"""
self._error_if_not_finalized("faces_z", is_property=True)
self._error_if_not_finalized("faces_z")
if(self._dim == 2): return self.cell_centers

cdef np.float64_t[:, :] gridFz
Expand Down Expand Up @@ -2395,7 +2398,7 @@ cdef class _TreeMesh:
(n_hanging_faces_x, dim) numpy.ndarray of float
Gridded locations of all hanging x-faces
"""
self._error_if_not_finalized("hanging_faces_x", is_property=True)
self._error_if_not_finalized("hanging_faces_x")
if(self._dim == 2): return self.hanging_edges_y

cdef np.float64_t[:, :] gridFx
Expand Down Expand Up @@ -2423,7 +2426,7 @@ cdef class _TreeMesh:
(n_hanging_faces_y, dim) numpy.ndarray of float
Gridded locations of all hanging y-faces
"""
self._error_if_not_finalized("hanging_faces_y", is_property=True)
self._error_if_not_finalized("hanging_faces_y")
if(self._dim == 2): return self.hanging_edges_x

cdef np.float64_t[:, :] gridhFy
Expand Down Expand Up @@ -2451,7 +2454,7 @@ cdef class _TreeMesh:
(n_hanging_faces_z, dim) numpy.ndarray of float
Gridded locations of all hanging z-faces
"""
self._error_if_not_finalized("hanging_faces_z", is_property=True)
self._error_if_not_finalized("hanging_faces_z")
if(self._dim == 2): return np.array([])

cdef np.float64_t[:, :] gridhFz
Expand Down Expand Up @@ -2481,7 +2484,7 @@ cdef class _TreeMesh:
(n_boundary_faces, dim) numpy.ndarray of float
Gridded boundary face locations
"""
self._error_if_not_finalized("boundary_faces", is_property=True)
self._error_if_not_finalized("boundary_faces")
faces_x = self.faces_x
faces_y = self.faces_y
x0, xF = self._xs[0], self._xs[-1]
Expand Down Expand Up @@ -2511,7 +2514,7 @@ cdef class _TreeMesh:
(n_boundary_faces, dim) numpy.ndarray of float
Outward normals of boundary faces
"""
self._error_if_not_finalized("boundary_face_outward_normals", is_property=True)
self._error_if_not_finalized("boundary_face_outward_normals")
faces_x = self.faces_x
faces_y = self.faces_y
x0, xF = self._xs[0], self._xs[-1]
Expand Down Expand Up @@ -2554,7 +2557,7 @@ cdef class _TreeMesh:
- *3D:* Returns the cell volumes
"""
self._error_if_not_finalized("cell_volumes", is_property=True)
self._error_if_not_finalized("cell_volumes")
cdef np.float64_t[:] vol
if self._cell_volumes is None:
self._cell_volumes = np.empty(self.n_cells, dtype=np.float64)
Expand All @@ -2579,7 +2582,7 @@ cdef class _TreeMesh:
respectively
- *3D:* returns the x, y and z-face areas in order
"""
self._error_if_not_finalized("face_areas", is_property=True)
self._error_if_not_finalized("face_areas")
if self._dim == 2 and self._face_areas is None:
self._face_areas = np.r_[self.edge_lengths[self.n_edges_x:], self.edge_lengths[:self.n_edges_x]]
cdef np.float64_t[:] area
Expand Down Expand Up @@ -2622,7 +2625,7 @@ cdef class _TreeMesh:
- *2D:* returns the x-edge and y-edge lengths in order
- *3D:* returns the x, y and z-edge lengths in order
"""
self._error_if_not_finalized("edge_lengths", is_property=True)
self._error_if_not_finalized("edge_lengths")
cdef np.float64_t[:] edge_l
cdef Edge *edge
cdef int_t ind, offset
Expand Down Expand Up @@ -3587,7 +3590,7 @@ cdef class _TreeMesh:
(n_total_faces_x, n_cells) scipy.sparse.csr_matrix
The stencil for the x-component of the cell gradient
"""
self._error_if_not_finalized("stencil_cell_gradient_x", is_property=True)
self._error_if_not_finalized("stencil_cell_gradient_x")
if getattr(self, '_stencil_cell_gradient_x', None) is not None:
return self._stencil_cell_gradient_x
cdef np.int64_t[:] I = np.zeros(2*self.n_total_faces_x, dtype=np.int64)
Expand Down Expand Up @@ -3665,7 +3668,7 @@ cdef class _TreeMesh:
(n_total_faces_y, n_cells) scipy.sparse.csr_matrix
The stencil for the y-component of the cell gradient
"""
self._error_if_not_finalized("stencil_cell_gradient_y", is_property=True)
self._error_if_not_finalized("stencil_cell_gradient_y")
if getattr(self, '_stencil_cell_gradient_y', None) is not None:
return self._stencil_cell_gradient_y

Expand Down Expand Up @@ -3744,7 +3747,7 @@ cdef class _TreeMesh:
(n_total_faces_z, n_cells) scipy.sparse.csr_matrix
The stencil for the z-component of the cell gradient
"""
self._error_if_not_finalized("stencil_cell_gradient_z", is_property=True)
self._error_if_not_finalized("stencil_cell_gradient_z")
if getattr(self, '_stencil_cell_gradient_z', None) is not None:
return self._stencil_cell_gradient_z

Expand Down Expand Up @@ -5045,7 +5048,7 @@ cdef class _TreeMesh:
phi_f = Acf @ phi_c
"""
self._error_if_not_finalized("average_cell_to_face", is_property=True)
self._error_if_not_finalized("average_cell_to_face")
if self._average_cell_to_face is not None:
return self._average_cell_to_face
stacks = [self.average_cell_to_face_x, self.average_cell_to_face_y]
Expand Down Expand Up @@ -5106,7 +5109,7 @@ cdef class _TreeMesh:
in the x-direction. For boundary faces, nearest neighbor is used to extrapolate
the values.
"""
self._error_if_not_finalized("average_cell_vector_to_face", is_property=True)
self._error_if_not_finalized("average_cell_vector_to_face")
if self._average_cell_vector_to_face is not None:
return self._average_cell_vector_to_face
stacks = [self.average_cell_to_face_x, self.average_cell_to_face_y]
Expand All @@ -5130,7 +5133,7 @@ cdef class _TreeMesh:
(n_faces_x, n_cells) scipy.sparse.csr_matrix
The scalar averaging operator from cell centers to x faces
"""
self._error_if_not_finalized("average_cell_to_face_x", is_property=True)
self._error_if_not_finalized("average_cell_to_face_x")
if self._average_cell_to_face_x is not None:
return self._average_cell_to_face_x
cdef np.int64_t[:] I = np.zeros(2*self.n_total_faces_x, dtype=np.int64)
Expand Down Expand Up @@ -5247,7 +5250,7 @@ cdef class _TreeMesh:
(n_faces_y, n_cells) scipy.sparse.csr_matrix
The scalar averaging operator from cell centers to y faces
"""
self._error_if_not_finalized("average_cell_to_face_y", is_property=True)
self._error_if_not_finalized("average_cell_to_face_y")
if self._average_cell_to_face_y is not None:
return self._average_cell_to_face_y
cdef np.int64_t[:] I = np.zeros(2*self.n_total_faces_y, dtype=np.int64)
Expand Down Expand Up @@ -5364,7 +5367,7 @@ cdef class _TreeMesh:
(n_faces_z, n_cells) scipy.sparse.csr_matrix
The scalar averaging operator from cell centers to z faces
"""
self._error_if_not_finalized("average_cell_to_face_z", is_property=True)
self._error_if_not_finalized("average_cell_to_face_z")
if self.dim == 2:
raise Exception('TreeMesh has no z-faces in 2D')
if self._average_cell_to_face_z is not None:
Expand Down Expand Up @@ -5455,7 +5458,7 @@ cdef class _TreeMesh:
scipy.sparse.csr_matrix
(n_boundary_faces, n_faces) Projection matrix with shape
"""
self._error_if_not_finalized("project_face_to_boundary_face", is_property=True)
self._error_if_not_finalized("project_face_to_boundary_face")
faces_x = self.faces_x
faces_y = self.faces_y

Expand Down Expand Up @@ -5491,7 +5494,7 @@ cdef class _TreeMesh:
(n_boundary_edges, n_edges) scipy.sparse.csr_matrix
Projection matrix with shape
"""
self._error_if_not_finalized("project_edge_to_boundary_edge", is_property=True)
self._error_if_not_finalized("project_edge_to_boundary_edge")
edges_x = self.edges_x
edges_y = self.edges_y

Expand Down Expand Up @@ -5534,7 +5537,7 @@ cdef class _TreeMesh:
(n_boundary_nodes, n_nodes) scipy.sparse.csr_matrix
Projection matrix with shape
"""
self._error_if_not_finalized("project_node_to_boundary_node", is_property=True)
self._error_if_not_finalized("project_node_to_boundary_node")
nodes = self.nodes
x0, xF = self._xs[0], self._xs[-1]
y0, yF = self._ys[0], self._ys[-1]
Expand Down Expand Up @@ -6998,7 +7001,7 @@ cdef class _TreeMesh:
"""
return self.get_cells_in_aabb(*rectangle.reshape(self.dim, 2).T)

def _error_if_not_finalized(self, method: str, is_property: bool):
def _error_if_not_finalized(self, method: str):
"""
Raise error if mesh is not finalized.
"""
Expand Down
5 changes: 2 additions & 3 deletions discretize/tree_mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,12 @@
from discretize.base import BaseTensorMesh
from discretize.operators import InnerProducts, DiffOperators
from discretize.mixins import InterfaceMixins, TreeMeshIO
from discretize._extensions.tree_ext import _TreeMesh, TreeCell # NOQA F401
from discretize._extensions.tree_ext import _TreeMesh, TreeCell, TreeMeshNotFinalizedError # NOQA F401
import numpy as np
import scipy.sparse as sp
from discretize.utils.code_utils import deprecate_property
from scipy.spatial import Delaunay


class TreeMesh(
_TreeMesh,
InnerProducts,
Expand Down Expand Up @@ -768,7 +767,7 @@ def total_nodes(self):
(n_total_nodes, dim) numpy.ndarray of float
Gridded hanging and non-hanging node locations
"""
self._error_if_not_finalized("total_nodes", is_property=True)
self._error_if_not_finalized("total_nodes")
return np.vstack((self.nodes, self.hanging_nodes))

@property
Expand Down
6 changes: 3 additions & 3 deletions tests/tree/test_safeguards.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest

from discretize import TreeMesh
from discretize.tree_mesh import TreeMeshNotFinalizedError


@pytest.fixture
Expand Down Expand Up @@ -82,10 +83,9 @@ def test_errors(self, mesh, prop_name, refine):
if refine:
refine_mesh(mesh)
msg = re.escape(
f"The `{prop_name}` property cannot be accessed before "
"the mesh is finalized."
f"`TreeMesh.{prop_name}` requires a finalized mesh. "
)
with pytest.raises(AttributeError, match=msg):
with pytest.raises(TreeMeshNotFinalizedError, match=msg):
getattr(mesh, prop_name)

@pytest.mark.parametrize("prop_name", PROPERTIES)
Expand Down

0 comments on commit e1d144b

Please sign in to comment.