OGS
MeshElementGrid.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "MeshElementGrid.h"
5
6#include <algorithm>
7#include <bitset>
8#include <cmath>
9#include <memory>
10
12#include "MeshLib/Mesh.h"
13#include "MeshLib/Node.h"
14
15namespace MeshLib
16{
18 : _aabb{mesh.getNodes().cbegin(), mesh.getNodes().cend()},
19 _n_steps({{1, 1, 1}})
20{
21 auto getDimensions = [](auto const& min, auto const& max)
22 {
23 std::bitset<3> dim; // all bits are set to zero.
24 for (std::size_t k(0); k < 3; ++k)
25 {
26 double const tolerance(
27 std::nexttoward(max[k], std::numeric_limits<double>::max()) -
28 max[k]);
29 if (std::abs(max[k] - min[k]) > tolerance)
30 {
31 dim[k] = true;
32 }
33 }
34 return dim;
35 };
36
37 auto const [min_pnt, max_pnt] = _aabb.getMinMaxPoints();
38 auto const dim = getDimensions(min_pnt, max_pnt);
39
40 std::array<double, 3> const delta{{max_pnt[0] - min_pnt[0],
41 max_pnt[1] - min_pnt[1],
42 max_pnt[2] - min_pnt[2]}};
43
44 const std::size_t n_eles(mesh.getNumberOfElements());
45 const std::size_t n_eles_per_cell(100);
46
47 // *** condition: n_eles / n_cells < n_eles_per_cell
48 // where n_cells = _n_steps[0] * _n_steps[1] * _n_steps[2]
49 // *** with _n_steps[0] =
50 // ceil(pow(n_eles*delta[0]*delta[0]/(n_eles_per_cell*delta[1]*delta[2]),
51 // 1/3.)));
52 // _n_steps[1] = _n_steps[0] * delta[1]/delta[0],
53 // _n_steps[2] = _n_steps[0] * delta[2]/delta[0]
54 auto sc_ceil = [](double v)
55 { return static_cast<std::size_t>(std::ceil(v)); };
56
57 switch (dim.count())
58 {
59 case 3: // 3d case
60 _n_steps[0] =
61 sc_ceil(std::cbrt(n_eles * delta[0] * delta[0] /
62 (n_eles_per_cell * delta[1] * delta[2])));
63 _n_steps[1] =
64 sc_ceil(_n_steps[0] * std::min(delta[1] / delta[0], 100.0));
65 _n_steps[2] =
66 sc_ceil(_n_steps[0] * std::min(delta[2] / delta[0], 100.0));
67 break;
68 case 2: // 2d cases
69 if (dim[0] && dim[2])
70 { // 2d case: xz plane, y = const
71 _n_steps[0] = sc_ceil(std::sqrt(n_eles * delta[0] /
72 (n_eles_per_cell * delta[2])));
73 _n_steps[2] = sc_ceil(_n_steps[0] * delta[2] / delta[0]);
74 }
75 else if (dim[0] && dim[1])
76 { // 2d case: xy plane, z = const
77 _n_steps[0] = sc_ceil(std::sqrt(n_eles * delta[0] /
78 (n_eles_per_cell * delta[1])));
79 _n_steps[1] = sc_ceil(_n_steps[0] * delta[1] / delta[0]);
80 }
81 else if (dim[1] && dim[2])
82 { // 2d case: yz plane, x = const
83 _n_steps[1] = sc_ceil(std::sqrt(n_eles * delta[1] /
84 (n_eles_per_cell * delta[2])));
85 _n_steps[2] =
86 sc_ceil(n_eles * delta[2] / (n_eles_per_cell * delta[1]));
87 }
88 break;
89 case 1: // 1d cases
90 for (std::size_t k(0); k < 3; ++k)
91 {
92 if (dim[k])
93 {
94 _n_steps[k] =
95 sc_ceil(static_cast<double>(n_eles) / n_eles_per_cell);
96 }
97 }
98 }
99
100 // some frequently used expressions to fill the vector of elements per grid
101 // cell
102 for (std::size_t k(0); k < 3; k++)
103 {
104 _step_sizes[k] = delta[k] / _n_steps[k];
105 _inverse_step_sizes[k] = 1.0 / _step_sizes[k];
106 }
107
108 _elements_in_grid_box.resize(_n_steps[0] * _n_steps[1] * _n_steps[2]);
109 sortElementsInGridCells(mesh);
110}
111
112Eigen::Vector3d const& MeshElementGrid::getMinPoint() const
113{
114 return _aabb.getMinPoint();
115}
116
117Eigen::Vector3d const& MeshElementGrid::getMaxPoint() const
118{
119 return _aabb.getMaxPoint();
120}
121
123{
124 for (auto const element : mesh.getElements())
125 {
126 if (!sortElementInGridCells(*element))
127 {
128 OGS_FATAL("Sorting element (id={:d}) into mesh element grid.",
129 element->getID());
130 }
131 }
132}
133
135{
136 std::array<std::size_t, 3> min{};
137 std::array<std::size_t, 3> max{};
138 std::pair<bool, std::array<std::size_t, 3>> c(getGridCellCoordinates(
139 *(static_cast<MathLib::Point3d const*>(element.getNode(0)))));
140 if (c.first)
141 {
142 min = c.second;
143 max = min;
144 }
145 else
146 {
147 return false;
148 }
149
150 for (std::size_t k(1); k < element.getNumberOfNodes(); ++k)
151 {
152 // compute coordinates of the grid for each node of the element
154 *(static_cast<MathLib::Point3d const*>(element.getNode(k))));
155 if (!c.first)
156 {
157 return false;
158 }
159
160 for (std::size_t j(0); j < 3; ++j)
161 {
162 if (min[j] > c.second[j])
163 {
164 min[j] = c.second[j];
165 }
166 if (max[j] < c.second[j])
167 {
168 max[j] = c.second[j];
169 }
170 }
171 }
172
173 const std::size_t n_plane(_n_steps[0] * _n_steps[1]);
174
175 // If a node of an element is almost equal to the upper right point of the
176 // AABB the grid cell coordinates computed by getGridCellCoordintes() could
177 // be to large (due to numerical errors). The following lines ensure that
178 // the grid cell coordinates are in the valid range.
179 for (std::size_t k(0); k < 3; ++k)
180 {
181 max[k] = std::min(_n_steps[k] - 1, max[k]);
182 }
183
184 // insert the element into the grid cells
185 for (std::size_t i(min[0]); i <= max[0]; i++)
186 {
187 for (std::size_t j(min[1]); j <= max[1]; j++)
188 {
189 for (std::size_t k(min[2]); k <= max[2]; k++)
190 {
191 _elements_in_grid_box[i + j * _n_steps[0] + k * n_plane]
192 .push_back(&element);
193 }
194 }
195 }
196
197 return true;
198}
199
200std::pair<bool, std::array<std::size_t, 3>>
202{
203 bool valid(true);
204 std::array<std::size_t, 3> coords{};
205
206 for (std::size_t k(0); k < 3; ++k)
207 {
208 const double d(p[k] - _aabb.getMinPoint()[k]);
209 if (d < 0.0)
210 {
211 valid = false;
212 coords[k] = 0;
213 }
214 else if (_aabb.getMaxPoint()[k] <= p[k])
215 {
216 valid = false;
217 coords[k] = _n_steps[k] - 1;
218 }
219 else
220 {
221 coords[k] = static_cast<std::size_t>(d * _inverse_step_sizes[k]);
222 }
223 }
224
225 return std::make_pair(valid, coords);
226}
227} // namespace MeshLib
#define OGS_FATAL(...)
Definition Error.h:19
std::vector< std::size_t > getNodes(GeoLib::Point const &pnt, std::vector< MeshLib::Node * > const &nodes, MeshLib::PropertyVector< int > const &mat_ids, std::pair< int, int > const &mat_limits, std::pair< double, double > const &elevation_limits, MeshLib::Mesh const &mesh)
std::pair< std::size_t, std::size_t > getDimensions(std::string const &line)
Returns raster dimensions from the "Zone"-description.
virtual unsigned getNumberOfNodes() const =0
virtual const Node * getNode(unsigned idx) const =0
void sortElementsInGridCells(MeshLib::Mesh const &mesh)
std::vector< std::vector< MeshLib::Element const * > > _elements_in_grid_box
MeshElementGrid(MeshLib::Mesh const &mesh)
std::pair< bool, std::array< std::size_t, 3 > > getGridCellCoordinates(MathLib::Point3d const &p) const
bool sortElementInGridCells(MeshLib::Element const &element)
Eigen::Vector3d const & getMinPoint() const
std::array< double, 3 > _inverse_step_sizes
std::array< std::size_t, 3 > _n_steps
Eigen::Vector3d const & getMaxPoint() const
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:100