Skip to content

Commit e3aae3f

Browse files
authored
Merge branch 'main' into 1.0.0_alpha
2 parents 3589370 + 4690ff5 commit e3aae3f

24 files changed

Lines changed: 557 additions & 41 deletions

.ci/azure/test.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ jobs:
1212
linux-Python312:
1313
image: ubuntu-latest
1414
python.version: '3.12'
15+
linux-Python313:
16+
image: ubuntu-latest
17+
python.version: '3.13'
1518
osx-Python310:
1619
image: macOS-latest
1720
python.version: '3.10'
@@ -21,6 +24,9 @@ jobs:
2124
osx-Python312:
2225
image: macOS-latest
2326
python.version: '3.12'
27+
osx-Python313:
28+
image: macOS-latest
29+
python.version: '3.13'
2430
win-Python310:
2531
image: windows-latest
2632
python.version: '3.10'
@@ -30,6 +36,9 @@ jobs:
3036
win-Python312:
3137
image: windows-latest
3238
python.version: '3.12'
39+
win-Python313:
40+
image: windows-latest
41+
python.version: '3.13'
3342
displayName: "${{ variables.image }} ${{ variables.python.version }}"
3443
pool:
3544
vmImage: $(image)

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2013-2024 SimPEG Developers
3+
Copyright (c) 2013-2025 SimPEG Developers
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy of
66
this software and associated documentation files (the "Software"), to deal in

discretize/_extensions/tree_ext.pyx

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ cimport numpy as np
66
from libc.stdlib cimport malloc, free
77
from libcpp.vector cimport vector
88
from libcpp cimport bool
9-
from numpy.math cimport INFINITY
9+
from libc.math cimport INFINITY
1010

1111
from .tree cimport int_t, Tree as c_Tree, PyWrapper, Node, Edge, Face, Cell as c_Cell
1212
from . cimport geom
@@ -15,6 +15,9 @@ import scipy.sparse as sp
1515
import numpy as np
1616
from .interputils_cython cimport _bisect_left, _bisect_right
1717

18+
class TreeMeshNotFinalizedError(RuntimeError):
19+
"""Raise when a TreeMesh is not finalized."""
20+
1821

