Skip to content

Commit 7252aa3

Browse files
committed
initial refine_image functionality
1 parent 8d780d2 commit 7252aa3

4 files changed

Lines changed: 95 additions & 0 deletions

File tree

discretize/_extensions/tree.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,48 @@ void Cell::refine_func(node_map_t& nodes, function test_func, double *xs, double
418418
}
419419
}
420420

421+
void Cell::refine_image(node_map_t& nodes, double* image, int_t *shape_cells, double *xs, double*ys, double *zs, bool diagonal_balance){
422+
// early exit if my level is higher than or equal to target
423+
if (level == max_level){
424+
return;
425+
}
426+
int_t start_ix = points[0].location_ind[0]/2;
427+
int_t start_iy = points[0].location_ind[1]/2;
428+
int_t start_iz = n_dim == 2 ? 0 : points[0].location_ind[2]/2;
429+
int_t nx = shape_cells[0]
430+
int_t ny = shape_cells[1]
431+
int_t nz = shape_cells[2]
432+
433+
// same as 2**(max_level - level), but quicker since power of 2 and integers
434+
int_t span = 1<<(max_level - level);
435+
int_t span_z = n_dim == 2 ? 1 : span;
436+
int_t i_image = (nz * ny) * start_ix + nz * start_iy + start_iz;
437+
double val_start = image[0];
438+
bool subdivide = false;
439+
440+
// if any of the image data contained in the cell are different, subdivide myself
441+
for(int_t ix=0; ix<span && !subdivide; ++ix){
442+
for(int_t iy=0; iy<span && !subdivide; ++iy){
443+
for(int_t iz=0; iz<span_z && !subdivide; ++iz){
444+
subdivide = image[i_image] != val_start;
445+
i_image += 1;
446+
}
447+
i_image += nz;
448+
}
449+
i_image += nz * ny;
450+
}
451+
if(subdivide){
452+
if(is_leaf()){
453+
divide(nodes, xs, ys, zs, true, diag_balance);
454+
}
455+
// recurse into children
456+
for(int_t i = 0; i < (1<<n_dim); ++i){
457+
children[i]->refine_image(nodes, geom, p_level, xs, ys, zs, diag_balance);
458+
}
459+
}
460+
461+
}
462+
421463
void Cell::divide(node_map_t& nodes, double* xs, double* ys, double* zs, bool balance, bool diag_balance){
422464
// Gaurd against dividing a cell that is already at the max level
423465
if (level == max_level){
@@ -896,6 +938,18 @@ void Tree::refine_function(function test_func, bool diagonal_balance){
896938
roots[iz][iy][ix]->refine_func(nodes, test_func, xs, ys, zs, diagonal_balance);
897939
};
898940

941+
void Tree:refine_image(double *image, bool diagonal_balance){
942+
int_t[3] shape_cells;
943+
shape_cells[0] = nx/2;
944+
shape_cells[1] = ny/2;
945+
shape_cells[2] = nz/2;
946+
for(int_t iz=0; iz<nz_roots; ++iz)
947+
for(int_t iy=0; iy<ny_roots; ++iy)
948+
for(int_t ix=0; ix<nx_roots; ++ix)
949+
roots[iz][iy][ix]->refine_image(nodes, image, xs, ys, zs, diagonal_balance);
950+
}
951+
952+
899953
void Tree::finalize_lists(){
900954
for(int_t iz=0; iz<nz_roots; ++iz)
901955
for(int_t iy=0; iy<ny_roots; ++iy)

discretize/_extensions/tree.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class Cell{
136136
void insert_cell(node_map_t &nodes, double *new_center, int_t p_level, double* xs, double *ys, double *zs, bool diag_balance=false);
137137

138138
void refine_func(node_map_t& nodes, function test_func, double *xs, double *ys, double* zs, bool diag_balance=false);
139+
void refine_image(node_map_t& nodes, double* image, int_t *shape_cells, double *xs, double*ys, double *zs, bool diagonal_balance=false);
139140

140141
inline bool is_leaf(){ return children[0]==NULL;};
141142
void spawn(node_map_t& nodes, Cell *kids[8], double* xs, double *ys, double *zs);
@@ -217,6 +218,8 @@ class Tree{
217218

218219
void refine_function(function test_func, bool diagonal_balance=false);
219220

221+
void refine_image(double* image, bool diagonal_balance=false);
222+
220223
template <class T>
221224
void refine_geom(const T& geom, int_t p_level, bool diagonal_balance=false){
222225
for(int_t iz=0; iz<nz_roots; ++iz)

discretize/_extensions/tree.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ cdef extern from "tree.h":
9393

9494
void refine_geom[T](const T&, int_t, bool)
9595

96+
void refine_image(double*, bool)
97+
9698
void number()
9799
void initialize_roots()
98100
void insert_cell(double *new_center, int_t p_level, bool)

discretize/_extensions/tree_ext.pyx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ from libc.stdlib cimport malloc, free
77
from libcpp.vector cimport vector
88
from libcpp cimport bool
99
from numpy.math cimport INFINITY
10+
from pkg_resources import require
1011

1112
from .tree cimport int_t, Tree as c_Tree, PyWrapper, Node, Edge, Face, Cell as c_Cell
1213
from . cimport geom
@@ -1197,6 +1198,41 @@ cdef class _TreeMesh:
11971198
if finalize:
11981199
self.finalize()
11991200

1201+
def refine_image(self, image, finalize=True, diagonal_balance=None):
1202+
"""Refine using an ND image, ensuring that each cell contains exactly one unique value.
1203+
1204+
This function takes an N-dimensional image, defined on the underlying fine tensor mesh,
1205+
and recursively subdivides each cell if that cell contains more than 1 unique value in the
1206+
image. This is useful when using the TreeMesh to represent an exact compressed form of an input
1207+
model.
1208+
1209+
Parameters
1210+
----------
1211+
image : (shape_cells) numpy.ndarray
1212+
Must have the same shape as the base tensor mesh (TreeMesh.shape_cells), as if every cell on this mesh was
1213+
refined to it's maximum level.
1214+
1215+
"""
1216+
cdef int max_level = self.max_level
1217+
if diagonal_balance is None:
1218+
diagonal_balance = self._diagonal_balance
1219+
cdef bool diag_balance = diagonal_balance
1220+
1221+
image = self._require_ndarray_with_dim('image', image, ndim=self.dim, dtype=np.float64)
1222+
if image.shape != self.shape_cells:
1223+
raise ValueError(
1224+
f"image array shape: {image.shape} must match the base cell shapes: {self.shape_cells}"
1225+
)
1226+
if self.dim == 2:
1227+
image = image[..., None]
1228+
1229+
cdef double[:,:,::1] image_dat = image
1230+
self.tree.refine_image(&image[0, 0, 0], diagonal_balance)
1231+
if finalize:
1232+
self.finalize()
1233+
1234+
1235+
12001236
def finalize(self):
12011237
"""Finalize the :class:`~discretize.TreeMesh`.
12021238

0 commit comments

Comments
 (0)