MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
bb_grid_map.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12/* The BBoxTensorGridMap class is adapted from similar functionality in the
13gslib library. Below is the gslib license and copyright statement:
14
15Copyright (c) 2008-2024, UCHICAGO ARGONNE, LLC.
16
17The UChicago Argonne, LLC as Operator of Argonne National
18Laboratory holds copyright in the Software. The copyright holder
19reserves all rights except those expressly granted to licensees,
20and U.S. Government license rights.
21
22Redistribution and use in source and binary forms, with or without
23modification, are permitted provided that the following conditions
24are met:
25
261. Redistributions of source code must retain the above copyright
27notice, this list of conditions and the disclaimer below.
28
292. Redistributions in binary form must reproduce the above copyright
30notice, this list of conditions and the disclaimer (as noted below)
31in the documentation and/or other materials provided with the
32distribution.
33
343. Neither the name of ANL nor the names of its contributors
35may be used to endorse or promote products derived from this software
36without specific prior written permission.
37
38THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
41FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
42UCHICAGO ARGONNE, LLC, THE U.S. DEPARTMENT OF
43ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
45TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
46DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
47THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
48(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
49OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50*/
51
52#include "bb_grid_map.hpp"
53
54#include <limits>
55#include <cmath>
56#include <algorithm>
57
58namespace mfem
59{
60
61using namespace std;
62
64{
65 GridFunction *nodes = mesh.GetNodes();
66 const int nel = mesh.GetNE();
67 sdim = mesh.SpaceDimension();
68 Vector elmin(nel*sdim), elmax(nel*sdim);
69 elmin = numeric_limits<real_t>::max();
70 elmax = -numeric_limits<real_t>::max();
71 if (!nodes)
72 {
73 Array<int> verts;
74 real_t *coord;
75 // create bounding boxes from vertex coordinates
76 for (int e = 0; e < nel; e++)
77 {
78 mesh.GetElementVertices(e, verts);
79 for (int v = 0; v < verts.Size(); v++)
80 {
81 coord = mesh.GetVertex(verts[v]);
82 for (int d = 0; d < sdim; d++)
83 {
84 elmin(d*nel + e) = min(elmin(d*nel + e), coord[d]);
85 elmax(d*nel + e) = max(elmax(d*nel + e), coord[d]);
86 }
87 }
88 }
89 }
90 else
91 {
92 int nref = 3;
93 nodes->GetElementBounds(elmin, elmax, nref);
94 }
95 Array<int> nx_arr(sdim);
96 nx_arr = nx;
97 Setup(elmin, elmax, nel, nx_arr, false);
98}
99
101 Vector &elmax,
102 int nel,
103 int sdim_,
104 int n,
105 bool by_max_size)
106{
107 sdim = sdim_;
108 MFEM_VERIFY(0 < sdim && sdim <= 3,
109 "BBoxTensorGridMap only supports spatial dimensions 1, 2, and 3.");
110 if (nel > 0)
111 {
112 MFEM_VERIFY(elmin.Size() == sdim * nel && elmax.Size() == sdim * nel,
113 "Element bounds size must match dim * nel.");
114 }
115 Array<int> nx_arr(sdim);
116 nx_arr = n;
117 Setup(elmin, elmax, nel, nx_arr, by_max_size);
118}
119
121 int nel, int sdim_,
122 Array<int> &nx,
123 bool by_max_size)
124{
125 sdim = sdim_;
126 Setup(elmin, elmax, nel, nx, by_max_size);
127}
128
129void BBoxTensorGridMap::Setup(Vector &elmin, Vector &elmax,
130 int nel, Array<int> &nx, bool by_max_size)
131{
132 MFEM_VERIFY(0 < sdim && sdim <= 3,
133 "BBoxTensorGridMap only supports spatial dimensions 1, 2, and 3.");
134 MFEM_VERIFY(nx.Size() == sdim,
135 "BBoxTensorGridMap requires nx to have the same size as the number of dimensions.");
136 if (nel > 0)
137 {
138 MFEM_VERIFY(elmin.Size() == sdim * nel && elmax.Size() == sdim * nel,
139 "Element bounds size must match dim * nel.");
140 }
141 lmap_bnd_min.SetSize(sdim);
142 lmap_bnd_max.SetSize(sdim);
143 lmap_fac.SetSize(sdim);
144 lmap_nx.SetSize(sdim);
145 lmap_nx = nx;
146
147 if (by_max_size)
148 {
149 MFEM_VERIFY(nx[0] >= 0,
150 "BBoxTensorGridMap requires a nonnegative max-size hint.");
151 }
152 else
153 {
154 for (int d = 0; d < nx.Size(); d++)
155 {
156 MFEM_VERIFY(nx[d] > 0,
157 "BBoxTensorGridMap requires positive number of divisions in each dimension.");
158 }
159 }
160 if (nel == 0)
161 {
162 lmap_bnd_min = 0.0;
163 lmap_bnd_max = 1.0;
164 if (by_max_size) { lmap_nx = 1; }
165 SetGridFac(lmap_fac, lmap_nx, lmap_bnd_min, lmap_bnd_max);
166
167 lmap_nxd = lmap_nx[0];
168 for (int d = 1; d < sdim; d++)
169 {
170 lmap_nxd *= lmap_nx[d];
171 }
172
173 lgrid_map.SetSize(lmap_nxd + 1);
174 lgrid_map = lmap_nxd + 1;
175 return;
176 }
177
178 for (int d = 0; d < sdim; d++)
179 {
180 Vector elmind(elmin.GetData() + d*nel, nel);
181 Vector elmaxd(elmax.GetData() + d*nel, nel);
182 lmap_bnd_min[d] = elmind.Min();
183 lmap_bnd_max[d] = elmaxd.Max();
184 }
185
186 Array<int> elmin_h, elmax_h;
187 unsigned int store_size;
188 if (by_max_size)
189 {
190 int nmax = nx[0];
191 int nlow = 1, nhigh = nmax > nel ? ceil(pow(nmax - nel, 1.0 / sdim)) : 1;
192 int size_low = 2 + nel;
193 int size = 0;
194 while (nhigh - nlow > 1)
195 {
196 int nmid = nlow + (nhigh - nlow) / 2;
197 int nmd = nmid;
198 for (int d = 1; d < sdim; d++)
199 {
200 nmd *= nmid;
201 }
202 lmap_nx = nmid;
203 SetGridFac(lmap_fac, lmap_nx, lmap_bnd_min, lmap_bnd_max);
204 size = nmd + 1 + GetGridCountAndRange(lmap_nx, lmap_fac,
205 lmap_bnd_min, lmap_bnd_max,
206 elmin, elmax,
207 elmin_h, elmax_h);
208 if (size <= nmax) { nlow = nmid; size_low = size; }
209 else { nhigh = nmid; }
210 }
211 lmap_nx = nlow;
212 lmap_nxd = nlow;
213 for (int d = 1; d < sdim; d++)
214 {
215 lmap_nxd *= nlow;
216 }
217 store_size = size_low;
218 SetGridFac(lmap_fac, lmap_nx, lmap_bnd_min, lmap_bnd_max);
219 if (size != size_low)
220 {
221 GetGridCountAndRange(lmap_nx, lmap_fac,
222 lmap_bnd_min, lmap_bnd_max,
223 elmin, elmax,
224 elmin_h, elmax_h);
225 }
226 }
227 else
228 {
229 SetGridFac(lmap_fac, lmap_nx, lmap_bnd_min, lmap_bnd_max);
230
231 lmap_nxd = lmap_nx[0];
232 for (int d = 1; d < sdim; d++)
233 {
234 lmap_nxd *= lmap_nx[d];
235 }
236
237 // Grid cell ranges for each element in each direction
238 store_size = lmap_nxd + 1 + GetGridCountAndRange(lmap_nx, lmap_fac,
239 lmap_bnd_min,
240 lmap_bnd_max,
241 elmin, elmax,
242 elmin_h, elmax_h);
243 }
244
245 lgrid_map.SetSize(store_size);
246 lgrid_map[0] = lmap_nxd + 1;
247
248 Array<unsigned int> grid_el_count(lmap_nxd);
249 grid_el_count = 0;
250
251 for (int e = 0; e < nel; e++)
252 {
253 int klim = sdim < 3 ? 1 : (elmax_h[2*nel+e]-elmin_h[2*nel+e]);
254 int jlim = sdim < 2 ? 1 : (elmax_h[1*nel+e]-elmin_h[1*nel+e]);
255 int ilim = (elmax_h[0*nel+e]-elmin_h[0*nel+e]);
256 for (int k = 0; k < klim; k++)
257 {
258 int koff = sdim < 3 ? 0 :
259 (elmin_h[2*nel + e] + k) * lmap_nx[0] * lmap_nx[1];
260 for (int j = 0; j < jlim; j++)
261 {
262 int joff = sdim < 2 ? 0 : (elmin_h[1*nel + e] + j) * lmap_nx[0];
263 for (int i = 0; i < ilim; i++)
264 {
265 int ioff = elmin_h[e] + i;
266 int idx = ioff + joff + koff;
267 grid_el_count[idx]++;
268 }
269 }
270 }
271 }
272
273 for (unsigned int e = 0; e < lmap_nxd; e++)
274 {
275 lgrid_map[e + 1] = lgrid_map[e] + grid_el_count[e];
276 }
277
278 for (int e = 0; e < nel; e++)
279 {
280 int klim = sdim < 3 ? 1 : (elmax_h[2*nel+e]-elmin_h[2*nel+e]);
281 int jlim = sdim < 2 ? 1 : (elmax_h[1*nel+e]-elmin_h[1*nel+e]);
282 int ilim = (elmax_h[0*nel+e]-elmin_h[0*nel+e]);
283 for (int k = 0; k < klim; k++)
284 {
285 int koff = sdim < 3 ? 0 :
286 (elmin_h[2*nel+e] + k) * lmap_nx[0] * lmap_nx[1];
287 for (int j = 0; j < jlim; j++)
288 {
289 int joff = sdim < 2 ? 0 : (elmin_h[1*nel + e] + j) * lmap_nx[0];
290 for (int i = 0; i < ilim; i++)
291 {
292 int ioff = elmin_h[e] + i;
293 int idx = ioff + joff + koff;
294 lgrid_map[lgrid_map[idx+1]-grid_el_count[idx]]=e;
295 grid_el_count[idx]--;
296 }
297 }
298 }
299 }
300}
301
303{
304 MFEM_ASSERT(i >= 0 && (unsigned int)i < lmap_nxd,
305 "Access element " << i << " of local grid with cells = "
306 << lmap_nxd);
307 int start = lgrid_map[i];
308 int end = lgrid_map[i + 1];
309 Array<int> elements(end - start);
310 for (int j = start; j < end; j++)
311 {
312 elements[j - start] = lgrid_map[j];
313 }
314 return elements;
315}
316
318{
319 MFEM_ASSERT(xyz.Size() == sdim,
320 "Point must have the same dimension as the grid.");
321 int sum = 0;
322 for (int d = sdim-1; d >= 0; --d)
323 {
324 if (xyz(d) < lmap_bnd_min(d) || xyz(d) > lmap_bnd_max(d))
325 {
326 return -1; // Point is outside the bounds of the grid
327 }
328 sum *= lmap_nx[d];
329 int i = (int)floor((xyz(d) - lmap_bnd_min(d)) * lmap_fac[d]);
330 sum += i < 0 ? 0 : (lmap_nx[d] - 1 < i ? lmap_nx[d] - 1 : i);
331 }
332 return sum;
333}
334
336{
337 MFEM_ASSERT(xyz.Size() == sdim,
338 "Point must have the same dimension as the grid.");
339 int cell = GetGridCellFromPoint(xyz);
340 if (cell < 0)
341 {
342 return Array<int>(); // Point is outside the bounds of the tensor grid
343 }
344 return GridCellToElements(cell);
345}
346
347void BBoxTensorGridMap::GetGridRange(const int d, const Array<int> &lh_n,
348 const Vector &lh_fac,
349 const Vector &lh_bnd_min,
350 const real_t &xmin, const real_t &xmax,
351 int &imin, int &imax)
352{
353 // Use a half-open interval [imin, imax) for the covered grid-cell range.
354 // If xmin is exactly on a grid boundary, use the cell on the right/high
355 // side. If xmax is exactly on a grid boundary, stop before the cell on the
356 // right/high side.
357 int i0 = floor( (xmin - lh_bnd_min[d]) * lh_fac[d] );
358 int i1 = ceil ( (xmax - lh_bnd_min[d]) * lh_fac[d] );
359 imin = std::clamp(i0, 0, lh_n[d] - 1);
360 imax = std::clamp(i1, imin + 1, lh_n[d]);
361}
362
364 const Vector &lh_bnd_min,
365 const Vector &lh_bnd_max)
366{
367 int dim = lh_bnd_min.Size();
368 for (int d = 0; d < dim; d++)
369 {
370 real_t length = lh_bnd_max[d] - lh_bnd_min[d];
371 if (length > 0.0)
372 {
373 lh_fac[d] = nx[d] / length;
374 }
375 else
376 {
377 lh_fac[d] = 0.0;
378 }
379 }
380}
381
383 const Vector &lh_fac,
384 const Vector &lh_bnd_min,
385 const Vector &lh_bnd_max,
386 const Vector &elmin,
387 const Vector &elmax,
388 Array<int> &elmin_h,
389 Array<int> &elmax_h)
390{
391 int count = 0;
392 const int dim = lh_bnd_min.Size();
393 const int nel = elmin.Size()/dim;
394 elmin_h.SetSize(dim * nel);
395 elmax_h.SetSize(dim * nel);
396 for (int i = 0; i < nel; i++)
397 {
398 int count_el = 1;
399 for (int d = 0; d < dim; d++)
400 {
401 GetGridRange(d, lh_n, lh_fac, lh_bnd_min,
402 elmin[d*nel + i], elmax[d*nel + i],
403 elmin_h[d*nel + i], elmax_h[d*nel + i]);
404 int imax = elmax_h[d*nel + i];
405 int imin = elmin_h[d*nel + i];
406 count_el *= (imax - imin);
407 }
408 count += count_el;
409 }
410 return count;
411}
412
413} // namespace mfem
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:869
int Size() const
Return the logical size of the array.
Definition array.hpp:192
Array< int > GridCellToElements(int i) const
Get list of elements corresponding to a grid cell.
static void GetGridRange(const int d, const Array< int > &lh_n, const Vector &lh_fac, const Vector &lh_bnd_min, const real_t &xmin, const real_t &xmax, int &imin, int &imax)
Get local (1D) indices for cells of tensor grid that intersect with the given bounding box.
int GetGridCellFromPoint(Vector &xyz) const
Get grid cell index for a given point.
BBoxTensorGridMap(Mesh &mesh, int nx)
Constructor for a given mesh and resolution of Cartesian grid.
static void SetGridFac(Vector &lh_fac, const Array< int > &nx, const Vector &lh_bnd_min, const Vector &lh_bnd_max)
Set grid fac - number of grid cells per unit grid extent.
static int GetGridCountAndRange(const Array< int > &lh_n, const Vector &lh_fac, const Vector &lh_bnd_min, const Vector &lh_bnd_max, const Vector &elmin, const Vector &elmax, Array< int > &elmin_h, Array< int > &elmax_h)
Get grid count and range - total number of grid cells that intersect with all elements of the mesh an...
Array< int > MapPointToElements(Vector &xyz) const
Map a point to possible overlapping elements.
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
Mesh data type.
Definition mesh.hpp:67
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition mesh.hpp:1622
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1390
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1317
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:10112
const real_t * GetVertex(int i) const
Return pointer to vertex i's coordinates.
Definition mesh.hpp:1429
Vector data type.
Definition vector.hpp:82
real_t Max() const
Returns the maximal element of the vector.
Definition vector.cpp:1200
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
real_t Min() const
Returns the minimal element of the vector.
Definition vector.cpp:1154
int dim
Definition ex24.cpp:53
MFEM_HOST_DEVICE dual< value_type, gradient_type > pow(dual< value_type, gradient_type > a, dual< value_type, gradient_type > b)
implementation of a (dual) raised to the b (dual) power
Definition dual.hpp:374
float real_t
Definition config.hpp:46
STL namespace.
std::array< int, NCMesh::MaxFaceNodes > nodes