1922
cdef class TreeCell:
2023
"""A class for defining cells within instances of :class:`~discretize.TreeMesh`.
@@ -1959,6 +1962,7 @@ cdef class _TreeMesh:
19591962
(n_cells, dim) numpy.ndarray of float
19601963
Gridded cell center locations
19611964
"""
1965+
self._error_if_not_finalized("cell_centers")
19621966
cdef np.float64_t[:, :] gridCC
19631967
cdef np.int64_t ii, ind, dim
19641968
if self._cell_centers is None:
@@ -1984,6 +1988,7 @@ cdef class _TreeMesh:
19841988
(n_nodes, dim) numpy.ndarray of float
19851989
Gridded non-hanging node locations
19861990
"""
1991+
self._error_if_not_finalized("nodes")
19871992
cdef np.float64_t[:, :] gridN
19881993
cdef Node *node
19891994
cdef np.int64_t ii, ind, dim
@@ -2012,6 +2017,7 @@ cdef class _TreeMesh:
20122017
(n_hanging_nodes, dim) numpy.ndarray of float
20132018
Gridded hanging node locations
20142019
"""
2020+
self._error_if_not_finalized("hanging_nodes")
20152021
cdef np.float64_t[:, :] gridN
20162022
cdef Node *node
20172023
cdef np.int64_t ii, ind, dim
@@ -2038,6 +2044,7 @@ cdef class _TreeMesh:
20382044
(n_boundary_nodes, dim) numpy.ndarray of float
20392045
Gridded boundary node locations
20402046
"""
2047+
self._error_if_not_finalized("boundary_nodes")
20412048
nodes = self.nodes
20422049
x0, xF = self._xs[0], self._xs[-1]
20432050
y0, yF = self._ys[0], self._ys[-1]
@@ -2069,6 +2076,7 @@ cdef class _TreeMesh:
20692076
(n_cells, dim) numpy.ndarray of float
20702077
Gridded cell dimensions
20712078
"""
2079+
self._error_if_not_finalized("h_gridded")
20722080
if self._h_gridded is not None:
20732081
return self._h_gridded
20742082
cdef np.float64_t[:, :] gridCH
@@ -2097,6 +2105,7 @@ cdef class _TreeMesh:
20972105
(n_edges_x, dim) numpy.ndarray of float
20982106
Gridded locations of all non-hanging x-edges
20992107
"""
2108+
self._error_if_not_finalized("edges_x")
21002109
cdef np.float64_t[:, :] gridEx
21012110
cdef Edge *edge
21022111
cdef np.int64_t ii, ind, dim
@@ -2124,6 +2133,7 @@ cdef class _TreeMesh:
21242133
(n_hanging_edges_x, dim) numpy.ndarray of float
21252134
Gridded locations of all hanging x-edges
21262135
"""
2136+
self._error_if_not_finalized("hanging_edges_x")
21272137
cdef np.float64_t[:, :] gridhEx
21282138
cdef Edge *edge
21292139
cdef np.int64_t ii, ind, dim
@@ -2149,6 +2159,7 @@ cdef class _TreeMesh:
21492159
(n_edges_y, dim) numpy.ndarray of float
21502160
Gridded locations of all non-hanging y-edges
21512161
"""
2162+
self._error_if_not_finalized("edges_y")
21522163
cdef np.float64_t[:, :] gridEy
21532164
cdef Edge *edge
21542165
cdef np.int64_t ii, ind, dim
@@ -2176,6 +2187,7 @@ cdef class _TreeMesh:
21762187
(n_haning_edges_y, dim) numpy.ndarray of float
21772188
Gridded locations of all hanging y-edges
21782189
"""
2190+
self._error_if_not_finalized("hanging_edges_y")
21792191
cdef np.float64_t[:, :] gridhEy
21802192
cdef Edge *edge
21812193
cdef np.int64_t ii, ind, dim
@@ -2201,6 +2213,7 @@ cdef class _TreeMesh:
22012213
(n_edges_z, dim) numpy.ndarray of float
22022214
Gridded locations of all non-hanging z-edges
22032215
"""
2216+
self._error_if_not_finalized("edges_z")
22042217
cdef np.float64_t[:, :] gridEz
22052218
cdef Edge *edge
22062219
cdef np.int64_t ii, ind, dim
@@ -2228,6 +2241,7 @@ cdef class _TreeMesh:
22282241
(n_hanging_edges_z, dim) numpy.ndarray of float
22292242
Gridded locations of all hanging z-edges
22302243
"""
2244+
self._error_if_not_finalized("hanging_edges_z")
22312245
cdef np.float64_t[:, :] gridhEz
22322246
cdef Edge *edge
22332247
cdef np.int64_t ii, ind, dim
@@ -2255,6 +2269,7 @@ cdef class _TreeMesh:
22552269
(n_boundary_edges, dim) numpy.ndarray of float
22562270
Gridded boundary edge locations
22572271
"""
2272+
self._error_if_not_finalized("boundary_edges")
22582273
edges_x = self.edges_x
22592274
edges_y = self.edges_y
22602275
x0, xF = self._xs[0], self._xs[-1]
@@ -2294,6 +2309,7 @@ cdef class _TreeMesh:
22942309
(n_faces_x, dim) numpy.ndarray of float
22952310
Gridded locations of all non-hanging x-faces
22962311
"""
2312+
self._error_if_not_finalized("faces_x")
22972313
if(self._dim == 2): return self.edges_y
22982314

22992315
cdef np.float64_t[:, :] gridFx
@@ -2323,6 +2339,7 @@ cdef class _TreeMesh:
23232339
(n_faces_y, dim) numpy.ndarray of float
23242340
Gridded locations of all non-hanging y-faces
23252341
"""
2342+
self._error_if_not_finalized("faces_y")
23262343
if(self._dim == 2): return self.edges_x
23272344
cdef np.float64_t[:, :] gridFy
23282345
cdef Face *face
@@ -2351,6 +2368,7 @@ cdef class _TreeMesh:
23512368
(n_faces_z, dim) numpy.ndarray of float
23522369
Gridded locations of all non-hanging z-faces
23532370
"""
2371+
self._error_if_not_finalized("faces_z")
23542372
if(self._dim == 2): return self.cell_centers
23552373

23562374
cdef np.float64_t[:, :] gridFz
@@ -2380,6 +2398,7 @@ cdef class _TreeMesh:
23802398
(n_hanging_faces_x, dim) numpy.ndarray of float
23812399
Gridded locations of all hanging x-faces
23822400
"""
2401+
self._error_if_not_finalized("hanging_faces_x")
23832402
if(self._dim == 2): return self.hanging_edges_y
23842403

23852404
cdef np.float64_t[:, :] gridFx
@@ -2407,6 +2426,7 @@ cdef class _TreeMesh:
24072426
(n_hanging_faces_y, dim) numpy.ndarray of float
24082427
Gridded locations of all hanging y-faces
24092428
"""
2429+
self._error_if_not_finalized("hanging_faces_y")
24102430
if(self._dim == 2): return self.hanging_edges_x
24112431

