opm-common
GeometryUtil.hpp
1 #ifndef GEOMETRYUTIL_H
2 #define GEOMETRYUTIL_H
3 
4 #include <opm/common/utility/numeric/VectorUtil.hpp>
5 
6 #include <cmath>
7 #include <cstddef>
8 #include <numeric>
9 #include <vector>
10 
11 namespace GeometryUtil {
12 
13 constexpr double epslon = 1e-6;
14 // A simple utility function to calculate area of a rectangle
15 double calculateRectangleArea(double width, double height);
16 
17 template <typename T = double>
18 T calcTetraVol(const std::array<T,4>& x, const std::array<T,4>& y, const std::array<T,4>& z ){
19  T det = x[0]*y[2]*z[1] - x[0]*y[1]*z[2] + x[1]*y[0]*z[2]
20  - x[1]*y[2]*z[0] - x[2]*y[0]*z[1] + x[2]*y[1]*z[0]
21  + x[0]*y[1]*z[3] - x[0]*y[3]*z[1] - x[1]*y[0]*z[3]
22  + x[1]*y[3]*z[0] + x[3]*y[0]*z[1] - x[3]*y[1]*z[0]
23  - x[0]*y[2]*z[3] + x[0]*y[3]*z[2] + x[2]*y[0]*z[3]
24  - x[2]*y[3]*z[0] - x[3]*y[0]*z[2] + x[3]*y[2]*z[0]
25  + x[1]*y[2]*z[3] - x[1]*y[3]*z[2] - x[2]*y[1]*z[3]
26  + x[2]*y[3]*z[1] + x[3]*y[1]*z[2] - x[3]*y[2]*z[1];
27  return std::abs(det)/6;
28 }
29 
30 template <typename T = double>
31 T calcHexaVol(const std::array<T,8>& x, const std::array<T,8>& y, const std::array<T,8>& z,
32  const T& cx, const T& cy, const T& cz )
33 {
34  constexpr std::array<std::array<int, 3>, 12> faceConfigurations
35  {
36  std::array<int, 3>{0, 1, 5},
37  {1, 5, 4}, // Face 0
38  {0, 4, 6},
39  {4, 6, 2}, // Face 1
40  {2, 3, 7},
41  {3, 7, 6}, // Face 2
42  {1, 3, 7},
43  {3, 7, 5}, // Face 3
44  {0, 1, 3},
45  {1, 3, 2}, // Face 4
46  {4, 5, 7},
47  {5, 7, 6} // Face 5
48  };
49  auto getNodes = [](const std::array<T, 8>& X, const std::array<T, 8>& Y, const std::array<T, 8>& Z,
50  const std::array<int,3>& ind){
51  std::array<T, 3> filtered_vectorX;
52  std::array<T, 3> filtered_vectorY;
53  std::array<T, 3> filtered_vectorZ;
54  for (std::size_t index = 0; index < ind.size(); index++) {
55  filtered_vectorX[index] = X[ind[index]];
56  filtered_vectorY[index] = Y[ind[index]];
57  filtered_vectorZ[index] = Z[ind[index]];
58  }
59  return std::make_tuple(filtered_vectorX,filtered_vectorY,filtered_vectorZ);
60  };
61  // note: some CPG grids may have collapsed faces that are not planar, therefore
62  // the hexadron is subdivided in terahedrons.
63  // calculating the volume of the pyramid with F0 as base and pc as center
64  T totalVolume = 0.0;
65  for (std::size_t i = 0; i < faceConfigurations.size(); i += 2) {
66  auto [fX0, fY0, fZ0] = getNodes(x, y, z, faceConfigurations[i]);
67  totalVolume += std::apply(calcTetraVol<T>, VectorUtil::appendNode<double>(fX0, fY0, fZ0, cx, cy, cz));
68 
69  auto [fX1, fY1, fZ1] = getNodes(x, y, z, faceConfigurations[i + 1]);
70  totalVolume += std::apply(calcTetraVol<T>, VectorUtil::appendNode<double>(fX1, fY1, fZ1, cx, cy, cz));
71  }
72  return totalVolume;
73 }
74 
75 template <typename T = double>
76 std::vector<int> isInsideElement(const std::vector<T>& tpX, const std::vector<T>& tpY, const std::vector<T>& tpZ,
77  const std::vector<std::array<T, 8>>& X, const std::vector<std::array<T, 8>>& Y,
78  const std::vector<std::array<T, 8>>& Z)
79 {
80  std::vector<int> in_elements(tpX.size(),0);
81  // check if it is insde or outside boundary box
82  T minX, minY, minZ, maxX, maxY, maxZ;
83  T pcX, pcY, pcZ, element_volume, test_element_volume;
84  bool flag;
85  for (std::size_t outerIndex = 0; outerIndex < X.size(); outerIndex++) {
86  minX = *std::ranges::min_element(X[outerIndex]);
87  minY = *std::ranges::min_element(Y[outerIndex]);
88  minZ = *std::ranges::min_element(Z[outerIndex]);
89  maxX = *std::ranges::max_element(X[outerIndex]);
90  maxY = *std::ranges::max_element(Y[outerIndex]);
91  maxZ = *std::ranges::max_element(Z[outerIndex]);
92  pcX = std::accumulate(X[outerIndex].begin(), X[outerIndex].end(), 0.0)/8;
93  pcY = std::accumulate(Y[outerIndex].begin(), Y[outerIndex].end(), 0.0)/8;
94  pcZ = std::accumulate(Z[outerIndex].begin(), Z[outerIndex].end(), 0.0)/8;
95  element_volume = calcHexaVol(X[outerIndex],Y[outerIndex],Z[outerIndex], pcX, pcY,pcZ);
96  for (std::size_t innerIndex = 0; innerIndex < tpX.size(); innerIndex++){
97  // check if center of refined volume is outside the boundary box of a coarse volume.
98  // Only computes volumed base test is this condition is met.
99  flag = (minX < tpX[innerIndex]) && (maxX > tpX[innerIndex]) &&
100  (minY < tpY[innerIndex]) && (maxY > tpY[innerIndex]) &&
101  (minZ < tpZ[innerIndex]) && (maxZ > tpZ[innerIndex]);
102  if (flag && (in_elements[innerIndex] == 0)) {
103  test_element_volume = calcHexaVol(X[outerIndex],Y[outerIndex],Z[outerIndex],
104  tpX[innerIndex], tpY[innerIndex],tpZ[innerIndex]);
105  if (std::abs(test_element_volume - element_volume) < epslon){
106  in_elements[innerIndex] = static_cast<int>(outerIndex);
107  }
108  }
109  }
110  }
111  return in_elements;
112 }
113 
114 
115 // Example for other utilities...
116 
117 } // namespace GeometryUtils
118 
119 #endif // GEOMETRY_UTILS_H
Definition: GeometryUtil.hpp:11