adaptive_refinement_mesh.h
Go to the documentation of this file.
1 /*
2 This file is part of the Ristra Wonton project.
3 Please see the license file at the root of this repository, or at:
4  https://github.com/laristra/wonton/blob/master/LICENSE
5 */
6 
7 #ifndef WONTON_ADAPTIVE_REFINEMENT_MESH_H_
8 #define WONTON_ADAPTIVE_REFINEMENT_MESH_H_
9 
10 #include <array>
11 #include <cassert>
12 #include <functional>
13 #include <tuple>
14 #include <vector>
15 
16 #include "wonton/support/wonton.h"
19 #include "wonton/support/Point.h"
20 
31 namespace Wonton {
32 
50 template<int D, class CoordSys=DefaultCoordSys>
52 
53  private:
54 
56  using mesh_data_t = std::vector<BoundingBox<D>>;
57 
58  public:
59 
60  // ==========================================================================
61  // Constructors and destructors
62 
64  Adaptive_Refinement_Mesh() = delete;
65 
78  std::function<int(const Point<D>)> func,
79  const Point<D> &plo, const Point<D> &phi);
80 
83  const Adaptive_Refinement_Mesh<D,CoordSys> &) = delete;
84 
85 
86  // ==========================================================================
87  // Accessors
88 
90  int space_dimension() const;
91 
93  int num_cells() const;
94 
99  BoundingBox<D> cell_get_bounds(const int id) const;
100 
101 
102  private:
103 
104  // ==========================================================================
105  // Private support methods
106 
108  bool check_for_refinement(const BoundingBox<D> &cell, const int level);
109 
111  mesh_data_t split_cell(const int d, const BoundingBox<D> &cell);
112 
113  // Refine a single cell.
114  std::pair<mesh_data_t, std::vector<int>> refine_cell(
115  const mesh_data_t &cells, const std::vector<int> &level, const int n);
116 
118  void build_mesh();
119 
120  // ==========================================================================
121  // Class data
122 
129  std::function<int(const Point<D>)> refinement_level_;
130 
132  BoundingBox<D> mesh_corners_;
133 
135  mesh_data_t cells_;
136 
137 }; // class Adaptive_Refinement_Mesh
138 
139 
140 // ============================================================================
141 // Constructor
142 
143 template<int D, class CoordSys>
145  std::function<int(const Point<D>)> func,
146  const Point<D> &plo, const Point<D> &phi) {
147  // Verify dimensionality
148  assert(D > 0);
149  // Save refinement level function pointer
150  refinement_level_ = func;
151  // Save mesh corners
152  for (int d = 0; d < D; ++d) {
153  mesh_corners_[d][LO] = plo[d];
154  mesh_corners_[d][HI] = phi[d];
155  }
156  // Build mesh
157  build_mesh();
158 }
159 
160 
161 // ============================================================================
162 // Private support methods
163 
164 // ____________________________________________________________________________
165 // Check to see if the current cell needs to be refined further
166 template<int D, class CoordSys>
168  const BoundingBox<D> &cell, const int level) {
169  // Evaluate refinement function
170  // -- In principle one could do something like integrate to get the
171  // average value or find the maximum value, but for now we'll just sample
172  // the center of the cell. This is equivalent to using the average value
173  // to second order for Cartesian geometries (if you use the centroid
174  // instead, you get second-order equivalence on other geometries).
175  Point<D> center;
176  for (int d = 0; d < D; ++d) {
177  center[d] = 0.5 * (cell[d][LO] + cell[d][HI]);
178  }
179  int value = refinement_level_(center);
180  // Some AMR grids enforce further restrictions, such as the requirement that
181  // adjacent cells differ by no more than a single level of refinement, or
182  // that you need to refine in larger patches rather than by cell, etc. This
183  // is a simple mesh, and by not imposing these constraints it actually makes
184  // this mesh more general.
185  return(value > level);
186 }
187 
188 // ____________________________________________________________________________
189 // Recursive procedure to perform the actual splitting of a cell by axis.
190 // -- Refinement is done by splitting in half along each axis.
191 template<int D, class CoordSys>
192 typename Adaptive_Refinement_Mesh<D,CoordSys>::mesh_data_t
194  const int d, const BoundingBox<D> &cell) {
195  // Splitting point
196  double midpoint = 0.5 * (cell[d][LO] + cell[d][HI]);
197  // Create the lower cell
198  BoundingBox<D> cell_lo;
199  for (int d2 = 0; d2 < D; ++d2) {
200  cell_lo[d2][LO] = cell[d2][LO];
201  cell_lo[d2][HI] = cell[d2][HI];
202  }
203  cell_lo[d][HI] = midpoint;
204  // Create the upper cell
205  BoundingBox<D> cell_hi;
206  for (int d2 = 0; d2 < D; ++d2) {
207  cell_hi[d2][LO] = cell[d2][LO];
208  cell_hi[d2][HI] = cell[d2][HI];
209  }
210  cell_hi[d][LO] = midpoint;
211  // Compose all the data together
212  mesh_data_t newcells;
213  const int N = 1<<(d+1);
214  newcells.resize(N);
215  if (d > 0) { // Recursive case
216  // Split lower cell along other axes
217  auto tempcells = split_cell(d-1, cell_lo);
218  for (int n = 0; n < N/2; ++n) {
219  newcells[n] = tempcells[n];
220  }
221  // Split upper cell along other axes
222  tempcells = split_cell(d-1, cell_hi);
223  for (int n = 0; n < N/2; ++n) {
224  newcells[n+N/2] = tempcells[n];
225  }
226  } else { // Base case
227  // Return the two new cells
228  newcells[0] = cell_lo;
229  newcells[1] = cell_hi;
230  }
231  return newcells;
232 }
233 
234 // ____________________________________________________________________________
235 // Refine a single cell.
236 // -- Remove the specified cell and replace it with refined cells.
237 // -- Some AMR meshes preserve non-leaf cells, but this mesh throws them
238 // away as they are irrelevant to mapping to another grid.
239 template<int D, class CoordSys>
240 std::pair<
241  typename Adaptive_Refinement_Mesh<D,CoordSys>::mesh_data_t,
242  std::vector<int>>
244  const Adaptive_Refinement_Mesh<D,CoordSys>::mesh_data_t &cells,
245  const std::vector<int> &level, const int n) {
246  assert(n >= 0);
247  assert(unsigned(n) < cells.size());
248  // Create new storage
249  // -- New storage replaces 1 cell with 2^D cells
250  const int num_new_cells = (1<<D) - 1;
251  const int newsize = cells.size() + num_new_cells;
252  mesh_data_t newcells;
253  std::vector<int> newlevel;
254  newcells.resize(newsize);
255  newlevel.resize(newsize);
256  // Copy elements prior to the one to refine
257  for (int i = 0; i < n; ++i) {
258  newcells[i] = cells[i];
259  newlevel[i] = level[i];
260  }
261  // Replace specified cell with new cells
262  mesh_data_t tempcells = split_cell(D-1,cells[n]);
263  for (unsigned i = 0; i < tempcells.size(); ++i) {
264  newcells[n+i] = tempcells[i];
265  newlevel[n+i] = level[n] + 1;
266  }
267  // Copy elements after the one to refine
268  for (unsigned i = n+1; i < level.size(); ++i) {
269  newcells[i+num_new_cells] = cells[i];
270  newlevel[i+num_new_cells] = level[i];
271  }
272  // Return
273  return std::make_pair(newcells, newlevel);
274 }
275 
276 // ____________________________________________________________________________
277 // Build the mesh based on the mesh corners and the refinement function.
278 template<int D, class CoordSys>
280  // Build the level-zero grid
281  cells_.resize(1);
282  cells_[0] = mesh_corners_;
283  std::vector<int> level = {0};
284  // Refinement loop
285  for (unsigned n = 0; n < level.size(); ++n) {
286  if (check_for_refinement(cells_[n], level[n])) {
287  std::tie(cells_, level) = refine_cell(cells_, level, n);
288  --n; // Decrement to repeat the current cell, as it was replaced
289  }
290  }
291 }
292 
293 
294 // ============================================================================
295 // Accessors
296 
297 // ____________________________________________________________________________
298 // Get the dimensionality of the mesh.
299 template<int D, class CoordSys>
301  return(D);
302 }
303 
304 // ____________________________________________________________________________
305 // Get the total number of cells in the mesh.
306 template<int D, class CoordSys>
308  return cells_.size();
309 }
310 
311 // ____________________________________________________________________________
312 // Get the lower and upper bounds of the specified cell.
313 template<int D, class CoordSys>
315  const int id) const {
316  int n = id;
317  return(cells_[n]);
318 }
319 
320 } // namespace Wonton
321 
322 #endif // WONTON_ADAPTIVE_REFINEMENT_MESH_H_
Adaptive_Refinement_Mesh()=delete
Default constructor (disabled)
Factorize a number N into D equal (or nearly equal) factors.
Definition: adaptive_refinement_mesh.h:31
Adaptive_Refinement_Mesh & operator=(const Adaptive_Refinement_Mesh< D, CoordSys > &)=delete
Assignment operator (disabled).
int num_cells() const
Get the total number of cells in the mesh.
Definition: adaptive_refinement_mesh.h:307
A simple mesh that mimics a cell-by-cell AMR mesh.
Definition: adaptive_refinement_mesh.h:51
Represents a point in an N-dimensional space.
Definition: Point.h:50
std::array< std::array< double, 2 >, D > BoundingBox
Bounding Box type.
Definition: BoundingBox.h:21
int space_dimension() const
Get the dimensionality of the mesh.
Definition: adaptive_refinement_mesh.h:300
const int HI
Definition: BoundingBox.h:24
BoundingBox< D > cell_get_bounds(const int id) const
Get the lower and upper bounds of the specified cell.
Definition: adaptive_refinement_mesh.h:314
const int LO
Definition: BoundingBox.h:23