24122432
cdef np.float64_t[:, :] gridhFy
@@ -2434,6 +2454,7 @@ cdef class _TreeMesh:
24342454
(n_hanging_faces_z, dim) numpy.ndarray of float
24352455
Gridded locations of all hanging z-faces
24362456
"""
2457+
self._error_if_not_finalized("hanging_faces_z")
24372458
if(self._dim == 2): return np.array([])
24382459

24392460
cdef np.float64_t[:, :] gridhFz
@@ -2463,6 +2484,7 @@ cdef class _TreeMesh:
24632484
(n_boundary_faces, dim) numpy.ndarray of float
24642485
Gridded boundary face locations
24652486
"""
2487+
self._error_if_not_finalized("boundary_faces")
24662488
faces_x = self.faces_x
24672489
faces_y = self.faces_y
24682490
x0, xF = self._xs[0], self._xs[-1]
@@ -2492,6 +2514,7 @@ cdef class _TreeMesh:
24922514
(n_boundary_faces, dim) numpy.ndarray of float
24932515
Outward normals of boundary faces
24942516
"""
2517+
self._error_if_not_finalized("boundary_face_outward_normals")
24952518
faces_x = self.faces_x
24962519
faces_y = self.faces_y
24972520
x0, xF = self._xs[0], self._xs[-1]
@@ -2534,6 +2557,7 @@ cdef class _TreeMesh:
25342557
- *3D:* Returns the cell volumes
25352558
25362559
"""
2560+
self._error_if_not_finalized("cell_volumes")
25372561
cdef np.float64_t[:] vol
25382562
if self._cell_volumes is None:
25392563
self._cell_volumes = np.empty(self.n_cells, dtype=np.float64)
@@ -2558,6 +2582,7 @@ cdef class _TreeMesh:
25582582
respectively
25592583
- *3D:* returns the x, y and z-face areas in order
25602584
"""
2585+
self._error_if_not_finalized("face_areas")
25612586
if self._dim == 2 and self._face_areas is None:
25622587
self._face_areas = np.r_[self.edge_lengths[self.n_edges_x:], self.edge_lengths[:self.n_edges_x]]
25632588
cdef np.float64_t[:] area
@@ -2600,6 +2625,7 @@ cdef class _TreeMesh:
26002625
- *2D:* returns the x-edge and y-edge lengths in order
26012626
- *3D:* returns the x, y and z-edge lengths in order
26022627
"""
2628+
self._error_if_not_finalized("edge_lengths")
26032629
cdef np.float64_t[:] edge_l
26042630
cdef Edge *edge
26052631
cdef int_t ind, offset
@@ -3564,6 +3590,7 @@ cdef class _TreeMesh:
35643590
(n_total_faces_x, n_cells) scipy.sparse.csr_matrix
35653591
The stencil for the x-component of the cell gradient
35663592
"""
3593+
self._error_if_not_finalized("stencil_cell_gradient_x")
35673594
if getattr(self, '_stencil_cell_gradient_x', None) is not None:
35683595
return self._stencil_cell_gradient_x
35693596
cdef np.int64_t[:] I = np.zeros(2*self.n_total_faces_x, dtype=np.int64)
@@ -3641,6 +3668,7 @@ cdef class _TreeMesh:
36413668
(n_total_faces_y, n_cells) scipy.sparse.csr_matrix
36423669
The stencil for the y-component of the cell gradient
36433670
"""
3671+
self._error_if_not_finalized("stencil_cell_gradient_y")
36443672
if getattr(self, '_stencil_cell_gradient_y', None) is not None:
36453673
return self._stencil_cell_gradient_y
36463674

