GeometryRefinement.hpp
Go to the documentation of this file.
1//===========================================================================
2//
3// File: GeometryRefinement.hpp
4//
5// Created: Fri May 29 23:29:24 2009
6//
7// Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
8// B�rd Skaflestad <bard.skaflestad@sintef.no>
9// Antonella Ritorto <antonella.ritorto@opm-op.com>
10//
11// $Date$
12//
13// $Revision$
14//
15//===========================================================================
16
17/*
18 Copyright 2009, 2010, 2011 SINTEF ICT, Applied Mathematics.
19 Copyright 2009, 2010, 2011, 2022 Equinor ASA.
20
21 This file is part of the Open Porous Media project (OPM).
22
23 OPM is free software: you can redistribute it and/or modify
24 it under the terms of the GNU General Public License as published by
25 the Free Software Foundation, either version 3 of the License, or
26 (at your option) any later version.
27
28 OPM is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
32
33 You should have received a copy of the GNU General Public License
34 along with OPM. If not, see <http://www.gnu.org/licenses/>.
35*/
36
37#ifndef OPM_GEOMETRY_REFINEMENT_HEADER
38#define OPM_GEOMETRY_REFINEMENT_HEADER
39
40// Definitions of Geometry<3, cdim>'s refinement members; included by Geometry.hpp.
41
42namespace Dune
43{
44 namespace cpgrid
45 {
46
47template <int cdim>
48void Geometry<3, cdim>::refineCellifiedPatch(const std::array<int,3>& cells_per_dim,
49DefaultGeometryPolicy& all_geom,
50std::vector<std::array<int,8>>& refined_cell_to_point,
51cpgrid::OrientedEntityTable<0,1>& refined_cell_to_face,
52Opm::SparseTable<int>& refined_face_to_point,
53cpgrid::OrientedEntityTable<1,0>& refined_face_to_cell,
55cpgrid::SignedEntityVariable<typename Geometry<3, cdim>::PointType, 1>& refined_face_normals,
56const std::array<int,3>& patch_dim,
57const std::vector<double>& widthsX,
58const std::vector<double>& lengthsY,
59const std::vector<double>& heightsZ) const
60 {
62 all_geom.geomVector(std::integral_constant<int,3>());
64 all_geom.geomVector(std::integral_constant<int,1>());
66 all_geom.geomVector(std::integral_constant<int,0>());
67 EntityVariableBase<enum face_tag>& mutable_face_tags = refined_face_tags;
68 EntityVariableBase<PointType>& mutable_face_normals = refined_face_normals;
69
71 // The strategy is to compute the local refined corners
72 // of the unit/reference cube, and then apply the map global().
73 // Determine the size of the vector containing all the corners
74 // of all the global refined cells (children cells).
75 // For easier notation:
76 const std::array<int,3>& refined_dim = { cells_per_dim[0]*patch_dim[0],
77 cells_per_dim[1]*patch_dim[1],
78 cells_per_dim[2]*patch_dim[2]};
79 refined_corners.resize((refined_dim[0] + 1)*(refined_dim[1] + 1)*(refined_dim[2] + 1));
80 // The nummbering starts at the botton, so k=0 (z-axis), and j=0 (y-axis), i=0 (x-axis).
81 // Then, increasing k ('going up'), followed by increasing i ('going right->'),
82 // and finally, increasing j ('going back'). This order criteria for corners
83 // 'Up [increasing k]- Right [incresing i]- Back [increasing j]'
84 // is consistant with cpgrid numbering.
85 //
86 assert(static_cast<int>(widthsX.size()) == patch_dim[0]);
87 assert(static_cast<int>(lengthsY.size()) == patch_dim[1]);
88 assert(static_cast<int>(heightsZ.size()) == patch_dim[2]);
89 const auto localCoordNumerator = []( const std::vector<double>& vec, int sumLimit, double multiplier) {
90 double lcn = 0;
91 assert(!vec.empty());
92 assert(sumLimit < static_cast<int>(vec.size()));
93 lcn += multiplier*vec[sumLimit];
94 for (int m = 0; m < sumLimit; ++m) {
95 lcn += vec[m];
96 }
97 return lcn;
98 };
99 // E.g. localCoordNumerator( dx, 3, 0.25) = x0 + x1 + x2 + 0.25.x3
100 //
101 const double sumWidths = std::accumulate(widthsX.begin(), widthsX.end(), double(0));
102 // x0 + x1 + ... + xL, if dx = {x0, x1, ..., xL}
103 const double sumLengths = std::accumulate(lengthsY.begin(), lengthsY.end(), double(0));
104 // y0 + y1 + ... + yM, if dy = {y0, y1, ..., yM}
105 const double sumHeights = std::accumulate(heightsZ.begin(), heightsZ.end(), double(0));
106 // z0 + z1 + ... + zN, if dz = {z0, z1, ..., zN}
107
108 for (int j = 0; j < refined_dim[1] +1; ++j) {
109 double local_y = 0;
110 for (int i = 0; i < refined_dim[0] +1; ++i) {
111 double local_x = 0.;
112 for (int k = 0; k < refined_dim[2] +1; ++k) {
113 double local_z = 0.;
114
115 // Compute the index of each global refined corner associated with 'jik'.
116 int refined_corner_idx =
117 (j*(refined_dim[0]+1)*(refined_dim[2]+1)) + (i*(refined_dim[2]+1)) + k;
118
119 // Compute the local refined corner of the unit/reference cube associated with 'jik'.
120 if ( i == refined_dim[0]) { // last corner in the x-direction
121 local_x = sumWidths;
122 } else {
123 local_x = localCoordNumerator(widthsX, i/cells_per_dim[0], double((i % cells_per_dim[0])) / cells_per_dim[0]);
124 }
125 if ( j == refined_dim[1]) { // last corner in the y-direction
126 local_y = sumLengths;
127 } else {
128 local_y = localCoordNumerator(lengthsY, j/cells_per_dim[1], double((j % cells_per_dim[1])) / cells_per_dim[1]);
129 }
130 if ( k == refined_dim[2]) { // last corner in the z-direction
131 local_z = sumHeights;
132 } else {
133 local_z = localCoordNumerator(heightsZ, k/cells_per_dim[2], double((k % cells_per_dim[2])) /cells_per_dim[2]);
134 }
135
136 const LocalCoordinate& local_refined_corner = { local_x/sumWidths, local_y/sumLengths, local_z/sumHeights };
137 assert(local_x/sumWidths <= 1.);
138 assert(local_y/sumLengths <= 1.);
139 assert(local_z/sumHeights <= 1.);
140
141 // Compute the global refined corner 'jik' and add it in its corresponfing entry in "refined_corners".
142 refined_corners[refined_corner_idx] = Geometry<0, 3>(this->global(local_refined_corner));
143 } // end k-for-loop
144 } // end i-for-loop
145 } // end j-for-loop
147 //
149 // We want to populate "refined_faces". The size of "refined_faces" is
150 const int refined_faces_size =
151 (refined_dim[0]*refined_dim[1]*(refined_dim[2]+1)) // 'bottom/top faces'
152 + ((refined_dim[0]+1)*refined_dim[1]*refined_dim[2]) // 'left/right faces'
153 + (refined_dim[0]*(refined_dim[1]+1)*refined_dim[2]); // 'front/back faces'
154 refined_faces.resize(refined_faces_size);
155 refined_face_tags.resize(refined_faces_size);
156 refined_face_normals.resize(refined_faces_size);
157 //
158 // To create a face as a Geometry<2,3> type object we need its CENTROID and its VOLUME(area).
159 // We store the centroids/areas in the following order:
160 // - Bottom-top faces -> 3rd coordinate constant in each face.
161 // - Left-right faces -> 1st coordinate constant in each face.
162 // - Front-back faces -> 2nd coordinate constant in each face.
163 //
164 // REFINED FACE AREAS
165 // To compute the area of each face, we divide it in 4 triangles,
166 // compute the area of those with "area()", where the arguments
167 // are the 3 corners of each triangle. Then, sum them up to get the area
168 // of the global refined face.
169 // For each face, we construct 4 triangles with
170 // (1) centroid of the face,
171 // (2) one of the edges of the face.
172 //
173 // A triangle has 3 edges. Once we choose a face to base a triangle on,
174 // we choose an edge of that face as one of the edges of the triangle.
175 // The other 2 edges are fixed, since the centroid of the face the triangle
176 // is based on is one of its corners. That's why to identify
177 // a triangle we only need two things:
178 // (1) the face it's based on and
179 // (2) one of the four edges of that face.
180 //
181 // For each face, we need
182 // 1. index of the refined face
183 // [needed to access indices of the 4 edges of the face in "refined_face_to_edges"]
184 // 2. centroid of the face (common corner of the 4 triangles based on that face).
185 // [available via "['face'].center()"
186 // 3. container of 4 entries (the 4 edges of the face).
187 // Each entry consists in the 2 indices defining each edge of the face.
188 // [available in "refined_face_to_edges"].
189 //
190 // Populate "mutable_face_tags/normals", "refined_face_to_point/cell",
191 // "refined_faces".
192 //
193 for (int constant_direction = 0; constant_direction < 3; ++constant_direction){
194 // adding %3 and constant_direction, we go through the 3 type of faces.
195 // 0 -> 3rd coordinate constant: l('k') < cells_per_dim[2]+1, m('j') < cells_per_dim[1], n('i') < cells_per_dim[0]
196 // 1 -> 1rt coordinate constant: l('i') < cells_per_dim[0]+1, m('k') < cells_per_dim[2], n('j') < cells_per_dim[1]
197 // 2 -> 2nd coordinate constant: l('j') < cells_per_dim[1]+1, m('i') < cells_per_dim[0], n('k') < cells_per_dim[2]
198 std::array<int,3> refined_dim_mixed = {
199 refined_dim[(2+constant_direction)%3],
200 refined_dim[(1+constant_direction)%3],
201 refined_dim[constant_direction % 3] };
202 for (int l = 0; l < refined_dim_mixed[0] + 1; ++l) {
203 for (int m = 0; m < refined_dim_mixed[1]; ++m) {
204 for (int n = 0; n < refined_dim_mixed[2]; ++n) {
205 // Compute the face data.
206 auto [face_tag, idx, face_to_point, face_to_cell, wrong_local_centroid] =
207 getIndicesFace(l, m, n, constant_direction, refined_dim);
208 // Add the tag to "refined_face_tags".
209 mutable_face_tags[idx]= face_tag;
210 // Add the 4 corners of the face to "refined_face_to_point".
211 refined_face_to_point.appendRow(face_to_point.begin(), face_to_point.end());
212 // Add the neighboring cells of the face to "refined_face_to_cell".
213 refined_face_to_cell.appendRow(face_to_cell.begin(), face_to_cell.end());
214 // Compute the centroid as the average of the 4 corners of the face
215 GlobalCoordinate face_center = { 0., 0., 0.};
216 for (int corn = 0; corn < 4; ++corn){
217 face_center += refined_corners[face_to_point[corn]].center();
218 }
219 face_center /= 4.;
220 // Construct global face normal(s) (only one 'needed') and add it to "mutable_face_normals"
221 // Construct two vectors in the face, e.g. difference of two conners with the centroid,
222 // then obtain an orthogonal vector to both of them. Finally, normalize.
223 // Auxuliary vectors on the face:
224 GlobalCoordinate face_vector0 = refined_corners[face_to_point[0]].center() - face_center;
225 GlobalCoordinate face_vector1 = refined_corners[face_to_point[1]].center() - face_center;
226 mutable_face_normals[idx] = {
227 (face_vector0[1]*face_vector1[2]) - (face_vector0[2]*face_vector1[1]),
228 (face_vector0[2]*face_vector1[0]) - (face_vector0[0]*face_vector1[2]),
229 (face_vector0[0]*face_vector1[1]) - (face_vector0[1]*face_vector1[0])};
230 mutable_face_normals[idx] /= mutable_face_normals[idx].two_norm();
231 if (face_tag == J_FACE) {
232 mutable_face_normals[idx] *= -1;
233 }
234 // Construct "refined_face_to_edges"
235 // with the {edge_indix[0], edge_index[1]} for each edge of the refined face.
236 std::vector<std::array<int,2>> refined_face_to_edges = {
237 { face_to_point[0], face_to_point[1] },
238 { face_to_point[1], face_to_point[2] },
239 { face_to_point[2], face_to_point[3] },
240 { face_to_point[3], face_to_point[0] }
241 };
242 // Calculate the AREA of each face of a global refined face,
243 // by adding the 4 areas of the triangles partitioning each face.
244 double refined_face_area = 0.0;
245 for (int edge = 0; edge < 4; ++edge) {
246 // Construction of each triangle on the current face with one
247 // of its edges equal to "edge".
248 Geometry<0,3>::GlobalCoordinate trian_corners[3] = {
249 refined_corners[refined_face_to_edges[edge][0]].center(),
250 refined_corners[refined_face_to_edges[edge][1]].center(),
251 face_center };
252 refined_face_area += std::fabs(area(trian_corners));
253 } // end edge-for-loop
254 //
255 //
256 // Construct the Geometry<2,3> of the global refined face.
257 refined_faces[idx] = Geometry<2,cdim>(face_center, refined_face_area);
258 } // end n-for-loop
259 } // end m-for-loop
260 } // end l-for-loop
261 } // end r-for-loop
263 //
265 // We need to populate "refined_cells"
266 // "refined_cells"'s size is cells_per_dim[0] * cells_per_dim[1] * cells_per_dim[2].
267 // To build each global refined cell, we need
268 // 1. its global refined CENTER
269 // 2. its VOLUME
270 // 3. all global refined corners [available in "refined_corners"]
271 // 4. indices of its 8 corners.
272 //
273 refined_cells.resize(refined_dim[0] * refined_dim[1] * refined_dim[2]);
274 // Vector to store, in each entry, the 8 indices of the 8 corners
275 // of each global refined cell. Determine its size.
276 refined_cell_to_point.resize(refined_dim[0] * refined_dim[1] * refined_dim[2]);
277 // The numembering starts with index 0 for the refined cell with corners
278 // {0,0,0}, ...,{1/cells_per_dim[0], 1/cells_per_dim[1], 1/cells_per_dim[2]},
279 // then the indices grow first picking the cells in the x-axis (Right, i), then y-axis (Back, j), and
280 // finally, z-axis (Up, k).
281 //
282 // CENTERS
283 // REFINED CELL CENTERS
284 // The strategy is to compute the centers of the refined local
285 // unit/reference cube, and then apply the map global().
286 //
287 // VOLUMES OF THE REFINED CELLS
288 // REMARK: Each global refined 'cell' is a hexahedron since it may not be cube-shaped
289 // since its a 'deformation' of unit/reference cube. We may use 'hexahedron' to refer
290 // to the global refined cell in the computation of its volume.
291 //
292 // The strategy is to construct 24 tetrahedra in each hexahedron.
293 // Each tetrahedron is built with
294 // (1) the center of the hexahedron,
295 // (2) the middle point of the face the tetrahedron is based on, and
296 // (3) one of the edges of the face mentioned in 2.
297 // Each face 'supports' 4 tetrahedra, and we have 6 faces per hexahedron, which
298 // gives us the 24 tetrahedra per 'cell' (hexahedron).
299 //
300 // To compute the volume of each tetrahedron, we use "simplex_volume()" with
301 // the 6 corners of the tetrahedron as arguments. Summing up the 24 volumes,
302 // we get the volumne of the hexahedorn (global refined 'cell').
303 //
304 // Sum of all the volumes of all the (children) global refined cells.
305 double sum_all_refined_cell_volumes = 0.0;
306 //
307 // For each (global refined 'cell') hexahedron, to create 24 tetrahedra and their volumes,
308 // we introduce
309 // Vol1. "hexa_to_face" (needed to access face centroids).
310 // Vol2. "hexa_face_centroids" (one of the 6 corners of all 4 tetrahedra based on that face).
311 // Vol3. the center of the global refined 'cell' (hexahedron)
312 // (common corner of the 24 tetrahedra).
313 // Vol4. "tetra_edge_indices" indices of the 4x6 tetrahedra per 'cell',
314 // grouped by the face they are based on.
315 // Then we construct and compute the volume of the 24 tetrahedra with mainly
316 // "hexa_face_centroids" (Vol2.), global refined cell center (Vol3.), and "tetra_edge_indices" (Vol4.).
317 //
318 for (int k = 0; k < refined_dim[2]; ++k) {
319 for (int j = 0; j < refined_dim[1]; ++j) {
320 for (int i = 0; i < refined_dim[0]; ++i) {
321 // INDEX of the global refined cell associated with 'kji'.
322 int refined_cell_idx = (k*refined_dim[0]*refined_dim[1]) + (j*refined_dim[0]) +i;
323 // Obtain the global refined center with 'this->global(local_refined_cell_center)'.
324 // 2. VOLUME of the global refined 'kji' cell
325 double refined_cell_volume = 0.0; // (computed below!)
326 // 3. All Global refined corners ("refined_corners")
327 // 4. Indices of the 8 corners of the global refined cell associated with 'kji'.
328 std::array<int,8> cell_to_point = { //
329 (j*(refined_dim[0]+1)*(refined_dim[2]+1)) + (i*(refined_dim[2]+1)) +k, // fake '0' {0,0,0}
330 (j*(refined_dim[0]+1)*(refined_dim[2]+1)) + ((i+1)*(refined_dim[2]+1)) +k, // fake '1' {1,0,0}
331 ((j+1)*(refined_dim[0]+1)*(refined_dim[2]+1)) + (i*(refined_dim[2]+1)) +k, // fake '2' {0,1,0}
332 ((j+1)*(refined_dim[0]+1)*(refined_dim[2]+1)) + ((i+1)*(refined_dim[2]+1)) +k, // fake '3' {1,1,0}
333 (j*(refined_dim[0]+1)*(refined_dim[2]+1)) + (i*(refined_dim[2]+1)) +k+1, // fake '4' {0,0,1}
334 (j*(refined_dim[0]+1)*(refined_dim[2]+1)) + ((i+1)*(refined_dim[2]+1)) +k+1, // fake '5' {1,0,1}
335 ((j+1)*(refined_dim[0]+1)*(refined_dim[2]+1)) + (i*(refined_dim[2]+1)) +k+1, // fake '6' {0,1,1}
336 ((j+1)*(refined_dim[0]+1)*(refined_dim[2]+1)) + ((i+1)*(refined_dim[2]+1)) +k+1 // fake '7' {1,1,1}
337 };
338 // Add this 8 corners to the corresponding entry of "refined_cell_to_point".
339 refined_cell_to_point[refined_cell_idx] = cell_to_point;
340 // 1. CENTER of the global refined cell associated with 'kji' (Vol3.)
341 // Compute the center of the local refined unit/reference cube associated with 'kji'.
342 GlobalCoordinate refined_cell_center = {0., 0., 0.};
343 for (int corn = 0; corn < 8; ++corn) {
344 refined_cell_center += refined_corners[cell_to_point[corn]].center();
345 }
346 refined_cell_center /= 8.;
347 //
348 // VOLUME HEXAHEDRON (GLOBAL REFINED 'CELL')
349 // Vol1. INDICES ('from 0 to 5') of the faces of the hexahedron (needed to access face centroids).
350 std::vector<int> hexa_to_face = { //hexa_face_0to5_indices = {
351 // index face '0' bottom
352 (k*refined_dim[0]*refined_dim[1]) + (j*refined_dim[0]) + i,
353 // index face '1' front
354 (refined_dim[0]*refined_dim[1]*(refined_dim[2]+1))
355 + ((refined_dim[0]+1)*refined_dim[1]*refined_dim[2])
356 + (j*refined_dim[0]*refined_dim[2]) + (i*refined_dim[2]) + k,
357 // index face '2' left
358 (refined_dim[0]*refined_dim[1]*(refined_dim[2]+1))
359 + (i*refined_dim[1]*refined_dim[2]) + (k*refined_dim[1]) + j,
360 // index face '3' right
361 (refined_dim[0]*refined_dim[1]*(refined_dim[2]+1))
362 + ((i+1)*refined_dim[1]*refined_dim[2]) + (k*refined_dim[1]) + j,
363 // index face '4' back
364 (refined_dim[0]*refined_dim[1]*(refined_dim[2]+1)) +
365 ((refined_dim[0]+1)*refined_dim[1]*refined_dim[2])
366 + ((j+1)*refined_dim[0]*refined_dim[2]) + (i*refined_dim[2]) + k,
367 // index face '5' top
368 ((k+1)*refined_dim[0]*refined_dim[1]) + (j*refined_dim[0]) + i};
369 //
370 // We add the 6 faces of the cell into "refined_cell_to_face".
371 using cpgrid::EntityRep;
372 // First value is index, Second is orientation.
373 // Still have to find out what the orientation should be.
374 // right face ('3') outer normal points 'from left to right' -> orientation true
375 // back face ('4') outer normal points 'from front to back' -> orientation true
376 // top face ('5') outer normal points 'from bottom to top' -> orientation true
377 // (the other cases are false)
378 std::vector<cpgrid::EntityRep<1>> cell_to_face = {
379 { hexa_to_face[0], false}, {hexa_to_face[1], false},
380 { hexa_to_face[2], false}, {hexa_to_face[3], true},
381 { hexa_to_face[4], true}, {hexa_to_face[5], true} };
382 refined_cell_to_face.appendRow(cell_to_face.begin(), cell_to_face.end());
383 //
384 // Vol2. CENTROIDS of the faces of the hexahedron.
385 // (one of the 6 corners of all 4 tetrahedra based on that face).
386 std::vector<Geometry<0,3>::GlobalCoordinate> hexa_face_centroids;
387 for (auto& idx : hexa_to_face) {
388 hexa_face_centroids.push_back(refined_faces[idx].center());
389 }
390 // Indices of the 4 edges of each face of the hexahedron.
391 // A tetrahedron has six edges. Once we choose a face to base a
392 // tetrahedron on, we choose an edge of that face as one of the
393 // edges of the tetrahedron. The other five edges are fixed, since
394 // the center of the hexahedron and the center of the face are
395 // the reminder 2 corners of the tetrahedron. That's why to identify
396 // a tetrahedron we only need two things:
397 // (1) the face it's based on and
398 // (2) one of the four edges of that face.
399 //
400 // Container with 6 entries, one per face. Each entry has the
401 // 4 indices of the 4 corners of each face.
402 std::vector<std::array<int,4>> cell_face4corners;
403 cell_face4corners.reserve(6);
404 for (int face = 0; face < 6; ++face) {
405 cell_face4corners.push_back({
406 refined_face_to_point[hexa_to_face[face]][0],
407 refined_face_to_point[hexa_to_face[face]][1],
408 refined_face_to_point[hexa_to_face[face]][2],
409 refined_face_to_point[hexa_to_face[face]][3] });
410 }
411 // Vol4. Container with indices of the edges of the 4 tetrahedra per face
412 // [according to description above]
413 std::vector<std::vector<std::array<int,2>>> tetra_edge_indices;
414 tetra_edge_indices.reserve(6);
415 for (auto& face_indices : cell_face4corners)
416 {
417 std::vector<std::array<int,2>> face4edges_indices = {
418 { face_indices[0], face_indices[1]}, // fake '{0,1}'/'{4,5}'
419 { face_indices[0], face_indices[2]}, // fake '{0,2}'/'{4,6}'
420 { face_indices[1], face_indices[3]}, // fake '{1,3}'/'{5,7}'
421 { face_indices[2], face_indices[3]} }; // fake '{2,3}'/'{6,7}'
422 tetra_edge_indices.push_back(face4edges_indices);
423 }
424 // Sum of the 24 volumes to get the volume of the hexahedron,
425 // stored in "refined_cell_volume".
426 // Calculate the volume of each hexahedron, by adding
427 // the 4 tetrahedra at each face (4x6 = 24 tetrahedra).
428 for (int face = 0; face < 6; ++face) {
429 for (int edge = 0; edge < 4; ++edge) {
430 // Construction of each tetrahedron based on "face" with one
431 // of its edges equal to "edge".
432 const Geometry<0, 3>::GlobalCoordinate tetra_corners[4] = {
433 refined_corners[tetra_edge_indices[face][edge][0]].center(), // (see Vol4.)
434 refined_corners[tetra_edge_indices[face][edge][1]].center(), // (see Vol4.)
435 hexa_face_centroids[face], // (see Vol2.)
436 refined_cell_center }; // (see Vol3.)
437 refined_cell_volume += std::fabs(simplex_volume(tetra_corners));
438 } // end edge-for-loop
439 } // end face-for-loop
440 // Add the volume of the hexahedron (global refined 'cell')
441 // to the container with of all volumes of all the refined cells.
442 sum_all_refined_cell_volumes += refined_cell_volume;
443 // Create a pointer to the first element of "refined_cell_to_point"
444 // (required as the fourth argement to construct a Geometry<3,3> type object).
445 int* indices_storage_ptr = refined_cell_to_point[refined_cell_idx].data();
446 // Construct the Geometry of the refined cell associated with 'kji'.
447 refined_cells[refined_cell_idx] =
448 Geometry<3,cdim>(refined_cell_center,
449 refined_cell_volume,
450 all_geom.pointGeometryPtr(),
451 indices_storage_ptr);
452 } // end i-for-loop
453 } // end j-for-loop
454 } // end k-for-loop
455 // Rescale all volumes if the sum of volume of all the global refined 'cells' does not match the
456 // volume of the 'parent cell'.
457 // Compare the sum of all the volumes of all refined cells with 'parent cell' volume.
458 if (std::fabs(sum_all_refined_cell_volumes - this->volume())
459 > std::numeric_limits<Geometry<3, cdim>::ctype>::epsilon()) {
460 Geometry<3, cdim>::ctype correction = this->volume() / sum_all_refined_cell_volumes;
461 for(auto& cell: refined_cells){
462 cell.vol_ *= correction;
463 }
464 } // end if-statement
466 }
467
468template <int cdim>
469const std::tuple< enum face_tag, int,
470std::array<int, 4>, std::vector<cpgrid::EntityRep<0>>,
472Geometry<3, cdim>::getIndicesFace(int l, int m, int n, int constant_direction, const std::array<int, 3>& cells_per_dim) const
473 {
474 using cpgrid::EntityRep;
475 std::vector<cpgrid::EntityRep<0>> neighboring_cells_of_one_face; // {index, orientation}
476 switch(constant_direction) {
477 case 0: // {l,m,n} = {k,j,i}, constant in z-direction
478 // Orientation true when outer normal points 'from bottom to top'
479 // Orientation false when outer normal points 'from top to bottom'
480 if (l != 0) {
481 neighboring_cells_of_one_face.push_back({((l-1)*cells_per_dim[0]*cells_per_dim[1])
482 + (m*cells_per_dim[0]) + n, true});
483 }
484 if (l != cells_per_dim[2]) {
485 neighboring_cells_of_one_face.push_back({ (l*cells_per_dim[0]*cells_per_dim[1])
486 + (m*cells_per_dim[0]) + n, false});
487 }
488 return { face_tag::K_FACE,
489 (l*cells_per_dim[0]*cells_per_dim[1]) + (m*cells_per_dim[0]) + n,
490 {(m*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (n*(cells_per_dim[2]+1)) +l,
491 (m*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + ((n+1)*(cells_per_dim[2]+1)) +l,
492 ((m+1)*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + ((n+1)*(cells_per_dim[2]+1)) +l,
493 ((m+1)*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (n*(cells_per_dim[2]+1)) +l},
494 neighboring_cells_of_one_face,
495 {(.5 + n)/cells_per_dim[0], (.5 + m)/cells_per_dim[1], double(l)/cells_per_dim[2]}};
496 case 1: // {l,m,n} = {i,k,j}, constant in the x-direction
497 // Orientation true when outer normal points 'from left to right'
498 // Orientation false when outer normal points 'from right to left'
499 if (l != 0) {
500 neighboring_cells_of_one_face.push_back({(m*cells_per_dim[0]*cells_per_dim[1])
501 + (n*cells_per_dim[0]) +l-1, true});
502 }
503 if (l != cells_per_dim[0]) {
504 neighboring_cells_of_one_face.push_back({ (m*cells_per_dim[0]*cells_per_dim[1])
505 + (n*cells_per_dim[0]) + l, false});
506 }
507 return { face_tag::I_FACE,
508 (cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1))
509 + (l*cells_per_dim[1]*cells_per_dim[2]) + (m*cells_per_dim[1]) + n,
510 {(n*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (l*(cells_per_dim[2]+1)) +m,
511 ((n+1)*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (l*(cells_per_dim[2]+1)) +m,
512 ((n+1)*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (l*(cells_per_dim[2]+1)) +m+1,
513 (n*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (l*(cells_per_dim[2]+1)) +m+1},
514 neighboring_cells_of_one_face,
515 { double(l)/cells_per_dim[0], (.5 + n)/cells_per_dim[1], (.5 + m)/cells_per_dim[2]}};
516 case 2: // {l,m,n} = {j,i,k}, constant in the y-direction
517 // Orientation true when outer normal points 'from front to back'
518 // Orientation false when outer normal points 'from back to front'
519 if (l != 0) {
520 neighboring_cells_of_one_face.push_back({(n*cells_per_dim[0]*cells_per_dim[1])
521 + ((l-1)*cells_per_dim[0]) +m, true});
522 }
523 if (l != cells_per_dim[1]) {
524 neighboring_cells_of_one_face.push_back({(n*cells_per_dim[0]*cells_per_dim[1])
525 + (l*cells_per_dim[0]) + m, false});
526 }
527 return { face_tag::J_FACE,
528 (cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2] +1))
529 + ((cells_per_dim[0]+1)*cells_per_dim[1]*cells_per_dim[2])
530 + (l*cells_per_dim[0]*cells_per_dim[2]) + (m*cells_per_dim[2]) + n,
531 {(l*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (m*(cells_per_dim[2]+1)) +n,
532 (l*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + ((m+1)*(cells_per_dim[2]+1)) +n,
533 (l*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + ((m+1)*(cells_per_dim[2]+1)) +n+1,
534 (l*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (m*(cells_per_dim[2]+1)) +n+1},
535 neighboring_cells_of_one_face,
536 {(.5 + m)/cells_per_dim[0], double(l)/cells_per_dim[1], (.5 + n)/cells_per_dim[2]}};
537 default:
538 // Should never be reached, but prevents compiler warning
539 OPM_THROW(std::logic_error, "Unhandled dimension. This should never happen!");
540 }
541 }
542
543 } // namespace cpgrid
544} // namespace Dune
545
546#endif // OPM_GEOMETRY_REFINEMENT_HEADER
Definition: DefaultGeometryPolicy.hpp:53
const EntityVariable< cpgrid::Geometry< 3 - codim, 3 >, codim > & geomVector() const
Definition: DefaultGeometryPolicy.hpp:86
std::shared_ptr< const EntityVariable< cpgrid::Geometry< 0, 3 >, 3 > > pointGeometryPtr() const
Keep the corner geometries alive when constructing cell geometries.
Definition: DefaultGeometryPolicy.hpp:129
Represents an entity of a given codim, with positive or negative orientation.
Definition: EntityRep.hpp:98
Base class for EntityVariable and SignedEntityVariable. Forwards a restricted subset of the std::vect...
Definition: EntityRep.hpp:218
Definition: Geometry.hpp:229
Specialization for 3-dimensional geometries, i.e. cells.
Definition: Geometry.hpp:374
FieldVector< ctype, coorddimension > GlobalCoordinate
Range type of.
Definition: Geometry.hpp:394
FieldVector< ctype, mydimension > LocalCoordinate
Domain type of.
Definition: Geometry.hpp:392
Definition: Geometry.hpp:76
A class design to hold a variable with a value for each entity of the given codimension,...
Definition: EntityRep.hpp:306
The namespace Dune is the main namespace for all Dune code.
Definition: common/CartesianIndexMapper.hpp:10
T area(const Point< T, 2 > *c)
Definition: Volumes.hpp:119
T volume(const Point< T, 3 > *c)
Computes the volume of a 3D simplex (embedded i 3D space).
Definition: Volumes.hpp:138
T simplex_volume(const Point< T, Dim > *a)
Definition: Volumes.hpp:104
face_tag
Definition: preprocess.h:66
@ K_FACE
Definition: preprocess.h:69
@ J_FACE
Definition: preprocess.h:68
@ I_FACE
Definition: preprocess.h:67