@@ -3719,6 +3747,7 @@ cdef class _TreeMesh:
37193747
(n_total_faces_z, n_cells) scipy.sparse.csr_matrix
37203748
The stencil for the z-component of the cell gradient
37213749
"""
3750+
self._error_if_not_finalized("stencil_cell_gradient_z")
37223751
if getattr(self, '_stencil_cell_gradient_z', None) is not None:
37233752
return self._stencil_cell_gradient_z
37243753

@@ -5019,6 +5048,7 @@ cdef class _TreeMesh:
50195048
50205049
phi_f = Acf @ phi_c
50215050
"""
5051+
self._error_if_not_finalized("average_cell_to_face")
50225052
if self._average_cell_to_face is not None:
50235053
return self._average_cell_to_face
50245054
stacks = [self.average_cell_to_face_x, self.average_cell_to_face_y]
@@ -5079,6 +5109,7 @@ cdef class _TreeMesh:
50795109
in the x-direction. For boundary faces, nearest neighbor is used to extrapolate
50805110
the values.
50815111
"""
5112+
self._error_if_not_finalized("average_cell_vector_to_face")
50825113
if self._average_cell_vector_to_face is not None:
50835114
return self._average_cell_vector_to_face
50845115
stacks = [self.average_cell_to_face_x, self.average_cell_to_face_y]
@@ -5102,6 +5133,7 @@ cdef class _TreeMesh:
51025133
(n_faces_x, n_cells) scipy.sparse.csr_matrix
51035134
The scalar averaging operator from cell centers to x faces
51045135
"""
5136+
self._error_if_not_finalized("average_cell_to_face_x")
51055137
if self._average_cell_to_face_x is not None:
51065138
return self._average_cell_to_face_x
51075139
cdef np.int64_t[:] I = np.zeros(2*self.n_total_faces_x, dtype=np.int64)
@@ -5218,6 +5250,7 @@ cdef class _TreeMesh:
52185250
(n_faces_y, n_cells) scipy.sparse.csr_matrix
52195251
The scalar averaging operator from cell centers to y faces
52205252
"""
5253+
self._error_if_not_finalized("average_cell_to_face_y")
52215254
if self._average_cell_to_face_y is not None:
52225255
return self._average_cell_to_face_y
52235256
cdef np.int64_t[:] I = np.zeros(2*self.n_total_faces_y, dtype=np.int64)
@@ -5334,6 +5367,7 @@ cdef class _TreeMesh:
53345367
(n_faces_z, n_cells) scipy.sparse.csr_matrix
53355368
The scalar averaging operator from cell centers to z faces
53365369
"""
5370+
self._error_if_not_finalized("average_cell_to_face_z")
53375371
if self.dim == 2:
53385372
raise Exception('TreeMesh has no z-faces in 2D')
53395373
if self._average_cell_to_face_z is not None:
@@ -5424,6 +5458,7 @@ cdef class _TreeMesh:
54245458
scipy.sparse.csr_matrix
54255459
(n_boundary_faces, n_faces) Projection matrix with shape
54265460
"""
5461+
self._error_if_not_finalized("project_face_to_boundary_face")
54275462
faces_x = self.faces_x
54285463
faces_y = self.faces_y
54295464

@@ -5459,6 +5494,7 @@ cdef class _TreeMesh:
54595494
(n_boundary_edges, n_edges) scipy.sparse.csr_matrix
54605495
Projection matrix with shape
54615496
"""
5497+
self._error_if_not_finalized("project_edge_to_boundary_edge")
54625498
edges_x = self.edges_x
54635499
edges_y = self.edges_y
54645500

@@ -5501,6 +5537,7 @@ cdef class _TreeMesh:
55015537
(n_boundary_nodes, n_nodes) scipy.sparse.csr_matrix
55025538
Projection matrix with shape
55035539
"""
5540+
self._error_if_not_finalized("project_node_to_boundary_node")
55045541
nodes = self.nodes
55055542
x0, xF = self._xs[0], self._xs[-1]
55065543
y0, yF = self._ys[0], self._ys[-1]
@@ -6964,6 +7001,17 @@ cdef class _TreeMesh:
69647001
"""
69657002
return self.get_cells_in_aabb(*rectangle.reshape(self.dim, 2).T)
69667003

7004+
def _error_if_not_finalized(self, method: str):
7005+
"""
7006+
Raise error if mesh is not finalized.
7007+
"""
7008+
if not self.finalized:
7009+
msg = (
7010+
f"`{type(self).__name__}.{method}` requires a finalized mesh. "
7011+
"Use the `finalize()` method to finalize it."
7012+
)
7013+
raise TreeMeshNotFinalizedError(msg)
7014+
69677015
def _require_ndarray_with_dim(self, name, arr, ndim=1, dtype=None, requirements=None):
69687016
"""Returns an ndarray that has dim along it's last dimension, with ndim dims,
69697017

discretize/mixins/mesh_io.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ def read_UBC(TreeMesh, file_name, directory=None):
466466
else:
467467
max_level = min(ls) + 1
468468

469-
mesh = TreeMesh(hs, origin=origin)
469+
mesh = TreeMesh(hs, origin=origin, diagonal_balance=False)
470470
levels = indArr[:, -1]
471471
indArr = indArr[:, :-1]
472472

discretize/mixins/mpl_mod.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2053,7 +2053,7 @@ def __plot_slice_tree(
20532053
normal[normalInd] = 1
20542054

20552055
# create a temporary TreeMesh with the slice through
2056-
temp_mesh = discretize.TreeMesh(h2d, x2d)
2056+
temp_mesh = discretize.TreeMesh(h2d, x2d, diagonal_balance=False)
20572057
level_diff = self.max_level - temp_mesh.max_level
20582058

20592059
# get list of cells which intersect the slicing plane

0 commit comments

Comments
 (0)