Loading [MathJax]/extensions/tex2jax.js
MAIA bb96820c
Multiphysics at AIA
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
geometryintersection.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
8#include "geometryelement.h"
9
10using namespace std;
11using namespace maia;
12
13#define SWAP_ENDIAN
14
15//#ifdef SSADAKSDPLAKSD
16
17
18// -------------------------------------------------------------------------------
19
27template <MInt nDim_>
28void GeometryIntersection<nDim_>::addPoint(const std::vector<polyVertex>* vertices, const MInt* indices, const MInt n,
29 std::array<MFloat, nDim> res) {
30 TRACE();
31
32 res.fill(0.0);
33
34 // sum up all vertex coordinates
35 for(MInt v = 0; v < n; v++) {
36 for(MInt i = 0; i < nDim_; i++) {
37 res[i] += (*vertices)[indices[v]].coordinates[i];
38 }
39 }
40
41 // determine midpoint (as mean value of the verticies)
42 for(MInt i = 0; i < nDim_; i++)
43 res[i] /= n;
44}
45
46//-----------------------------------------------------------------------------
47
48// computes the face-properties by subdividing any polygon-face into multiple triangles!
49template <>
50void GeometryIntersection<3>::compFaceIntegrals_pyraBased3(polyFace* face, const std::vector<polyVertex>* vertices,
51 MFloat* MC, MFloat* VC, MFloat* XC) {
52 // compute Midpoint of face as arithmetic mean of bounding points
53 const MInt noPoints = (signed)(*face).vertices.size();
54 array<MFloat, 3> faceMidPoint{};
55
56 for(MInt i = 0; i < noPoints; i++) {
57 const MInt vertex = (*face).vertices[i];
58 for(MInt j = 0; j < nDim; j++) {
59 faceMidPoint[j] += (*vertices)[vertex].coordinates[j];
60 }
61 }
62
63 for(MInt j = 0; j < nDim; j++) {
64 faceMidPoint[j] /= noPoints;
65 }
66
67 array<MFloat, 3> center{};
68 MFloat area = 0.0;
69
70 // compute area, center, tetraeder volume and tetraeder center (with MC) of each face triangle
71 if(face->isLine) {
72 center = faceMidPoint;
73 } else {
74 const MInt vertex0 = (*face).vertices[0];
75 for(MInt i = 1; i < noPoints - 1; i++) {
76 const MInt vertex1 = (*face).vertices[i];
77 const MInt vertex2 = (*face).vertices[i + 1];
78
79 MFloat a[3], b[3], c[3];
80 MFloat centerTetra[3]{};
81 MFloat centerTri[3]{};
82 for(MInt j = 0; j < nDim; j++) {
83 a[j] = (*vertices)[vertex1].coordinates[j] - (*vertices)[vertex0].coordinates[j];
84 b[j] = (*vertices)[vertex2].coordinates[j] - (*vertices)[vertex0].coordinates[j];
85 c[j] = MC[j] - (*vertices)[vertex0].coordinates[j];
86 centerTri[j] = (*vertices)[vertex0].coordinates[j] + (*vertices)[vertex1].coordinates[j]
87 + (*vertices)[vertex2].coordinates[j];
88 centerTetra[j] = centerTri[j] + MC[j];
89 }
90 MFloat aCrossB[3];
91 aCrossB[0] = a[1] * b[2] - a[2] * b[1];
92 aCrossB[1] = a[2] * b[0] - a[0] * b[2];
93 aCrossB[2] = a[0] * b[1] - a[1] * b[0];
94 MFloat aCrossBTimesC = F0;
95 MFloat normACrossB = F0;
96 for(MInt j = 0; j < nDim; j++) {
97 aCrossBTimesC += aCrossB[j] * c[j];
98 normACrossB += aCrossB[j] * aCrossB[j];
99 centerTri[j] *= F1B3;
100 centerTetra[j] *= F1B4;
101 }
102 normACrossB = sqrt(normACrossB);
103 MFloat volumeTetra = F1B6 * aCrossBTimesC;
104 MFloat areaTri = F1B2 * normACrossB;
105
106 area += areaTri;
107 *VC += volumeTetra;
108 for(MInt j = 0; j < nDim; j++) {
109 center[j] += areaTri * centerTri[j];
110 XC[j] += volumeTetra * centerTetra[j];
111 }
112 }
113 if(area > m_eps) {
114 for(MInt j = 0; j < nDim; j++) {
115 center[j] /= area;
116 }
117 } else {
118 area = 0.0;
119 center = faceMidPoint;
120 }
121 }
122 face->area = area;
123 ASSERT(!(std::isnan(area)), "");
124 // ASSERT(! (std::isnan(1/area)),"");
125 for(MInt j = 0; j < nDim; j++) {
126 face->center[j] = center[j];
127 ASSERT(!(std::isnan(center[j])), "");
128 }
129}
130
131//-----------------------------------------------------------------------------
132
133template <>
134void GeometryIntersection<3>::compVolumeIntegrals_pyraBased3(std::vector<polyCutCell>* cutCells,
135 std::vector<polyFace>* faces,
136 const std::vector<polyVertex>* vertices) {
137 for(MInt cC = 0; (unsigned)cC < cutCells->size(); cC++) {
138 MFloat volume = F0;
139 MFloat center[3] = {F0, F0, F0};
140 polyCutCell* cutCell = &(*cutCells)[cC];
141 MFloat M[3] = {F0, F0, F0};
142 MInt count = 0;
143 for(MInt i = 0; (unsigned)i < cutCell->faces.size(); i++) {
144 const MInt face = cutCell->faces[i];
145 for(MInt j = 0; j < (signed)(*faces)[face].vertices.size(); j++) {
146 const MInt vertex = (*faces)[face].vertices[j];
147 for(MInt k = 0; k < nDim; k++) {
148 M[k] += (*vertices)[vertex].coordinates[k];
149 }
150 count++;
151 }
152 }
153 if(count) {
154 for(MInt k = 0; k < nDim; k++) {
155 M[k] /= count;
157 }
158 for(MInt i = 0; (unsigned)i < cutCell->faces.size(); i++) {
159 polyFace* face = &(*faces)[cutCell->faces[i]];
160 compFaceIntegrals_pyraBased3(face, vertices, M, &volume, center);
161 }
162
163 cutCell->volume = volume;
164 if(fabs(volume) > 1e2 * m_eps) {
165 for(MInt i = 0; i < nDim; i++) {
166 cutCell->center[i] = center[i] / volume;
167 }
168 } else {
169 cutCell->volume = fabs(volume);
170 for(MInt i = 0; i < nDim; i++) {
171 cutCell->center[i] = M[i];
172 }
173 }
174 }
175}
176
177
178//-----------------------------------------------------------------------------
179
180template <>
181void GeometryIntersection<3>::writeVTKFileOfCell(MInt cellId, std::vector<polyFace>* faces,
182 const std::vector<polyVertex>* vertices, MInt set) {
183 const MChar* fileName = "cell_";
184 stringstream fileName2;
185 fileName2 << fileName << grid().tree().globalId(cellId) << "_s" << set << ".vtk";
186 ofstream ofl;
187 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
188
189 if(ofl) {
190 // set fixed floating point output
191 ofl.setf(ios::fixed);
192 ofl.precision(16);
193
194 ofl << "# vtk DataFile Version 3.0" << endl
195 << "MAIAD cutsurface file" << endl
196 << "ASCII" << endl
197 << endl
198 << "DATASET UNSTRUCTURED_GRID" << endl
199 << endl;
200
201 ofl << "POINTS " << (*vertices).size() << " float" << endl;
202
203 for(MInt v = 0; (unsigned)v < (*vertices).size(); v++) {
204 for(MInt i = 0; i < 3; i++)
205 ofl << (*vertices)[v].coordinates[i] << " ";
206 ofl << endl;
207 }
208
209 ofl << endl;
210 MInt numPoints = 0;
211 MInt noFaces = 0;
212 for(MInt f = 0; (unsigned)f < (*faces).size(); f++) {
213 numPoints += (*faces)[f].vertices.size();
214 noFaces++;
215 }
216 ofl << "CELLS " << noFaces << " " << noFaces + numPoints << endl;
217
218 for(MInt f = 0; (unsigned)f < (*faces).size(); f++) {
219 MInt noEdges = (signed)(*faces)[f].vertices.size();
220 ofl << noEdges << " ";
221
222 for(MInt i = noEdges - 1; i >= 0; i--) {
223 ofl << (*faces)[f].vertices[i] << " ";
224 }
225 ofl << endl;
226 }
227
228
229 ofl << "CELL_TYPES " << noFaces << endl;
230 for(MInt i = 0; i < noFaces; i++) {
231 ofl << 7 << endl;
232 }
233
234 ofl << "CELL_DATA " << noFaces << endl;
235 ofl << "SCALARS bodyId int 1" << endl;
236 ofl << "LOOKUP_TABLE default" << endl;
237 for(MInt f = 0; (unsigned)f < (*faces).size(); f++) {
238 ofl << (*faces)[f].bodyId << endl;
239 }
240
241 ofl << "SCALARS face int 1" << endl;
242 ofl << "LOOKUP_TABLE default" << endl;
243 for(MInt f = 0; (unsigned)f < (*faces).size(); f++) {
244 ofl << f << endl;
245 }
247 ofl << "SCALARS faceId int 1" << endl;
248 ofl << "LOOKUP_TABLE default" << endl;
249 for(MInt f = 0; (unsigned)f < (*faces).size(); f++) {
250 ofl << (*faces)[f].faceId << endl;
251 }
252
253 ofl << "SCALARS faceType int 1" << endl;
254 ofl << "LOOKUP_TABLE default" << endl;
255 for(MInt f = 0; (unsigned)f < (*faces).size(); f++) {
256 ofl << (*faces)[f].faceType << endl;
257 }
258
259 ofl << "SCALARS cutCell int 1" << endl;
260 ofl << "LOOKUP_TABLE default" << endl;
261 for(MInt f = 0; (unsigned)f < (*faces).size(); f++) {
262 ofl << (*faces)[f].cutCell << endl;
263 }
264
265 ofl << "SCALARS isLine int 1" << endl;
266 ofl << "LOOKUP_TABLE default" << endl;
267 for(MInt f = 0; (unsigned)f < (*faces).size(); f++) {
268 ofl << (*faces)[f].isLine << endl;
269 }
270
271 ofl << "POINT_DATA " << (*vertices).size() << endl;
272 ofl << "SCALARS point int 1" << endl;
273 ofl << "LOOKUP_TABLE default" << endl;
274 for(MInt v = 0; (unsigned)v < (*vertices).size(); v++) {
275 ofl << v << endl;
276 }
277
278 ofl << "SCALARS pointId int 1" << endl;
279 ofl << "LOOKUP_TABLE default" << endl;
280 for(MInt v = 0; (unsigned)v < (*vertices).size(); v++) {
281 ofl << (*vertices)[v].pointId << endl;
282 }
283
284 ofl << "SCALARS pointType int 1" << endl;
285 ofl << "LOOKUP_TABLE default" << endl;
286 for(MInt v = 0; (unsigned)v < (*vertices).size(); v++) {
287 ofl << (*vertices)[v].pointType << endl;
288 }
289
290 ofl.close();
291 }
292}
293//------------------------------------------------------------------------------
294
295template <MInt nDim_>
296void GeometryIntersection<nDim_>::writeInfo(std::vector<CutCell<nDim>>& cutCellData, MUint cutc, MInt nameId) {
297 MInt cellId = cutCellData[cutc].cellId;
298
299 const MChar* fileName = "cell-Info_";
300 stringstream fileName2;
301 fileName2 << fileName << grid().tree().globalId(cellId) << "_Id" << nameId << ".txt";
302
303 ofstream ofl;
304 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
305
306 const MInt lastDim = nDim - 1;
307
308 if(ofl) {
309 ofl.setf(ios::fixed);
310 ofl.precision(12);
311
312 ofl << "Writing Cell " << grid().tree().globalId(cellId) << " " << cellId << " " << cutc << " vol "
313 << cutCellData[cutc].volume << " SplitChilds " << cutCellData[cutc].noSplitChilds << " "
314 << cutCellData[cutc].splitParentId << endl
315 << endl;
316 for(MInt dir = 0; dir < m_noDirs; dir++) {
317 ofl << "Dir " << dir << " external " << cutCellData[cutc].externalFaces[dir] << " faces "
318 << cutCellData[cutc].noFacesPerCartesianDir[dir] << endl
319 << endl;
320 }
321
322 ofl << " Cartesian-Surf: " << cutCellData[cutc].noCartesianSurfaces << endl << endl;
323
324 for(MInt id = 0; id < cutCellData[cutc].noCartesianSurfaces; id++) {
325 ofl << "Id " << id << " dir " << cutCellData[cutc].cartFaceDir[id] << " area "
326 << cutCellData[cutc].cartFaceArea[id] << " coord " << cutCellData[cutc].cartFaceCentroid[id][0]
327 << cutCellData[cutc].cartFaceCentroid[id][1] << cutCellData[cutc].cartFaceCentroid[id][lastDim] << endl
328 << endl;
329 }
330
331 ofl << " Bndry-Surfaces: " << cutCellData[cutc].noBoundarySurfaces << endl << endl;
332
333 for(MInt id = 0; id < cutCellData[cutc].noBoundarySurfaces; id++) {
334 ofl << "Id " << id << " normal " << cutCellData[cutc].boundarySurfaceNormal[id][0]
335 << cutCellData[cutc].boundarySurfaceNormal[id][1] << cutCellData[cutc].boundarySurfaceNormal[id][lastDim]
336 << " center " << cutCellData[cutc].boundarySurfaceCentroid[id][0]
337 << cutCellData[cutc].boundarySurfaceCentroid[id][1] << cutCellData[cutc].boundarySurfaceCentroid[id][lastDim]
338 << " area " << cutCellData[cutc].boundarySurfaceArea[id] << endl
339 << endl;
340 }
341 }
342}
343
344//------------------------------------------------------------------------------
345
351template <>
353 static constexpr MInt edgeCode[24] = {8, 10, 0, 4, 9, 11, 1, 5, 2, 6, 8, 9, 3, 7, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7};
354 static constexpr MInt faceCode[24] = {0, 4, 1, 4, 2, 4, 3, 4, 0, 5, 1, 5, 2, 5, 3, 5, 0, 2, 1, 2, 0, 3, 1, 3};
355 static constexpr MInt pointCode[6][4] = {{0, 2, 6, 4}, {1, 3, 7, 5}, {0, 1, 5, 4},
356 {2, 3, 7, 6}, {0, 1, 3, 2}, {4, 5, 7, 6}};
357 static constexpr MInt edgeCode2[6][4] = {{0, 10, 4, 8}, {1, 11, 5, 9}, {2, 9, 6, 8},
358 {3, 11, 7, 10}, {2, 1, 3, 0}, {6, 5, 7, 4}};
359 static constexpr MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
360 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
361
362 static constexpr MBool improvedCentroidComputation = false; // true;
363 // new scheme for more accurate face and volume centroids, Lennart
364
365 const MInt noEdges = CutCell<nDim>::noEdges;
366 MBool cutFaces[m_noDirs];
367 ScratchSpace<MBool> cutEdgesAll(noEdges, AT_, "cutEdgesAll");
368 ScratchSpace<MBool> nonFluidSideEdge(noEdges, AT_, "nonFluidSideEdge");
369 MBool shapeIsInside[m_noDirs];
370 MBool positiveSlope;
371 MBool pointInside;
372 MBool pointBRInside;
373 MBool pointTLInside;
374 const MFloat epsNormal = 1e-15;
375 MInt corner;
376 MInt edgeCounter;
377 MInt face0, face1;
378 MInt face0Space, face0Side;
379 MInt noCutFaces;
380 MInt side0, side1;
381 MInt sideId;
382 MInt spaceId, spaceId1, spaceId2;
383 MInt space0, space1, space0Relative, space1Relative;
384 MFloat h;
385 ScratchSpace<MInt> cutPointOnEdge(noEdges, AT_, "cutPointOnEdge");
386 MInt noNonFluidEdges[m_noDirs];
387 MInt cutEdges[4];
388 MInt cutPoint[4];
389 MFloat cc0[nDim];
390 MFloat cc1[nDim];
391 MFloat cellHalfLength[nDim];
392 MFloat cellLength[nDim];
393 ScratchSpace<MFloat> cutLineLength(noEdges, AT_, "cutLineLength");
394 MFloat faceVolume[m_noDirs];
395 MFloat gridFaceVolume[m_noDirs];
396 MFloat cutOutVolume;
397 MFloat dA;
398 MFloat dfcc[2];
399 MFloat eps;
400 MFloat Fvol;
401 MFloat minX, maxX, minY, maxY;
402 MFloat negativePoint[3] = {0, 0, 0};
403 MFloat oppositePoint[3] = {0, 0, 0};
404 MFloat point[3] = {0, 0, 0};
405 MFloat pointP[3] = {0, 0, 0};
406 MFloat pointM[3] = {0, 0, 0};
407 MFloat pointW[3] = {0, 0, 0};
408 MFloat pointE[3] = {0, 0, 0};
409 MFloat rectVolume, triVolume;
410 MFloat trianglePoint[3] = {0, 0, 0};
411 MFloat trianglePointP[3] = {0, 0, 0};
412 MFloat trianglePointM[3] = {0, 0, 0};
413 MFloat trianglePointW[3] = {0, 0, 0};
414 MFloat trianglePointE[3] = {0, 0, 0};
415 MFloat cutLineCentroid[6][3];
416 MFloat delta[6][3];
417 MFloat faceCentroid[6][3];
418 MFloat triangleCentroid[6][3];
419 MFloat normalVector[6][3];
420
421 MInt cellId = cutCell.cellId;
422
423
424 for(MInt f = 0; f < m_noDirs; f++) {
425 cutCell.externalFaces[f] = false;
426 cutCell.noFacesPerCartesianDir[f] = 1;
427 }
428
429 noCutFaces = 0;
430 cutCell.noBoundarySurfaces = 1;
431
432 face0 = -1;
433 face1 = -1;
434
435 // reset all local variables
436 for(MInt i = 0; i < noEdges; i++) {
437 cutEdgesAll[i] = false;
438 nonFluidSideEdge[i] = false;
439 cutPointOnEdge[i] = -1;
440 }
441 for(MInt i = 0; i < m_noDirs; i++) {
442 cutFaces[i] = false;
443 shapeIsInside[i] = false;
444 }
445
446 // determine cell geometry
447 for(MInt i = 0; i < nDim; i++) {
448 cellLength[i] = a_cellLengthAtCell(cellId);
449 cellHalfLength[i] = F1B2 * cellLength[i];
450 }
451 eps = F0;
452
453 // store all cut points in a separate array
454 for(MInt cp = 0; cp < cutCell.noCutPoints; cp++) {
455 cutPointOnEdge[cutCell.cutEdges[cp]] = cp;
456 }
457
458
459 cutCell.noCartesianSurfaces = 0;
460 cutCell.noTotalFaces = 0;
461
462 // I.
463 // --
464 // determine the cut geometry for each face
465 // assuming that each face has either 0 or 2 cut points
466 for(MInt face = 0; face < m_noDirs; face++) {
467 // assemble face edges and cut points
468 MInt n = 0;
469 for(MInt e = 0; e < 4; e++) {
470 MInt cp = cutPointOnEdge[edgeCode[4 * face + e]];
471 if(cp > -1) {
472 cutPoint[n] = cp;
473 cutEdges[n] = e;
474 cutEdgesAll[edgeCode[4 * face + e]] = true;
475 n++;
476 }
477 }
478
479 if(n > 0) {
480 cutFaces[face] = true;
481 noCutFaces++;
482 }
483 MBool faceIsActive = true;
484 if(n == 1 || n > 2) {
485 cerr << "** ERROR create cut face: " << n << " cut points for face " << face << " body "
486 << cutCell.associatedBodyIds[0] << endl;
487 stringstream errorMessage;
488 errorMessage << "** ERROR create cut face: " << n << " cut points for face " << face << endl;
489 cerr << "cell " << cellId << " cog " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " "
490 << a_coordinate(cellId, 2) << endl;
491 return false;
492 } else {
493 spaceId = face / 2;
494 sideId = face % 2;
495 spaceId1 = (spaceId + 1) % nDim;
496 spaceId2 = (spaceId1 + 1) % nDim;
497
498 gridFaceVolume[face] = cellLength[spaceId1] * cellLength[spaceId2];
499 faceVolume[face] = gridFaceVolume[face];
500
501 // set the reference points
502 for(MInt i = 0; i < nDim; i++) {
503 point[i] = a_coordinate(cellId, i) - cellHalfLength[i];
504 negativePoint[i] = point[i];
505 oppositePoint[i] = point[i] + cellLength[i];
506 }
507
508 // set the secondary coordinate (spaceId) of the reference points
509 point[spaceId] += (MFloat)sideId * cellLength[spaceId];
510 oppositePoint[spaceId] = point[spaceId];
511
512 // inside / outside check for point
513 for(MInt i = 0; i < nDim; i++) {
514 pointP[i] = point[i];
515 pointM[i] = point[i];
516 pointW[i] = point[i];
517 pointE[i] = point[i];
518 }
519 pointP[spaceId1] += eps;
520 pointM[spaceId1] -= eps;
521 pointW[spaceId2] += eps;
522 pointE[spaceId2] -= eps;
523
524 corner = 0;
525 if(sideId) corner = IPOW2(spaceId);
526
527 pointInside = cutCell.cornerIsInsideGeometry[0][corner] != 0;
528
529 MInt cornerBR = corner + IPOW2(spaceId1);
530 MInt cornerTL = corner + IPOW2(spaceId2);
531 MInt cornerOP = corner + IPOW2(spaceId1) + IPOW2(spaceId2);
532
533 pointBRInside = cutCell.cornerIsInsideGeometry[0][cornerBR];
534 pointTLInside = cutCell.cornerIsInsideGeometry[0][cornerTL];
535
536
537 const MInt pointIds[4] = {corner, cornerBR, cornerOP, cornerTL};
538
539 faceIsActive = true;
540 if(n == 0) {
541 if(cutCell.cornerIsInsideGeometry[0][pointIds[0]] && cutCell.cornerIsInsideGeometry[0][pointIds[1]]
542 && cutCell.cornerIsInsideGeometry[0][pointIds[2]] && cutCell.cornerIsInsideGeometry[0][pointIds[3]]) {
543 faceIsActive = false;
544 }
545 }
546
547 faceCentroid[face][spaceId] = point[spaceId];
548
549 if(n == 2) {
550 // delta of cut point coordinates, sign of the cut line slope
551 for(MInt i = 0; i < nDim; i++) {
552 delta[face][i] = cutCell.cutPoints[cutPoint[0]][i] - cutCell.cutPoints[cutPoint[1]][i];
553 }
554 positiveSlope = delta[face][spaceId1] * delta[face][spaceId2] > 0;
555
556 for(MInt i = 0; i < nDim; i++) {
557 delta[face][i] = fabs(delta[face][i]);
558 }
559
560 // compute the length of the cut line
561 cutLineLength[face] = sqrt(POW2(delta[face][spaceId1]) + POW2(delta[face][spaceId2]));
562
563 // compute the coordinates of the cut line centroid
564 for(MInt i = 0; i < nDim; i++) {
565 cutLineCentroid[face][i] = F1B2 * (cutCell.cutPoints[cutPoint[0]][i] + cutCell.cutPoints[cutPoint[1]][i]);
566 }
567
568 // compute the volume and the normal vector of the cut face
569 // assuming 2 cut points!!! (checked above)
570 // space0: space Id of the first cut edge
571 // space1: space Id of the second cut edge
572 // *Relative: in two-dimensional space0-space1 space, either 0 or 1
573 space0Relative = cutEdges[0] / 2;
574 space1Relative = cutEdges[1] / 2;
575 space0 = (space0Relative + spaceId + 1) % nDim;
576 side0 = cutEdges[0] % 2;
577 space1 = (space1Relative + spaceId + 1) % nDim;
578 side1 = cutEdges[1] % 2;
579
580 // compute the absolute values of the normal vector components
581 normalVector[face][spaceId] = 0;
582 normalVector[face][spaceId1] = delta[face][spaceId2] / cutLineLength[face];
583 normalVector[face][spaceId2] = delta[face][spaceId1] / cutLineLength[face];
584
585
586 // determine the cut geometry and compute
587 // - the volume of the boundary cell
588 // - the coordinate shift
589 // - nonFluidSides
590 if(space0 != space1) {
591 // 1. the cut geometry is a triangle
592 faceVolume[face] = F1B2 * (delta[face][spaceId1] * delta[face][spaceId2]);
593
594 trianglePoint[space0] = point[space0] + cellLength[space0] * (MFloat)side0;
595 trianglePoint[space1] = point[space1] + cellLength[space1] * (MFloat)side1;
596 trianglePoint[spaceId] = point[spaceId];
597
598 for(MInt i = 0; i < nDim; i++) {
599 trianglePointP[i] = trianglePoint[i];
600 trianglePointM[i] = trianglePoint[i];
601 trianglePointW[i] = trianglePoint[i];
602 trianglePointE[i] = trianglePoint[i];
603 }
604 trianglePointP[spaceId1] += eps;
605 trianglePointM[spaceId1] -= eps;
606 trianglePointW[spaceId2] += eps;
607 trianglePointE[spaceId2] -= eps;
608
609 faceCentroid[face][space0] = trianglePoint[space0] + F2B3 * (F1B2 - (MFloat)side0) * delta[face][space0];
610 faceCentroid[face][space1] = trianglePoint[space1] + F2B3 * (F1B2 - (MFloat)side1) * delta[face][space1];
611
612 for(MInt i = 0; i < nDim; i++) {
613 triangleCentroid[face][i] = faceCentroid[face][i];
614 }
615
616
617 MInt triangleCorner = 0;
618 triangleCorner += sideId * IPOW2(spaceId);
619 triangleCorner += side0 * IPOW2(space0);
620 triangleCorner += side1 * IPOW2(space1);
621
622
623 // check if the third triangle point is inside or outside
624
625 if(cutCell.cornerIsInsideGeometry[0][triangleCorner]) {
626 // computed volume is inside the geometry and cut out
627 shapeIsInside[face] = true;
628 cutOutVolume = faceVolume[face];
629 faceVolume[face] = gridFaceVolume[face] - faceVolume[face];
630 faceCentroid[face][space0] =
631 F1 / faceVolume[face]
632 * ((gridFaceVolume[face] * a_coordinate(cellId, space0)) - (cutOutVolume * faceCentroid[face][space0]));
633 faceCentroid[face][space1] =
634 F1 / faceVolume[face]
635 * ((gridFaceVolume[face] * a_coordinate(cellId, space1)) - (cutOutVolume * faceCentroid[face][space1]));
636
637 // no non-fluid edge
638 noNonFluidEdges[face] = 0;
639 // DEBUG (not required)
640 for(MInt e = 0; e < 4; e++) {
641 if(nonFluidSideEdge[edgeCode[4 * face + e]]) {
642 cerr << "Error non-fluid edge was true for edge " << edgeCode[4 * face + e] << " face " << face << endl;
643 cerr << "All face data " << noNonFluidEdges[0] << noNonFluidEdges[1] << noNonFluidEdges[2]
644 << noNonFluidEdges[3] << noNonFluidEdges[4] << noNonFluidEdges[5] << endl;
645 cerr << "All edge data " << nonFluidSideEdge[edgeCode[0]] << nonFluidSideEdge[edgeCode[1]]
646 << nonFluidSideEdge[edgeCode[2]] << nonFluidSideEdge[edgeCode[3]] << " "
647 << nonFluidSideEdge[edgeCode[4]] << nonFluidSideEdge[edgeCode[5]] << nonFluidSideEdge[edgeCode[6]]
648 << nonFluidSideEdge[edgeCode[7]] << " " << nonFluidSideEdge[edgeCode[8]]
649 << nonFluidSideEdge[edgeCode[9]] << nonFluidSideEdge[edgeCode[10]]
650 << nonFluidSideEdge[edgeCode[11]] << endl;
651 cerr << "cell " << cellId << " " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " "
652 << a_coordinate(cellId, 2) << endl;
653 cerr << " " << endl;
654 }
655 nonFluidSideEdge[edgeCode[4 * face + e]] = false;
656 }
657 // END DEBUG
658
659 } else {
660 // computed volume is the boundary cell volume
661 noNonFluidEdges[face] = 2;
662 nonFluidSideEdge[edgeCode[4 * face + 2 * space0Relative + ((side0 + 1) % 2)]] = true;
663 nonFluidSideEdge[edgeCode[4 * face + 2 * space1Relative + ((side1 + 1) % 2)]] = true;
664 }
665
666 // determine the sign of the normal vector components
667 if(!pointInside) {
668 if(pointTLInside) {
669 if(pointBRInside) {
670 // bottom right corner is inside the geometry
671 normalVector[face][spaceId1] = -normalVector[face][spaceId1];
672 normalVector[face][spaceId2] = -normalVector[face][spaceId2];
673 } else {
674 // top left corner is inside the geometry
675 normalVector[face][spaceId2] = -normalVector[face][spaceId2];
676 }
677 } else {
678 if(pointBRInside) {
679 // bottom right corner is inside the geometry
680 normalVector[face][spaceId1] = -normalVector[face][spaceId1];
681 } else {
682 // top right corner is inside the geometry
683 normalVector[face][spaceId1] = -normalVector[face][spaceId1];
684 normalVector[face][spaceId2] = -normalVector[face][spaceId2];
685 }
686 }
687 } else {
688 if(pointTLInside) {
689 if(pointBRInside) {
690 // top right corner is outside the geometry
691 } else {
692 // bottom right corner is outside the geometry
693 normalVector[face][spaceId2] = -normalVector[face][spaceId2];
694 }
695 } else {
696 if(pointBRInside) {
697 // top left corner is outside the geometry
698 normalVector[face][spaceId1] = -normalVector[face][spaceId1];
699 } else {
700 // bottom left corner is inside the geometry
701 }
702 }
703 }
704 } else {
705 // 2. the cut geometry is a trapezoid
706 noNonFluidEdges[face] = 1;
707 if(space0 == spaceId1) {
708 // 2.a) the cut face is along the x_spaceId1 coordinate
709 faceVolume[face] = cellLength[spaceId1] * (cutLineCentroid[face][spaceId2] - point[spaceId2]);
710
711 // check if point is inside or outside
712 if(pointInside) {
713 faceVolume[face] = gridFaceVolume[face] - faceVolume[face];
714 nonFluidSideEdge[edgeCode[4 * face + 2]] = true;
715 // * compute boundary cell center
716 // * set signs of the normal vector
717 // - x_0 sign according to the slope (+/-,-/+)
718 // - x_1 sign is positive
719 maxY = cutLineCentroid[face][spaceId2] + F1B2 * delta[face][spaceId2];
720 cc0[0] = a_coordinate(cellId, spaceId1);
721 cc0[1] = F1B2 * (oppositePoint[spaceId2] + maxY);
722 if(positiveSlope) {
723 cc1[0] = point[spaceId1] + F1B3 * cellLength[spaceId1];
724 normalVector[face][spaceId1] = -normalVector[face][spaceId1];
725 } else {
726 cc1[0] = point[spaceId1] + F2B3 * cellLength[spaceId1];
727 }
728 cc1[1] = maxY - F1B3 * delta[face][spaceId2];
729 rectVolume = (oppositePoint[spaceId2] - maxY) * cellLength[spaceId1];
730 triVolume = faceVolume[face] - rectVolume;
731 } else {
732 nonFluidSideEdge[edgeCode[4 * face + 3]] = true;
733 // * compute boundary cell center
734 // * set signs of the normal vector
735 // - x_0 sign according to the slope (+/+,-/-)
736 // - x_1 sign is negative
737 normalVector[face][spaceId2] = -normalVector[face][spaceId2];
738 minY = cutLineCentroid[face][spaceId2] - F1B2 * delta[face][spaceId2];
739 cc0[0] = a_coordinate(cellId, spaceId1);
740 cc0[1] = F1B2 * (point[spaceId2] + minY);
741 if(positiveSlope) {
742 cc1[0] = point[spaceId1] + F2B3 * cellLength[spaceId1];
743 } else {
744 normalVector[face][spaceId1] = -normalVector[face][spaceId1];
745 cc1[0] = point[spaceId1] + F1B3 * cellLength[spaceId1];
746 }
747 cc1[1] = minY + F1B3 * delta[face][spaceId2];
748 rectVolume = (minY - point[spaceId2]) * cellLength[spaceId1];
749 triVolume = faceVolume[face] - rectVolume;
750 }
751 } else {
752 // 2.b) the cut face is along the x_spaceId2 coordinate
753 faceVolume[face] = cellLength[spaceId2] * (cutLineCentroid[face][spaceId1] - point[spaceId1]);
754
755 // check if point is inside or outside
756 if(pointInside) {
757 faceVolume[face] = gridFaceVolume[face] - faceVolume[face];
758 nonFluidSideEdge[edgeCode[4 * face]] = true;
759 // * compute boundary cell center
760 // * set signs of the normal vector
761 // - x_0 sign is positive
762 // - x_1 sign according to the slope (+/-,-/+)
763 maxX = cutLineCentroid[face][spaceId1] + F1B2 * delta[face][spaceId1];
764 cc0[0] = F1B2 * (oppositePoint[spaceId1] + maxX);
765 cc0[1] = a_coordinate(cellId, spaceId2);
766 cc1[0] = maxX - F1B3 * delta[face][spaceId1];
767 if(positiveSlope) {
768 normalVector[face][spaceId2] = -normalVector[face][spaceId2];
769 cc1[1] = point[spaceId2] + F1B3 * cellLength[spaceId2];
770 } else {
771 cc1[1] = point[spaceId2] + F2B3 * cellLength[spaceId2];
772 }
773 rectVolume = (oppositePoint[spaceId1] - maxX) * cellLength[spaceId2];
774 triVolume = faceVolume[face] - rectVolume;
775 } else {
776 nonFluidSideEdge[edgeCode[4 * face + 1]] = true;
777 // * compute boundary cell center
778 // * set signs of the normal vector
779 // - x_0 sign is negative
780 // - x_1 sign according to the slope (+/+,-/-)
781 normalVector[face][spaceId1] = -normalVector[face][spaceId1];
782 minX = cutLineCentroid[face][spaceId1] - F1B2 * delta[face][spaceId1];
783 cc0[0] = F1B2 * (point[spaceId1] + minX);
784 cc0[1] = a_coordinate(cellId, spaceId2);
785 cc1[0] = minX + F1B3 * delta[face][spaceId1];
786 if(positiveSlope) {
787 cc1[1] = point[spaceId2] + F2B3 * cellLength[spaceId2];
788 } else {
789 normalVector[face][spaceId2] = -normalVector[face][spaceId2];
790 cc1[1] = point[spaceId2] + F1B3 * cellLength[spaceId2];
791 }
792 rectVolume = (minX - point[spaceId1]) * cellLength[spaceId2];
793 triVolume = faceVolume[face] - rectVolume;
794 }
795 }
796
797 faceCentroid[face][spaceId1] = (rectVolume * cc0[0] + triVolume * cc1[0]) / faceVolume[face];
798 faceCentroid[face][spaceId2] = (rectVolume * cc0[1] + triVolume * cc1[1]) / faceVolume[face];
799 }
800
801 for(MInt i = 0; i < nDim; i++) {
802 cutCell.cartFaceCentroid[cutCell.noCartesianSurfaces][i] = faceCentroid[face][i];
803 }
804 cutCell.cartFaceArea[cutCell.noCartesianSurfaces] = faceVolume[face];
805 cutCell.cartFaceDir[cutCell.noCartesianSurfaces] = face;
806 cutCell.noCartesianSurfaces++;
807
808 } else {
809 // set the nonFluidSideEdge flag
810 // none of the face edges is cut
811 if(pointInside) {
812 for(MInt e = 0; e < 4; e++) {
813 nonFluidSideEdge[edgeCode[4 * face + e]] = true;
814 }
815 }
816
817 if(faceIsActive) {
818 for(MInt i = 0; i < nDim; i++) {
819 cutCell.cartFaceCentroid[cutCell.noCartesianSurfaces][i] = a_coordinate(cellId, i);
820 }
821 if(face % 2 == 0) {
822 cutCell.cartFaceCentroid[cutCell.noCartesianSurfaces][face / 2] -= cellHalfLength[0];
823 } else {
824 cutCell.cartFaceCentroid[cutCell.noCartesianSurfaces][face / 2] += cellHalfLength[0];
825 }
826 cutCell.cartFaceArea[cutCell.noCartesianSurfaces] = POW2(cellLength[0]);
827 cutCell.cartFaceDir[cutCell.noCartesianSurfaces] = face;
828 cutCell.noCartesianSurfaces++;
829 }
830 }
831 }
832 }
833
834
835 // from here on the whole control volume is concerned
836
837 // II.
838 // --
839 // set the non fluid side Ids
840 for(MInt face = 0; face < m_noDirs; face++) {
841 MBool nonFluidSide = true;
842 for(MInt e = 0; e < 4; e++) {
843 if(!nonFluidSideEdge[edgeCode[4 * face + e]]) {
844 nonFluidSide = false;
845 break;
846 }
847 }
848 if(nonFluidSide) {
849 cutCell.externalFaces[face] = true;
850 cutCell.noFacesPerCartesianDir[face] = 0;
851 faceVolume[face] = F0;
852 }
853 }
854
855
856 // III.
857 // --
858 // determine the 3D cell geometry
859 switch(noCutFaces) {
860 case 0: {
861 cerr << "case 0 " << endl;
862 cerr << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, 2) << " "
863 << cellHalfLength[0] << " " << grid().tree().level(cellId) << endl;
864 return false;
865 // mTerm(1,AT_, "case 0");
866 }
867
868 case 3: {
869 // III. 1.
870 // the cut geometry is a tetraeder
871
872 // find the cut sides
873 face0 = -1;
874 face1 = -1;
875 for(MInt face = 0; face < m_noDirs; face++) {
876 if(cutFaces[face]) {
877 if(face0 == -1) {
878 face0 = face;
879 } else {
880 if(face1 == -1) {
881 face1 = face;
882 }
883 }
884 }
885 }
886 edgeCounter = 0;
887 // find the two cut edges of face0
888 for(MInt e = 0; e < 4; e++) {
889 cutEdges[e] = 0;
890 if(cutEdgesAll[edgeCode[4 * face0 + e]]) {
891 cutEdges[edgeCounter] = e;
892 edgeCounter++;
893 }
894 }
895
896 // DEBUG
897 if(edgeCounter != 2) cerr << "ERROR create cut face, tetraeter shape, not enough cut edges" << endl;
898 // find the remaining cut edge (face1)
899 for(MInt e = 0; e < 4; e++) {
900 if(cutEdgesAll[edgeCode[4 * face1 + e]]) {
901 if(faceCode[2 * edgeCode[4 * face1 + e]] != face0 && faceCode[2 * edgeCode[4 * face1 + e] + 1] != face0) {
902 cutEdges[2] = e;
903 }
904 }
905 }
906
907 // determine the cut point on the remaining cut edge
908 // for( MInt cp = 0; cp < m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_srfcs[0]->m_noCutPoints; cp++ ) {
909 for(MInt cp = 0; cp < cutCell.noCutPoints; cp++) {
910 if(cutCell.cutEdges[cp] == edgeCode[4 * face1 + cutEdges[2]]) {
911 cutPoint[0] = cp;
912 }
913 }
914
915 face0Space = face0 / 2;
916 face0Side = face0 % 2;
917
918 // determine the center and the volume of the tetraeder
919 // center of the triangle
920 for(MInt i = 0; i < nDim; i++) {
921 cutCell.volumetricCentroid[i] = F3B4 * triangleCentroid[face0][i] + F1B4 * cutCell.cutPoints[cutPoint[0]][i];
922 }
923
924 // volume
925 h = F2 * (F1B2 - (MFloat)face0Side)
926 * (cutCell.cutPoints[cutPoint[0]][face0Space]
927 - (negativePoint[face0Space] + (MFloat)face0Side * cellLength[face0Space]));
928 if(shapeIsInside[face0]) {
929 cutCell.volume = F1B3 * (gridFaceVolume[face0] - faceVolume[face0]) * h;
930 } else {
931 cutCell.volume = F1B3 * faceVolume[face0] * h;
932 }
933
934 // correct the volume and the cell center of the reshaped cell if the geometry is cut out
935 if(shapeIsInside[face0]) {
936 cutOutVolume = cutCell.volume;
937 cutCell.volume = a_gridCellVolume(cellId) - cutCell.volume;
938 for(MInt i = 0; i < nDim; i++) {
939 cutCell.volumetricCentroid[i] =
940 F1 / mMax(m_eps, cutCell.volume)
941 * (a_gridCellVolume(cellId) * a_coordinate(cellId, i) - cutOutVolume * cutCell.volumetricCentroid[i]);
942 }
943 }
944 // compute the coordinate shift
945 for(MInt i = 0; i < nDim; i++) {
946 cutCell.volumetricCentroid[i] -= a_coordinate(cellId, i);
947 }
948
949 // compute the cut surface area (store surface components in the normal vector member)
950 for(MInt i = 0; i < nDim; i++) {
951 cutCell.boundarySurfaceNormal[0][i] = faceVolume[2 * i + 1] - faceVolume[2 * i];
952 }
953 cutCell.boundarySurfaceArea[0] =
954 sqrt(POW2(cutCell.boundarySurfaceNormal[0][0]) + POW2(cutCell.boundarySurfaceNormal[0][1])
955 + POW2(cutCell.boundarySurfaceNormal[0][2]));
956
957 cutCell.boundarySurfaceArea[0] = mMax(epsNormal, cutCell.boundarySurfaceArea[0]);
958
959 cutCell.boundarySurfaceBndryCndId[0] = -1;
960 cutCell.boundarySurfaceBodyId[0] = cutCell.cutBodyIds[0];
961
962 // compute the normal vector
963 for(MInt i = 0; i < nDim; i++) {
964 cutCell.boundarySurfaceNormal[0][i] /= cutCell.boundarySurfaceArea[0];
965 }
966
967 // compute the cut surface centroid
968 for(MInt i = 0; i < nDim; i++) {
969 cutCell.boundarySurfaceCentroid[0][i] =
970 F2B3 * cutLineCentroid[face0][i] + F1B3 * cutCell.cutPoints[cutPoint[0]][i];
971 }
972 break;
973 }
974 case 4:
975 case 5:
976 case 6: {
977 // III. 2.
978
979 // find a pair of opposite cut sides (the one with the largest area)
980 cutLineLength[6] = F0;
981 for(MInt face = 0; face < m_noDirs; face += 2) {
982 if(cutFaces[face]) {
983 if(cutFaces[face + 1]) {
984 cutLineLength[7] = cutLineLength[face] + cutLineLength[face + 1];
985 if(cutLineLength[7] > cutLineLength[6]) {
986 face0 = face;
987 face1 = face + 1;
988 cutLineLength[6] = cutLineLength[7];
989 }
990 }
991 }
992 }
993 if(face0 < 0 || face1 < 0) {
994 cerr << "Error: opposite cut faces not found" << endl;
995 return false;
996 }
997
998 spaceId = face0 / 2;
999 spaceId1 = (spaceId + 1) % nDim;
1000 spaceId2 = (spaceId1 + 1) % nDim;
1001
1002 // compute the new cell center
1003 // coordinate spaceId1 and Id2
1004 Fvol = F1 / (faceVolume[face0] + faceVolume[face1]);
1005 dA = faceVolume[face1] - faceVolume[face0];
1006 dfcc[0] = faceCentroid[face1][spaceId1] - faceCentroid[face0][spaceId1];
1007 dfcc[1] = faceCentroid[face1][spaceId2] - faceCentroid[face0][spaceId2];
1008
1009 cutCell.volumetricCentroid[spaceId] =
1010 faceCentroid[face0][spaceId] + F1B3 * (F1 + Fvol * faceVolume[face1]) * cellLength[spaceId];
1011
1012 cutCell.volumetricCentroid[spaceId1] =
1013 F2 * Fvol
1014 * (faceVolume[face0] * faceCentroid[face0][spaceId1]
1015 + F1B2 * (faceVolume[face0] * dfcc[0] + dA * faceCentroid[face0][spaceId1]) + F1B3 * dA * dfcc[0]);
1016
1017 cutCell.volumetricCentroid[spaceId2] =
1018 F2 * Fvol
1019 * (faceVolume[face0] * faceCentroid[face0][spaceId2]
1020 + F1B2 * (faceVolume[face0] * dfcc[1] + dA * faceCentroid[face0][spaceId2]) + F1B3 * dA * dfcc[1]);
1021
1022 for(MInt i = 0; i < nDim; i++) {
1023 cutCell.volumetricCentroid[i] -= a_coordinate(cellId, i);
1024 }
1025
1026 // compute the cut surface area (store surface components in the normal vector member)
1027 for(MInt i = 0; i < nDim; i++) {
1028 cutCell.boundarySurfaceNormal[0][i] = faceVolume[2 * i + 1] - faceVolume[2 * i];
1029 }
1030 cutCell.boundarySurfaceArea[0] =
1031 sqrt(POW2(cutCell.boundarySurfaceNormal[0][0]) + POW2(cutCell.boundarySurfaceNormal[0][1])
1032 + POW2(cutCell.boundarySurfaceNormal[0][2]));
1033
1034 cutCell.boundarySurfaceArea[0] = mMax(epsNormal, cutCell.boundarySurfaceArea[0]);
1035
1036 cutCell.boundarySurfaceBndryCndId[0] = -1;
1037 cutCell.boundarySurfaceBodyId[0] = cutCell.cutBodyIds[0];
1038
1039 // compute the normal vector
1040 for(MInt i = 0; i < nDim; i++) {
1041 cutCell.boundarySurfaceNormal[0][i] /= cutCell.boundarySurfaceArea[0];
1042 }
1043
1044 // compute the cut surface centroid
1045 for(MInt i = 0; i < nDim; i++) {
1046 cutCell.boundarySurfaceCentroid[0][i] = F1B2 * (cutLineCentroid[face0][i] + cutLineCentroid[face1][i]);
1047 }
1048
1049 // compute the boundary cell volume using Gauss theorem
1050 cutCell.volume = -F1B3
1051 * (faceVolume[0] * faceCentroid[0][0] - faceVolume[1] * faceCentroid[1][0]
1052 + faceVolume[2] * faceCentroid[2][1] - faceVolume[3] * faceCentroid[3][1]
1053 + faceVolume[4] * faceCentroid[4][2] - faceVolume[5] * faceCentroid[5][2]
1054 + cutCell.boundarySurfaceArea[0]
1055 * (cutCell.boundarySurfaceNormal[0][0] * cutCell.boundarySurfaceCentroid[0][0]
1056 + cutCell.boundarySurfaceNormal[0][1] * cutCell.boundarySurfaceCentroid[0][1]
1057 + cutCell.boundarySurfaceNormal[0][2] * cutCell.boundarySurfaceCentroid[0][2]));
1058
1059 break;
1060 }
1061 default: {
1062 cerr << "this case has not yet been implemented" << endl;
1063 cerr << "cell " << cellId << endl;
1064 cerr << "coordinates"
1065 << " " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, 2)
1066 << endl;
1067 cerr << "number of cut faces: " << noCutFaces << endl;
1068 return false;
1069 // mTerm(1,AT_, "This case has not yet been implemented");
1070 }
1071 }
1072
1073 multimap<MFloat, MInt> sortedCPs;
1074 MFloat pCoords[nDim];
1075 MFloat vec_a[nDim];
1076 MFloat vec_b[nDim];
1077 MFloat normal[nDim];
1078 MFloat acentre[nDim] = {F0, F0, F0};
1079 for(MInt cp = 0; cp < cutCell.noCutPoints; cp++) {
1080 for(MInt i = 0; i < nDim; i++) {
1081 acentre[i] += cutCell.cutPoints[cp][i];
1082 }
1083 }
1084 for(MInt i = 0; i < nDim; i++) {
1085 acentre[i] /= (MFloat)cutCell.noCutPoints;
1086 }
1087 for(MInt i = 0; i < nDim; i++) {
1088 normal[i] = cutCell.boundarySurfaceNormal[0][i];
1089 }
1090 spaceId = 0;
1091 MFloat maxC = fabs(normal[0]);
1092 for(MInt i = 1; i < nDim; i++) {
1093 if(fabs(normal[i]) > maxC) {
1094 maxC = fabs(normal[i]);
1095 spaceId = i;
1096 }
1097 }
1098 spaceId1 = (spaceId + 1) % nDim;
1099 spaceId2 = (spaceId1 + 1) % nDim;
1100 vec_a[spaceId1] = F1;
1101 vec_a[spaceId2] = F1;
1102 vec_a[spaceId] = -(vec_a[spaceId1] * normal[spaceId1] + vec_a[spaceId2] * normal[spaceId2]) / normal[spaceId];
1103 MFloat vecsum = sqrt(POW2(vec_a[0]) + POW2(vec_a[1]) + POW2(vec_a[2]));
1104 for(MInt i = 0; i < nDim; i++) {
1105 vec_a[i] /= vecsum;
1106 }
1107 vec_b[spaceId] = normal[spaceId1] * vec_a[spaceId2] - normal[spaceId2] * vec_a[spaceId1];
1108 vec_b[spaceId1] = normal[spaceId2] * vec_a[spaceId] - normal[spaceId] * vec_a[spaceId2];
1109 vec_b[spaceId2] = normal[spaceId] * vec_a[spaceId1] - normal[spaceId1] * vec_a[spaceId];
1110 vecsum = sqrt(POW2(vec_b[0]) + POW2(vec_b[1]) + POW2(vec_b[2]));
1111 for(MInt i = 0; i < nDim; i++) {
1112 vec_b[i] /= vecsum;
1113 }
1114 for(MInt cp = 0; cp < cutCell.noCutPoints; cp++) {
1115 for(MInt i = 0; i < nDim; i++) {
1116 pCoords[i] = cutCell.cutPoints[cp][i];
1117 }
1118 MFloat dx = F0;
1119 MFloat dy = F0;
1120 for(MInt i = 0; i < nDim; i++) {
1121 dx += vec_a[i] * (pCoords[i] - acentre[i]);
1122 dy += vec_b[i] * (pCoords[i] - acentre[i]);
1123 }
1124 sortedCPs.insert(make_pair(atan2(dy, dx), cp));
1125 }
1126 ASSERT((signed)sortedCPs.size() == cutCell.noCutPoints, "");
1127
1128 cutCell.allFacesNoPoints[cutCell.noTotalFaces] = 0;
1129 cutCell.allFacesBodyId[cutCell.noTotalFaces] = cutCell.cutBodyIds[0];
1130 for(auto& sortedCP : sortedCPs) {
1131 cutCell.allFacesPointIds[cutCell.noTotalFaces][cutCell.allFacesNoPoints[cutCell.noTotalFaces]] =
1132 CutCell<nDim>::noCorners + sortedCP.second;
1133 cutCell.allFacesNoPoints[cutCell.noTotalFaces]++;
1134 }
1135 cutCell.noTotalFaces++;
1136
1137 for(MInt face = 0; face < m_noDirs; face++) {
1138 if(!cutCell.externalFaces[face]) {
1139 cutCell.allFacesNoPoints[cutCell.noTotalFaces] = 0;
1140 cutCell.allFacesBodyId[cutCell.noTotalFaces] = -1;
1141 for(MInt p = 0; p < 4; p++) {
1142 if(!cutCell.cornerIsInsideGeometry[0][pointCode[face][p]]) {
1143 cutCell.allFacesPointIds[cutCell.noTotalFaces][cutCell.allFacesNoPoints[cutCell.noTotalFaces]] =
1144 pointCode[face][p];
1145 cutCell.allFacesNoPoints[cutCell.noTotalFaces]++;
1146 }
1147 for(MInt cp = 0; cp < cutCell.noCutPoints; cp++) {
1148 if(cutCell.cutEdges[cp] == edgeCode2[face][p]) {
1149 cutCell.allFacesPointIds[cutCell.noTotalFaces][cutCell.allFacesNoPoints[cutCell.noTotalFaces]] =
1151 cutCell.allFacesNoPoints[cutCell.noTotalFaces]++;
1152 }
1153 }
1154 }
1155 cutCell.noTotalFaces++;
1156 }
1157 }
1158
1159 // added by Lennart
1160 // recompute surface and volume centroids:
1161 // first create triangulation of each surface and determine surface centroid as average triangle centroid
1162 // then connect all triangles to single point inside the cut cell to form several tetrahedrons which fill up the whole
1163 // cell volume and compute the volumetric centroid as volume-average of the tetrahedron centroids
1164 if(improvedCentroidComputation) {
1165 MFloat vec0[nDim];
1166 MFloat vec1[nDim];
1167 MFloat vec2[nDim];
1168
1169 ASSERT(cutCell.noBoundarySurfaces == 1, "");
1170 ASSERT(cutCell.allFacesBodyId[0] > -1, "");
1171 for(MInt bs = 0; bs < cutCell.noBoundarySurfaces; bs++) {
1172 MFloat bscentroid[nDim] = {F0, F0, F0};
1173 MFloat bsarea = F0;
1174
1175 const MInt cp0 = cutCell.allFacesPointIds[bs][0] - CutCell<nDim>::noCorners;
1176 ASSERT(cutCell.allFacesNoPoints[bs] > 2, "");
1177 for(MInt v = 2; v < cutCell.allFacesNoPoints[bs]; v++) {
1178 MInt cp1 = cutCell.allFacesPointIds[bs][v - 1] - CutCell<nDim>::noCorners;
1179 MInt cp2 = cutCell.allFacesPointIds[bs][v] - CutCell<nDim>::noCorners;
1180 for(MInt i = 0; i < nDim; i++) {
1181 vec1[i] = cutCell.cutPoints[cp1][i] - cutCell.cutPoints[cp0][i];
1182 vec2[i] = cutCell.cutPoints[cp2][i] - cutCell.cutPoints[cp0][i];
1183 }
1184 crossProduct(vec0, vec1, vec2);
1185 MFloat area = F0;
1186 for(MInt i = 0; i < nDim; i++) {
1187 area += POW2(vec0[i]);
1188 }
1189 area = F1B2 * sqrt(area);
1190 for(MInt i = 0; i < nDim; i++) {
1191 bscentroid[i] +=
1192 area * F1B3 * (cutCell.cutPoints[cp0][i] + cutCell.cutPoints[cp1][i] + cutCell.cutPoints[cp2][i]);
1193 }
1194 bsarea += area;
1195 }
1196
1197 for(MInt i = 0; i < nDim; i++) {
1198 bscentroid[i] /= mMax(1e-14, bsarea);
1199 }
1200 for(MInt i = 0; i < nDim; i++) {
1201 cutCell.boundarySurfaceCentroid[bs][i] = bscentroid[i];
1202 }
1203 }
1204
1205 MFloat acentroid[nDim] = {F0, F0, F0};
1206 MFloat acnt = F0;
1207 for(MInt cs = 0; cs < cutCell.noCartesianSurfaces; cs++) {
1208 for(MInt i = 0; i < nDim; i++) {
1209 acentroid[i] += cutCell.cartFaceCentroid[cs][i];
1210 }
1211 acnt += F1;
1212 }
1213 for(MInt bs = 0; bs < cutCell.noBoundarySurfaces; bs++) {
1214 for(MInt i = 0; i < nDim; i++) {
1215 acentroid[i] += cutCell.boundarySurfaceCentroid[bs][i];
1216 }
1217 acnt += F1;
1218 }
1219 for(MInt i = 0; i < nDim; i++) {
1220 acentroid[i] /= acnt;
1221 }
1222
1223 MFloat vcentroid[nDim] = {F0, F0, F0};
1224 MFloat vol2 = F0;
1225 MFloat vec_tmp[nDim];
1226 for(MInt as = 0; as < cutCell.noTotalFaces; as++) {
1227 const MInt p0 = cutCell.allFacesPointIds[as][0];
1228 if(p0 < CutCell<nDim>::noCorners) {
1229 for(MInt i = 0; i < nDim; i++) {
1230 vec0[i] = a_coordinate(cellId, i) + signStencil[p0][i] * cellHalfLength[0] - acentroid[i];
1231 }
1232 } else {
1233 MInt cp0 = p0 - CutCell<nDim>::noCorners;
1234 for(MInt i = 0; i < nDim; i++) {
1235 vec0[i] = cutCell.cutPoints[cp0][i] - acentroid[i];
1236 }
1237 }
1238 ASSERT(cutCell.allFacesNoPoints[as] > 2, "");
1239 for(MInt v = 2; v < cutCell.allFacesNoPoints[as]; v++) {
1240 MInt p1 = cutCell.allFacesPointIds[as][v - 1];
1241 MInt p2 = cutCell.allFacesPointIds[as][v];
1242 if(p1 < CutCell<nDim>::noCorners) {
1243 for(MInt i = 0; i < nDim; i++) {
1244 vec1[i] = a_coordinate(cellId, i) + signStencil[p1][i] * cellHalfLength[0] - acentroid[i];
1245 }
1246 } else {
1247 MInt cp1 = p1 - CutCell<nDim>::noCorners;
1248 for(MInt i = 0; i < nDim; i++) {
1249 vec1[i] = cutCell.cutPoints[cp1][i] - acentroid[i];
1250 }
1251 }
1252 if(p2 < CutCell<nDim>::noCorners) {
1253 for(MInt i = 0; i < nDim; i++) {
1254 vec2[i] = a_coordinate(cellId, i) + signStencil[p2][i] * cellHalfLength[0] - acentroid[i];
1255 }
1256 } else {
1257 MInt cp2 = p2 - CutCell<nDim>::noCorners;
1258 for(MInt i = 0; i < nDim; i++) {
1259 vec2[i] = cutCell.cutPoints[cp2][i] - acentroid[i];
1260 }
1261 }
1262 crossProduct(vec_tmp, vec0, vec1);
1263 MFloat tvol = F0;
1264 for(MInt i = 0; i < nDim; i++) {
1265 tvol += F1B6 * vec_tmp[i] * vec2[i];
1266 }
1267 vol2 += fabs(tvol);
1268 for(MInt i = 0; i < nDim; i++) {
1269 vcentroid[i] +=
1270 fabs(tvol) * (F3B4 * (acentroid[i] + F1B3 * (vec0[i] + vec1[i] + vec2[i])) + F1B4 * acentroid[i]);
1271 }
1272 }
1273 }
1274 for(MInt i = 0; i < nDim; i++) {
1275 vcentroid[i] /= vol2;
1276 vcentroid[i] -= a_coordinate(cellId, i);
1277 }
1278
1279 for(MInt i = 0; i < nDim; i++) {
1280 cutCell.volumetricCentroid[i] = vcentroid[i];
1281 }
1282 // cutCell.volume = vol2;
1283 }
1284
1285 return true;
1286}
1287
1288
1289//-----------------------------------------------------------------------------------------------------
1290
1291template <>
1292void GeometryIntersection<3>::computeCutFaces(std::vector<CutCell<nDim>>& cutCellData, const MInt maxNoSurfaces,
1293 const MInt tCutGroup) {
1294 using CC = CutCell<nDim>;
1295 const MUint noCutCells = cutCellData.size();
1296
1297 // the following variables describe the different corner/edge/face numbering in MAIA and MarchingCubes table
1298 // const MInt cornersMCtoSOLVER[ 8 ] = { 2,0,1,3,6,4,5,7 };
1299 static constexpr MInt cornersSOLVERtoMC[8] = {1, 2, 0, 3, 5, 6, 4, 7};
1300 static constexpr MInt edgesMCtoSOLVER[12] = {0, 2, 1, 3, 4, 6, 5, 7, 10, 8, 9, 11};
1301 static constexpr MInt facesMCtoSOLVER[6] = {0, 2, 1, 3, 4, 5};
1302 static constexpr MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
1303 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
1304 static constexpr MInt edgeCornerCode[12][2] = {{0, 2}, {1, 3}, {0, 1}, {2, 3}, {4, 6}, {5, 7},
1305 {4, 5}, {6, 7}, {0, 4}, {1, 5}, {2, 6}, {3, 7}};
1306 static constexpr MInt faceEdgeCode[6][4] = {{0, 10, 4, 8}, {1, 9, 5, 11}, {2, 8, 6, 9},
1307 {3, 11, 7, 10}, {2, 1, 3, 0}, {6, 4, 7, 5}};
1308 static constexpr MInt edgeFaceCode[12][2] = {{0, 4}, {1, 4}, {2, 4}, {3, 4}, {0, 5}, {1, 5},
1309 {2, 5}, {3, 5}, {0, 2}, {1, 2}, {0, 3}, {1, 3}};
1310 static constexpr MInt faceCornerCode[6][4] = {{0, 2, 6, 4}, {3, 1, 5, 7}, {1, 0, 4, 5},
1311 {2, 3, 7, 6}, {0, 1, 3, 2}, {5, 4, 6, 7}};
1312 const MInt maxNoSets = 6;
1313 ASSERT(m_noLevelSetsUsedForMb < maxNoSets, "");
1314
1315 MIntScratchSpace presentCases(m_noLevelSetsUsedForMb, 15, AT_, "presentCases");
1316 for(MInt s = 0; s < m_noLevelSetsUsedForMb; s++) {
1317 for(MInt i = 0; i < 15; i++) {
1318 presentCases(s, i) = 0;
1319 }
1320 }
1321
1322 const MInt maxNoFaces = 100;
1323 const MInt maxNoVertices = 300;
1324 const MInt maxNoEdges = 300;
1325
1326 std::vector<polyVertex> vertices[maxNoSets];
1327 std::vector<polyFace> faces[maxNoSets];
1328 std::vector<polyEdge> edges[maxNoSets];
1329 std::vector<polyCutCell> cutCells;
1330
1331 stack<MInt> faceStack;
1332
1333 std::vector<polyMultiFace> multiFaces;
1334 MIntScratchSpace edgeCutCellPointer(maxNoEdges, AT_, "edgeCutCellPointer");
1335 std::list<MInt> pureBodyEdges;
1336 MIntScratchSpace tmp_faces(maxNoFaces, AT_, "tmp_faces");
1337 MIntScratchSpace multiFaceConnection(maxNoFaces, AT_, "multiFaceConnection");
1338
1339 MIntScratchSpace outcode_MC_set(m_noLevelSetsUsedForMb, AT_, "outcode_MC_set");
1340 MIntScratchSpace noCutPointsFromSet(m_noLevelSetsUsedForMb, AT_, "cutSetPointers");
1341 MIntScratchSpace cutSetPointers(m_noLevelSetsUsedForMb, AT_, "cutSetPointers");
1342
1343 std::vector<CsgPolygon> csg_polygons;
1344 std::vector<CsgVertex> csg_vertices;
1345 std::vector<Csg> csg;
1346 std::vector<CsgPolygon> result;
1347 std::vector<polyVertex> vertices_result;
1348 MIntScratchSpace vertices_renamed(mMax(2, m_noLevelSetsUsedForMb), maxNoVertices, AT_, "vertices_renamed");
1349 std::list<std::pair<MInt, MInt>> openEdges;
1350
1351 MIntScratchSpace vertexTouches(maxNoVertices, AT_, "vertexTouches");
1352 std::vector<MInt> faceVertices;
1353 MIntScratchSpace bodyFaces(maxNoFaces, AT_, "bodyFaces");
1354 MFloatScratchSpace normalDotProduct(maxNoFaces, maxNoFaces, AT_,
1355 "normalDotProduct"); // stores 1 - n1*n2 -> in [0;2]
1356 MIntScratchSpace pointEdgeId(2 * m_noEdges, AT_, "pointEdgeId");
1357 MIntScratchSpace newCutPointId(maxNoVertices, AT_, "newCutPointId");
1358 MBoolScratchSpace isPartOfBodySurface(maxNoVertices, AT_, "isPartOfBodySurface");
1359 MFloatScratchSpace dotProdMatrix(maxNoEdges, maxNoEdges, AT_, "dotProdMatrix");
1360 // MIntScratchSpace splitFaceCellIds(m_fvBndryCnd->m_maxNoBndryCells,AT_,"splitFaceCellIds");
1361 // splitFaceCellIds.fill(-1);
1362 // MIntScratchSpace splitCellIds(noCutCells,AT_,"splitCellIds");
1363 // std::vector<cellWithSplitFace> splitFaceCells;
1364 MIntScratchSpace surfaceIdentificatorCounters(m_noDirs + m_noEmbeddedBodies, AT_, "surfaceIdentificatorCounters");
1365 MIntScratchSpace cellSurfaceMapping_backup(m_noDirs, AT_, "cellSurfaceMapping_backup");
1366 MIntScratchSpace splitCellList(CC::maxSplitCells, AT_, "splitCellList");
1367
1368 NEW_SUB_TIMER_STATIC(tCutFace_0, "cutFaceNew_0", tCutGroup);
1369 NEW_SUB_TIMER_STATIC(tCutFace_1a, "cutFaceNew_1a", tCutGroup);
1370 NEW_SUB_TIMER_STATIC(tCutFace_1, "cutFaceNew_1", tCutGroup);
1371 NEW_SUB_TIMER_STATIC(tCutFace_2, "cutFaceNew_2", tCutGroup);
1372 NEW_SUB_TIMER_STATIC(tCutFace_3, "cutFaceNew_3", tCutGroup);
1373 NEW_SUB_TIMER_STATIC(tCutFace_3b, "cutFaceNew_3b", tCutGroup);
1374 NEW_SUB_TIMER_STATIC(tCutFace_4, "cutFaceNew_4", tCutGroup);
1375 NEW_SUB_TIMER_STATIC(tCutFace_5a, "cutFaceNew_5a", tCutGroup);
1376 NEW_SUB_TIMER_STATIC(tCutFace_5b, "cutFaceNew_5b", tCutGroup);
1377 NEW_SUB_TIMER_STATIC(tCutFace_6, "cutFaceNew_6", tCutGroup);
1378 NEW_SUB_TIMER_STATIC(tCutFace_7, "cutFaceNew_7", tCutGroup);
1379
1380#ifdef CutCell_DEBUG
1381 const MInt debugDomainId = 5;
1382 const MInt debugTimeStep = 0;
1383 const MInt debugCellId = 21866;
1384#endif
1385
1386
1387 // Use of meaningful bndry-Value for keeping vertices
1388 // needs to be 10 * m_eps to detect different vertices
1389 // and needs to be even larger to meaningfully merge edges(angle/calculation)
1390 // Thus different bounding-values for the different point-Types are used!
1391 // 10^8*m_eps for point-Types 3 and 10 * m_eps for all other PointTypes!
1392 const MFloat difBound1 = 10 * m_eps;
1393 const MFloat difBound2 = 100000000 * m_eps;
1394
1395 // for( MInt bndryId = m_noOuterBndryCells; bndryId < noBndryCells; bndryId++ ) {
1396 for(MUint cutc = 0; cutc < noCutCells; cutc++) {
1397 // MInt bndryId = cutCellData[cutc].cutCellId;
1398 RECORD_TIMER_START(tCutFace_0);
1399 // FvBndryCell<nDim>* bndryCell = &m_fvBndryCnd->m_bndryCells->a[bndryId];
1400
1401 // 0. prepare some cell information
1402 // const MInt cellId = bndryCell->m_cellId;
1403 const MInt cellId = cutCellData[cutc].cellId;
1404 // const MInt cndId = m_bndryCandidateIds->a[ cellId ];
1405 // ASSERT( cndId > -1, "" );
1406 const MFloat cellLength0 = a_cellLengthAtCell(cellId);
1407 const MFloat cellHalfLength = F1B2 * cellLength0;
1408
1409 for(MBool& externalFace : cutCellData[cutc].externalFaces) {
1410 externalFace = false;
1411 }
1412
1413 // if ( m_noLevelSetsUsedForMb == 1 ) {
1414 // RECORD_TIMER_START(tCutFace_1a);
1415 // computeCutFaceSimple( cutCellData[cutc] );
1416 // RECORD_TIMER_STOP(tCutFace_1a);
1417 // continue;
1418 // }
1419
1420
1421 // reset some variables
1422 for(MInt s = 0; s < m_noLevelSetsUsedForMb; s++) {
1423 vertices[s].clear();
1424 faces[s].clear();
1425 edges[s].clear();
1426 cutSetPointers[s] = -1;
1427 noCutPointsFromSet[s] = 0;
1428 }
1429 cutCells.clear();
1430 const MBool isGapCell = cutCellData[cutc].isGapCell;
1431
1432 MInt startSet = 0;
1433 MInt endSet = 1;
1434 if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (!isGapCell)) {
1435 startSet = 1;
1436 endSet = m_noLevelSetsUsedForMb;
1437 }
1438
1439 // preprocess cut points - find out which level set functions contain relevant cut points
1440 // if no relevant cut points are present -> don't cut the cell with the set
1441 MInt noCutSets = 0;
1442 MBool isCompletelyOutside = false;
1443 MBool hasAmbiguousFaces = false;
1444 for(MInt s = startSet; s < endSet; s++) {
1445 // 1.1. get In/Outcode of the corners of the voxel
1446 // 0 -> Corner is outside Fluid Domain
1447 // 1 -> Corner is inside Fluid Domain or on Boundary
1448 unsigned char outcode_MC = 0;
1449 for(MInt c = 0; c < m_noCorners; c++) {
1450 // MBool currentOutcode = (!m_pointIsInside[ bndryId ][ IDX_LSSETMB(c, s) ]);
1451 MBool currentOutcode = (!cutCellData[cutc].cornerIsInsideGeometry[s][c]);
1452 if(currentOutcode) {
1453 outcode_MC = outcode_MC | (1 << cornersSOLVERtoMC[c]);
1454 }
1455 }
1456 outcode_MC_set[s] = outcode_MC;
1457 if(outcode_MC == 0) {
1458 isCompletelyOutside = true;
1459 }
1460 }
1461 // for( MInt cutPoint = 0; cutPoint < bndryCell->m_srfcs[0]->m_noCutPoints; cutPoint++){
1462 for(MInt cutPoint = 0; cutPoint < cutCellData[cutc].noCutPoints; cutPoint++) {
1463 MInt set = 0;
1464 if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (!isGapCell)) {
1465 // set = m_bodyToSetTable[bndryCell->m_srfcs[0]->m_bodyId[cutPoint]];
1466 set = m_bodyToSetTable[cutCellData[cutc].cutBodyIds[cutPoint]];
1467 }
1468
1469 noCutPointsFromSet[set]++;
1470 }
1471 for(MInt set = startSet; set < endSet; set++) {
1472 if(noCutPointsFromSet[set] && !isCompletelyOutside) {
1473 cutSetPointers[set] = noCutSets++;
1474 }
1475 }
1476 MInt maxCutsPerFace = 0;
1477 MInt cutsPerFace[m_noCorners] = {0, 0, 0, 0, 0, 0};
1478 for(MInt cutPoint = 0; cutPoint < cutCellData[cutc].noCutPoints; cutPoint++) {
1479 MInt edge = cutCellData[cutc].cutEdges[cutPoint];
1480 cutsPerFace[edgeFaceCode[edge][0]]++;
1481 cutsPerFace[edgeFaceCode[edge][1]]++;
1482 }
1483 for(MInt k = 0; k < CC::noFaces; k++) {
1484 maxCutsPerFace = mMax(maxCutsPerFace, cutsPerFace[k]);
1485 }
1486
1487 RECORD_TIMER_STOP(tCutFace_0);
1488
1489
1490 for(MInt set = startSet; set < endSet; set++) {
1491 MInt setIndex = cutSetPointers[set];
1492 if(setIndex < 0) {
1493 continue;
1494 }
1495 MInt outcode_MC = outcode_MC_set[set];
1496 // 1.2. determine Case and check if case is implemented
1497 MInt currentCase = cases[outcode_MC][0];
1498 if(!caseStatesLs[currentCase][0]) {
1499 cerr << "Error: Case not implemented: " << currentCase << endl;
1500 mTerm(1, AT_, "Case not implemented, see error file for deatails.");
1501 }
1502 // 1.2 determine ambiguous cells
1503 if(!caseStatesLs[currentCase][1]) { // ambiguous case -> disambiguate
1504 hasAmbiguousFaces = true;
1505 }
1506 }
1507
1508 // CutCell<nDim> cutcbak = CutCell<nDim>();
1509
1510 MBool simpleMarchingCubesSucceeds = false;
1511
1512 if(!hasAmbiguousFaces && noCutSets == 1 && maxCutsPerFace == 2 && !isCompletelyOutside
1513 && m_noLevelSetsUsedForMb == 1) {
1514 // if (!hasAmbiguousFaces && noCutSets == 1 && maxCutsPerFace == 2 && !isCompletelyOutside ) {
1515 RECORD_TIMER_START(tCutFace_1a);
1516 // dispatch faster MC routine here, store relevant data, and continue
1517 simpleMarchingCubesSucceeds = computeCutFaceSimple(cutCellData[cutc]);
1518 RECORD_TIMER_STOP(tCutFace_1a);
1519 }
1520
1521 if(simpleMarchingCubesSucceeds) {
1522 continue;
1523 }
1524
1525 MIntScratchSpace noTriangles(m_noLevelSetsUsedForMb, AT_, "noTriangles");
1526 for(MInt i = 0; i < m_noLevelSetsUsedForMb; i++) {
1527 noTriangles[i] = 0;
1528 }
1529
1530
1531 // computation of cuts with individual sets
1532 for(MInt set = startSet; set < endSet; set++) { // until line 2552
1533 MInt setIndex = cutSetPointers[set];
1534 if(setIndex < 0) {
1535 continue;
1536 }
1537
1538#ifdef CutCell_DEBUG
1539 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
1540 cerr << "Cutting-Cell with " << set << " Index " << setIndex << " bodyId "
1541 << cutCellData[cutc].associatedBodyIds[set] << endl;
1542 }
1543#endif
1544
1545 RECORD_TIMER_START(tCutFace_1);
1546
1547 // MInt bodyId = m_associatedBodyIds[ IDX_LSSETMB( cellId, set) ];
1548 MInt bodyId = cutCellData[cutc].associatedBodyIds[set];
1549 if(bodyId < 0) continue;
1550
1551 // store all cut points in a separate array
1552 // and prepare all vertices for polyeder/polygon datastructure
1553 // vertices = cut points and fluid corners of the cell
1554 MInt cutPoints[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
1555 MInt cutPointToVertexMap[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
1556 MInt noCutPoints = 0;
1557 // for( MInt cutPoint = 0; cutPoint < bndryCell->m_srfcs[0]->m_noCutPoints; cutPoint++){
1558 for(MInt cutPoint = 0; cutPoint < cutCellData[cutc].noCutPoints; cutPoint++) {
1559 if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (!isGapCell)) {
1560 // if( m_bodyToSetTable[bndryCell->m_srfcs[0]->m_bodyId[ cutPoint ]] !=set )
1561 if(m_bodyToSetTable[cutCellData[cutc].cutBodyIds[cutPoint]] != set) {
1562 continue;
1563 }
1564 }
1565 noCutPoints++;
1566 // cutPoints[ bndryCell->m_srfcs[0]->m_cutEdge[ cutPoint ] ] = cutPoint;
1567 cutPoints[cutCellData[cutc].cutEdges[cutPoint]] = cutPoint;
1568 // vertices[setIndex].push_back(polyVertex(bndryCell->m_srfcs[0]->m_cutCoordinates[cutPoint], cutPoint, 1));
1569 vertices[setIndex].emplace_back(cutCellData[cutc].cutPoints[cutPoint], cutPoint, 1);
1570 cutPointToVertexMap[cutPoint] = vertices[setIndex].size() - 1;
1571 }
1572 MInt cornerToVertexMap[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
1573 for(MInt c = 0; c < m_noCorners; c++) {
1574 // if( !m_pointIsInside[ bndryId ][ IDX_LSSETMB(c, set) ]){
1575 if(!cutCellData[cutc].cornerIsInsideGeometry[set][c]) {
1576 std::array<MFloat, nDim> tmp_coords{};
1577 for(MInt i = 0; i < nDim; i++) {
1578 tmp_coords[i] = a_coordinate(cellId, i) + signStencil[c][i] * cellHalfLength;
1579 }
1580 vertices[setIndex].emplace_back(tmp_coords, c, 0);
1581 cornerToVertexMap[c] = vertices[setIndex].size() - 1;
1582 }
1583 }
1584 // NOTE: the precision of the vertices coordinates is at 3.5 *10^-16
1585
1586 // 1. find correct marching cubes state and substate -> including disambiguation
1587
1588 // 1.1. get In/Outcode of the corners of the voxel
1589 // 0 -> Corner is outside Fluid Domain
1590 // 1 -> Corner is inside Fluid Domain or on Boundary
1591 MInt outcode_MC = outcode_MC_set[set];
1592
1593 // 1.2. determine Case and check if case is implemented
1594 MInt currentCase = cases[outcode_MC][0];
1595 presentCases(set, currentCase)++;
1596 MInt currentSubCase = cases[outcode_MC][1];
1597 MInt subConfig = 0;
1598 if(!caseStatesLs[currentCase][0]) {
1599 cerr << "Error:Case not implemented: " << currentCase << endl;
1600 mTerm(1, AT_, "Case not implemented, see error file for deatails.");
1601 }
1602
1603#ifdef CutCell_DEBUG
1604 m_caseCheckList[outcode_MC] = 1;
1605#endif
1606
1607#ifdef CutCell_DEBUG
1608 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
1609 cerr << "cases: " << outcode_MC << " case " << currentCase << " subcase " << currentSubCase << " ambiguous "
1610 << caseStatesLs[currentCase][1] << endl;
1611 }
1612#endif
1613
1614 // 1.2 determine ambiguous cells
1615 if(!caseStatesLs[currentCase][1]) { // ambiguous case -> disambiguate
1616 // hasAmbiguousFaces = true;
1617 MInt faceMax = noAmbiguousFaces[currentCase];
1618 const MInt* testPointer;
1619 switch(currentCase) {
1620 case 3:
1621 testPointer = test3[currentSubCase];
1622 break;
1623 case 6:
1624 testPointer = test6[currentSubCase];
1625 break;
1626 case 7:
1627 testPointer = test7[currentSubCase];
1628 break;
1629 case 10:
1630 testPointer = test10[currentSubCase];
1631 break;
1632 case 12:
1633 testPointer = test12[currentSubCase];
1634 break;
1635 case 13:
1636 testPointer = test13[currentSubCase];
1637 break;
1638 default:
1639 mTerm(1, AT_, "this should not happen!");
1640 break;
1641 }
1642 for(MInt i = 0; i < faceMax; i++) {
1643 MInt face = testPointer[i]; // MC face
1644 MBool revert = false;
1645 if(face < F0) {
1646 if(face == -6) {
1647 face = 0;
1648 } else {
1649 face = -face;
1650 }
1651 revert = true;
1652 }
1653 face = facesMCtoSOLVER[face]; // convert to MAIA face
1654 // MBool testResult = test_face( cndId, face, set );
1655 MBool testResult = cutCellData[cutc].faceCentroidIsInsideGeometry[set][face];
1656
1657 if(revert) testResult = !testResult; // invert result for MC processing of body surface
1658
1659 if(testResult) {
1660 subConfig += IPOW2(i);
1661 }
1662 }
1663 }
1664
1665 // 1.3. decide which tiling should be used,
1666 // how many triangles are to be created for the cut face(s), etc.
1667 const MInt* tilingPointer = nullptr;
1668 MBool addVertex = false;
1669 noTriangles[set] = noTriangles_simpleCases[currentCase];
1670 switch(currentCase) {
1671 case 0:
1672 break;
1673
1674 case 1:
1675 tilingPointer = tiling1Ls[currentSubCase];
1676 break;
1677 case 2:
1678 tilingPointer = tiling2Ls[currentSubCase];
1679 break;
1680 case 4:
1681 tilingPointer = tiling4Ls[currentSubCase];
1682 break;
1683 case 5:
1684 tilingPointer = tiling5Ls[currentSubCase];
1685 break;
1686 case 8:
1687 tilingPointer = tiling8Ls[currentSubCase];
1688 break;
1689 case 9:
1690 tilingPointer = tiling9Ls[currentSubCase];
1691 break;
1692 case 11:
1693 tilingPointer = tiling11Ls[currentSubCase];
1694 break;
1695 case 14:
1696 tilingPointer = tiling14Ls[currentSubCase];
1697 break;
1698
1699 case 3:
1700 switch(subConfig) {
1701 case 0:
1702 tilingPointer = tiling3_1Ls[currentSubCase];
1703 noTriangles[set] = 2;
1704 break;
1705 case 1:
1706 tilingPointer = tiling3_2Ls[currentSubCase];
1707 noTriangles[set] = 4;
1708 break;
1709 default:
1710 mTerm(1, AT_, "This should not happen - we have case 3 with subConfig > 1... exiting");
1711 break;
1712 }
1713 break;
1714
1715 case 6:
1716 switch(subConfig) {
1717 case 0:
1718 tilingPointer = tiling6_1_1Ls[currentSubCase];
1719 noTriangles[set] = 3;
1720 break;
1721 case 1:
1722 tilingPointer = tiling6_2Ls[currentSubCase];
1723 noTriangles[set] = 5;
1724 break;
1725 default:
1726 mTerm(1, AT_, "This should not happen - we have case 6 with subConfig > 1... exiting");
1727 break;
1728 }
1729 break;
1730
1731 case 7:
1732 switch(subConfig) {
1733 case 0:
1734 tilingPointer = tiling7_1Ls[currentSubCase];
1735 noTriangles[set] = 3;
1736 break;
1737 case 1:
1738 tilingPointer = tiling7_2Ls[currentSubCase][0];
1739 noTriangles[set] = 5;
1740 break;
1741 case 2:
1742 tilingPointer = tiling7_2Ls[currentSubCase][1];
1743 noTriangles[set] = 5;
1744 break;
1745 case 3:
1746 tilingPointer = tiling7_3Ls[currentSubCase][0];
1747 noTriangles[set] = 9;
1748 addVertex = true;
1749 break;
1750 case 4:
1751 tilingPointer = tiling7_2Ls[currentSubCase][2];
1752 noTriangles[set] = 5;
1753 break;
1754 case 5:
1755 tilingPointer = tiling7_3Ls[currentSubCase][1];
1756 noTriangles[set] = 9;
1757 addVertex = true;
1758 break;
1759 case 6:
1760 tilingPointer = tiling7_3Ls[currentSubCase][2];
1761 noTriangles[set] = 9;
1762 addVertex = true;
1763 break;
1764 case 7:
1765 tilingPointer = tiling7_4_1Ls[currentSubCase];
1766 noTriangles[set] = 5;
1767 break;
1768 default:
1769 mTerm(1, AT_, "This should not happen - we have case 7 with subConfig > 7... exiting");
1770 break;
1771 }
1772 break;
1773
1774 case 10:
1775 switch(subConfig) {
1776 case 0:
1777 tilingPointer = tiling10_1_1Ls[currentSubCase];
1778 noTriangles[set] = 4;
1779 break;
1780 case 1:
1781 tilingPointer = tiling10_2Ls[currentSubCase];
1782 noTriangles[set] = 8;
1783 addVertex = true;
1784 break;
1785 case 2:
1786 tilingPointer = tiling10_2_Ls[currentSubCase];
1787 noTriangles[set] = 8;
1788 addVertex = true;
1789 break;
1790 case 3:
1791 tilingPointer = tiling10_1_1_Ls[currentSubCase];
1792 noTriangles[set] = 4;
1793 break;
1794 default:
1795 mTerm(1, AT_, "This should not happen - we have case 10 with subConfig > 3... exiting");
1796 break;
1797 }
1798 break;
1799
1800 case 12:
1801 switch(subConfig) {
1802 case 0:
1803 tilingPointer = tiling12_1_1Ls[currentSubCase];
1804 noTriangles[set] = 4;
1805 break;
1806 case 1:
1807 tilingPointer = tiling12_2Ls[currentSubCase];
1808 noTriangles[set] = 8;
1809 addVertex = true;
1810 break;
1811 case 2:
1812 tilingPointer = tiling12_2_Ls[currentSubCase];
1813 noTriangles[set] = 8;
1814 addVertex = true;
1815 break;
1816 case 3:
1817 tilingPointer = tiling12_1_1_Ls[currentSubCase];
1818 noTriangles[set] = 4;
1819 break;
1820 default:
1821 mTerm(1, AT_, "This should not happen - we have case 12 with subConfig > 3... exiting");
1822 break;
1823 }
1824 break;
1825
1826 case 13: {
1827 MInt config_identificator = 0;
1828 subConfig = subconfig13[subConfig];
1829 config_identificator = 0;
1830 switch(subConfig) {
1831 case 0: /* 13.1 */
1832 tilingPointer = tiling13_1Ls[currentSubCase];
1833 noTriangles[set] = 4;
1834 break;
1835
1836 case 1: /* 13.2 */
1837 case 2: /* 13.2 */
1838 case 3: /* 13.2 */
1839 case 4: /* 13.2 */
1840 case 5: /* 13.2 */
1841 case 6: /* 13.2 */
1842 config_identificator = subConfig - 1;
1843 tilingPointer = tiling13_2Ls[currentSubCase][config_identificator];
1844 noTriangles[set] = 6;
1845 break;
1846
1847 case 7: /* 13.3 */
1848 case 8: /* 13.3 */
1849 case 9: /* 13.3 */
1850 case 10: /* 13.3 */
1851 case 11: /* 13.3 */
1852 case 12: /* 13.3 */
1853 case 13: /* 13.3 */
1854 case 14: /* 13.3 */
1855 case 15: /* 13.3 */
1856 case 16: /* 13.3 */
1857 case 17: /* 13.3 */
1858 case 18: /* 13.3 */
1859 config_identificator = subConfig - 7;
1860 tilingPointer = tiling13_3Ls[currentSubCase][config_identificator];
1861 noTriangles[set] = 10;
1862 addVertex = true;
1863 break;
1864
1865 case 19: /* 13.4 */
1866 case 20: /* 13.4 */
1867 case 21: /* 13.4 */
1868 case 22: /* 13.4 */
1869 config_identificator = subConfig - 19;
1870 tilingPointer = tiling13_4Ls[currentSubCase][config_identificator];
1871 noTriangles[set] = 12;
1872 addVertex = true;
1873 break;
1874
1875 case 23: /* 13.5 */
1876 case 24: /* 13.5 */
1877 case 25: /* 13.5 */
1878 case 26: /* 13.5 */
1879 config_identificator = subConfig - 23;
1880 tilingPointer = tiling13_5_1Ls[currentSubCase][config_identificator];
1881 noTriangles[set] = 6;
1882 break;
1883
1884 case 27: /* 13.3 */
1885 case 28: /* 13.3 */
1886 case 29: /* 13.3 */
1887 case 30: /* 13.3 */
1888 case 31: /* 13.3 */
1889 case 32: /* 13.3 */
1890 case 33: /* 13.3 */
1891 case 34: /* 13.3 */
1892 case 35: /* 13.3 */
1893 case 36: /* 13.3 */
1894 case 37: /* 13.3 */
1895 case 38: /* 13.3 */
1896 config_identificator = subConfig - 27;
1897 tilingPointer = tiling13_3_Ls[currentSubCase][config_identificator];
1898 noTriangles[set] = 10;
1899 addVertex = true;
1900 break;
1901
1902 case 39: /* 13.2 */
1903 case 40: /* 13.2 */
1904 case 41: /* 13.2 */
1905 case 42: /* 13.2 */
1906 case 43: /* 13.2 */
1907 case 44: /* 13.2 */
1908 config_identificator = subConfig - 39;
1909 tilingPointer = tiling13_2_Ls[currentSubCase][config_identificator];
1910 noTriangles[set] = 6;
1911 break;
1912
1913 case 45: /* 13.1 */
1914 tilingPointer = tiling13_1_Ls[currentSubCase];
1915 noTriangles[set] = 4;
1916 break;
1917
1918 default:
1919 mTerm(1, AT_, "impossible MC case 13 subConfig, how could this happen? exiting...");
1920 break;
1921 }
1922 } break;
1923
1924 default:
1925 mTerm(1, AT_, "invalid MC case, how could this happen? exiting...");
1926 break;
1927 }
1928 RECORD_TIMER_STOP(tCutFace_1);
1929
1930
1931 RECORD_TIMER_START(tCutFace_2);
1932 // 2. build additional vertices, edges, and polygons for body surfaces -> MC
1933 MInt additionalVertexId = -1;
1934 if(addVertex) {
1935 additionalVertexId = vertices[setIndex].size();
1936 vertices[setIndex].emplace_back(-1, 2);
1937 addPoint(&vertices[setIndex], cutPointToVertexMap, noCutPoints,
1938 vertices[setIndex][additionalVertexId].coordinates);
1939 }
1940
1941 ASSERT(noCutPoints >= nDim, "");
1942 ASSERT(noCutPoints == caseCutPoints[currentCase], to_string(grid().tree().globalId(cellId)));
1943
1944 for(MInt t = 0; t < noTriangles[set]; t++) {
1945 // create a new body-face
1946 // the total body face consinst of noTriangles triangles with each 3 vertices and edges!
1947 MInt currentFace = faces[setIndex].size();
1948 faces[setIndex].emplace_back(-1, 1, bodyId);
1949 // add edges to face; for each edge, check if it already exists!
1950 MInt p[3];
1951 for(MInt pt = 0; pt < 3; pt++) {
1952 MInt cutEdge = tilingPointer[t * 3 + pt];
1953 if(cutEdge == 12) {
1954 p[pt] = additionalVertexId;
1955 } else {
1956 p[pt] = cutPointToVertexMap[cutPoints[edgesMCtoSOLVER[cutEdge]]];
1957 }
1958 ASSERT(p[pt] >= 0, to_string(cutEdge) + " " + to_string(isGapCell) + " " + to_string(cellId) + " "
1959 + to_string(grid().tree().globalId(cellId)) + " " + to_string(edgesMCtoSOLVER[cutEdge])
1960 + " " + to_string(cutPoints[edgesMCtoSOLVER[cutEdge]]) + " "
1961 + to_string(cutPointToVertexMap[cutPoints[edgesMCtoSOLVER[cutEdge]]]) + " "
1962 + to_string(cutCellData[cutc].noCutPoints));
1963 }
1964 for(MInt te = 0; te < 3; te++) {
1965 MInt point = p[te];
1966 ASSERT(point > -1, "");
1967 vertices[setIndex][point].surfaceIdentificators.insert(bodyId + m_noDirs);
1968 MInt nextPoint = p[(te + 1) % 3];
1969 MBool edgeExists = false;
1970 for(MInt e = 0; (unsigned)e < vertices[setIndex][p[te]].edges.size(); e++) {
1971 MInt edge = vertices[setIndex][point].edges[e];
1972 if(edges[setIndex][edge].vertices[1] == nextPoint) {
1973 // edge already exists. Link this edge to the face, direction is correct
1974 faces[setIndex][currentFace].edges.emplace_back(edge, 1);
1975 const MInt vertexId = edges[setIndex][edge].vertices[0];
1976 faces[setIndex][currentFace].vertices.push_back(vertexId);
1977 edges[setIndex][edge].face[0] = currentFace;
1978 edgeExists = true;
1979 } else if(edges[setIndex][edge].vertices[0] == nextPoint) {
1980 // edge already exists. Link this edge to the face, reverse direction
1981 faces[setIndex][currentFace].edges.emplace_back(edge, -1);
1982 const MInt vertexId = edges[setIndex][edge].vertices[1];
1983 faces[setIndex][currentFace].vertices.push_back(vertexId);
1984
1985 edges[setIndex][edge].face[1] = currentFace;
1986 edgeExists = true;
1987 }
1988 }
1989 if(!edgeExists) {
1990 // edge does not exist yet. Create a new edge.
1991 MInt newEdge = edges[setIndex].size();
1992 MInt edgeType = 2;
1993 if(vertices[setIndex][point].pointType == 2 || vertices[setIndex][nextPoint].pointType == 2) {
1994 edgeType = 3;
1995 }
1996 MInt edgeId = -1;
1997 if(edgeType == 2) {
1998 MInt p0 = vertices[setIndex][point].pointId;
1999 MInt p1 = vertices[setIndex][nextPoint].pointId;
2000 // MInt edge0 = bndryCell->m_srfcs[0]->m_cutEdge[p0];
2001 MInt edge0 = cutCellData[cutc].cutEdges[p0];
2002 // MInt edge1 = bndryCell->m_srfcs[0]->m_cutEdge[p1];
2003 MInt edge1 = cutCellData[cutc].cutEdges[p1];
2004 if(edgeFaceCode[edge0][0] == edgeFaceCode[edge1][0] || edgeFaceCode[edge0][0] == edgeFaceCode[edge1][1])
2005 edgeId = edgeFaceCode[edge0][0];
2006 else if(edgeFaceCode[edge0][1] == edgeFaceCode[edge1][0]
2007 || edgeFaceCode[edge0][1] == edgeFaceCode[edge1][1])
2008 edgeId = edgeFaceCode[edge0][1];
2009 }
2010 edges[setIndex].emplace_back(point, nextPoint, edgeId, edgeType);
2011 vertices[setIndex][point].edges.push_back(newEdge);
2012 vertices[setIndex][nextPoint].edges.push_back(newEdge);
2013 faces[setIndex][currentFace].edges.emplace_back(newEdge, 1);
2014 const MInt vertexId = edges[setIndex][newEdge].vertices[0];
2015 faces[setIndex][currentFace].vertices.push_back(vertexId);
2016
2017 edges[setIndex][newEdge].face[0] = currentFace;
2018 }
2019 }
2020 // compute normal:
2021 computeNormal(vertices[setIndex][p[0]].coordinates, vertices[setIndex][p[1]].coordinates,
2022 vertices[setIndex][p[2]].coordinates, faces[setIndex][currentFace].normal,
2023 faces[setIndex][currentFace].w);
2024 }
2025
2026 for(auto& f : faces[setIndex]) {
2027 ASSERT(f.vertices.size() == 3, "");
2028 }
2029
2030#ifdef CutCell_DEBUG
2031 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2032 cerr << "Body surfaces: " << endl;
2033 cerr << "Set: " << set << " noTriangles " << noTriangles[set] << " noFaces " << faces[setIndex].size()
2034 << " noEdges " << edges[setIndex].size() << " noVertices " << vertices[setIndex].size() << endl;
2035 }
2036#endif
2037
2038
2039 RECORD_TIMER_STOP(tCutFace_2);
2040
2041 RECORD_TIMER_START(tCutFace_3);
2042
2043 // 3. build polygons for Cartesian faces
2044 // -> all edges should already be built, just compose the faces!
2045 // -> other than the body-faces cartesian faces are poligons, so they may be triangles or other
2046 // multiple-edge-faces!
2047 // 3.1. prepare basic edges -> between two inside corner vertices or between a corner vertex and a cut point
2048 for(MInt e = 0; e < m_noEdges; e++) {
2049 // MBool p0Fluid = !m_pointIsInside[ bndryId ][ IDX_LSSETMB(edgeCornerCode[e][0], set) ];
2050 MBool p0Fluid = !cutCellData[cutc].cornerIsInsideGeometry[set][edgeCornerCode[e][0]];
2051 // MBool p1Fluid = !m_pointIsInside[ bndryId ][ IDX_LSSETMB(edgeCornerCode[e][1], set) ];
2052 MBool p1Fluid = !cutCellData[cutc].cornerIsInsideGeometry[set][edgeCornerCode[e][1]];
2053 if(p0Fluid && p1Fluid) { // created a full Cartesian edge
2054 MInt v0 = cornerToVertexMap[edgeCornerCode[e][0]];
2055 MInt v1 = cornerToVertexMap[edgeCornerCode[e][1]];
2056 edges[setIndex].emplace_back(v0, v1, e, 0);
2057 vertices[setIndex][v0].edges.push_back(edges[setIndex].size() - 1);
2058 vertices[setIndex][v1].edges.push_back(edges[setIndex].size() - 1);
2059 } else if(p0Fluid) { // create a cut edge from p0 to cut point
2060 MInt v0 = cornerToVertexMap[edgeCornerCode[e][0]];
2061 MInt v1 = cutPointToVertexMap[cutPoints[e]];
2062 edges[setIndex].emplace_back(v0, v1, e, 1);
2063 vertices[setIndex][v0].edges.push_back(edges[setIndex].size() - 1);
2064 vertices[setIndex][v1].edges.push_back(edges[setIndex].size() - 1);
2065 } else if(p1Fluid) { // create a cut edge from p1 to cut point
2066 MInt v0 = cornerToVertexMap[edgeCornerCode[e][1]];
2067 MInt v1 = cutPointToVertexMap[cutPoints[e]];
2068 edges[setIndex].emplace_back(v0, v1, e, 1);
2069 vertices[setIndex][v0].edges.push_back(edges[setIndex].size() - 1);
2070 vertices[setIndex][v1].edges.push_back(edges[setIndex].size() - 1);
2071 } // else create no edge since edge is fully located outside
2072 }
2073
2074 // 3.2. compose faces
2075 // add cartesian faces!
2076 for(MInt cartFace = 0; cartFace < m_noDirs; cartFace++) {
2077 // find starting point: cut point on first edge of face
2078 MBool edgeTouched[4] = {false, false, false, false};
2079 for(MInt e = 0; e < 4; e++) {
2080 if(edgeTouched[e]) continue;
2081 MInt cartEdge = faceEdgeCode[cartFace][e];
2082 MInt startVertex = cornerToVertexMap[faceCornerCode[cartFace][e]]; // first point of the corresponding edge
2083 // in math pos. sense of rotation
2084 if(startVertex == -1) continue;
2085
2086 // add a new face
2087 MInt currentFace = faces[setIndex].size();
2088 faces[setIndex].emplace_back(cartFace, 0, -1);
2089 for(MInt i = 0; i < nDim; i++) {
2090 faces[setIndex][currentFace].normal[i] = F0;
2091 }
2092 MInt normalDir = cartFace / 2;
2093 MFloat normalSign = -F1;
2094 if(cartFace % 2 == 0) {
2095 normalSign = F1;
2096 }
2097 faces[setIndex][currentFace].w = -vertices[setIndex][startVertex].coordinates[normalDir] * normalSign;
2098 faces[setIndex][currentFace].normal[normalDir] = normalSign;
2099
2100 // do loop around the edges until the starting vertex is reached again
2101 MInt currentE = e;
2102 MInt currentVertex = startVertex;
2103 do {
2104 vertices[setIndex][currentVertex].surfaceIdentificators.insert(cartFace);
2105 edgeTouched[currentE] = true;
2106 // check all edges of the currentVertex; if the edge is found which is located on the investigated
2107 // cartesianEdge, continue along this edge!
2108 MBool edgeFound = false;
2109 for(MInt ve = 0; (unsigned)ve < vertices[setIndex][currentVertex].edges.size(); ve++) {
2110 MInt edge = vertices[setIndex][currentVertex].edges[ve];
2111 if(edges[setIndex][edge].edgeType > 1) // only a Cartesian line (cut or uncut) can be followed
2112 continue;
2113 if(edges[setIndex][edge].edgeId != cartEdge) continue;
2114 // otherwise we found cut or uncut Cartesian edge to follow!
2115 edgeFound = true;
2116 MInt edgeDirection = 1;
2117 if(edges[setIndex][edge].vertices[1] == currentVertex) {
2118 edgeDirection = -1; // reverse edge
2119 }
2120 faces[setIndex][currentFace].edges.emplace_back(edge, edgeDirection);
2121 MInt vertexId = edges[setIndex][edge].vertices[0];
2122 if(edgeDirection == -1) vertexId = edges[setIndex][edge].vertices[1];
2123 faces[setIndex][currentFace].vertices.push_back(vertexId);
2124
2125 if(edges[setIndex][edge].face[0] > -1)
2126 edges[setIndex][edge].face[1] = currentFace;
2127 else
2128 edges[setIndex][edge].face[0] = currentFace;
2129 if(edgeDirection == 1)
2130 currentVertex = edges[setIndex][edge].vertices[1];
2131 else
2132 currentVertex = edges[setIndex][edge].vertices[0];
2133 break;
2134 }
2135 ASSERT(edgeFound, "");
2136 // check if new vertex is a cut point. if no, just proceed to the next edge; otherwise, continue along the
2137 // corresponding cut line before returning to loop;
2138 if(vertices[setIndex][currentVertex].pointType == 0) {
2139 currentE = (currentE + 1) % 4;
2140 cartEdge = faceEdgeCode[cartFace][currentE];
2141 } else if(vertices[setIndex][currentVertex].pointType == 1) {
2142 edgeFound = false;
2143 for(MInt ve = 0; (unsigned)ve < vertices[setIndex][currentVertex].edges.size(); ve++) {
2144 MInt edge = vertices[setIndex][currentVertex].edges[ve];
2145 if(edges[setIndex][edge].edgeType != 2) // only a cut line on a Cartesian face can be followed
2146 continue;
2147 if(edges[setIndex][edge].edgeId != cartFace) continue;
2148 // otherwise we found cut line on cartFace to follow
2149 edgeFound = true;
2150 MInt edgeDirection = 1;
2151 if(edges[setIndex][edge].vertices[1] == currentVertex) {
2152 edgeDirection = -1; // reverse edge
2153 }
2154 faces[setIndex][currentFace].edges.emplace_back(edge, edgeDirection);
2155 MInt vertexId = edges[setIndex][edge].vertices[0];
2156 if(edgeDirection == -1) vertexId = edges[setIndex][edge].vertices[1];
2157 faces[setIndex][currentFace].vertices.push_back(vertexId);
2158
2159 edges[setIndex][edge].face[1] = currentFace;
2160 if(edgeDirection == 1)
2161 currentVertex = edges[setIndex][edge].vertices[1];
2162 else
2163 currentVertex = edges[setIndex][edge].vertices[0];
2164 // cartEdge = bndryCell->m_srfcs[0]->m_cutEdge[vertices[setIndex][currentVertex].pointId];
2165 cartEdge = cutCellData[cutc].cutEdges[vertices[setIndex][currentVertex].pointId];
2166 while(faceEdgeCode[cartFace][currentE] != cartEdge) {
2167 currentE = (currentE + 1) % 4; // adjust the relative edge counter
2168 }
2169 break;
2170 }
2171 ASSERT(edgeFound, "");
2172 }
2173 } while(currentVertex != startVertex); // end while
2174
2175 } // end for e
2176 } // end for cartFace
2177
2178#ifdef CutCell_DEBUG
2179 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2180 cerr << "Including cartesian faces: " << endl;
2181 cerr << "Set: " << set << " SetIndex:" << setIndex << " faces : " << faces[setIndex].size()
2182 << " edges : " << edges[setIndex].size() << " certices : " << vertices[setIndex].size() << endl;
2183 for(MUint i = 0; i < vertices[setIndex].size(); i++) {
2184 cerr << " vertices " << setprecision(19) << vertices[setIndex][i].coordinates[0] << " "
2185 << vertices[setIndex][i].coordinates[1] << " " << vertices[setIndex][i].coordinates[2] << endl;
2186 }
2187 }
2188#endif
2189
2190
2191 RECORD_TIMER_STOP(tCutFace_3);
2192 }
2193
2194 RECORD_TIMER_START(tCutFace_3b);
2195
2196 MInt noIndividualCuts = 0;
2197 for(MInt set = startSet; set < endSet; set++) {
2198 if(cutSetPointers[set] > -1) {
2199 noIndividualCuts++;
2200 }
2201 }
2202
2203#ifdef CutCell_DEBUG
2204 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2205 cerr << "noIndividualCuts: " << noIndividualCuts << endl;
2206 }
2207#endif
2208
2209 if(noIndividualCuts == 0) {
2210 cutCellData[cutc].volume = F0;
2211 RECORD_TIMER_STOP(tCutFace_3b);
2212 continue;
2213 }
2214 ASSERT(noIndividualCuts > 0, "");
2215 ASSERT(noCutSets > 0, " ");
2216 ASSERT(noCutSets == noIndividualCuts, "");
2217
2218 // 4.a combine polyhedra that are computed with different sets to one polyhedron
2219 // set up the CSG datastructure for each polyhedron
2220 MBool error = false;
2221 const MInt startSetIndex = 0;
2222 MInt referenceSet = startSet;
2223 for(MInt set = startSet; set < endSet; set++) {
2224 if(cutSetPointers[set] > -1) {
2225 referenceSet = set;
2226 break;
2227 }
2228 }
2229
2230 // NOTE: at this point we have multiple bodySurfaces/faces/triangles which each have 3 vertices/edges!
2231 // and multiple cartisain-faces which are poligons
2232 // (the poligons can be described through a normal in one of the coordinate diretions
2233 // and a coordinate value in that direction)
2234
2235
2236 // check that face-edges and face-vertices match!
2237 for(MInt set = startSet; set < endSet; set++) {
2238 MInt setIndex = cutSetPointers[set];
2239 if(setIndex < 0) continue;
2240
2241 for(MInt faceId = 0; faceId < (signed)faces[setIndex].size(); faceId++) {
2242 ASSERT(faces[setIndex][faceId].edges.size() == faces[setIndex][faceId].vertices.size(), "");
2243 for(MInt edgeId = 0; edgeId < (signed)faces[setIndex][faceId].edges.size(); edgeId++) {
2244 const MInt edge = faces[setIndex][faceId].edges[edgeId].first;
2245 const MInt newVertexId = faces[setIndex][faceId].vertices[edgeId];
2246 const MInt direction = faces[setIndex][faceId].edges[edgeId].second;
2247 MInt vertexId = edges[setIndex][edge].vertices[0];
2248 if(direction == -1) vertexId = edges[setIndex][edge].vertices[1];
2249 ASSERT(newVertexId == vertexId, "");
2250 }
2251 }
2252 }
2253
2254 // NOTE: the bodySurfaces/faces (triangles) can not be joined into poligons at this point yet,
2255 // as the current cgs-libary can either handle triangles or
2256 // poligons with normals into one of the coordinate-directions!
2257
2258 MInt noInitialFaces = 0;
2259
2260 //====== /MC ======
2261 //====== /MC ======
2262 //====== /MC ======
2263
2264 if(noIndividualCuts > 1) { // until line 3011
2265
2266 ASSERT(m_complexBoundary && m_noLevelSetsUsedForMb > 1, "");
2267 ASSERT(m_bodyFaceJoinMode == 4 || m_bodyFaceJoinMode == 1, "ERROR: using unrecommended bodyFaceJoinMode");
2268
2269 // referenceSet is the first Set with cutPoints
2270 // -> loop though all other sets!
2271 for(MInt set = referenceSet + 1; set < endSet; set++) {
2272 MInt setIndex = cutSetPointers[set];
2273 if(setIndex < 0) continue;
2274
2275 csg.clear();
2276 csg_polygons.clear();
2277
2278
2279 // now adding the faces for the zero SetIndex (the first set with cutPoints)
2280 for(MInt face = faces[startSetIndex].size() - 1; face > -1; face--) {
2281 csg_vertices.clear();
2282 polyFace* faceP = &faces[startSetIndex][face];
2283
2284 for(MInt e = 0; (unsigned)e < faceP->vertices.size(); e++) {
2285 const MInt vertexId = faceP->vertices[e];
2286 csg_vertices.emplace_back(CsgVector(vertices[startSetIndex][vertexId].coordinates), vertexId,
2287 startSetIndex);
2288 }
2289 if(faceP->faceType == 0) {
2290 CsgVector normal(faceP->normal);
2291 CsgPlane plane(normal, -faceP->w);
2292 csg_polygons.emplace_back(csg_vertices, startSetIndex, faceP->faceId, faceP->faceType, faceP->bodyId,
2293 plane);
2294 } else {
2295 csg_polygons.emplace_back(csg_vertices, startSetIndex, faceP->faceId, faceP->faceType, faceP->bodyId);
2296 }
2297 }
2298
2299 csg.emplace_back(csg_polygons);
2300 csg_polygons.clear();
2301
2302 // now adding the faces for current setIndex (second/third.. set with cutPoints)
2303 for(MInt face = faces[setIndex].size() - 1; face > -1; face--) {
2304 csg_vertices.clear();
2305 polyFace* faceP = &faces[setIndex][face];
2306
2307 for(MInt e = 0; (unsigned)e < faceP->vertices.size(); e++) {
2308 const MInt vertexId = faceP->vertices[e];
2309 csg_vertices.emplace_back(CsgVector(vertices[setIndex][vertexId].coordinates), vertexId, setIndex);
2310 }
2311 if(faceP->faceType == 0) {
2312 CsgVector normal(faceP->normal);
2313 CsgPlane plane(normal, -faceP->w);
2314 csg_polygons.emplace_back(csg_vertices, setIndex, faceP->faceId, faceP->faceType, faceP->bodyId, plane);
2315 } else {
2316 csg_polygons.emplace_back(csg_vertices, setIndex, faceP->faceId, faceP->faceType, faceP->bodyId);
2317 }
2318 }
2319 csg.emplace_back(csg_polygons);
2320
2321#ifdef CutCell_DEBUG
2322 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2323 cerr << "Combine: reference " << referenceSet << " with " << set << "Index " << startSetIndex << "face-size "
2324 << faces[startSetIndex].size() << "Index " << setIndex << "face-size " << faces[setIndex].size() << endl;
2325 }
2326#endif
2327
2328 // call intersect
2329 // currently alle sets are intersected with the zero-set!
2330 // this is not meaning-ful for triple-set-intersections!
2331 result.clear();
2332 result = csg[0].intersect(csg[1]);
2333 vertices_result.clear();
2334
2335// the result (a vector of poligons) holds all information for all intersected poligons!
2336#ifdef CutCell_DEBUG
2337 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2338 cerr << "result-size: " << result.size() << "vertices_result " << vertices_result.size() << endl;
2339
2340 for(MInt poligon = 0; (unsigned)poligon < result.size(); poligon++) {
2341 cerr << "resultId " << poligon << " body " << result[poligon].bodyId << " type " << result[poligon].faceType
2342 << " setIndex " << setIndex << endl;
2343 for(MInt vertex = 0; (unsigned)vertex < result[poligon].vertices.size(); vertex++) {
2344 cerr << "vertex " << vertex << "coordinate: " << setprecision(21)
2345 << result[poligon].vertices[vertex].pos.xx[0] << " " << result[poligon].vertices[vertex].pos.xx[1]
2346 << " " << result[poligon].vertices[vertex].pos.xx[2] << " "
2347 << result[poligon].vertices[vertex].vertexId << " " << result[poligon].vertices[vertex].setIndex
2348 << endl;
2349 }
2350 cerr << "faceId " << result[poligon].faceId << endl;
2351 }
2352 }
2353#endif
2354
2355 // -------- postprocess the poligon intersection (vertices, edges & faces) --------------
2356
2357 // --------1) regenerate polyVertices in a new vertices_result vector
2358 // which holds all unique vertices and removes double-entries from the result-class!
2359
2360
2361 // maximal amount of vertices for the two boundarySurfaces
2362 for(MInt i = 0; i < mMax(2, m_noLevelSetsUsedForMb); i++) {
2363 for(MInt j = 0; j < maxNoVertices; j++) {
2364 vertices_renamed(i, j) = -1;
2365 }
2366 }
2367
2368 // count of unique vertices
2369 MInt noVertices = 0;
2370
2371 // a) add vertices which were already part of ther original vertices-vector and thus hold
2372 // additional polyVertex information!
2373
2374 // loop over all resulting poligons
2375 for(MInt p = 0; (unsigned)p < result.size(); p++) {
2376 ASSERT(result[p].vertices.size() <= (unsigned)maxNoVertices, "");
2377 ASSERT((signed)result[p].vertices.size() >= 3, "");
2378
2379 // loop over all vertices of each poligon
2380 for(MInt v = 0; (unsigned)v < result[p].vertices.size(); v++) {
2381 MInt vertexId = result[p].vertices[v].vertexId;
2382 MInt vertexSetIndex = result[p].vertices[v].setIndex;
2383 if(vertexSetIndex < 0) continue;
2384
2385 if(vertexId < 0) continue;
2386 //-> vertex corresponds to an existing vertex
2387 // and has not been added to the result vector yet!
2388
2389 if(vertices_renamed(vertexSetIndex, vertexId) == -1) {
2390 // -> vertex has not been added to vertices_result vector yet!
2391 MBool vertexFound = false;
2392 MInt vertexIndex = -1;
2393
2394 // loop over all vertices already added to the result-vector
2395 for(MInt i = 0; (unsigned)i < vertices_result.size(); i++) {
2396 MFloat coord_diff = F0;
2397 coord_diff += pow(result[p].vertices[v].pos.xx[0] - vertices_result[i].coordinates[0], 2);
2398 coord_diff += pow(result[p].vertices[v].pos.xx[1] - vertices_result[i].coordinates[1], 2);
2399 coord_diff += pow(result[p].vertices[v].pos.xx[2] - vertices_result[i].coordinates[2], 2);
2400
2401 if(m_multiCutCell) coord_diff = pow(coord_diff, 0.5);
2402
2403
2404 if(coord_diff < difBound1) {
2405#ifdef CutCell_DEBUG
2406 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2407 cerr << "Small diff " << p << " " << vertexId << " " << vertices_result[i].coordinates[0] << " "
2408 << vertices_result[i].coordinates[1] << " " << vertices_result[i].coordinates[2] << " eps "
2409 << difBound1 << " dif " << coord_diff << " " << result[p].vertices[v].pos.xx[0] << " "
2410 << result[p].vertices[v].pos.xx[1] << " " << result[p].vertices[v].pos.xx[2] << " " << endl;
2411 }
2412#endif
2413
2414 vertexFound = true;
2415 vertexIndex = i;
2416 break;
2417 }
2418 }
2419 if(vertexFound) {
2420 vertices_renamed(vertexSetIndex, vertexId) = vertexIndex;
2421 } else {
2422 // only add a vertex if its not already part of other poligon-faces!
2423 vertices_renamed(vertexSetIndex, vertexId) = noVertices;
2424 vertices_result.emplace_back(vertices[vertexSetIndex][vertexId].pointId,
2425 vertices[vertexSetIndex][vertexId].pointType);
2426 // only adding corner-, cut- ord clipping points at this time!
2427 ASSERT(vertices[vertexSetIndex][vertexId].pointType == 0
2428 || vertices[vertexSetIndex][vertexId].pointType == 1
2429 || vertices[vertexSetIndex][vertexId].pointType == 2,
2430 "");
2431 vertices_result[noVertices].coordinates[0] = vertices[vertexSetIndex][vertexId].coordinates[0];
2432 vertices_result[noVertices].coordinates[1] = vertices[vertexSetIndex][vertexId].coordinates[1];
2433 vertices_result[noVertices].coordinates[2] = vertices[vertexSetIndex][vertexId].coordinates[2];
2434 noVertices++;
2435 }
2436 }
2437 // reset vertexId and set setIndex to be jumped
2438 result[p].vertices[v].vertexId = vertices_renamed(vertexSetIndex, vertexId);
2439 result[p].vertices[v].setIndex = -1;
2440 }
2441 }
2442
2443 // b) add new/additional vertices that are created due to the multi-cutCell intersection
2444 // are only existing in the result-class
2445
2446 for(MInt p = 0; (unsigned)p < result.size(); p++) {
2447 for(MInt v = 0; (unsigned)v < result[p].vertices.size(); v++) {
2448 MInt vertexId = result[p].vertices[v].vertexId;
2449 if(vertexId == -1) { // remaining vertices...
2450 // check if vertex has been added to vertices_result vector
2451 MBool vertexFound = false;
2452 MInt vertexIndex = -1;
2453 for(MInt i = 0; (unsigned)i < vertices_result.size(); i++) {
2454 MFloat coord_diff = F0;
2455 coord_diff += pow(result[p].vertices[v].pos.xx[0] - vertices_result[i].coordinates[0], 2);
2456 coord_diff += pow(result[p].vertices[v].pos.xx[1] - vertices_result[i].coordinates[1], 2);
2457 coord_diff += pow(result[p].vertices[v].pos.xx[2] - vertices_result[i].coordinates[2], 2);
2458
2459 if(m_multiCutCell) coord_diff = pow(coord_diff, 0.5);
2460
2461 // use different bound between mc vertices!
2462 MFloat difBound = difBound1;
2463 if(m_multiCutCell) {
2464 difBound = difBound2;
2465 }
2466
2467 if(coord_diff < difBound) {
2468#ifdef CutCell_DEBUG
2469 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2470 cerr << "2 Small diff " << p << " " << vertexId << " " << vertices_result[i].coordinates[0] << " "
2471 << vertices_result[i].coordinates[1] << " " << vertices_result[i].coordinates[2] << " eps "
2472 << coord_diff << " " << result[p].vertices[v].pos.xx[0] << " "
2473 << result[p].vertices[v].pos.xx[1] << " " << result[p].vertices[v].pos.xx[2] << " " << endl;
2474 }
2475#endif
2476
2477 vertexFound = true;
2478 vertexIndex = i;
2479 break;
2480 }
2481 }
2482 if(vertexFound) {
2483 result[p].vertices[v].vertexId = vertexIndex;
2484 result[p].vertices[v].setIndex = -1;
2485 } else {
2486 // all points with pointId -1 and PointType 3!
2487 // thus additional points from multiCutCell generation! (MC vertex!)
2488 vertices_result.emplace_back(-1, 3);
2489 vertices_result[noVertices].coordinates[0] = result[p].vertices[v].pos.xx[0];
2490 vertices_result[noVertices].coordinates[1] = result[p].vertices[v].pos.xx[1];
2491 vertices_result[noVertices].coordinates[2] = result[p].vertices[v].pos.xx[2];
2492 result[p].vertices[v].vertexId = noVertices;
2493 result[p].vertices[v].setIndex = -1;
2494 noVertices++;
2495 }
2496 }
2497 }
2498 }
2499
2500 // copy vertices-result into vertices
2501 vertices[startSetIndex].swap(vertices_result);
2502 vertices_result.clear();
2503 edges[startSetIndex].clear();
2504 faces[startSetIndex].clear();
2505
2506#ifdef CutCell_DEBUG
2507 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2508 cerr << "VertexId-check: " << endl;
2509
2510 for(MInt poligon = 0; (unsigned)poligon < result.size(); poligon++) {
2511 cerr << "resultId " << poligon << " body " << result[poligon].bodyId << " type " << result[poligon].faceType
2512 << " setIndex " << setIndex << endl;
2513 for(MInt vertex = 0; (unsigned)vertex < result[poligon].vertices.size(); vertex++) {
2514 cerr << "vertex " << vertex << "coordinate: " << setprecision(21)
2515 << result[poligon].vertices[vertex].pos.xx[0] << " " << result[poligon].vertices[vertex].pos.xx[1]
2516 << " " << result[poligon].vertices[vertex].pos.xx[2] << " "
2517 << result[poligon].vertices[vertex].vertexId << " " << result[poligon].vertices[vertex].setIndex
2518 << endl;
2519 }
2520 cerr << "faceId " << result[poligon].faceId << endl;
2521 }
2522
2523 for(MInt poligon = 0; (unsigned)poligon < result.size(); poligon++) {
2524 for(MInt vertex = 0; (unsigned)vertex < result[poligon].vertices.size(); vertex++) {
2525 MInt vertexId = result[poligon].vertices[vertex].vertexId;
2526 for(MInt i = 0; i < nDim; i++) {
2527 if(fabs(result[poligon].vertices[vertex].pos.xx[i] - vertices[startSetIndex][vertexId].coordinates[i])
2528 > m_eps * 10) {
2529 cerr << " VertexId-missmatch " << cellId << " " << vertexId << " " << vertex << " " << i
2530 << setprecision(21) << result[poligon].vertices[vertex].pos.xx[i] << " "
2531 << vertices[startSetIndex][vertexId].coordinates[i] << endl;
2532 }
2533 }
2534 }
2535 }
2536 }
2537
2538#endif
2539
2540
2541 // --------1) regenerate unique edges and faces (already unique)
2542 // edge regeneration is rather complicated, as the poligons hold no edge
2543 // information! Just their verticies!
2544 MInt noFaces = 0;
2545 noInitialFaces = 0;
2546 MIntScratchSpace faceMapping(result.size(), AT_, "faceMapping");
2547
2548 // a) add all poligon faces with more than 3 valid vertices to the resulting faces-vector!
2549 for(MInt p = 0; (unsigned)p < result.size(); p++) {
2550 MBoolScratchSpace vertexValid(result[p].vertices.size(), AT_, "vertexValid");
2551 MBool polygonValid = true;
2552 MInt validVertices = 0;
2553 faceMapping[p] = -1;
2554
2555 for(MInt v = 0; (unsigned)v < result[p].vertices.size(); v++) {
2556 const MInt j = (v + 1) % result[p].vertices.size();
2557 const MInt vertexId = result[p].vertices[v].vertexId;
2558 const MInt vertexIdNext = result[p].vertices[j].vertexId;
2559 if(vertexId == vertexIdNext) {
2560 vertexValid[v] = false;
2561 } else {
2562 vertexValid[v] = true;
2563 validVertices++;
2564 }
2565 // add surface surfaceIdentificators
2566 if(vertexValid[v]) {
2567 MInt surfaceIndicator = -1;
2568 if(result[p].faceType == 0) {
2569 surfaceIndicator = result[p].faceId;
2570 } else {
2571 surfaceIndicator = result[p].bodyId + m_noDirs;
2572 }
2573 vertices[startSetIndex][vertexId].surfaceIdentificators.insert(surfaceIndicator);
2574 }
2575 }
2576 if(validVertices < 3) {
2577#ifdef CutCell_DEBUG
2578 // uncomment the part below for additional debug output
2579 // can be helpful for debugging
2580 /*
2581 cerr << grid().domainId() << " Invalid poligon-Id " << p << "with less than 3 verticies! "
2582 << " in cell " << grid().tree().globalId(cellId) << " at TS " << globalTimeStep
2583 << " result vertices: " << endl;
2584 for(MInt v = 0; (unsigned)v < result[p].vertices.size(); v++) {
2585 cerr << result[p].vertices[v].vertexId;
2586 }
2587 cerr << endl;
2588 */
2589#endif
2590 polygonValid = false;
2591 }
2592
2593 if(!polygonValid) continue;
2594
2595 faces[startSetIndex].emplace_back(result[p].faceId, result[p].faceType, result[p].bodyId);
2596 faces[startSetIndex][noFaces].normal[0] = result[p].plane.normal.xx[0];
2597 faces[startSetIndex][noFaces].normal[1] = result[p].plane.normal.xx[1];
2598 faces[startSetIndex][noFaces].normal[2] = result[p].plane.normal.xx[2];
2599 ASSERT(
2600 !(std::isnan(result[p].plane.normal.xx[0] + result[p].plane.normal.xx[1] + result[p].plane.normal.xx[2])),
2601 "");
2602 faces[startSetIndex][noFaces].tmpSetIndex = result[p].setIndex;
2603 faces[startSetIndex][noFaces].w = -result[p].plane.w;
2604 faceMapping[p] = noFaces;
2605 faces[startSetIndex][noFaces].edges.clear();
2606 faces[startSetIndex][noFaces].vertices.clear();
2607
2608 // new method to find face-Vertices!
2609 for(MInt v = 0; (unsigned)v < result[p].vertices.size(); v++) {
2610 const MInt vertexId = result[p].vertices[v].vertexId;
2611 MBool vertexUsed = false;
2612 for(MInt vertice : faces[startSetIndex][noFaces].vertices) {
2613 if(vertexId == vertice) {
2614 vertexUsed = true;
2615 break;
2616 }
2617 }
2618
2619 if(!vertexUsed) {
2620 faces[startSetIndex][noFaces].vertices.push_back(vertexId);
2621 vertices[startSetIndex][vertexId].faceIds.push_back(noFaces);
2622 }
2623 }
2624 ASSERT((signed)faces[startSetIndex][noFaces].vertices.size() >= 3, "");
2625 noFaces++;
2626 noInitialFaces++;
2627 }
2628
2629#ifdef CutCell_DEBUG
2630 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2631 cerr << "Current-Face-Count " << noFaces << endl;
2632 }
2633#endif
2634
2635 // b) add edges to all valid faces
2636 // in the original version vertices are also added at this point!
2637 MInt noEdges = 0;
2638#if defined CutCell_DEBUG || !defined NDEBUG
2639 MBool onlySingleEdges = true;
2640#endif
2641 for(MInt p = 0; (unsigned)p < result.size(); p++) {
2642 MInt faceId = faceMapping[p];
2643 if(faceId < 0) continue;
2644
2645 // add edges to the face
2646 for(MInt v = 0; (unsigned)v < result[p].vertices.size(); v++) {
2647 MInt j = (v + 1) % result[p].vertices.size();
2648 MInt vertexId = result[p].vertices[v].vertexId;
2649 MInt vertexIdNext = result[p].vertices[j].vertexId;
2650 if(vertexId == vertexIdNext) {
2651 continue;
2652 }
2653
2654 MInt direction = 1;
2655 MBool edgeFound = false;
2656 MInt edgeId = -1;
2657 for(MInt e = 0; (unsigned)e < edges[startSetIndex].size(); e++) {
2658 MInt v0 = edges[startSetIndex][e].vertices[0];
2659 MInt v1 = edges[startSetIndex][e].vertices[1];
2660 if(vertexId == v0 && vertexIdNext == v1) {
2661 edgeFound = true;
2662 edgeId = e;
2663 direction = 1;
2664 break;
2665 }
2666 if(vertexId == v1 && vertexIdNext == v0) {
2667 edgeFound = true;
2668 edgeId = e;
2669 direction = -1;
2670 break;
2671 }
2672 }
2673 // adding a new edge
2674 if(!edgeFound) {
2675 edges[startSetIndex].emplace_back(vertexId, vertexIdNext, -1, -1);
2676 edges[startSetIndex][noEdges].face[0] = faceId;
2677 edgeId = noEdges;
2678 direction = 1;
2679 vertices[startSetIndex][vertexId].edges.push_back(noEdges);
2680 vertices[startSetIndex][vertexIdNext].edges.push_back(noEdges);
2681 noEdges++;
2682
2683#ifdef CutCell_DEBUG
2684 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2685 cerr << "Adding Edge " << noEdges << " " << vertexId << " " << vertexIdNext << " " << faceId << endl;
2686 }
2687#endif
2688
2689 // edge already exists and has only one other face
2690 } else if(edges[startSetIndex][edgeId].face[1] < 0) {
2691 edges[startSetIndex][edgeId].face[1] = faceId;
2692
2693#ifdef CutCell_DEBUG
2694 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2695 cerr << "Adding 2nd face to egde " << edgeId << " " << vertexId << " " << vertexIdNext << " " << faceId
2696 << endl;
2697 cerr << "edge vertices are: " << edges[startSetIndex][edgeId].vertices[0] << " "
2698 << edges[startSetIndex][edgeId].vertices[1] << endl;
2699 }
2700#endif
2701 } else {
2702 // edge exists and already has two valid faces!
2703 //=> adding new edge which is identical to the first edge
2704#if defined CutCell_DEBUG || !defined NDEBUG
2705 onlySingleEdges = false;
2706#endif
2707 edges[startSetIndex].emplace_back(vertexId, vertexIdNext, -1, -1);
2708 edges[startSetIndex][noEdges].face[0] = faceId;
2709 edgeId = noEdges;
2710 direction = 1;
2711 vertices[startSetIndex][vertexId].edges.push_back(noEdges);
2712 vertices[startSetIndex][vertexIdNext].edges.push_back(noEdges);
2713 noEdges++;
2714#ifdef CutCell_DEBUG
2715 cerr << cellId << "Has a duplicate edge!" << endl;
2716 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2717 cerr << "Adding Duplicate Edge " << noEdges << " " << vertexId << " " << vertexIdNext << " " << faceId
2718 << endl;
2719 }
2720#endif
2721 }
2722 faces[startSetIndex][faceId].edges.emplace_back(edgeId, direction);
2723 }
2724 }
2725
2726 // debug check:
2727 for(MInt faceId = 0; faceId < static_cast<MInt>(faces[startSetIndex].size()); faceId++) {
2728 ASSERT(faces[startSetIndex][faceId].edges.size() == faces[startSetIndex][faceId].vertices.size(), "");
2729 for(MInt edgeId = 0; edgeId < static_cast<MInt>(faces[startSetIndex][faceId].edges.size()); edgeId++) {
2730 const MInt edge = faces[startSetIndex][faceId].edges[edgeId].first;
2731 const MInt newVertexId = faces[startSetIndex][faceId].vertices[edgeId];
2732 const MInt direction = faces[startSetIndex][faceId].edges[edgeId].second;
2733 MInt vertexId = edges[startSetIndex][edge].vertices[0];
2734 if(direction == -1) {
2735 vertexId = edges[startSetIndex][edge].vertices[1];
2736 }
2737 ASSERT(newVertexId == vertexId, "");
2738 }
2739 }
2740
2741 // openEdges: are edges which only belong to only one face!
2742
2743 // 1) create openEdge vectors/information
2744 // openEdges : vector with edgeId and edge-Direction
2745 // openEdgeList : vector with edgeId and edge-Direction (identical)
2746 // openEdgeId : collector which is -1 for closedEdges and has the openEdgeId for openEdges
2747 openEdges.clear();
2748
2749 for(MInt e = 0; e < static_cast<MInt>(edges[startSetIndex].size()); e++) {
2750 ASSERT(edges[startSetIndex][e].face[0] > -1, "");
2751 if(edges[startSetIndex][e].face[1] == -1) {
2752 MInt face = edges[startSetIndex][e].face[0];
2753 MInt dir = 0;
2754 for(MInt fe = 0; fe < (signed)faces[startSetIndex][face].edges.size(); fe++) {
2755 if(faces[startSetIndex][face].edges[fe].first == e) {
2756 dir = faces[startSetIndex][face].edges[fe].second;
2757 }
2758 }
2759 ASSERT(dir, "");
2760 if(dir == 1) {
2761 openEdges.emplace_back(e, -1);
2762 } else {
2763 openEdges.emplace_back(e, 1);
2764 }
2765 }
2766 }
2767
2768 vector<std::pair<MInt, MInt>> openEdgeList;
2769 MIntScratchSpace openEdgeId(maxNoEdges, AT_, "openEdgeId");
2770 openEdgeId.fill(-1);
2771 for(auto& openEdge : openEdges) {
2772 openEdgeId(openEdge.first) = static_cast<MInt>(openEdgeList.size());
2773 openEdgeList.push_back(openEdge);
2774 }
2775
2776#ifdef CutCell_DEBUG
2777 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
2778 cerr << openEdges.size() << " initially open edges! " << endl;
2779 cerr << "Count: " << faces[startSetIndex].size() << " faces " << edges[startSetIndex].size() << " edges "
2780 << vertices[startSetIndex].size() << " vertices " << endl;
2781
2782 for(auto it2 = openEdges.begin(); it2 != openEdges.end(); it2++) {
2783 const MInt edgdeId = (*it2).first;
2784 cerr << " openEdge with Id " << (*it2).first << " v1 " << edges[startSetIndex][edgdeId].vertices[0] << " "
2785 << edges[startSetIndex][edgdeId].vertices[1] << endl;
2786 }
2787 }
2788#endif
2789
2790 //
2791 // NOTE: connect single large edge with two coinciding smaller edges and intermediate point,
2792 // which is indeed meaningful and necessary!!!
2793
2794
2795 // a) debug-check
2796 // no same edges(with the same vertices, but different direction) should occour:
2797 // no already deleted/invalid edges should occour!
2798 // NOTE: edges are considered deleted if their face[0] = -1!
2799#if defined CutCell_DEBUG || !defined NDEBUG
2800 for(MInt i = 0; i < (signed)openEdgeList.size(); i++) {
2801 const MInt e = openEdgeList[i].first;
2802 const MInt dir = openEdgeList[i].second;
2803 const MInt id0 = (dir == 1) ? 0 : 1;
2804 const MInt id1 = (dir == 1) ? 1 : 0;
2805 const MInt v0 = edges[startSetIndex][e].vertices[id0];
2806 const MInt v1 = edges[startSetIndex][e].vertices[id1];
2807
2808 ASSERT(edges[startSetIndex][e].face[0] > -1, "");
2809
2810 // loop over all edged which share the first vertex
2811 for(MInt j = 0; j < (signed)vertices[startSetIndex][v0].edges.size(); j++) {
2812 const MInt e2 = vertices[startSetIndex][v0].edges[j];
2813
2814 if(e2 == e) continue;
2815
2816 const MInt face = edges[startSetIndex][e2].face[0];
2817 MInt dir2 = 0;
2818 for(MInt fe = 0; fe < (signed)faces[startSetIndex][face].edges.size(); fe++) {
2819 if(faces[startSetIndex][face].edges[fe].first == e2) {
2820 dir2 = faces[startSetIndex][face].edges[fe].second;
2821 }
2822 }
2823 const MInt id00 = (dir2 == 1) ? 0 : 1;
2824 const MInt id11 = (dir2 == 1) ? 1 : 0;
2825 const MInt v00 = edges[startSetIndex][e2].vertices[id00];
2826 const MInt v11 = edges[startSetIndex][e2].vertices[id11];
2827
2828 ASSERT(edges[startSetIndex][e2].face[0] > -1, "");
2829 if(onlySingleEdges) {
2830 ASSERT(v0 != v00 || v1 != v11, "");
2831 ASSERT(v0 != v11 || v1 != v00, "");
2832 }
2833 }
2834 }
2835#endif
2836
2837
2838 // necessary while loop to join edges
2839 //---------------------------------------------------------------------------------------
2840 MBool somethingChanged = !openEdgeList.empty();
2841 while(somethingChanged) {
2842 somethingChanged = false;
2843
2844 MBool alreadyResolved = false;
2845
2846 for(MUint k1 = 0; k1 < openEdgeList.size(); k1++) {
2847 // gather infomation for openEdge e1!
2848 const MInt e1 = openEdgeList[k1].first;
2849 if(openEdgeId(e1) < 0) continue;
2850 const MInt dir1 = openEdgeList[k1].second;
2851 const MInt rdir1 = (dir1 == 1) ? -1 : 1;
2852 const MInt id0 = (dir1 == 1) ? 0 : 1;
2853 const MInt id1 = (dir1 == 1) ? 1 : 0;
2854 const MInt v0 = edges[startSetIndex][e1].vertices[id0];
2855 const MInt v1 = edges[startSetIndex][e1].vertices[id1];
2856 const MInt face = edges[startSetIndex][e1].face[0];
2857
2858 // determine the faceEdgeId fe
2859 MInt fe = -1;
2860 for(fe = 0; (unsigned)fe < faces[startSetIndex][face].edges.size(); fe++) {
2861 if(faces[startSetIndex][face].edges[fe].first == e1) {
2862 break;
2863 }
2864 }
2865 ASSERT(fe < (signed)faces[startSetIndex][face].edges.size(), "");
2866
2867 // determine insert-position for new vertex:
2868 // the new vertex is added between v0 and v1 (thus the +1)
2869 MInt fv = -1;
2870 for(fv = 0; (unsigned)fv < faces[startSetIndex][face].vertices.size(); fv++) {
2871 if(faces[startSetIndex][face].vertices[fv] == v0 || faces[startSetIndex][face].vertices[fv] == v1) {
2872 if(fv + 1 < (signed)faces[startSetIndex][face].vertices.size()
2873 && (faces[startSetIndex][face].vertices[fv + 1] == v0
2874 || faces[startSetIndex][face].vertices[fv + 1] == v1)) {
2875 break;
2876 }
2877 }
2878 }
2879 fv = fv + 1;
2880
2881 MFloat a[3] = {F0, F0, F0};
2882 MFloat a_abs = F0;
2883 for(MInt i = 0; i < nDim; i++) {
2884 a[i] = vertices[startSetIndex][v1].coordinates[i] - vertices[startSetIndex][v0].coordinates[i];
2885 a_abs += a[i] * a[i];
2886 }
2887 a_abs = sqrt(a_abs);
2888
2889 // loop over all edges at vertex v0
2890 for(MInt k2 = 0; (unsigned)k2 < vertices[startSetIndex][v0].edges.size(); k2++) {
2891 // find other openEdges at v0
2892 const MInt e2 = vertices[startSetIndex][v0].edges[k2];
2893 if(e2 == e1) continue;
2894 if(openEdgeId(e2) < 0) continue;
2895 ASSERT(openEdgeList[openEdgeId(e2)].first == e2, "");
2896 // gather information for the also openEdge e2!
2897 const MInt dir2 = openEdgeList[openEdgeId(e2)].second;
2898 const MInt id00 = (dir2 == 1) ? 0 : 1;
2899 const MInt id11 = (dir2 == 1) ? 1 : 0;
2900 const MInt v00 = edges[startSetIndex][e2].vertices[id00];
2901 const MInt v11 = edges[startSetIndex][e2].vertices[id11];
2902
2903 if(v11 != v0) continue;
2904
2905 MFloat b[3]{};
2906 MFloat b_abs = F0;
2907 MFloat dotProduct = F0;
2908 for(MInt i = 0; i < nDim; i++) {
2909 b[i] = vertices[startSetIndex][v11].coordinates[i] - vertices[startSetIndex][v00].coordinates[i];
2910 b_abs += b[i] * b[i];
2911 dotProduct += a[i] * b[i];
2912 }
2913 b_abs = sqrt(b_abs);
2914 // dotProduct should be -1 if intermediate vertex on edge was found
2915 dotProduct = fabs(F1 + (dotProduct / (a_abs * b_abs)));
2916 // TODO labels:GEOM,totest use meaningful restriction, which also changes testcases!
2917 // if ( dotProduct < m_eps*1000000 && b_abs < a_abs ) {
2918 if(dotProduct < 1e-10 && b_abs < a_abs) {
2919 // splitting e1 into e2 and e3:
2920 // v0 == v11 version!
2921 // version 1
2922
2923 // check if the third edge e3, which shall replace e1, already exists
2924 // NOTE: if the edge is triple-split e3 must not already be existing!
2925 // a new edge is then created, which is split again in the next iteration!
2926 MInt e3 = -1;
2927 MInt dir3 = -2;
2928 MInt v000 = -1;
2929 MInt v111 = -1;
2930 MInt id000 = -1;
2931 MInt id111 = -1;
2932 MBool foundMatchingEdge = false;
2933 for(MUint k3 = 0; k3 < openEdgeList.size(); k3++) {
2934 e3 = openEdgeList[k3].first;
2935 if(openEdgeId(e3) < 0) continue;
2936 dir3 = openEdgeList[k3].second;
2937 id000 = (dir3 == 1) ? 0 : 1;
2938 id111 = (dir3 == 1) ? 1 : 0;
2939 v000 = edges[startSetIndex][e3].vertices[id000];
2940 v111 = edges[startSetIndex][e3].vertices[id111];
2941 if(v111 == v00 && v000 == v1) {
2942 foundMatchingEdge = true;
2943 break;
2944 }
2945 if(v000 == v00 && v111 == v1) {
2946 foundMatchingEdge = true;
2947 break;
2948 }
2949 }
2950 // check that the matchingEdge is not already a closed edge
2951 // if it is, the edges must not be split!
2952 // instead the open edges will be resolved by adding faceLines!
2953 /*
2954 if(!foundMatchingEdge) {
2955 MBool alreadyExisting = false;
2956 for(MInt e = 0; e < static_cast<MInt>(edges[startSetIndex].size()); e++) {
2957 MInt vl = edges[startSetIndex][e].vertices[0];
2958 MInt vr = edges[startSetIndex][e].vertices[1];
2959
2960 if((v00 == vl && v1 == vr) || (v00 == vr && v1 == vl)) {
2961 alreadyExisting = true;
2962 break;
2963 }
2964 }
2965 if(alreadyExisting) {
2966 continue;
2967 }
2968 }
2969 */
2970 // make e1 equal e3
2971 edges[startSetIndex][e1].vertices[id0] = v00;
2972
2973 // adding face to e2
2974 edges[startSetIndex][e2].face[1] = face;
2975
2976 // adding e2 to the face of e1
2977 MInt otherDir = (edges[startSetIndex][e2].vertices[id0] == v0) ? rdir1 : dir1;
2978 auto pos = faces[startSetIndex][face].edges.begin() + fe;
2979 pos += (dir1 == 1) ? 0 : 1;
2980 faces[startSetIndex][face].edges.insert(pos, make_pair(e2, otherDir));
2981
2982
2983 if(!m_multiCutCell) {
2984 // replacing e1 at the vertex v0
2985 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v0].edges.size(); edg++) {
2986 if(vertices[startSetIndex][v0].edges[edg] == e1) {
2987 vertices[startSetIndex][v0].edges[edg] = e2;
2988 }
2989 }
2990 } else {
2991 // removing e1 at the vertex v0
2992 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v0].edges.size(); edg++) {
2993 if(vertices[startSetIndex][v0].edges[edg] == e1) {
2994 auto epos = vertices[startSetIndex][v0].edges.begin() + edg;
2995 vertices[startSetIndex][v0].edges.erase(epos);
2996 }
2997 }
2998 }
2999 // add e1 to v00
3000 if(m_multiCutCell) vertices[startSetIndex][v00].edges.push_back(e1);
3001
3002
3003 if(foundMatchingEdge) {
3004 MInt otherDir2 = (edges[startSetIndex][e2].vertices[id0] == v0) ? rdir1 : dir1;
3005
3006 // find new position of e1 in the face (might be shifted due to the insertion of e2)!
3007 for(fe = 0; fe < (signed)faces[startSetIndex][face].edges.size(); fe++) {
3008 if(faces[startSetIndex][face].edges[fe].first == e1) {
3009 faces[startSetIndex][face].edges[fe].first = e3;
3010 faces[startSetIndex][face].edges[fe].second = otherDir2;
3011 }
3012 }
3013
3014 // add the face to the edge e3
3015 edges[startSetIndex][e3].face[1] = face;
3016
3017 // deleting edge e1
3018 edges[startSetIndex][e1].face[0] = -1;
3019 edges[startSetIndex][e1].face[1] = -1;
3020
3021#ifdef CutCell_DEBUG
3022 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
3023 cerr << "Replacing edge " << e1 << " with " << e3 << " and adding vertex " << v00 << " to face "
3024 << face << endl;
3025 cerr << "Intermediate edge is " << e2 << " with v " << v1 << " v2 " << v0 << endl;
3026 }
3027#endif
3028
3029 if(!m_multiCutCell) {
3030 // replacing e1 with e3
3031 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v00].edges.size(); edg++) {
3032 if(vertices[startSetIndex][v00].edges[edg] == e1) {
3033 vertices[startSetIndex][v00].edges[edg] = e3;
3034 }
3035 }
3036 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v1].edges.size(); edg++) {
3037 if(vertices[startSetIndex][v1].edges[edg] == e1) {
3038 vertices[startSetIndex][v1].edges[edg] = e3;
3039 }
3040 }
3041 } else {
3042 // removing e1 at the vertices v00 and v1
3043 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v00].edges.size(); edg++) {
3044 if(vertices[startSetIndex][v00].edges[edg] == e1) {
3045 auto epos = vertices[startSetIndex][v00].edges.begin() + edg;
3046 vertices[startSetIndex][v00].edges.erase(epos);
3047 }
3048 }
3049 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v1].edges.size(); edg++) {
3050 if(vertices[startSetIndex][v1].edges[edg] == e1) {
3051 auto epos = vertices[startSetIndex][v1].edges.begin() + edg;
3052 vertices[startSetIndex][v1].edges.erase(epos);
3053 }
3054 }
3055 }
3056
3057 // remove both edges from the openEdgeList
3058 openEdgeId(e1) = -1;
3059 openEdgeId(e3) = -1;
3060 }
3061
3062 // adding the additional vertex v00 to the face
3063 auto vpos = faces[startSetIndex][face].vertices.begin() + fv;
3064 if(vpos > faces[startSetIndex][face].vertices.end()) {
3065 faces[startSetIndex][face].vertices.push_back(v00);
3066 } else {
3067 faces[startSetIndex][face].vertices.insert(vpos, v00);
3068 }
3069
3070 // remove as openEdge
3071 openEdgeId(e2) = -1;
3072
3073 somethingChanged = true;
3074 alreadyResolved = true;
3075 break;
3076 }
3077 }
3078
3079 if(alreadyResolved) continue;
3080
3081 // loop over all edges at vertex v1
3082 for(MInt k2 = 0; (unsigned)k2 < vertices[startSetIndex][v1].edges.size(); k2++) {
3083 const MInt e2 = vertices[startSetIndex][v1].edges[k2];
3084 if(e2 == e1) continue;
3085 if(openEdgeId(e2) < 0) continue;
3086 ASSERT(openEdgeList[openEdgeId(e2)].first == e2, "");
3087 const MInt dir2 = openEdgeList[openEdgeId(e2)].second;
3088 const MInt id00 = (dir2 == 1) ? 0 : 1;
3089 const MInt id11 = (dir2 == 1) ? 1 : 0;
3090 const MInt v00 = edges[startSetIndex][e2].vertices[id00];
3091 const MInt v11 = edges[startSetIndex][e2].vertices[id11];
3092
3093 if(v00 != v1) continue;
3094
3095 MFloat b[3] = {F0, F0, F0};
3096 MFloat b_abs = F0;
3097 MFloat dotProduct = F0;
3098 for(MInt i = 0; i < nDim; i++) {
3099 b[i] = vertices[startSetIndex][v11].coordinates[i] - vertices[startSetIndex][v00].coordinates[i];
3100 b_abs += b[i] * b[i];
3101 dotProduct += a[i] * b[i];
3102 }
3103 b_abs = sqrt(b_abs);
3104 // dotProduct should be -1 if intermediate vertex on edge was found
3105 dotProduct = fabs(F1 + (dotProduct / (a_abs * b_abs)));
3106 // TODO labels:GEOM,totest use meaningful restriction, which also changes testcases!
3107 // if ( dotProduct < m_eps*1000000 && b_abs < a_abs ) {
3108 if(dotProduct < 1e-10 && b_abs < a_abs) {
3109 // splitting e1 into e2 and e3:
3110 // v1 == v00 version!
3111 // version 2
3112
3113 // check if the third edge e3, which shall replace e1, already exists
3114 // NOTE: if the edge is triple-split e3 must not already be existing!
3115 // a new edge is then created, which is split again in the next iteration!
3116 MInt e3 = -1;
3117 MInt dir3 = -2;
3118 MInt v000 = -1;
3119 MInt v111 = -1;
3120 MInt id000 = -1;
3121 MInt id111 = -1;
3122 MBool foundMatchingEdge = false;
3123 for(auto& k3 : openEdgeList) {
3124 e3 = k3.first;
3125 if(openEdgeId(e3) < 0) continue;
3126 dir3 = k3.second;
3127 id000 = (dir3 == 1) ? 0 : 1;
3128 id111 = (dir3 == 1) ? 1 : 0;
3129 v000 = edges[startSetIndex][e3].vertices[id000];
3130 v111 = edges[startSetIndex][e3].vertices[id111];
3131 if(v000 == v0 && v111 == v11) {
3132 foundMatchingEdge = true;
3133 break;
3134 } else if(v000 == v11 && v111 == v0) {
3135 foundMatchingEdge = true;
3136 break;
3137 }
3138 }
3139 // check that the matchingEdge is not already a closed edge
3140 /*
3141 if(!foundMatchingEdge) {
3142 MBool alreadyExisting = false;
3143 for(MInt e = 0; e < static_cast<MInt>(edges[startSetIndex].size()); e++) {
3144 MInt vl = edges[startSetIndex][e].vertices[0];
3145 MInt vr = edges[startSetIndex][e].vertices[1];
3146
3147 if((v11 == vl && v1 == vr) || (v11 == vr && v1 == vl)) {
3148 alreadyExisting = true;
3149 break;
3150 }
3151 }
3152 if(alreadyExisting) {
3153 continue;
3154 }
3155 }
3156 */
3157
3158 // adding e2 to the face of e1
3159 MInt otherDir = (edges[startSetIndex][e2].vertices[id1] == v1) ? rdir1 : dir1;
3160 auto pos = faces[startSetIndex][face].edges.begin() + fe;
3161 pos += (dir1 == 1) ? 1 : 0;
3162 faces[startSetIndex][face].edges.insert(pos, make_pair(e2, otherDir));
3163
3164 // adding the additional vertex v11 to the face
3165 auto vpos = faces[startSetIndex][face].vertices.begin() + fv;
3166 if(vpos > faces[startSetIndex][face].vertices.end()) {
3167 faces[startSetIndex][face].vertices.push_back(v11);
3168 } else {
3169 faces[startSetIndex][face].vertices.insert(vpos, v11);
3170 }
3171
3172 // adding face to e2
3173 edges[startSetIndex][e2].face[1] = face;
3174
3175 // replacing e1 at the vertex v1 with e2
3176 if(!m_multiCutCell) {
3177 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v1].edges.size(); edg++) {
3178 if(vertices[startSetIndex][v1].edges[edg] == e1) {
3179 vertices[startSetIndex][v1].edges[edg] = e2;
3180 }
3181 }
3182 } else {
3183 // removing e1 at the vertex v1
3184 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v1].edges.size(); edg++) {
3185 if(vertices[startSetIndex][v1].edges[edg] == e1) {
3186 auto epos = vertices[startSetIndex][v1].edges.begin() + edg;
3187 vertices[startSetIndex][v1].edges.erase(epos);
3188 }
3189 }
3190 }
3191 // adding e1 to vertex v11
3192 if(m_multiCutCell) vertices[startSetIndex][v11].edges.push_back(e1);
3193
3194 // make e1 euqal e3
3195 edges[startSetIndex][e1].vertices[id1] = v11;
3196
3197 // remove as openEdge
3198 openEdgeId(e2) = -1;
3199
3200
3201 if(foundMatchingEdge) {
3202 // removing edge e1:
3203
3204 // replacing e1 with e3 for the face
3205 const MInt otherDir2 = (edges[startSetIndex][e3].vertices[id1] == v1) ? rdir1 : dir1;
3206
3207 // find new position of e1 in the face (might be shifted due to the insertion of e2)!
3208 for(fe = 0; fe < (signed)faces[startSetIndex][face].edges.size(); fe++) {
3209 if(faces[startSetIndex][face].edges[fe].first == e1) {
3210 faces[startSetIndex][face].edges[fe].first = e3;
3211 faces[startSetIndex][face].edges[fe].second = otherDir2;
3212 break;
3213 }
3214 }
3215
3216#ifdef CutCell_DEBUG
3217 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
3218 cerr << "Replacing edge " << e1 << " with " << e3 << " and adding vertex " << v00 << " to face "
3219 << face << endl;
3220 cerr << "Intermediate edge is " << e2 << " with v " << v11 << " v2 " << v1 << endl;
3221 }
3222#endif
3223
3224 // delete e1/remove all faces:
3225 edges[startSetIndex][e1].face[0] = -1;
3226 edges[startSetIndex][e1].face[1] = -1;
3227
3228 // replacing e1 with e3
3229 if(!m_multiCutCell) {
3230 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v0].edges.size(); edg++) {
3231 if(vertices[startSetIndex][v0].edges[edg] == e1) {
3232 vertices[startSetIndex][v0].edges[edg] = e3;
3233 }
3234 }
3235 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v11].edges.size(); edg++) {
3236 if(vertices[startSetIndex][v11].edges[edg] == e1) {
3237 vertices[startSetIndex][v11].edges[edg] = e3;
3238 }
3239 }
3240 } else {
3241 // removing e1 from all vertices
3242 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v0].edges.size(); edg++) {
3243 if(vertices[startSetIndex][v0].edges[edg] == e1) {
3244 auto epos = vertices[startSetIndex][v0].edges.begin() + edg;
3245 vertices[startSetIndex][v0].edges.erase(epos);
3246 }
3247 }
3248 for(MInt edg = 0; (unsigned)edg < vertices[startSetIndex][v11].edges.size(); edg++) {
3249 if(vertices[startSetIndex][v11].edges[edg] == e1) {
3250 auto epos = vertices[startSetIndex][v11].edges.begin() + edg;
3251 vertices[startSetIndex][v11].edges.erase(epos);
3252 }
3253 }
3254 }
3255 // remove openEdges
3256 openEdgeId(e1) = -1;
3257 openEdgeId(e3) = -1;
3258
3259 // add the face to e3
3260 edges[startSetIndex][e3].face[1] = face;
3261 }
3262
3263 somethingChanged = true;
3264 break;
3265 }
3266 }
3267 }
3268 }
3269//----------------------------------------------------------------------------------------
3270
3271// debug-checks:
3272// no same edges(with the same vertices, but different direction) should occour,
3273// unless they are marked as deleted!
3274#ifdef CutCell_DEBUG
3275 for(MUint i = 0; i < openEdgeList.size(); i++) {
3276 const MInt e = openEdgeList[i].first;
3277 const MInt dir = openEdgeList[i].second;
3278 const MInt id0 = (dir == 1) ? 0 : 1;
3279 const MInt id1 = (dir == 1) ? 1 : 0;
3280 const MInt v0 = edges[startSetIndex][e].vertices[id0];
3281 const MInt v1 = edges[startSetIndex][e].vertices[id1];
3282
3283 // skip-deleted edges:
3284 if(edges[startSetIndex][e].face[0] == -1 && edges[startSetIndex][e].face[1] == -1) continue;
3285
3286 // loop over all edged which share the first vertex
3287 for(MInt j = 0; (unsigned)j < vertices[startSetIndex][v0].edges.size(); j++) {
3288 const MInt e2 = vertices[startSetIndex][v0].edges[j];
3289 if(e2 == e) continue;
3290 const MInt dir2 = openEdgeList[openEdgeId(e2)].second;
3291 const MInt id00 = (dir2 == 1) ? 0 : 1;
3292 const MInt id11 = (dir2 == 1) ? 1 : 0;
3293 const MInt v00 = edges[startSetIndex][e2].vertices[id00];
3294 const MInt v11 = edges[startSetIndex][e2].vertices[id11];
3295
3296 // skip-deleted edges:
3297 if(edges[startSetIndex][e2].face[0] == -1 && edges[startSetIndex][e2].face[1] == -1) continue;
3298 if(onlySingleEdges) {
3299 ASSERT(v0 != v00 || v1 != v11, "");
3300 ASSERT(v0 != v11 || v1 != v00, "");
3301 }
3302 }
3303 }
3304#endif
3305
3306 // no face should have a reference to an deleted edge:
3307 for(MInt faceId = 0; faceId < (signed)faces[startSetIndex].size(); faceId++) {
3308 for(MInt edgeId = 0; edgeId < (signed)faces[startSetIndex][faceId].edges.size(); edgeId++) {
3309 const MInt edge = faces[startSetIndex][faceId].edges[edgeId].first;
3310 ASSERT(edges[startSetIndex][edge].face[0] > -1, "");
3311 }
3312 }
3313
3314 // no vertex should have a reference to an deleted edge:
3315 for(MInt v = 0; v < (signed)vertices[startSetIndex].size(); v++) {
3316 for(MInt edgeId = 0; (unsigned)edgeId < vertices[startSetIndex][v].edges.size(); edgeId++) {
3317 const MInt edge = vertices[startSetIndex][v].edges[edgeId];
3318 ASSERT(edges[startSetIndex][edge].face[0] > -1, "");
3319 }
3320 }
3321
3322 // vertex and edge information should match!
3323 for(MInt faceId = 0; faceId < (signed)faces[startSetIndex].size(); faceId++) {
3324 ASSERT(faces[startSetIndex][faceId].edges.size() == faces[startSetIndex][faceId].vertices.size(), "");
3325 for(MInt edgeId = 0; edgeId < (signed)faces[startSetIndex][faceId].edges.size(); edgeId++) {
3326 const MInt edge = faces[startSetIndex][faceId].edges[edgeId].first;
3327 const MInt newVertexId = faces[startSetIndex][faceId].vertices[edgeId];
3328 const MInt direction = faces[startSetIndex][faceId].edges[edgeId].second;
3329 MInt vertexId = edges[startSetIndex][edge].vertices[0];
3330 if(direction == -1) vertexId = edges[startSetIndex][edge].vertices[1];
3331 ASSERT(newVertexId == vertexId, "");
3332 }
3333 }
3334
3335 // determine remaining unsolved open edges
3336 std::list<std::pair<MInt, MInt>> openEdgesOld(openEdges);
3337 openEdges.clear();
3338 for(auto& it1 : openEdgesOld) {
3339 if(openEdgeId(it1.first) < 0) continue;
3340 openEdges.push_back(it1);
3341 }
3342
3343
3344#ifdef CutCell_DEBUG
3345 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
3346 cerr << openEdges.size() << " open edge remaining: " << endl;
3347 cerr << "Count: " << faces[startSetIndex].size() << " faces " << edges[startSetIndex].size() << " edges "
3348 << vertices[startSetIndex].size() << " vertices " << endl;
3349
3350 for(auto it2 = openEdges.begin(); it2 != openEdges.end(); it2++) {
3351 const MInt edgeId = (*it2).first;
3352 cerr << " openEdge with Id " << edgeId << " v1 " << edges[startSetIndex][edgeId].vertices[0] << " "
3353 << edges[startSetIndex][edgeId].vertices[1] << endl;
3354 }
3355 }
3356
3357 /*
3358 if(openEdges.size() > 0) {
3359 cerr << openEdges.size() << " openEdges remaining: adding face-Lines! at TS " << globalTimeStep << " for "
3360 << cellId << " on rank " << grid().domainId() << " result " << result.size() << " faces "
3361 << faces[startSetIndex].size() << endl;
3362 }
3363 */
3364
3365 if(openEdges.size() == 1) {
3366 cerr << " Only 1 open edge remaining: This means trouble! " << endl;
3367 cerr << "Re-checking coordinate-distances! " << endl;
3368 for(MInt i = 0; (unsigned)i < vertices[startSetIndex].size(); i++) {
3369 for(MInt j = 0; (unsigned)j < vertices[startSetIndex].size(); j++) {
3370 if(i == j) continue;
3371 MFloat coord_diff = 0;
3372 coord_diff +=
3373 pow(vertices[startSetIndex][i].coordinates[0] - vertices[startSetIndex][j].coordinates[0], 2);
3374 coord_diff +=
3375 pow(vertices[startSetIndex][i].coordinates[1] - vertices[startSetIndex][j].coordinates[1], 2);
3376 coord_diff +=
3377 pow(vertices[startSetIndex][i].coordinates[2] - vertices[startSetIndex][j].coordinates[2], 2);
3378
3379 MFloat dif_old = coord_diff;
3380 coord_diff = pow(coord_diff, 0.5);
3381
3382 if(coord_diff < cellLength0) {
3383 cerr << " Coord-dif " << coord_diff << " i " << i << " " << j << endl;
3384 cerr << " dif-old " << dif_old << " " << m_eps * 10 << endl;
3385 }
3386 }
3387 }
3388 }
3389
3390#endif
3391
3392 // NOTE: these open-edges are due to the deletion of MC-verticies close to each other
3393 // this was done to reduce the overall number of vertices, limited by maxNoFaceVertices
3394
3395 // prepare decision array ->
3396 // compute the angle between all open edges!
3397 // and always connect edges with angle closest to 180 degrees!
3398 for(auto it1 = openEdges.begin(); it1 != openEdges.end(); it1++) {
3399 // first edge e1
3400 const MInt e1 = (*it1).first;
3401 const MInt dir1 = (*it1).second;
3402 MInt v11 = edges[startSetIndex][e1].vertices[0];
3403 MInt v12 = edges[startSetIndex][e1].vertices[1];
3404 if(dir1 == -1) {
3405 MInt tmp = v11;
3406 v11 = v12;
3407 v12 = tmp;
3408 }
3409 MFloat a[3]{};
3410 MFloat a_abs = F0;
3411 for(MInt i = 0; i < nDim; i++) {
3412 a[i] = vertices[startSetIndex][v12].coordinates[i] - vertices[startSetIndex][v11].coordinates[i];
3413 a_abs += a[i] * a[i];
3414 }
3415 a_abs = sqrt(a_abs);
3416 // loop ever all remaining openEdges
3417 for(auto& openEdge : openEdges) {
3418 const MInt e2 = openEdge.first;
3419 const MInt dir2 = openEdge.second;
3420 // identical edges, set to maximum!
3421 if(e2 == e1) {
3422 dotProdMatrix(e1, e2) = 1000.0;
3423 dotProdMatrix(e2, e1) = 1000.0;
3424 continue;
3425 }
3426 MInt v21 = edges[startSetIndex][e2].vertices[0];
3427 MInt v22 = edges[startSetIndex][e2].vertices[1];
3428 if(dir2 == -1) {
3429 MInt tmp = v21;
3430 v21 = v22;
3431 v22 = tmp;
3432 }
3433
3434 if(v12 == v21) {
3435 // edges are connected correctly, compute the dotProduct
3436 MFloat b[3] = {F0, F0, F0};
3437 MFloat b_abs = F0;
3438 MFloat dotProduct = F0;
3439 for(MInt i = 0; i < nDim; i++) {
3440 b[i] = vertices[startSetIndex][v22].coordinates[i] - vertices[startSetIndex][v21].coordinates[i];
3441 b_abs += b[i] * b[i];
3442 dotProduct += a[i] * b[i];
3443 }
3444 b_abs = sqrt(b_abs);
3445 dotProduct = abs(F1 - abs(dotProduct / (a_abs * b_abs)));
3446 dotProdMatrix(e1, e2) = dotProduct;
3447 } else {
3448 // edges with different orientation should never be matched!
3449 dotProdMatrix(e1, e2) = 1000.0;
3450 }
3451 }
3452 }
3453
3454 // loop over all remaining edges
3455 // adding face-lines for these!
3456 while(!openEdges.empty()) {
3457 faceVertices.clear();
3458 // openEdge eLast
3459 MInt e = -1;
3460 MInt eLast = openEdges.front().first;
3461 MInt dir = openEdges.front().second;
3462 MInt faceType = -1;
3463 MInt faceId = -1;
3464 MInt bodyId = -1;
3465 for(MInt i = 0; i < m_noDirs + m_noEmbeddedBodies; i++) {
3466 surfaceIdentificatorCounters[i] = 0;
3467 }
3468
3469 // adding a new face for the remaining unsolved edge (eLast)
3470 faces[startSetIndex].emplace_back(faceId, faceType, bodyId);
3471 // add the edge to the face
3472 faces[startSetIndex][noFaces].edges.emplace_back(eLast, dir);
3473 faces[startSetIndex][noFaces].isLine = 1;
3474
3475 // remove corresponding openEdge
3476 openEdges.pop_front();
3477
3478 MInt startVertex = edges[startSetIndex][eLast].vertices[0];
3479 MInt vertex = edges[startSetIndex][eLast].vertices[1];
3480 // switch vertex-order
3481 if(dir == -1) {
3482 MInt tmp = startVertex;
3483 startVertex = vertex;
3484 vertex = tmp;
3485 }
3486 // add vertices to the faceLine
3487 faces[startSetIndex][noFaces].vertices.push_back(startVertex);
3488
3489#ifdef CutCell_DEBUG
3490 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
3491 cerr << "Adding face line starting with edge " << eLast << " with vertex " << startVertex << " and "
3492 << vertex << endl;
3493 }
3494#endif
3495
3496 // add faceVertexId
3497 faceVertices.push_back(vertex);
3498 // increase all surfaceIdentificator of the vertex!
3499 for(MInt surfaceIdentificator : vertices[startSetIndex][vertex].surfaceIdentificators) {
3500 surfaceIdentificatorCounters[surfaceIdentificator]++;
3501 }
3502 // add the new faceLine to the edge (=> no longer open)
3503 edges[startSetIndex][eLast].face[1] = noFaces;
3504
3505 // loop over vertices to find a closed faceLine including other edges/vertices
3506 while(vertex != startVertex) {
3507 // first: find the right open edge for further connection, then connect it:
3508 auto bestEdgeIt = openEdges.end();
3509 MFloat minDotProduct = 1001.0;
3510 // loop over all other remaining open edges to find the bestEdgeId
3511 // meaning the edge with the lowest dotProduct!
3512 // NOTE: in some cases the edge with the lowest dotProduct is not the
3513 // best choice, as the edged might not be connected to the previous edge!
3514 for(auto it = openEdges.begin(); it != openEdges.end(); it++) {
3515 // other openEdge Id e
3516 e = (*it).first;
3517 if(dotProdMatrix(eLast, e) < minDotProduct) {
3518 // only use this edge if the edge continues the loop!
3519 dir = (*bestEdgeIt).second;
3520 MInt vStart = edges[startSetIndex][e].vertices[0];
3521 MInt vEnd = edges[startSetIndex][e].vertices[1];
3522 if(dir == -1) {
3523 MInt tmp = vStart;
3524 vStart = vEnd;
3525 vEnd = tmp;
3526 }
3527 if(vStart == vertex) {
3528 minDotProduct = dotProdMatrix(eLast, e);
3529 bestEdgeIt = it;
3530 } else if(vEnd == vertex) {
3531 minDotProduct = dotProdMatrix(eLast, e);
3532 bestEdgeIt = it;
3533 }
3534 }
3535 }
3536
3537 if(bestEdgeIt == openEdges.end()) {
3538 writeVTKFileOfCell(cellId, &faces[startSetIndex], &vertices[startSetIndex], globalTimeStep);
3539 cerr << grid().domainId() << "open edges for cell " << cellId << ": ";
3540 cerr << "Open edges size: " << openEdges.size() << endl;
3541 for(auto& openEdge : openEdges) {
3542 cerr << openEdge.first;
3543 }
3544 mTerm(1, AT_, "Open edge for cutCell!");
3545 }
3546
3547 // continue with the bestEdge
3548 e = (*bestEdgeIt).first;
3549 dir = (*bestEdgeIt).second;
3550 MInt vStart = edges[startSetIndex][e].vertices[0];
3551 MInt vEnd = edges[startSetIndex][e].vertices[1];
3552 if(dir == -1) {
3553 MInt tmp = vStart;
3554 vStart = vEnd;
3555 vEnd = tmp;
3556 }
3557 if(vStart != vertex) {
3558 if(vEnd == vertex) {
3559 // Switch direction of the edge
3560 if(dir == -1) {
3561 dir = 1;
3562 } else {
3563 dir = -1;
3564 }
3565 MInt vEndOld = vEnd;
3566 vEnd = vStart;
3567 vStart = vEndOld;
3568 } else {
3569 cerr << grid().domainId() << " missmatching edges for " << cellId << " "
3570 << grid().tree().globalId(cellId) << " vertices: " << vStart << " " << vEnd << " " << vertex
3571 << endl;
3572 }
3573 }
3574
3575 eLast = e;
3576
3577 // add the bestEdge to the face and remove it from the openEdges-list!
3578 faces[startSetIndex][noFaces].edges.emplace_back(e, dir);
3579 faces[startSetIndex][noFaces].vertices.push_back(vStart);
3580
3581#ifdef CutCell_DEBUG
3582 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
3583 cerr << "Adding edge " << e << " with vertex " << vStart << " and " << vEnd << endl;
3584 cerr << "The new face now has " << faces[startSetIndex][noFaces].vertices.size() << " vertices!" << endl;
3585 }
3586#endif
3587
3588 openEdges.erase(bestEdgeIt);
3589 vertex = vEnd;
3590 faceVertices.push_back(vertex);
3591 for(MInt surfaceIdentificator : vertices[startSetIndex][vertex].surfaceIdentificators)
3592 surfaceIdentificatorCounters[surfaceIdentificator]++;
3593 edges[startSetIndex][e].face[1] = noFaces;
3594 }
3595 // ASSERT(faceVertices.size() > 2, "");
3596 if(faceVertices.size() <= 2) {
3597 cerr << grid().domainId() << " face with only two vertices for " << cellId << " "
3598 << grid().tree().globalId(cellId) << " face : " << noFaces << endl;
3599 }
3600
3601 // check for vertices which are doubled in face:
3602 MInt noDoubleVertices = 0;
3603 ASSERT(vertices[startSetIndex].size() <= (unsigned)maxNoVertices, "");
3604 for(MInt v = 0; (unsigned)v < vertices[startSetIndex].size(); v++) {
3605 vertexTouches[v] = 0;
3606 }
3607 for(MInt fv = 0; (unsigned)fv < faceVertices.size(); fv++) {
3608 vertexTouches[faceVertices[fv]]++;
3609 }
3610 for(MInt v = 0; (unsigned)v < vertices[startSetIndex].size(); v++) {
3611 if(vertexTouches[v] > 1) {
3612 noDoubleVertices++;
3613 }
3614 }
3615
3616 if(noDoubleVertices != 0) {
3617 cerr << "double vertices for " << cellId << " on " << grid().domainId() << endl;
3618 error = true;
3619 }
3620
3621 // find out correct bodyId/faceId and faceType and set normal and w
3622 // for the new face, based on the bestIdentificator!
3623 MInt bestIdentificator = -1;
3624 MInt maxHits = 0;
3625 for(MInt i = 0; i < m_noDirs + m_noEmbeddedBodies; i++) {
3626 if(surfaceIdentificatorCounters[i] > maxHits) {
3627 maxHits = surfaceIdentificatorCounters[i];
3628 bestIdentificator = i;
3629 }
3630 }
3631 ASSERT(bestIdentificator > -1, "");
3632 ASSERT(bestIdentificator < m_noDirs + m_noEmbeddedBodies, "");
3633 faceType = (bestIdentificator < m_noDirs ? 0 : 1);
3634 if(faceType == 0) {
3635 faceId = bestIdentificator;
3636 } else {
3637 bodyId = bestIdentificator - m_noDirs;
3638 }
3639 faces[startSetIndex][noFaces].faceType = faceType;
3640 faces[startSetIndex][noFaces].faceId = faceId;
3641 faces[startSetIndex][noFaces].bodyId = bodyId;
3642
3643 // find correct face to inject w and normal from:
3644 MBool partnerFound = false;
3645 for(MInt e2 = 0; (unsigned)e2 < faces[startSetIndex][noFaces].edges.size(); e2++) {
3646 MInt edge = faces[startSetIndex][noFaces].edges[e2].first;
3647 MInt otherFace = edges[startSetIndex][edge].face[0];
3648 MInt otherFaceType = faces[startSetIndex][otherFace].faceType;
3649 MInt otherFaceId = faces[startSetIndex][otherFace].faceId;
3650 MInt otherBodyId = faces[startSetIndex][otherFace].bodyId;
3651 if(otherFaceType == faceType && otherFaceId == faceId && otherBodyId == bodyId) {
3652 partnerFound = true;
3653 faces[startSetIndex][noFaces].normal[0] = faces[startSetIndex][otherFace].normal[0];
3654 faces[startSetIndex][noFaces].normal[1] = faces[startSetIndex][otherFace].normal[1];
3655 faces[startSetIndex][noFaces].normal[2] = faces[startSetIndex][otherFace].normal[2];
3656 faces[startSetIndex][noFaces].w = faces[startSetIndex][otherFace].w;
3657
3658 break;
3659 }
3660 }
3661
3662 ASSERT(partnerFound, "");
3663
3664 noFaces++;
3665 }
3666
3667 } // loop though all other sets!
3668
3669 } // if ( noIndividualCuts > 1 )
3670
3671#ifdef CutCell_DEBUG
3672 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
3673 cerr << "Final count: " << faces[startSetIndex].size() << " faces " << edges[startSetIndex].size() << " edges "
3674 << vertices[startSetIndex].size() << " vertices " << endl;
3675 }
3676#endif
3677
3678 // debug check:
3679 // edge and vertex-information should match!
3680 for(MInt faceId = 0; faceId < (signed)faces[startSetIndex].size(); faceId++) {
3681 ASSERT(faces[startSetIndex][faceId].edges.size() == faces[startSetIndex][faceId].vertices.size(), "");
3682 for(MInt edgeId = 0; edgeId < (signed)faces[startSetIndex][faceId].edges.size(); edgeId++) {
3683 const MInt edge = faces[startSetIndex][faceId].edges[edgeId].first;
3684 const MInt newVertexId = faces[startSetIndex][faceId].vertices[edgeId];
3685 const MInt direction = faces[startSetIndex][faceId].edges[edgeId].second;
3686 MInt vertexId = edges[startSetIndex][edge].vertices[0];
3687 if(direction == -1) vertexId = edges[startSetIndex][edge].vertices[1];
3688 ASSERT(newVertexId == vertexId, "");
3689 }
3690 }
3691
3692 RECORD_TIMER_STOP(tCutFace_3b);
3693 RECORD_TIMER_START(tCutFace_4);
3694
3695 // 4. build polyhedron(polyhedra) structure
3696 // use a stack
3697 ASSERT(faceStack.empty(), "");
3698
3699 // add original cell, if zero faces are found
3700 if(faces[startSetIndex].size() == 0) {
3701 cutCells.emplace_back(cellId, &a_coordinate(cellId, 0));
3702 }
3703
3704 // add multiple cutCells if cutCell <= -1
3705 for(MInt faceCounter = 0; (unsigned)faceCounter < faces[startSetIndex].size(); faceCounter++) {
3706 if(faces[startSetIndex][faceCounter].cutCell > -1) continue;
3707 // NOTE: first faces are bodySurfaces, as cartesian surfaces were added afterwards
3708 // don't add lineFaces at the beginning!
3709 if(faces[startSetIndex][faceCounter].isLine) continue;
3710
3711#ifdef CutCell_DEBUG
3712 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
3713 cerr << "faceCounter: " << faceCounter << endl;
3714 }
3715#endif
3716 // adding cutCell
3717 faceStack.push(faceCounter);
3718 const MInt currentCutCell = cutCells.size();
3719 cutCells.emplace_back(cellId, &a_coordinate(cellId, 0));
3720 faces[startSetIndex][faceCounter].cutCell = currentCutCell;
3721 cutCells[currentCutCell].faces.push_back(faceCounter);
3722 // adding all other faces which share an edge to the current cutCell/bodySurface
3723 while(!faceStack.empty()) {
3724 MInt currentFace = faceStack.top();
3725 faceStack.pop();
3726 // find neighboring faces
3727 for(MInt e = 0; (unsigned)e < faces[startSetIndex][currentFace].edges.size(); e++) {
3728 MInt edge = faces[startSetIndex][currentFace].edges[e].first;
3729 MInt otherFace = edges[startSetIndex][edge].face[0];
3730 if(otherFace == currentFace) {
3731 otherFace = edges[startSetIndex][edge].face[1];
3732 }
3733 // if the neighboring face doesn't already belong to a different cutCell
3734 // add it to this one!
3735 if(faces[startSetIndex][otherFace].cutCell == -1) {
3736#ifdef CutCell_DEBUG
3737 if(grid().domainId() == debugDomainId && globalTimeStep == debugTimeStep && cellId == debugCellId) {
3738 cerr << "faceCounter: " << faceCounter << " cutCell " << currentCutCell
3739 << " is adding neighbor: " << otherFace << endl;
3740 }
3741#endif
3742 cutCells[currentCutCell].faces.push_back(otherFace);
3743 faces[startSetIndex][otherFace].cutCell = currentCutCell;
3744 faceStack.push(otherFace);
3745 }
3746 }
3747 }
3748 }
3749 ASSERT(faceStack.empty(), "");
3750
3751 RECORD_TIMER_STOP(tCutFace_4);
3752
3753 // 5. compute polyhedron(polyhedra)
3754 RECORD_TIMER_START(tCutFace_5a);
3755 compVolumeIntegrals_pyraBased3(&cutCells, &faces[startSetIndex], &vertices[startSetIndex]);
3756 RECORD_TIMER_STOP(tCutFace_5a);
3757
3758#ifdef CutCell_DEBUG
3759 if(globalTimeStep == debugTimeStep && cellId == debugCellId && grid().domainId() == debugDomainId) {
3760 writeVTKFileOfCell(cellId, &faces[startSetIndex], &vertices[startSetIndex], -73);
3761 }
3762#endif
3763
3764 if(error) {
3765 cerr << "[" << -1 << "]"
3766 << ": Warning: removal/suppression of doubly touched vertices seems to have failed!" << endl;
3767 writeVTKFileOfCell(cellId, &faces[startSetIndex], &vertices[startSetIndex], -1);
3768 }
3769
3770
3771 RECORD_TIMER_START(tCutFace_5b);
3772
3773 // --------------------------------------------------------------
3774 // --------5) faceJoin
3775 // --------------------------------------------------------------
3776
3777 // NOTE: it is not possible to easyly join all bodySurfaces with the same bodyId!
3778 // as disconnected faces with the same bodyId can occour and must not be joined!
3779 // -> a connective information between bodyFaces through edges is necessary!
3780
3781 // 5.1. if required, join cut surfaces if their normal vectors are similar enough
3782 if(m_bodyFaceJoinMode != 0) { // until line 4577
3783
3784 // set edgeCutCellPointer to -1 for deleted edges
3785 for(MInt e = 0; (unsigned)e < edges[startSetIndex].size(); e++) {
3786 MInt face = edges[startSetIndex][e].face[0];
3787 if(face < 0)
3788 edgeCutCellPointer[e] = -1;
3789 else
3790 edgeCutCellPointer[e] = faces[startSetIndex][face].cutCell;
3791 }
3792 for(MInt f = 0; (unsigned)f < faces[startSetIndex].size(); f++) {
3793 multiFaceConnection[f] = -1;
3794 }
3795 for(MInt c = 0; (unsigned)c < cutCells.size(); c++) {
3796 switch(m_bodyFaceJoinMode) {
3797 case 1: // all connected body faces with the same bodyId are joined
3798 case 3: // only cartesian faces are joined
3799 case 4: // connect body faces with the same bodyId only if the resulting face is not concave
3800 {
3801 list<MInt> bodyVertices;
3802 set<MInt> locBodySrfcs;
3803 ScratchSpace<MInt> isBodyEdge(maxNoVertices, AT_, "isBodyEdge");
3804 isBodyEdge.fill(-2);
3805
3806 // remove douple edges entries in vertices
3807 for(auto& vert : vertices[startSetIndex]) {
3808 sort(vert.edges.begin(), vert.edges.end());
3809 auto last = unique(vert.edges.begin(), vert.edges.end());
3810 vert.edges.erase(last, vert.edges.end());
3811 }
3812
3813 for(MInt e = 0; (unsigned)e < edges[startSetIndex].size(); e++) {
3814 if(edgeCutCellPointer[e] != c) continue;
3815 if(faces[startSetIndex][edges[startSetIndex][e].face[0]].faceType == 0
3816 && faces[startSetIndex][edges[startSetIndex][e].face[1]].faceType == 0) {
3817 if(faces[startSetIndex][edges[startSetIndex][e].face[0]].faceId
3818 == faces[startSetIndex][edges[startSetIndex][e].face[1]].faceId) {
3819 pureBodyEdges.push_back(e);
3820 }
3821 } else if(m_bodyFaceJoinMode == 1 || m_bodyFaceJoinMode == 4) {
3822 if(faces[startSetIndex][edges[startSetIndex][e].face[0]].faceType == 1
3823 && faces[startSetIndex][edges[startSetIndex][e].face[1]].faceType == 1) {
3824 if(faces[startSetIndex][edges[startSetIndex][e].face[0]].bodyId
3825 == faces[startSetIndex][edges[startSetIndex][e].face[1]].bodyId) {
3826 pureBodyEdges.push_back(e);
3827 isBodyEdge(e) = faces[startSetIndex][edges[startSetIndex][e].face[0]].bodyId;
3828 bodyVertices.push_back(edges[startSetIndex][e].vertices[0]);
3829 bodyVertices.push_back(edges[startSetIndex][e].vertices[1]);
3830 locBodySrfcs.insert(faces[startSetIndex][edges[startSetIndex][e].face[0]].bodyId);
3831 } else {
3832 isBodyEdge(e) = -1;
3833 }
3834 }
3835 }
3836 }
3837
3838 if(m_bodyFaceJoinMode == 4 && noIndividualCuts > 1) {
3839 bodyVertices.sort();
3840 bodyVertices.unique();
3841 const MInt noLocBodySrfcs = (signed)locBodySrfcs.size();
3842 MInt concaveCnt = 0;
3843 for(MInt vert : bodyVertices) {
3844 if(vertices[startSetIndex][vert].pointType > 1) {
3845 MInt noOuterEdges = 0;
3846 MInt noBodyEdges = 0;
3847 MInt outerEdges[6] = {-1};
3848 MInt bodyEdges[6] = {-1};
3849 for(MInt edge : vertices[startSetIndex][vert].edges) {
3850 if(isBodyEdge(edge) == -1) {
3851 outerEdges[noOuterEdges] = edge;
3852 noOuterEdges++;
3853 }
3854 if(isBodyEdge(edge) > -1) {
3855 bodyEdges[noBodyEdges] = edge;
3856 noBodyEdges++;
3857 }
3858 }
3859 if(noOuterEdges == 2 && noBodyEdges > 0) {
3860 for(MInt k = 0; k < noBodyEdges; k++) {
3861 MInt edge = bodyEdges[k];
3862 MInt otherVert = (edges[startSetIndex][edge].vertices[0] == vert) ? 1 : 0;
3863 otherVert = edges[startSetIndex][edge].vertices[otherVert];
3864 MInt face0 = edges[startSetIndex][edge].face[0];
3865 MInt face1 = edges[startSetIndex][edge].face[1];
3866
3867 MInt edge0 = -1;
3868 MInt edge1 = -1;
3869 MInt dir0 = -1;
3870 MInt dir1 = -1;
3871 MInt noEdges0 = (signed)faces[startSetIndex][face0].edges.size();
3872 MInt noEdges1 = (signed)faces[startSetIndex][face1].edges.size();
3873 MInt prevEdge = -1;
3874 MInt nextEdge = -1;
3875 MInt side = -1;
3876 for(MInt e = 0; e < noEdges0; e++) {
3877 if(faces[startSetIndex][face0].edges[e].first == edge) {
3878 edge0 = e;
3879 dir0 = faces[startSetIndex][face0].edges[e].second;
3880 if(prevEdge < 0 || nextEdge < 0) {
3881 MInt vA = edges[startSetIndex][edge].vertices[dir0 == 1 ? 1 : 0];
3882 MInt otherEdge = (vA == vert) ? (edge0 + 1) % noEdges0 : (edge0 + noEdges0 - 1) % noEdges0;
3883 otherEdge = faces[startSetIndex][face0].edges[otherEdge].first;
3884 if(otherEdge == outerEdges[0] || otherEdge == outerEdges[1]) {
3885 MInt otherEdge2 = (otherEdge == outerEdges[0]) ? outerEdges[1] : outerEdges[0];
3886 nextEdge = (vA == vert) ? otherEdge : otherEdge2;
3887 prevEdge = (vA == vert) ? otherEdge2 : otherEdge;
3888 side = 0;
3889 }
3890 }
3891 }
3892 }
3893 for(MInt e = 0; e < noEdges1; e++) {
3894 if(faces[startSetIndex][face1].edges[e].first == edge) {
3895 edge1 = e;
3896 dir1 = faces[startSetIndex][face1].edges[e].second;
3897 if(prevEdge < 0 || nextEdge < 0) {
3898 MInt vA = edges[startSetIndex][edge].vertices[dir1 == 1 ? 1 : 0];
3899 MInt otherEdge = (vA == vert) ? (edge1 + 1) % noEdges1 : (edge1 + noEdges1 - 1) % noEdges1;
3900 otherEdge = faces[startSetIndex][face1].edges[otherEdge].first;
3901 if(otherEdge == outerEdges[0] || otherEdge == outerEdges[1]) {
3902 MInt otherEdge2 = (otherEdge == outerEdges[0]) ? outerEdges[1] : outerEdges[0];
3903 nextEdge = (vA == vert) ? otherEdge : otherEdge2;
3904 prevEdge = (vA == vert) ? otherEdge2 : otherEdge;
3905 side = 1;
3906 }
3907 }
3908 }
3909 }
3910 if(edge0 < 0 || edge1 < 0) mTerm(1, AT_, "ERROR: pure body edge not found.");
3911 if(dir0 == dir1) mTerm(1, AT_, "ERROR: pure body edge not found (2).");
3912 if(faces[startSetIndex][face0].edges[edge0].first != edge
3913 || faces[startSetIndex][face1].edges[edge1].first != edge)
3914 mTerm(1, AT_, "ERROR: pure body edge not found (3).");
3915 ASSERT(outerEdges[0] > -1 && outerEdges[1] > -1, "");
3916
3917 if(prevEdge > -1 && nextEdge > -1) {
3918 ASSERT(side > -1, "");
3919 MInt id_p0 = edges[startSetIndex][prevEdge].vertices[0] == vert ? 0 : 1;
3920 MInt id_p1 = edges[startSetIndex][nextEdge].vertices[0] == vert ? 0 : 1;
3921 if(edges[startSetIndex][prevEdge].vertices[id_p0] != vert)
3922 mTerm(1, AT_, "ERROR: pure body edge not found (4).");
3923 if(edges[startSetIndex][nextEdge].vertices[id_p1] != vert)
3924 mTerm(1, AT_, "ERROR: pure body edge not found (5).");
3925 MInt otherId[2] = {1, 0};
3926 MInt vA2 = edges[startSetIndex][prevEdge].vertices[otherId[id_p0]];
3927 MInt vB2 = edges[startSetIndex][prevEdge].vertices[id_p0];
3928 MInt vA = edges[startSetIndex][nextEdge].vertices[id_p1];
3929 MInt vB = edges[startSetIndex][nextEdge].vertices[otherId[id_p1]];
3930
3931 MInt vV = vert;
3932 MInt vO = otherVert;
3933
3934 MFloat abs1 = F0;
3935 MFloat abs2 = F0;
3936 MFloat abs3 = F0;
3937 MFloat dotp = F0;
3938 MFloat dotp2 = F0;
3939 MFloat dotp3 = F0;
3940 MFloat dotp4 = F0;
3941 MFloat vec1[nDim] = {F0, F0, F0};
3942 MFloat vec2[nDim] = {F0, F0, F0};
3943 MFloat vec3[nDim] = {F0, F0, F0};
3944 MFloat ori[nDim] = {F0, F0, F0};
3945 MFloat normal[3] = {F0, F0, F0};
3946 MFloat area0 = faces[startSetIndex][face0].area;
3947 MFloat area1 = faces[startSetIndex][face1].area;
3948 ASSERT(area0 + area1 > F0, "");
3949 for(MInt i = 0; i < nDim; i++) {
3950 normal[i] = (area0 * faces[startSetIndex][face0].normal[i]
3951 + area1 * faces[startSetIndex][face1].normal[i])
3952 / (area0 + area1);
3953 }
3954 for(MInt i = 0; i < nDim; i++) {
3955 MFloat d1 =
3956 vertices[startSetIndex][vB2].coordinates[i] - vertices[startSetIndex][vA2].coordinates[i];
3957 MFloat d2 =
3958 vertices[startSetIndex][vB].coordinates[i] - vertices[startSetIndex][vA].coordinates[i];
3959 MFloat d3 =
3960 vertices[startSetIndex][vO].coordinates[i] - vertices[startSetIndex][vV].coordinates[i];
3961 vec1[i] = d1;
3962 vec2[i] = d2;
3963 vec3[i] = d3;
3964 dotp += d1 * d2;
3965 abs1 += POW2(d1);
3966 abs2 += POW2(d2);
3967 abs3 += POW2(d3);
3968 }
3969 abs1 = sqrt(abs1);
3970 abs2 = sqrt(abs2);
3971 abs3 = sqrt(abs3);
3972 dotp /= (abs1 * abs2);
3973 for(MInt i = 0; i < nDim; i++) {
3974 vec1[i] /= abs1;
3975 vec2[i] /= abs2;
3976 vec3[i] /= abs3;
3977 }
3978 crossProduct(ori, vec1, vec2);
3979 for(MInt i = 0; i < nDim; i++) {
3980 dotp2 += ori[i] * normal[i];
3981 }
3982 crossProduct(ori, vec1, vec3);
3983 for(MInt i = 0; i < nDim; i++) {
3984 dotp3 += ori[i] * normal[i];
3985 }
3986 crossProduct(ori, vec2, vec3);
3987 for(MInt i = 0; i < nDim; i++) {
3988 dotp4 += ori[i] * normal[i];
3989 }
3990
3991 if(dotp2 < -0.1 && fabs(F1 - dotp) > 1e-2
3992 && mMin(area0, area1) > 1e-5 * pow(cellLength0, (MFloat)(nDim - 1))) {
3993 if(noLocBodySrfcs + concaveCnt > maxNoSurfaces) {
3994 cerr << "Warning: removal of concave polygons was skipped, since "
3995 "FvBndryCell<nDim>::m_maxNoSurfaces is not large enough."
3996 << endl;
3997 continue;
3998 }
3999
4000 if(dotp3 > -1e-3 && dotp4 > -1e-3) {
4001 auto it2 = pureBodyEdges.begin();
4002 while(it2 != pureBodyEdges.end()) {
4003 // for( std::list<MInt>::iterator it2 = pureBodyEdges.begin(); it2 !=
4004 // pureBodyEdges.end(); it2++){
4005 MInt bedge = (*it2);
4006 if(edgeCutCellPointer[bedge] != c) {
4007 it2++;
4008 continue;
4009 }
4010 MInt faceA = edges[startSetIndex][bedge].face[0];
4011 MInt faceB = edges[startSetIndex][bedge].face[1];
4012 if((face0 == faceA && face1 == faceB) || (face1 == faceA && face0 == faceB)) {
4013 it2 = pureBodyEdges.erase(it2);
4014 concaveCnt++;
4015 } else {
4016 it2++;
4017 }
4018 }
4019 }
4020 }
4021 }
4022 }
4023 }
4024 }
4025 }
4026 }
4027
4028 multiFaces.clear();
4029
4030 // connect multifaces
4031 MBool somethingChanged = true;
4032 MInt currentMultiFace = 0;
4033 while(!pureBodyEdges.empty()) {
4034 MInt pbedge = pureBodyEdges.front();
4035 pureBodyEdges.pop_front();
4036 multiFaces.emplace_back();
4037 MInt pbface0 = edges[startSetIndex][pbedge].face[0];
4038 multiFaceConnection[pbface0] = currentMultiFace;
4039 multiFaces[currentMultiFace].faces.push_back(pbface0);
4040 multiFaces[currentMultiFace].bodyId = faces[startSetIndex][pbface0].bodyId;
4041 MInt pbface1 = edges[startSetIndex][pbedge].face[1];
4042 multiFaceConnection[pbface1] = currentMultiFace;
4043 multiFaces[currentMultiFace].faces.push_back(pbface1);
4044 for(MInt e = 0; (unsigned)e < faces[startSetIndex][pbface0].edges.size(); e++) {
4045 if(faces[startSetIndex][pbface0].edges[e].first != pbedge) {
4046 multiFaces[currentMultiFace].edges.emplace_back(faces[startSetIndex][pbface0].edges[e].first,
4047 faces[startSetIndex][pbface0].edges[e].second);
4048 } else { // insert edges of other face
4049 // find index of pbedge in face1
4050 MInt edgeIndex = 0;
4051 for(MInt ee = 0; (unsigned)ee < faces[startSetIndex][pbface1].edges.size(); ee++) {
4052 if(faces[startSetIndex][pbface1].edges[ee].first == pbedge) {
4053 edgeIndex = ee;
4054 break;
4055 }
4056 }
4057 for(MInt ee = 1; (unsigned)ee < faces[startSetIndex][pbface1].edges.size(); ee++) {
4058 MInt eee = (edgeIndex + ee) % faces[startSetIndex][pbface1].edges.size();
4059 multiFaces[currentMultiFace].edges.emplace_back(faces[startSetIndex][pbface1].edges[eee].first,
4060 faces[startSetIndex][pbface1].edges[eee].second);
4061 }
4062 }
4063 }
4064 somethingChanged = true;
4065
4066 while(somethingChanged) {
4067 somethingChanged = false;
4068 auto it = pureBodyEdges.begin();
4069 while(it != pureBodyEdges.end()) {
4070 // for( std::list<MInt>::iterator it=pureBodyEdges.begin();it != pureBodyEdges.end(); it++){
4071 MInt edge = (*it);
4072 if(edgeCutCellPointer[edge] != c) {
4073 it++;
4074 continue;
4075 }
4076 MInt face0 = edges[startSetIndex][edge].face[0];
4077 MInt face1 = edges[startSetIndex][edge].face[1];
4078 if(multiFaceConnection[face0] == currentMultiFace && multiFaceConnection[face1] == currentMultiFace) {
4079 it = pureBodyEdges.erase(it);
4080 } else {
4081 if(multiFaceConnection[face0] == currentMultiFace) {
4082 multiFaceConnection[face1] = currentMultiFace;
4083 it = pureBodyEdges.erase(it);
4084 multiFaces[currentMultiFace].faces.push_back(face1);
4085 auto it2 = multiFaces[currentMultiFace].edges.begin();
4086 for(it2 = multiFaces[currentMultiFace].edges.begin();
4087 it2 != multiFaces[currentMultiFace].edges.end();
4088 it2++) {
4089 MInt edge2 = (*it2).first;
4090 if(edge2 == edge) {
4091 break;
4092 }
4093 } // delete edge, insert edges of other face
4094 // find corresponding edgeIndex of new face
4095 MInt edgeIndex = 0;
4096 for(MInt e = 0; (unsigned)e < faces[startSetIndex][face1].edges.size(); e++) {
4097 if(faces[startSetIndex][face1].edges[e].first == edge) {
4098 edgeIndex = e;
4099 break;
4100 }
4101 }
4102 for(MInt e = 1; (unsigned)e < faces[startSetIndex][face1].edges.size(); e++) {
4103 MInt ee = (edgeIndex + e) % faces[startSetIndex][face1].edges.size();
4104 multiFaces[currentMultiFace].edges.insert(
4105 it2, make_pair(faces[startSetIndex][face1].edges[ee].first,
4106 faces[startSetIndex][face1].edges[ee].second));
4107 }
4108 multiFaces[currentMultiFace].edges.erase(it2);
4109 somethingChanged = true;
4110 } else if(multiFaceConnection[face1] == currentMultiFace) {
4111 multiFaceConnection[face0] = currentMultiFace;
4112 it = pureBodyEdges.erase(it);
4113 multiFaces[currentMultiFace].faces.push_back(face0);
4114 auto it2 = multiFaces[currentMultiFace].edges.begin();
4115 for(it2 = multiFaces[currentMultiFace].edges.begin();
4116 it2 != multiFaces[currentMultiFace].edges.end();
4117 it2++) {
4118 MInt edge2 = (*it2).first;
4119 if(edge2 == edge) {
4120 break;
4121 }
4122 } // delete edge, insert edges of other face
4123 // find corresponding edgeIndex of new face
4124 MInt edgeIndex = 0;
4125 for(MInt e = 0; (unsigned)e < faces[startSetIndex][face0].edges.size(); e++) {
4126 if(faces[startSetIndex][face0].edges[e].first == edge) {
4127 edgeIndex = e;
4128 break;
4129 }
4130 }
4131 for(MInt e = 1; (unsigned)e < faces[startSetIndex][face0].edges.size(); e++) {
4132 MInt ee = (edgeIndex + e) % faces[startSetIndex][face0].edges.size();
4133 multiFaces[currentMultiFace].edges.insert(
4134 it2, make_pair(faces[startSetIndex][face0].edges[ee].first,
4135 faces[startSetIndex][face0].edges[ee].second));
4136 }
4137 multiFaces[currentMultiFace].edges.erase(it2);
4138 somethingChanged = true;
4139 } else {
4140 it++;
4141 }
4142 }
4143 }
4144 }
4145 currentMultiFace++;
4146 }
4147 } break;
4148 case 2: // body faces are only joined when their normal vectors are similar
4149 {
4150 for(MInt e = 0; (unsigned)e < edges[startSetIndex].size(); e++) {
4151 if(edgeCutCellPointer[e] != c) continue;
4152 if(faces[startSetIndex][edges[startSetIndex][e].face[0]].faceType == 1
4153 && faces[startSetIndex][edges[startSetIndex][e].face[1]].faceType == 1) {
4154 if(faces[startSetIndex][edges[startSetIndex][e].face[0]].bodyId
4155 == faces[startSetIndex][edges[startSetIndex][e].face[1]].bodyId) {
4156 pureBodyEdges.push_back(e);
4157 }
4158 } else if(faces[startSetIndex][edges[startSetIndex][e].face[0]].faceType == 0
4159 && faces[startSetIndex][edges[startSetIndex][e].face[1]].faceType == 0) {
4160 if(faces[startSetIndex][edges[startSetIndex][e].face[0]].faceId
4161 == faces[startSetIndex][edges[startSetIndex][e].face[1]].faceId) {
4162 pureBodyEdges.push_back(e);
4163 }
4164 }
4165 }
4166
4167 const MInt faceNum = faces[startSetIndex].size();
4168 ASSERT(faceNum <= maxNoFaces, "");
4169 for(MInt i = 0; i < faceNum; i++)
4170 for(MInt j = 0; j < faceNum; j++)
4171 normalDotProduct(i, j) = F0;
4172 MInt noBodyFaces = 0;
4173 for(MInt f = 0; (unsigned)f < cutCells[c].faces.size(); f++) {
4174 MInt face = cutCells[c].faces[f];
4175 if(faces[startSetIndex][face].faceType == 1) bodyFaces[noBodyFaces++] = face;
4176 }
4177 for(MInt f = 0; f < noBodyFaces; f++) {
4178 MInt face1 = bodyFaces[f];
4179 for(MInt ff = 0; ff <= f; ff++) {
4180 MInt face2 = bodyFaces[ff];
4181 for(MInt i = 0; i < nDim; i++)
4182 normalDotProduct(face1, face2) +=
4183 faces[startSetIndex][face1].normal[i] * faces[startSetIndex][face2].normal[i];
4184 normalDotProduct(face1, face2) = F1 - normalDotProduct(face1, face2);
4185 normalDotProduct(face2, face1) = normalDotProduct(face1, face2);
4186 }
4187 }
4188
4189 multiFaces.clear();
4190
4191 // connect multifaces
4192 MBool somethingChanged = true;
4193 MInt currentMultiFace = 0;
4194 while(!pureBodyEdges.empty()) {
4195 MInt pbedge = pureBodyEdges.front();
4196 pureBodyEdges.pop_front();
4197 MInt pbface0 = edges[startSetIndex][pbedge].face[0];
4198 MInt pbface1 = edges[startSetIndex][pbedge].face[1];
4199 if(normalDotProduct(pbface0, pbface1) > m_bodyFaceJoinCriterion) continue;
4200 multiFaces.emplace_back();
4201 multiFaceConnection[pbface0] = currentMultiFace;
4202 multiFaces[currentMultiFace].faces.push_back(pbface0);
4203 multiFaces[currentMultiFace].bodyId = faces[startSetIndex][pbface0].bodyId;
4204 multiFaceConnection[pbface1] = currentMultiFace;
4205 multiFaces[currentMultiFace].faces.push_back(pbface1);
4206 for(MInt e = 0; (unsigned)e < faces[startSetIndex][pbface0].edges.size(); e++) {
4207 if(faces[startSetIndex][pbface0].edges[e].first != pbedge) {
4208 multiFaces[currentMultiFace].edges.emplace_back(faces[startSetIndex][pbface0].edges[e].first,
4209 faces[startSetIndex][pbface0].edges[e].second);
4210 } else { // insert edges of other face
4211 // find index of pbedge in face1
4212 MInt edgeIndex = 0;
4213 for(MInt ee = 0; (unsigned)ee < faces[startSetIndex][pbface1].edges.size(); ee++) {
4214 if(faces[startSetIndex][pbface1].edges[ee].first == pbedge) {
4215 edgeIndex = ee;
4216 break;
4217 }
4218 }
4219 for(MInt ee = 1; (unsigned)ee < faces[startSetIndex][pbface1].edges.size(); ee++) {
4220 MInt eee = (edgeIndex + ee) % faces[startSetIndex][pbface1].edges.size();
4221 multiFaces[currentMultiFace].edges.emplace_back(faces[startSetIndex][pbface1].edges[eee].first,
4222 faces[startSetIndex][pbface1].edges[eee].second);
4223 }
4224 }
4225 }
4226 somethingChanged = true;
4227
4228 while(somethingChanged) {
4229 somethingChanged = false;
4230 auto it = pureBodyEdges.begin();
4231 while(it != pureBodyEdges.end()) {
4232 // for( std::list<MInt>::iterator it=pureBodyEdges.begin();it != pureBodyEdges.end(); it++){
4233 MInt edge = (*it);
4234 if(edgeCutCellPointer[edge] != c) {
4235 it++;
4236 continue;
4237 }
4238 MInt face0 = edges[startSetIndex][edge].face[0];
4239 MInt face1 = edges[startSetIndex][edge].face[1];
4240 if(multiFaceConnection[face0] == currentMultiFace && multiFaceConnection[face1] == currentMultiFace) {
4241 it = pureBodyEdges.erase(it);
4242 } else if(multiFaceConnection[face0] == currentMultiFace) {
4243 it = pureBodyEdges.erase(it);
4244 MBool mayBeConnected = true;
4245 for(MInt nf = 0; (unsigned)nf < multiFaces[currentMultiFace].faces.size(); nf++) {
4246 MInt nFace = multiFaces[currentMultiFace].faces[nf];
4247 if(normalDotProduct(face1, nFace) > m_bodyFaceJoinCriterion) {
4248 mayBeConnected = false;
4249 break;
4250 }
4251 }
4252 if(!mayBeConnected) continue;
4253 multiFaceConnection[face1] = currentMultiFace;
4254 multiFaces[currentMultiFace].faces.push_back(face1);
4255 auto it2 = multiFaces[currentMultiFace].edges.begin();
4256 for(it2 = multiFaces[currentMultiFace].edges.begin();
4257 it2 != multiFaces[currentMultiFace].edges.end();
4258 it2++) {
4259 MInt edge2 = (*it2).first;
4260 if(edge2 == edge) {
4261 break;
4262 }
4263 } // delete edge, insert edges of other face
4264 // find corresponding edgeIndex of new face
4265 MInt edgeIndex = 0;
4266 for(MInt e = 0; (unsigned)e < faces[startSetIndex][face1].edges.size(); e++) {
4267 if(faces[startSetIndex][face1].edges[e].first == edge) {
4268 edgeIndex = e;
4269 break;
4270 }
4271 }
4272 for(MInt e = 1; (unsigned)e < faces[startSetIndex][face1].edges.size(); e++) {
4273 MInt ee = (edgeIndex + e) % faces[startSetIndex][face1].edges.size();
4274 multiFaces[currentMultiFace].edges.insert(
4275 it2, make_pair(faces[startSetIndex][face1].edges[ee].first,
4276 faces[startSetIndex][face1].edges[ee].second));
4277 }
4278 multiFaces[currentMultiFace].edges.erase(it2);
4279 somethingChanged = true;
4280 } else if(multiFaceConnection[face1] == currentMultiFace) {
4281 it = pureBodyEdges.erase(it);
4282 MBool mayBeConnected = true;
4283 for(MInt nf = 0; (unsigned)nf < multiFaces[currentMultiFace].faces.size(); nf++) {
4284 MInt nFace = multiFaces[currentMultiFace].faces[nf];
4285 if(normalDotProduct(face0, nFace) > m_bodyFaceJoinCriterion) {
4286 mayBeConnected = false;
4287 break;
4288 }
4289 }
4290 if(!mayBeConnected) continue;
4291 multiFaceConnection[face0] = currentMultiFace;
4292 multiFaces[currentMultiFace].faces.push_back(face0);
4293 auto it2 = multiFaces[currentMultiFace].edges.begin();
4294 for(it2 = multiFaces[currentMultiFace].edges.begin();
4295 it2 != multiFaces[currentMultiFace].edges.end();
4296 it2++) {
4297 MInt edge2 = (*it2).first;
4298 if(edge2 == edge) {
4299 break;
4300 }
4301 } // delete edge, insert edges of other face
4302 // find corresponding edgeIndex of new face
4303 MInt edgeIndex = 0;
4304 for(MInt e = 0; (unsigned)e < faces[startSetIndex][face0].edges.size(); e++) {
4305 if(faces[startSetIndex][face0].edges[e].first == edge) {
4306 edgeIndex = e;
4307 break;
4308 }
4309 }
4310 for(MInt e = 1; (unsigned)e < faces[startSetIndex][face0].edges.size(); e++) {
4311 MInt ee = (edgeIndex + e) % faces[startSetIndex][face0].edges.size();
4312 multiFaces[currentMultiFace].edges.insert(
4313 it2, make_pair(faces[startSetIndex][face0].edges[ee].first,
4314 faces[startSetIndex][face0].edges[ee].second));
4315 }
4316 multiFaces[currentMultiFace].edges.erase(it2);
4317 somethingChanged = true;
4318 } else {
4319 it++;
4320 }
4321 }
4322 }
4323 currentMultiFace++;
4324 }
4325 } break;
4326
4327 default:
4328 mTerm(1, AT_, "ERROR: invalid bodyFaceJoinMode specified. exiting...");
4329 break;
4330 }
4331
4332 // join faces that belong to a multi face -> compute multi face parameters
4333 for(MInt mf = 0; (unsigned)mf < multiFaces.size(); mf++) {
4334 MFloat normal[3] = {F0, F0, F0};
4335 MFloat center[3] = {F0, F0, F0};
4336 MFloat area2 = F0;
4337 for(MInt f = 0; (unsigned)f < multiFaces[mf].faces.size(); f++) {
4338 const MInt face = multiFaces[mf].faces[f];
4339 MFloat faceArea = faces[startSetIndex][face].area;
4340 // changes due to faces with zero area, which become part of a multiface
4341 if(faceArea < m_eps) {
4342 faceArea = m_eps;
4343 }
4344 area2 += faceArea;
4345 for(MInt i = 0; i < nDim; i++) {
4346 normal[i] += faces[startSetIndex][face].normal[i] * faceArea;
4347 center[i] += faces[startSetIndex][face].center[i] * faceArea;
4348 }
4349 }
4350 MFloat absNorm = F0;
4351 for(MInt i = 0; i < nDim; i++) {
4352 absNorm += normal[i] * normal[i];
4353 }
4354 absNorm = sqrt(absNorm);
4355 for(MInt i = 0; i < nDim; i++) {
4356 multiFaces[mf].center[i] = center[i] / area2;
4357 ASSERT(!std::isnan(multiFaces[mf].center[i]), "");
4358 multiFaces[mf].normal[i] = normal[i] / absNorm;
4359 ASSERT(!std::isnan(multiFaces[mf].normal[i]), "");
4360 }
4361 multiFaces[mf].area = absNorm;
4362 }
4363
4364 // recompute edges that belong to a multi face
4365 if(!multiFaces.empty()) {
4366 // remove all cutCell faces and only keep those without multiFaceConnection!
4367 MInt noFaces = 0;
4368 for(MInt f = 0; (unsigned)f < cutCells[c].faces.size(); f++) {
4369 MInt face = cutCells[c].faces[f];
4370 if(multiFaceConnection[face] == -1) tmp_faces[noFaces++] = cutCells[c].faces[f];
4371 }
4372 cutCells[c].faces.clear();
4373 for(MInt f = 0; f < noFaces; f++) {
4374 cutCells[c].faces.push_back(tmp_faces[f]);
4375 }
4376 }
4377
4378 // add multifaces to the face-collector
4379 for(MInt mf = 0; (unsigned)mf < multiFaces.size(); mf++) {
4380 // add a new face to faces collector
4381 // copy properties from the multiface collector
4382 const MInt newFace = faces[startSetIndex].size();
4383 const MInt faceId = faces[startSetIndex][multiFaces[mf].faces[0]].faceId;
4384 const MInt faceType = faces[startSetIndex][multiFaces[mf].faces[0]].faceType;
4385 const MInt bodyId = faces[startSetIndex][multiFaces[mf].faces[0]].bodyId;
4386
4387 faces[startSetIndex].emplace_back(faceId, faceType, bodyId);
4388 faces[startSetIndex][newFace].area = multiFaces[mf].area;
4389 for(MInt i = 0; i < nDim; i++) {
4390 faces[startSetIndex][newFace].center[i] = multiFaces[mf].center[i];
4391 faces[startSetIndex][newFace].normal[i] = multiFaces[mf].normal[i];
4392 }
4393 faces[startSetIndex][newFace].w = F0;
4394 faces[startSetIndex][newFace].cutCell = c;
4395
4396
4397 // preprocess edges: remove double entries:
4398 MBool somethingChanged = true;
4399 while(somethingChanged) {
4400 somethingChanged = false;
4401 // for( std::list<pair<MInt,MInt> >::iterator it=multiFaces[mf].edges.begin(); it !=
4402 // multiFaces[mf].edges.end(); it++){
4403 auto it = multiFaces[mf].edges.begin();
4404 while(it != multiFaces[mf].edges.end()) {
4405 auto itLast = multiFaces[mf].edges.end();
4406 if(it == multiFaces[mf].edges.begin()) {
4407 itLast = multiFaces[mf].edges.end();
4408 } else {
4409 itLast = it;
4410 }
4411 itLast--;
4412 ASSERT(itLast != it, "");
4413 if((it->first == itLast->first) && (it->second == -(itLast->second))) {
4414 multiFaces[mf].edges.erase(itLast);
4415 it = multiFaces[mf].edges.erase(it);
4416 somethingChanged = true;
4417 // it--;
4418 } else {
4419 it++;
4420 }
4421 }
4422 }
4423
4424
4425 for(auto& edge : multiFaces[mf].edges) {
4426 faces[startSetIndex][newFace].edges.emplace_back(edge.first, edge.second);
4427 MInt vertexId = edges[startSetIndex][edge.first].vertices[0];
4428 if(edge.second == -1) vertexId = edges[startSetIndex][edge.first].vertices[1];
4429 faces[startSetIndex][newFace].vertices.push_back(vertexId);
4430 }
4431 cutCells[c].faces.push_back(newFace);
4432 }
4433 }
4434 }
4435 RECORD_TIMER_STOP(tCutFace_5b);
4436
4437
4438 //---------------------------------------------------------------
4439 //---------- MULTI-CUT-CELL GENERATION FINISHED -----------------
4440 //---------------------------------------------------------------
4441
4442 // Euler's polyhedral formula check:
4443 // check the correct count of vertices, edges and faces for each splitCell!
4444 for(MInt sc = 0; sc < (MInt)cutCells.size(); sc++) {
4445 if(!cutCells[sc].faces.empty()) {
4446 MUint noEdges = 0;
4447 MInt pcnt = 0;
4448 MInt vertexRemap[maxNoVertices];
4449 fill_n(vertexRemap, maxNoVertices, -1);
4450 for(MInt f = 0; (unsigned)f < cutCells[sc].faces.size(); f++) {
4451 MInt face = cutCells[sc].faces[f];
4452 noEdges += faces[startSetIndex][face].vertices.size();
4453 for(MInt e = 0; (unsigned)e < faces[startSetIndex][face].vertices.size(); e++) {
4454 const MInt vertex = faces[startSetIndex][face].vertices[e];
4455 if(vertexRemap[vertex] < 0) {
4456 vertexRemap[vertex] = pcnt;
4457 pcnt++;
4458 }
4459 }
4460 }
4461 // edges are counted twice (once for each face) => noEdges / 2!
4462 if(pcnt + cutCells[sc].faces.size() != 2 + noEdges / 2 || noEdges % 2 == 1) {
4463 cerr << grid().domainId() << "Euler's polyhedral formula (1) not fulfilled ("
4464 << pcnt + (signed)cutCells[sc].faces.size() - 2 - noEdges / 2 << ") " << pcnt << " "
4465 << cutCells[sc].faces.size() << " " << noEdges / 2 << " " << noEdges << " for cell " << cellId << " "
4466 << globalTimeStep << " " << faces[startSetIndex].size() << " " << cutCells.size() << " "
4467 << grid().tree().globalId(cellId) << " " << sc << endl;
4468 writeVTKFileOfCell(cellId, &faces[startSetIndex], &vertices[startSetIndex], -1);
4469
4470 if(sc >= 1) {
4471 cerr << "Deleting splitchilds " << endl;
4472 cutCells.erase(cutCells.begin() + sc);
4473 }
4474 }
4475 }
4476 }
4477 // --------------------------------------------------------------
4478 // --------6) fill cutCellData-structure
4479 // --------------------------------------------------------------
4480
4481 // each Cell, which is cut by at least one boundary has one cutCell
4482 // only splitCells have multiple cutCells!
4483 // these are cells where the remaining fluid volume is not connected!
4484
4485 // 6. relate polyhedron(polyhedra) quantities to Cartesian cell quantities -> finish cell
4486 // 6.0. Split cells and split Cartesian need extra treatment -> check here!
4487 MInt splitCellId = -1;
4488 MInt noSplitChildren = cutCells.size();
4489 if(noSplitChildren > CC::maxSplitCells) {
4490 mTerm(1, AT_, "Too many split cells generated, see CutCell::maxSplitCells");
4491 }
4492 cutCellData[cutc].noSplitChilds = 0;
4493
4494
4495 if(noSplitChildren > 1) {
4496 // --------6.0.1) add splitChildren to the cutCellData-structure
4497 // prepare split parent and split children:
4498
4499
4500 for(MInt sc = 0; sc < noSplitChildren; sc++) {
4501 MUint splitcutc = cutCellData.size();
4502 cutCellData[cutc].splitChildIds[cutCellData[cutc].noSplitChilds++] = splitcutc;
4503 cutCellData.emplace_back();
4504 // MInt splitChildId = m_splitChilds[ splitCellId ][sc];
4505 // cutCellData[splitcutc].cellId = splitChildId;
4506 cutCellData[splitcutc].cellId = -1;
4507 // cutCellData[splitcutc].cutCellId = m_bndryCellIds->a[splitChildId];
4508 // cutCellData[splitcutc].cutCellId = -1;
4509 cutCellData[splitcutc].splitParentId = cutc;
4510 }
4511
4512
4513 //--RELOC1--
4514 /*
4515 for( MInt f = 0; f < m_noDirs; f++ ){
4516 bndryCell->m_associatedSrfc[f] = -2;
4517 // if cell has existing surfaces, they should not point to this cell anymore. Will be corrected later
4518 // if other neighbor of surface is already non-existent, delete the surface
4519 MInt srfcId = m_cellSurfaceMapping[ cellId ][ f ];
4520 if ( srfcId > -1 ) {
4521 MInt nghbr0 = m_surfaces->a[srfcId].m_nghbrCellIds[0];
4522 MInt nghbr1 = m_surfaces->a[srfcId].m_nghbrCellIds[1];
4523 if( nghbr0 == cellId ){
4524 m_surfaces->a[srfcId].m_nghbrCellIds[0] = -2;
4525 nghbr0 = -2;
4526 }else if(nghbr1 == cellId ){
4527 m_surfaces->a[srfcId].m_nghbrCellIds[1] = -2;
4528 nghbr1 = -2;
4529 }
4530 if( nghbr0 < 0 && nghbr1 < 0 ){
4531 m_surfaces->a[ srfcId ].m_area[0] = F0;
4532 m_isActiveSurface[ srfcId ] = false;
4533 deleteSurface( srfcId );
4534 }
4535 m_cellSurfaceMapping[ cellId ][ f ] = -2;
4536 }
4537 }*/
4538 }
4539 // splitCellIds(bndryId) = splitCellId;
4540 ASSERT(cutCellData[cutc].noSplitChilds == 0 || cutCellData[cutc].noSplitChilds > 1, "");
4541
4542 if(noSplitChildren > 1) {
4543 for(MInt sc = 0; sc < noSplitChildren; sc++) {
4544 splitCellList[sc] = cutCellData[cutc].splitChildIds[sc];
4545 }
4546 } else {
4547 splitCellList[0] = cutc;
4548 }
4549
4550 // bndryCell->m_volume = F0;
4551
4552 MInt noFacesPerCartesianFaceAll[6] = {0, 0, 0, 0, 0, 0};
4553 MInt noBodySurfacesAll = 0;
4554
4555 // --------6.0.2) Loop over all CutCells
4556
4557 for(MInt sc = 0; sc < noSplitChildren; sc++) {
4558 RECORD_TIMER_START(tCutFace_6);
4559
4560 // MInt splitChildId = cellId;
4561 // MInt scBndryId = bndryId;
4562 // FvBndryCell<nDim>* scBndryCell = &m_fvBndryCnd->m_bndryCells->a[scBndryId];
4563 // if( splitCellId > -1 ){
4564 // splitChildId =m_splitChilds[splitCellId][sc];
4565 // scBndryId = m_bndryCellIds->a[splitChildId];
4566 // scBndryCell = &m_fvBndryCnd->m_bndryCells->a[scBndryId];
4567 // }
4568 // ASSERT(scBndryId > -1 , " ");
4569
4570 MInt cutCellId = splitCellList[sc];
4571
4572 // if cell is a split child, set m_pointIsInside information correctly (needed for vtu output)
4573 // if( a_hasProperty(splitChildId, Cell::IsSplitChild) ){
4574
4575 // --------6.0.3) set m_pointIsInside information correctly for splitChilds
4576 if(cutCellData[cutCellId].splitParentId > -1) {
4577 for(MInt corner = 0; corner < m_noCorners; corner++) {
4578 cutCellData[cutCellId].cornerIsInsideGeometry[0][corner] = true;
4579 }
4580 for(MInt f = 0; (unsigned)f < cutCells[sc].faces.size(); f++) {
4581 MInt face = cutCells[sc].faces[f];
4582 for(MInt e = 0; (unsigned)e < faces[startSetIndex][face].vertices.size(); e++) {
4583 const MInt vStart = faces[startSetIndex][face].vertices[e];
4584 if(vertices[startSetIndex][vStart].pointType == 0) {
4585 MInt corner = vertices[startSetIndex][vStart].pointId;
4586 cutCellData[cutCellId].cornerIsInsideGeometry[0][corner] = false;
4587 }
4588 }
4589 }
4590 }
4591
4592 // --------6.0.4) count noFacesPerCartesianFace and noBodySurfaces
4593 // for each cutCell and for the combined splitParent
4594
4595 MInt noFacesPerCartesianFace[6] = {0, 0, 0, 0, 0, 0};
4596 MInt noBodySurfaces = 0;
4597 for(MInt f = 0; (unsigned)f < cutCells[sc].faces.size(); f++) {
4598 MInt face = cutCells[sc].faces[f];
4599 if(faces[startSetIndex][face].faceType == 0) {
4600 noFacesPerCartesianFace[faces[startSetIndex][face].faceId]++;
4601 noFacesPerCartesianFaceAll[faces[startSetIndex][face].faceId]++;
4602 } else {
4603 noBodySurfaces++;
4604 noBodySurfacesAll++;
4605 }
4606 }
4607 // for(MInt i : noFacesPerCartesianFace){
4608 // if( i > 1 ){
4609
4610 //--RELOC2--
4611 /*
4612 a_hasProperty( cellId , Cell::HasSplitFace ) = true;
4613 // prepare cell/surfaces
4614 MInt id = splitFaceCellIds[scBndryId];
4615 if( id < 0){
4616 id = splitFaceCells.size();
4617 splitFaceCells.push_back(cellWithSplitFace(splitChildId));
4618 splitFaceCellIds[scBndryId] = id;
4619 }
4620 cellWithSplitFace* scsCell = &splitFaceCells[id];
4621 scsCell->splitFaces.push_back(splitCartesianFace(i));
4622 bndryCell->m_associatedSrfc[i] = -2;
4623 // if cell has existing surfaces, they should not point to this cell anymore. Will be corrected later
4624 // if other neighbor of surface is already non-existent, delete the surface
4625 MInt srfcId = m_cellSurfaceMapping[ splitChildId ][ i ];
4626 if ( srfcId > -1 ) {
4627 MInt nghbr0 = m_surfaces->a[srfcId].m_nghbrCellIds[0];
4628 MInt nghbr1 = m_surfaces->a[srfcId].m_nghbrCellIds[1];
4629 if( nghbr0 == splitChildId ){
4630 m_surfaces->a[srfcId].m_nghbrCellIds[0] = -2;
4631 nghbr0 = -2;
4632 }else if(nghbr1 == splitChildId ){
4633 m_surfaces->a[srfcId].m_nghbrCellIds[1] = -2;
4634 nghbr1 = -2;
4635 }
4636 if( nghbr0 < 0 && nghbr1 < 0 ){
4637 m_surfaces->a[ srfcId ].m_area[0] = F0;
4638 m_isActiveSurface[ srfcId ] = false;
4639 deleteSurface( srfcId );
4640 }
4641 m_cellSurfaceMapping[ splitChildId ][ i ] = -2;
4642 }
4643 */
4644 // }
4645 // }
4646
4647 if(noBodySurfaces > maxNoSurfaces || noBodySurfaces > CC::maxNoBoundarySurfaces) {
4648 cerr << "more than FvBndryCell<nDim>::m_maxNoSurfaces cut surfaces detected for a cell. This is not "
4649 "implemented in MB framework yet. cell "
4650 << cellId << " " << grid().domainId() << " " << globalTimeStep << ", splitChild " << sc << " "
4651 << noBodySurfaces << " maximum " << maxNoSurfaces << " " << CC::maxNoBoundarySurfaces << " "
4652 << noSplitChildren << " " << faces[startSetIndex].size() << endl;
4653 writeVTKFileOfCell(cellId, &faces[startSetIndex], &vertices[startSetIndex], startSetIndex);
4654 mTerm(1, AT_,
4655 " more than 3 cut surfaces detected for a cell. This is not implemented in MB framework yet. "
4656 "exiting...");
4657 }
4658
4659 // --------6.0.5) initialise & limit volume
4660
4661 // 6.1. set bndry cell and surface properties
4662 // deactivate cells with no faces
4663 //--RELOC-3A--
4664 if(cutCells[sc].faces.empty()) {
4665 // m_cellIsInactive[ splitChildId ] = true;
4666 // a_hasProperty(splitChildId, Cell::IsOnCurrentMGLevel) = false;
4667 // cutCells[sc].volume = F0;
4668 // cutCells[sc].center[0] = a_coordinate(cellId, 0);
4669 // cutCells[sc].center[1] = a_coordinate(cellId, 1);
4670 // cutCells[sc].center[2] = a_coordinate(cellId, 2);
4671
4672 cutCellData[cutCellId].volume = F0;
4673
4674 // removeSurfaces(splitChildId);
4675 }
4676 if(cutCells[sc].volume > a_gridCellVolume(cutCellId)) {
4677 cutCells[sc].volume = a_gridCellVolume(cutCellId);
4678 }
4679
4680 // --------6.0.5) set externalFaces-Bool
4681
4682 // non fluid sides:
4683 for(MInt f = 0; f < m_noDirs; f++) {
4684 if(noFacesPerCartesianFace[f] == 0) { // non fluid face
4685 // scBndryCell->m_externalFaces[f] = true;
4686 cutCellData[cutCellId].externalFaces[f] = true;
4687
4688 //--RELOC3--
4689
4690 if(splitCellId < 0) {
4691 /*
4692 MInt srfcId = m_cellSurfaceMapping[ cellId ][ f ];
4693 if ( srfcId > -1 ) {
4694 m_surfaces->a[ srfcId ].m_area[0] = F0;
4695 m_isActiveSurface[ srfcId ] = false;
4696 deleteSurface( srfcId );
4697 }
4698 */
4699 // bndryCell->m_associatedSrfc[ f ] = -1;
4700 // m_cutFaceArea[ bndryId ][ f ] = F0;
4701 // cutCellData[cutc].cartFaceArea[ f ] = F0;
4702 /*
4703 MInt nghbrId = a_neighborId( cellId , f );
4704 MInt nghbrBndryId = -1;
4705 if( nghbrId > -1 )
4706 nghbrBndryId = m_bndryCellIds->a[ nghbrId ];
4707 if ( nghbrBndryId > -1 ) {
4708 m_bndryCells->a[ nghbrBndryId ].m_associatedSrfc[ m_revDir[f] ] = -1;
4709 m_cutFaceArea[ nghbrBndryId ][ m_revDir[f] ] = F0;
4710 }*/
4711
4712 /*
4713 // MInt cutNghbr = cutCellData[cutc].cutNghbrIds[f];
4714 // if ( cutNghbr > -1 ) {
4715 // if ( cutCellData[ cutNghbr ].cutNghbrIds[ m_revDir[f] ] != (signed)cutc ) {
4716 // cerr << cellId << " " << bndryId << " " << cutNghbr << " " << cutc << " " <<
4717 m_bndryCellIds->a[ a_neighborId(cellId, f) ] << endl;
4718 // mTerm(1,AT_,"Wrong cut cell neighbor.");
4719 // }
4720 // // cutCellData[cutNghbr].cartFaceArea[ m_revDir[f] ] = F0;
4721 // }
4722 */
4723 }
4724 }
4725 }
4726
4727 // --------6.1) before reassigning cutCell-structure, copy the relevant information
4728 // into the cutCellData-structure
4729
4730 ASSERT(vertices[startSetIndex].size() <= (unsigned)maxNoVertices, "");
4731 for(MInt cp = 0; cp < maxNoVertices; cp++)
4732 newCutPointId[cp] = -1;
4733 for(MInt i = 0; (unsigned)i < vertices[startSetIndex].size(); i++)
4734 isPartOfBodySurface[i] = false;
4735 for(MInt e = 0; e < 2 * m_noEdges; e++) {
4736 // pointEdgeId[e] = bndryCell->m_srfcs[0]->m_cutEdge[e];
4737 pointEdgeId[e] = cutCellData[cutc].cutEdges[e];
4738 }
4739 noBodySurfaces = 0;
4740
4741 ASSERT(cutCells[sc].volume >= F0, "");
4742 ASSERT(!(std::isnan(cutCells[sc].volume)), "");
4743 ASSERT(!(std::isnan(cutCells[sc].center[sc])), "");
4744 ASSERT(!(std::isnan(cutCells[sc].center[1])), "");
4745 ASSERT(!(std::isnan(cutCells[sc].center[2])), "");
4746 ASSERT(!(std::isinf(cutCells[sc].volume)), "");
4747 ASSERT(!(std::isinf(cutCells[sc].center[sc])), "");
4748 ASSERT(!(std::isinf(cutCells[sc].center[1])), "");
4749 ASSERT(!(std::isinf(cutCells[sc].center[2])), "");
4750
4751 // scBndryCell->m_volume = cutCells[sc].volume;
4752 cutCellData[cutCellId].volume = cutCells[sc].volume;
4753
4754 // if ( a_hasProperty(cellId, Cell::IsSplitCell) ) {
4755 // ASSERT( a_hasProperty(splitChildId, Cell::IsSplitChild ), "" );
4756 // bndryCell->m_volume += scBndryCell->m_volume;
4757 // }
4758 for(MInt i = 0; i < nDim; i++) {
4759 // scBndryCell->m_coordinates[i] = cutCells[sc].center[i] - a_coordinate( cellId , i );
4760 cutCellData[cutCellId].volumetricCentroid[i] = cutCells[sc].center[i] - a_coordinate(cellId, i);
4761 }
4762
4763 // cutCellData[cutCellId].noCutPoints = 0;
4764 cutCellData[cutCellId].noCartesianSurfaces = 0;
4765 cutCellData[cutCellId].noBoundarySurfaces = 0;
4766
4767 // --------6.1.1) transform face information in necessary cutCellData-information!
4768
4769 for(MInt f = 0; (unsigned)f < cutCells[sc].faces.size(); f++) {
4770 MInt face = cutCells[sc].faces[f];
4771 ASSERT(faces[startSetIndex][face].area >= F0, "");
4772 ASSERT(!(std::isnan(faces[startSetIndex][face].area)), "");
4773 ASSERT(!(std::isnan(faces[startSetIndex][face].center[0])), "");
4774 ASSERT(!(std::isnan(faces[startSetIndex][face].center[1])), "");
4775 ASSERT(!(std::isnan(faces[startSetIndex][face].center[2])), "");
4776 ASSERT(!(std::isinf(faces[startSetIndex][face].area)), "");
4777 ASSERT(!(std::isinf(faces[startSetIndex][face].center[0])), "");
4778 ASSERT(!(std::isinf(faces[startSetIndex][face].center[1])), "");
4779 ASSERT(!(std::isinf(faces[startSetIndex][face].center[2])), "");
4780
4781 // --------6.1.1) for body-faces:
4782 // boundarySurfaceArea, boundarySurfaceCentroid, boundarySurfaceNormal
4783 // boundarySurfaceBndryCndId, boundarySurfaceBodyId, noBoundarySurfaces
4784
4785 if(faces[startSetIndex][face].faceType == 1) { // body surface
4786 // FvBndryCell<nDim>::BodySurface* bodySurface = scBndryCell->m_srfcs[noBodySurfaces];
4787 // bodySurface->m_area = faces[startSetIndex][face].area;
4788 cutCellData[cutCellId].boundarySurfaceArea[noBodySurfaces] = faces[startSetIndex][face].area;
4789
4790 for(MInt i = 0; i < nDim; i++) {
4791 // bodySurface->m_coordinates[i] = faces[startSetIndex][face].center[i];
4792 // bodySurface->m_normalVector[i] = faces[startSetIndex][face].normal[i];
4793 cutCellData[cutCellId].boundarySurfaceCentroid[noBodySurfaces][i] = faces[startSetIndex][face].center[i];
4794 cutCellData[cutCellId].boundarySurfaceNormal[noBodySurfaces][i] = faces[startSetIndex][face].normal[i];
4795 }
4796 // bodySurface->m_noCutPoints = (MInt) faces[startSetIndex][face].edges.size();
4797 // bodySurface->m_bndryCndId = m_movingBndryCndId;
4798
4799 cutCellData[cutCellId].boundarySurfaceBndryCndId[noBodySurfaces] = -1; // m_movingBndryCndId;
4800 cutCellData[cutCellId].boundarySurfaceBodyId[noBodySurfaces] = faces[startSetIndex][face].bodyId;
4801
4802 // ASSERT(bodySurface->m_noCutPoints <= m_noEdges*2, "");
4803 for(MInt v = 0; (unsigned)v < faces[startSetIndex][face].vertices.size(); v++) {
4804 const MInt vertex = faces[startSetIndex][face].vertices[v];
4805 // check this!
4806 isPartOfBodySurface[vertex] = true;
4807 // MInt cutPointId = vertices[startSetIndex][vertex].pointId;
4808 newCutPointId[vertex] = v;
4809 vertices[startSetIndex][vertex].cartSrfcId = noBodySurfaces;
4810 // end check this!
4811
4812 // for( MInt i = 0; i < nDim; i++ ) {
4813 // bodySurface->m_cutCoordinates[v][i] =
4814 // vertices[startSetIndex][vertex].coordinates[i]; cutCellData[cutCellId].cutPoints[
4815 // cutCellData[cutCellId].noCutPoints ][i] =
4816 // vertices[startSetIndex][vertex].coordinates[i];
4817 // }
4818 // if( cutPointId > -1 ){
4819 // bodySurface->m_cutEdge[v] = pointEdgeId[cutPointId];
4820 // cutCellData[cutCellId].cutEdges[ cutCellData[cutCellId].noCutPoints ] =
4821 // pointEdgeId[cutPointId];
4822 // }
4823 // else{
4824 // bodySurface->m_cutEdge[v] = -1;
4825 // cutCellData[cutCellId].cutEdges[ cutCellData[cutCellId].noCutPoints ] = -1;
4826 // }
4827 // bodySurface->m_bodyId[v] = faces[startSetIndex][face].bodyId;
4828 // cutCellData[cutCellId].cutSrfcId[ cutCellData[cutCellId].noCutPoints ] =
4829 // noBodySurfaces; cutCellData[cutCellId].cutBodyIds[
4830 // cutCellData[cutCellId].noCutPoints ] = faces[startSetIndex][face].bodyId;
4831 // cutCellData[cutCellId].noCutPoints++;
4832 // if ( cutCellData[cutCellId].noCutPoints > CC::maxNoCutPoints )
4833 // mTerm(1,AT_,"More cutpoints than I can store...");
4834 }
4835 noBodySurfaces++;
4836 cutCellData[cutCellId].noBoundarySurfaces++;
4837 ASSERT(cutCellData[cutCellId].noBoundarySurfaces == noBodySurfaces, "");
4838 } else { // Cartesian face
4839
4840 // --------6.1.1) for cartesian-faces:
4841 // cartFaceCentroid, cartFaceArea, cartFaceDir, noCartesianSurfaces
4842
4843 //--RELOC4--
4844 const MInt dirId = faces[startSetIndex][face].faceId;
4845 const MInt spaceId = dirId / 2;
4846
4847 /*MInt srfcId = m_cellSurfaceMapping[ splitChildId ][ dirId ];
4848 if( noFacesPerCartesianFace[dirId] > 1 ){// check if we have multiple faces in this
4849 direction; if yes, we have to do something special! MInt sfCellId =
4850 splitFaceCellIds[scBndryId]; cellWithSplitFace* sfCell = &splitFaceCells[sfCellId];
4851 // search the right split surface of ssCell:
4852 MInt sf = -1;
4853 for( MInt s = 0; (unsigned) s < sfCell->splitFaces.size(); s++){
4854 MInt sfDir = sfCell->splitFaces[s].direction;
4855 if( sfDir == dirId ){ // found it!
4856 sf = s;
4857 break;
4858 }
4859 }
4860 ASSERT(sf > -1, "");
4861 ASSERT(srfcId < 0, "");
4862 // check if a surface should be generated - not between two halo cells!
4863 MBool createSrfc = true;
4864 if( a_hasProperty(cellId, Cell::IsHalo) ){
4865 if( grid().tree().hasNeighbor(cellId, dir)cellId, dirId)){
4866 MInt nghbrTmp = a_neighborId(cellId, dirId);
4867 if( a_hasProperty(nghbrTmp, Cell::IsHalo) ){
4868 createSrfc = false;
4869 }
4870 }else{
4871 createSrfc = false;
4872 }
4873 }
4874 if( createSrfc ){
4875 srfcId = getNewSurfaceId();
4876 createSurfaceSplit( srfcId, cellId, splitChildId, dirId );
4877 sfCell->splitFaces[sf].srfcIds.push_back(srfcId);
4878 m_cellSurfaceMapping[splitChildId][dirId]=-2;//indicate split surface
4879 }
4880 }
4881 else if( splitCellId > -1 ){ // split cell, but no split surface -> generate a new
4882 surface! ASSERT(srfcId < 0, "");
4883 // check if a surface should be generated - not between two halo cells!
4884 MBool createSrfc = true;
4885 if( a_hasProperty(cellId, Cell::IsHalo) ){
4886 if( grid().tree().hasNeighbor(cellId, dir)cellId, dirId)){
4887 MInt nghbrTmp = a_neighborId(cellId, dirId);
4888 if( a_hasProperty(nghbrTmp, Cell::IsHalo) ){
4889 createSrfc = false;
4890 }
4891 }else{
4892 createSrfc = false;
4893 }
4894 }
4895 if( createSrfc ){
4896 srfcId = getNewSurfaceId();
4897 createSurfaceSplit( srfcId, cellId, splitChildId, dirId );
4898 m_cellSurfaceMapping[splitChildId][dirId]=srfcId;
4899 }
4900 }*/
4901 MFloat sign = F1;
4902 if(dirId % 2 == 0) sign = -F1;
4903
4904 // if ( srfcId > -1 ) {
4905 for(MInt i = 0; i < nDim; i++) {
4906 // m_surfaces->a[ srfcId ].m_coordinates[ i ] =
4907 // faces[startSetIndex][face].center[i];
4908 cutCellData[cutCellId].cartFaceCentroid[cutCellData[cutCellId].noCartesianSurfaces][i] =
4909 faces[startSetIndex][face].center[i];
4910 }
4911 // m_surfaces->a[ srfcId ].m_coordinates[ spaceId ] = a_coordinate(cellId,
4912 // spaceId ) + sign * cellHalfLength;
4913 cutCellData[cutCellId].cartFaceCentroid[cutCellData[cutCellId].noCartesianSurfaces][spaceId] =
4914 a_coordinate(cellId, spaceId) + sign * cellHalfLength;
4915
4916 // m_surfaces->a[ srfcId ].m_area[0] = faces[startSetIndex][face].area;
4917 cutCellData[cutCellId].cartFaceArea[cutCellData[cutCellId].noCartesianSurfaces] =
4918 faces[startSetIndex][face].area;
4919 cutCellData[cutCellId].cartFaceDir[cutCellData[cutCellId].noCartesianSurfaces] =
4920 faces[startSetIndex][face].faceId;
4921
4922 // if( noFacesPerCartesianFace[dirId] == 1 ) // do not set this for split faces
4923 // scBndryCell->m_associatedSrfc[ dirId ] = srfcId;
4924 // }
4925 /*else{
4926 if( grid().tree().hasNeighbor(cellId, dir)cellId, dirId) > 0 && (!a_hasProperty(cellId,
4927Cell::IsHalo)) ){ cerr << " domain " << domainId() << " cellId " << cellId << " (" <<
4928grid().tree().globalId(cellId) << ") bndryId " << bndryId << " split child " << splitChildId << "
4929has no surface in dir " << dirId << " (" << splitCellId <<")" << endl; writeVTKFileOfCutCell(cellId,
4930&cutCells, &faces[startSetIndex], &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
4931 outputPolyData(cellId, &cutCells, &faces[startSetIndex], &edges[startSetIndex],
4932&vertices[startSetIndex], startSetIndex); cerr << " nghbr: " << a_neighborId(cellId, dirId) << "
4933nghbr is bndry cell: " << a_boundaryId(a_neighborId(cellId, dirId)) << " nghbr is inactive: " <<
4934m_cellIsInactive[a_neighborId(cellId, dirId)] << " nghbr properties: "
4935 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsDummy)
4936 << a_isBndryGhostCell(a_neighborId(cellId, dirId))
4937 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsInterface)
4938 << a_isPeriodic(a_neighborId(cellId, dirId))
4939 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsCutOff)
4940 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsNotGradient)
4941 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsValidMGC)
4942 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsExchange)
4943 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsFlux)
4944 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsActive)
4945 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsOnCurrentMGLevel)
4946 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsInSpongeLayer)
4947 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsHalo)
4948 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsWindow)
4949 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsPeriodicWithRot)
4950 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsPartLvlAncestor)
4951 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsPartitionCell)
4952 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsSplitCell)
4953 << a_hasProperty(a_neighborId(cellId, dirId), Cell::HasSplitFace)
4954 << a_hasProperty(a_neighborId(cellId, dirId), Cell::IsTempLinked)
4955 << endl;
4956 mTerm(1,AT_,"This was not supposed to happen - where is my
4957surface?!?");
4958// continue;
4959 }
4960 else
4961 continue;
4962 }
4963 m_cutFaceArea[ m_bndryCellIds->a[splitChildId] ][ dirId ] =
4964faces[startSetIndex][face].area;
4965
4966 MInt nghbrId = m_surfaces->a[srfcId].m_nghbrCellIds[dirId%2];
4967 MInt nghbrBndryId = -1;
4968 if( splitCellId < 0 && noFacesPerCartesianFace[dirId] == 1){
4969 if ( nghbrId > -1 )
4970 nghbrBndryId = m_bndryCellIds->a[ nghbrId ];
4971
4972 if ( nghbrBndryId > -1 ) {
4973 m_bndryCells->a[ nghbrBndryId ].m_associatedSrfc[ m_revDir[dirId] ] = srfcId;
4974 }
4975 }else{
4976 nghbrId = a_neighborId(cellId, dirId);
4977 if ( nghbrId > -1 )
4978 nghbrBndryId = m_bndryCellIds->a[ nghbrId ];
4979 }
4980 */
4981 cutCellData[cutCellId].noCartesianSurfaces++;
4982 if(cutCellData[cutCellId].noCartesianSurfaces > CC::maxNoCartesianSurfaces) {
4983 mTerm(1, AT_, "Increase CutCell::maxNoCartesianSurfaces");
4984 }
4985 } // end else
4986 }
4987
4988 if(noSplitChildren > 1) {
4989 // bndryCell->m_noSrfcs = 0;
4990 cutCellData[cutc].noBoundarySurfaces = 0;
4991 }
4992 // scBndryCell->m_noSrfcs = noBodySurfaces;
4993 cutCellData[cutCellId].noBoundarySurfaces = noBodySurfaces;
4994
4995 RECORD_TIMER_STOP(tCutFace_6);
4996
4997 for(MInt k = 0; k < CC::noFaces; k++) {
4998 cutCellData[cutCellId].noFacesPerCartesianDir[k] = noFacesPerCartesianFace[k];
4999 }
5000
5001 // --------6.2) transfer poly information to the cutCellData-structure
5002
5003 RECORD_TIMER_START(tCutFace_7);
5004
5005 // m_noCutCellFaces[ scBndryId ] = 0;
5006 // const MInt maxPointsXD = 12;
5007 cutCellData[cutCellId].noTotalFaces = 0;
5008 cutCellData[cutCellId].noAdditionalVertices = 0;
5009 MInt vertexMap[maxNoVertices];
5010 fill_n(vertexMap, maxNoVertices, -1);
5011
5012 for(MInt f = 0; (unsigned)f < cutCells[sc].faces.size(); f++) {
5013 MInt face = cutCells[sc].faces[f];
5014 // MInt nccf = m_noCutCellFaces[ scBndryId ];
5015 // m_noCutFacePoints[ scBndryId ][ nccf ] = 0;
5016 const MInt facecnt = cutCellData[cutCellId].noTotalFaces;
5017 cutCellData[cutCellId].allFacesNoPoints[facecnt] = 0;
5018 cutCellData[cutCellId].allFacesBodyId[facecnt] = faces[startSetIndex][face].bodyId;
5019
5020 for(MInt e = 0; (unsigned)e < faces[startSetIndex][face].vertices.size(); e++) {
5021 const MInt vertex = faces[startSetIndex][face].vertices[e];
5022 MInt pointId = vertices[startSetIndex][vertex].pointId;
5023 MInt storePointId = -1;
5024 if(vertices[startSetIndex][vertex].pointType == 0) {
5025 // ASSERT( m_noCutFacePoints[ scBndryId ][ nccf ] < maxPointsXD, "");
5026 // m_cutFacePointIds[ scBndryId ][ maxPointsXD * nccf + m_noCutFacePoints[ scBndryId ][ nccf ]] =
5027 // vertices[startSetIndex][vertex].pointId ; m_noCutFacePoints[ scBndryId ][ nccf ] ++;
5028 ASSERT(pointId < CC::noCorners, "");
5029 storePointId = pointId;
5030 } else if(pointId > -1) {
5031 ASSERT(vertices[startSetIndex][vertex].pointType == 1, "");
5032 // if( !isPartOfBodySurface[vertex] )
5033 // continue;
5034 /* if( isPartOfBodySurface[vertex] ) {
5035 MInt numCutPointsPreviousFaces = 0;
5036 for( MInt srfc = 0; srfc < vertices[startSetIndex][vertex].cartSrfcId; srfc++ ){
5037 numCutPointsPreviousFaces += m_fvBndryCnd->m_bndryCells->a[scBndryId].m_srfcs[srfc]->m_noCutPoints;
5038 }
5039 MInt cp = numCutPointsPreviousFaces + newCutPointId[vertex] ;
5040 m_cutFacePointIds[ scBndryId ][ maxPointsXD*nccf + m_noCutFacePoints[ scBndryId ][ nccf ] ] =
5041 m_noCellNodes + (cp); m_noCutFacePoints[ scBndryId ][ nccf ] ++;
5042 }*/
5043 ASSERT(pointId < cutCellData[cutc].noCutPoints, "");
5044 storePointId = CC::noCorners + pointId;
5045 } else {
5046 ASSERT(vertices[startSetIndex][vertex].pointType > 1, "");
5047 if(vertexMap[vertex] < 0) {
5048 for(MInt i = 0; i < nDim; i++) {
5049 cutCellData[cutCellId].additionalVertices[cutCellData[cutCellId].noAdditionalVertices][i] =
5050 vertices[startSetIndex][vertex].coordinates[i];
5051 }
5052 vertexMap[vertex] = cutCellData[cutCellId].noAdditionalVertices;
5053 cutCellData[cutCellId].noAdditionalVertices++;
5054 if(cutCellData[cutCellId].noAdditionalVertices > CC::maxNoAdditionalVertices) {
5055 writeVTKFileOfCell(cellId, &faces[startSetIndex], &vertices[startSetIndex], globalTimeStep);
5056 }
5057 ASSERT(cutCellData[cutCellId].noAdditionalVertices <= CC::maxNoAdditionalVertices, "");
5058 }
5059 storePointId = CC::noCorners + CC::maxNoCutPoints + vertexMap[vertex];
5060 }
5061 cutCellData[cutCellId].allFacesPointIds[facecnt][cutCellData[cutCellId].allFacesNoPoints[facecnt]] =
5062 storePointId;
5063 cutCellData[cutCellId].allFacesNoPoints[facecnt]++;
5064 ASSERT(cutCellData[cutCellId].allFacesNoPoints[facecnt] <= CC::maxNoFaceVertices,
5065 "has: " + to_string(cutCellData[cutCellId].allFacesNoPoints[facecnt]) + " max is "
5066 + to_string(CC::maxNoFaceVertices));
5067 }
5068 // m_noCutCellFaces[scBndryId]++;
5069 cutCellData[cutCellId].noTotalFaces++;
5070 }
5071 // not yet adjusted to split cells!
5072
5073
5074 //--RELOC6--
5075 // set splitface stream for vtu output
5076 /*
5077 MBool needFaceStream = false;
5078 m_fvBndryCnd->bndryCells[ scBndryId ].m_faceVertices.clear();
5079 m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream.resize(0);
5080 if ( !a_hasProperty(cellId, Cell::IsSplitCell) ) {
5081 if ( a_hasProperty( cellId , Cell::HasSplitFace ) ) {
5082 needFaceStream = true;
5083 }
5084 else {
5085 for( MInt f = 0; (unsigned) f < cutCells[sc].faces.size(); f++ ){
5086 if ( needFaceStream ) break;
5087 MInt face = cutCells[sc].faces[f];
5088 polyFace* faceP = &faces[startSetIndex][face];
5089 for( MInt e = 0; (unsigned) e < faceP->edges.size(); e++ ){
5090 if ( needFaceStream ) break;
5091 MInt edge = faceP->edges[e].first;
5092 MInt v0 = edges[startSetIndex][edge].vertices[0];
5093 MInt v1 = edges[startSetIndex][edge].vertices[1];
5094 if ( vertices[startSetIndex][v0].pointType > 1 || vertices[startSetIndex][v1].pointType > 1 ) {
5095 //attention: these additional vertices may render the face polygon concave and paraview/openGL does not
5096 render concave polygons properly! needFaceStream = true;
5097 }
5098 }
5099 }
5100 }
5101 }
5102
5103 if ( needFaceStream ) {
5104 m_fvBndryCnd->bndryCells[ scBndryId ].m_faceVertices.clear();
5105 m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream.resize(cutCells[sc].faces.size());
5106 MUint noEdges = 0;
5107 MBool vertexUsed[maxNoVertices] = {false};
5108 MUint fcnt = 0;
5109 for ( MInt faceType = 1; faceType >=0; faceType-- ) { //body faces first
5110 for( MInt f = 0; (unsigned) f < cutCells[sc].faces.size(); f++ ){
5111 MInt face = cutCells[sc].faces[f];
5112 polyFace* faceP = &faces[startSetIndex][face];
5113 if ( faceP->faceType != faceType ) continue;
5114 m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[fcnt].resize(0);
5115
5116 {
5117 MInt edge = faceP->edges[0].first;
5118 MInt dir = faceP->edges[0].second;
5119 MInt id0 = (dir==1) ? 0:1;
5120 MInt firstVertex = edges[startSetIndex][edge].vertices[id0];
5121 MInt previousVertex = firstVertex;
5122 MBool edgeChecked[maxNoEdges] = {false};
5123 for( MInt e = 0; (unsigned) e < faceP->edges.size(); e++ ){
5124 edge = faceP->edges[e].first;
5125 dir = faceP->edges[e].second;
5126 id0 = (dir==1) ? 0:1;
5127 MInt id1 = (dir==1) ? 1:0;
5128 MInt v0 = edges[startSetIndex][edge].vertices[id0];
5129 MInt v1 = edges[startSetIndex][edge].vertices[id1];
5130 ASSERT( v1 != v0,"");
5131 ASSERT( v0 == previousVertex, "" );
5132 m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[fcnt].push_back( v1 );
5133 previousVertex = v1;
5134 if ( edgeChecked[edge] ) cerr << "duplicate edge!" << endl;
5135 edgeChecked[edge] = true;
5136 }
5137 ASSERT( previousVertex == firstVertex, "" );
5138 }
5139
5140 noEdges += faceP->edges.size();
5141
5142 MBool vertexUsed2[maxNoVertices] = {false};
5143 for ( MUint s = 0; s < m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[fcnt].size(); s++ ) {
5144 if ( vertexUsed2[ m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[fcnt][s] ] ) {
5145 cerr << "duplicate face point " << globalTimeStep << " " << grid().tree().globalId(cellId) << " " <<
5146 bndryCell->m_noSrfcs << " " << face << " " << faceP->faceId << " " << faceP->area
5147 << " " << faceP->center[0] << " " << faceP->center[1] << " " << faceP->center[2]
5148 << " " << faceP->normal[0] << " " << faceP->normal[1] << " " << faceP->normal[2]
5149 << " " << m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[fcnt][s] << endl;
5150 for( MInt e = 0; (unsigned) e < faceP->edges.size(); e++ ){
5151 MInt edge = faceP->edges[e].first;
5152 MInt dir = faceP->edges[e].second;
5153 MInt id0 = dir==1?0:1;
5154 MInt id1 = dir==1?1:0;
5155 MInt v0 = edges[startSetIndex][edge].vertices[id0];
5156 MInt v1 = edges[startSetIndex][edge].vertices[id1];
5157 cerr << e << " " << dir << " " << edge << " " << v0 << " " << v1
5158 << " " << edges[startSetIndex][edge].edgeType
5159 << " " << edges[startSetIndex][edge].edgeId
5160 << " " << edges[startSetIndex][edge].face[0]
5161 << " " << edges[startSetIndex][edge].face[1]
5162 << endl;
5163 }
5164 }
5165 vertexUsed[ m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[fcnt][s] ] = true;
5166 vertexUsed2[ m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[fcnt][s] ] = true;
5167 }
5168
5169 fcnt++;
5170 }
5171 }
5172 MInt pcnt = 0;
5173 MInt vertexRemap[maxNoVertices] = {-1};
5174 for ( MUint v = 0; v < vertices[startSetIndex].size(); v++ ) {
5175 if ( !vertexUsed[v] ) continue;
5176 vertexRemap[v] = pcnt++;
5177 for ( MInt i = 0; i < nDim; i++ ) {
5178 m_fvBndryCnd->bndryCells[ scBndryId ].m_faceVertices.push_back( vertices[startSetIndex][v].coordinates[i] );
5179 }
5180 }
5181
5182 for ( MUint f = 0; f < m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream.size(); f++ ) {
5183 for ( MUint v = 0; v < m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[f].size(); v++ ) {
5184 MInt vid = m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[f][v];
5185 m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[f][v] = vertexRemap[vid];
5186 }
5187 for ( MUint v = 0; v < m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[f].size(); v++ ) {
5188 if ( m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[f][v] < 0
5189 || m_fvBndryCnd->bndryCells[ scBndryId ].m_faceStream[f][v] >= (signed)(m_fvBndryCnd->bndryCells[
5190 scBndryId ].m_faceVertices.size()/3) ) { cerr << "vertex stream out of range" << endl;
5191 }
5192 }
5193 }
5194 }
5195 */
5196
5197 // additional check!
5198 if(!cutCells[sc].faces.empty()) {
5199 MUint noEdges = 0;
5200 MInt pcnt = 0;
5201 MInt vertexRemap[maxNoVertices];
5202 fill_n(vertexRemap, maxNoVertices, -1);
5203 for(MInt f = 0; (unsigned)f < cutCells[sc].faces.size(); f++) {
5204 MInt face = cutCells[sc].faces[f];
5205 // noEdges += faces[startSetIndex][face].edges.size();
5206 noEdges += faces[startSetIndex][face].vertices.size();
5207 for(MInt e = 0; (unsigned)e < faces[startSetIndex][face].vertices.size(); e++) {
5208 const MInt vertex = faces[startSetIndex][face].vertices[e];
5209 if(vertexRemap[vertex] < 0) {
5210 vertexRemap[vertex] = pcnt;
5211 pcnt++;
5212 }
5213 }
5214 }
5215 if(pcnt + cutCells[sc].faces.size() != 2 + noEdges / 2 || noEdges % 2 == 1) {
5216 cerr << grid().domainId() << "Euler's polyhedral formula not fulfilled ("
5217 << pcnt + (signed)cutCells[sc].faces.size() - 2 - noEdges / 2 << ") " << pcnt << " "
5218 << cutCells[sc].faces.size() << " " << noEdges / 2 << " " << noEdges << " for cell " << cellId << " "
5219 << globalTimeStep << " " << faces[startSetIndex].size() << " " << cutCells.size() << " "
5220 << grid().tree().globalId(cellId) << " " << sc << endl;
5221 writeVTKFileOfCell(cellId, &faces[startSetIndex], &vertices[startSetIndex], -1);
5222 }
5223 }
5224 RECORD_TIMER_STOP(tCutFace_7);
5225 }
5226
5227
5228 if(noSplitChildren > 1) {
5229 cutCellData[cutc].volume = F0;
5230 for(MInt sc = 0; sc < noSplitChildren; sc++) {
5231 MInt cutCellId = splitCellList[sc];
5232 cutCellData[cutc].volume += cutCellData[cutCellId].volume;
5233 }
5234 for(MInt dir = 0; dir < m_noDirs; dir++) {
5235 cutCellData[cutc].noFacesPerCartesianDir[dir] = noFacesPerCartesianFaceAll[dir];
5236 //--REV_RELOC--
5237 if(cutCellData[cutc].noFacesPerCartesianDir[dir] == 0) {
5238 cutCellData[cutc].externalFaces[dir] = true;
5239 }
5240 }
5241 }
5242
5243
5244 /*
5245 MBool hasSplitFace = false;
5246 for ( MInt k = 0; k < CC::noFaces; k++ ) {
5247 if ( noFacesPerCartesianFaceAll[k] > 1 ) hasSplitFace = true;
5248 }
5249 if( noSplitChildren > 1 || hasSplitFace ) {
5250
5251 cerr << "TESTF "<< grid().tree().globalId(cellId) << " " << hasAmbiguousFaces <<" " << noCutSets <<"
5252 " << maxCutsPerFace << " / " << noSplitChildren << " " << hasSplitFace
5253 << " " << cutCellData[cutc].noBoundarySurfaces << " " <<
5254 cutCellData[cutc].boundarySurfaceBodyId[0] << endl;
5255 }
5256
5257
5258
5259 //if ( grid().tree().globalId(cellId) == 205407 || grid().tree().globalId(cellId) == 205408 ||
5260 grid().tree().globalId(cellId) == 205411 || grid().tree().globalId(cellId) == 205418 ) { if (
5261 grid().tree().globalId(cellId) == 205407 ) { MInt splitParentId = cutCellData[cutc].splitParentId; MInt
5262 noSplitChilds = cutCellData[cutc].noSplitChilds; cerr << "compare " << grid().tree().globalId(cellId) << endl; if (
5263 cutcbak.cellId != cutCellData[cutc].cellId ) { cerr << grid().tree().globalId(cellId) << ": diff0 " << cutc << " "
5264 << noSplitChilds << " " << splitParentId << endl; continue;
5265 }
5266 if ( cutcbak.noSplitChilds != cutCellData[cutc].noSplitChilds ) {
5267 cerr << grid().tree().globalId(cellId) << ": diff0a " << cutc << " " << noSplitChilds << " " <<
5268 splitParentId << endl;
5269 }
5270 if ( cutcbak.splitParentId != cutCellData[cutc].splitParentId ) {
5271 cerr << grid().tree().globalId(cellId) << ": diff0b " << cutc << " " << noSplitChilds << " " <<
5272 splitParentId << endl;
5273 }
5274 MInt globalId =
5275 (splitParentId>-1?grid().tree().globalId(splitParentId):grid().tree().globalId(cellId)); if (
5276 fabs(cutCellData[cutc].volume - cutcbak.volume) > 1e-15 ) cerr << grid().tree().globalId(cellId) << ": diff1 " <<
5277 cutc << " " << noSplitChilds << " " << splitParentId << " " << cutCellData[cutc].volume << " " << cutcbak.volume
5278 << endl; for ( MInt i = 0; i < nDim; i++ ) { if ( fabs(cutCellData[cutc].volumetricCentroid[i] -
5279 cutcbak.volumetricCentroid[i]) > 1e-15 ) cerr << grid().tree().globalId(cellId) << ": diff2 " << cutc << " " <<
5280 noSplitChilds << " " << splitParentId
5281 << " " << i << " " << cutCellData[cutc].volumetricCentroid[i]/a_cellLengthAtCell(cellId) <<
5282 " " << cutcbak.volumetricCentroid[i]/a_cellLengthAtCell(cellId) << endl;
5283 }
5284
5285 // cutCellData[cutc].volume = cutcbak.volume;
5286 for ( MInt i = 0; i < nDim; i++ ) {
5287 cerr << "set0 " << i << " " << cutCellData[cutc].volumetricCentroid[i] << " " <<
5288 cutcbak.volumetricCentroid[i]
5289 << " " << a_coordinate(cellId,i)+cutCellData[cutc].volumetricCentroid[i]
5290 << " " << a_coordinate(cellId,i)+cutcbak.volumetricCentroid[i] << endl;
5291 cutCellData[cutc].volumetricCentroid[i] = cutcbak.volumetricCentroid[i];
5292 }
5293
5294 MInt noSrfcs = cutcbak.noBoundarySurfaces;
5295 if ( noSrfcs != cutCellData[cutc].noBoundarySurfaces ) {
5296 cerr << grid().tree().globalId(cellId) << ": diff3 " << cutc << " " << noSplitChilds << " " <<
5297 (splitParentId>-1?grid().tree().globalId(splitParentId):-1) << " " << noSrfcs << " " <<
5298 cutCellData[cutc].noBoundarySurfaces << endl; continue;
5299 }
5300 for ( MInt bs = 0; bs < noSrfcs; bs++ ) {
5301 for( MInt i = 0; i < nDim; i++ ){
5302 if ( fabs( cutcbak.boundarySurfaceCentroid[bs][i] -
5303 cutCellData[cutc].boundarySurfaceCentroid[bs][i]) > 1e-15 ) cerr << grid().tree().globalId(cellId) << ": diff4 " <<
5304 cutc << " " << noSplitChilds << " " << splitParentId
5305 << " " << i << " " << cutcbak.boundarySurfaceCentroid[bs][i] << " " <<
5306 cutCellData[cutc].boundarySurfaceCentroid[bs][i] << endl; if ( fabs( cutcbak.boundarySurfaceNormal[bs][i] -
5307 cutCellData[cutc].boundarySurfaceNormal[bs][i]) > 1e-15 ) { cerr << grid().tree().globalId(cellId) << ": diff5 " <<
5308 cutc << " " << globalId << " " << noSplitChilds << " " << splitParentId
5309 << " " << i << " " << cutcbak.boundarySurfaceNormal[bs][i] << " " <<
5310 cutCellData[cutc].boundarySurfaceNormal[bs][i] << endl;
5311 }
5312 }
5313 if ( fabs( cutcbak.boundarySurfaceArea[bs] - cutCellData[cutc].boundarySurfaceArea[bs]) > 1e-15 )
5314 cerr << grid().tree().globalId(cellId) << ": diff6 " << cutc << " " << noSplitChilds << " " << splitParentId <<
5315 endl; if ( cutcbak.boundarySurfaceBndryCndId[bs] != cutCellData[cutc].boundarySurfaceBndryCndId[bs] ) cerr <<
5316 grid().tree().globalId(cellId) << ": diff7 " << cutc << " " << noSplitChilds << " " << splitParentId << endl; if (
5317 cutcbak.boundarySurfaceBodyId[bs] != cutCellData[cutc].boundarySurfaceBodyId[bs] ) cerr <<
5318 grid().tree().globalId(cellId) << ": diff8 " << cutc << " " << noSplitChilds << " " << splitParentId << endl;
5319
5320 // cutCellData[cutc].boundarySurfaceArea[bs] = cutcbak.boundarySurfaceArea[bs];
5321 // cutCellData[cutc].boundarySurfaceBndryCndId[bs] = cutcbak.boundarySurfaceBndryCndId[bs];
5322 // cutCellData[cutc].boundarySurfaceBodyId[bs] = cutcbak.boundarySurfaceBodyId[bs];
5323 for( MInt i = 0; i < nDim; i++ ){
5324 cerr << "set1 " << i << " " << cutCellData[cutc].boundarySurfaceCentroid[bs][i] << " " <<
5325 cutcbak.boundarySurfaceCentroid[bs][i] << endl; cutCellData[cutc].boundarySurfaceCentroid[bs][i] =
5326 cutcbak.boundarySurfaceCentroid[bs][i];
5327 // cutCellData[cutc].boundarySurfaceNormal[bs][i] = cutcbak.boundarySurfaceNormal[bs][i];
5328 }
5329
5330 MInt noCP = 0;
5331 for ( MInt c = 0; c < cutCellData[cutc].noCutPoints; c++ ) {
5332 //if ( cutCellData[cutc].cutSrfcId[c] == bs ) {
5333 for( MInt i = 0; i < nDim; i++ ) {
5334 if ( fabs( cutcbak.cutPoints[c][i] - cutCellData[cutc].cutPoints[c][i]) > 1e-15 ) cerr <<
5335 grid().tree().globalId(cellId) << ": diff9 " << cutc << " " << noSplitChilds << " " << splitParentId << endl;
5336 }
5337 if ( cutcbak.cutEdges[c] != cutCellData[cutc].cutEdges[c] ) cerr <<
5338 grid().tree().globalId(cellId) << ": diff10 " << cutc << " " << noSplitChilds << " " << splitParentId << endl; if (
5339 cutcbak.cutBodyIds[c] != cutCellData[cutc].cutBodyIds[c] ) cerr << grid().tree().globalId(cellId) << ": diff11 " <<
5340 cutc << " " << noSplitChilds << " " << splitParentId << endl; noCP++;
5341 //}
5342 }
5343 // if ( noCP != bodySurface->m_noCutPoints ) cerr << grid().tree().globalId(cellId) << ": diff12 " << globalId
5344 << " " << cutc << " " << noSrfcs << " " << noSplitChilds << " " << splitParentId
5345 // << " " << bs << " " << noCP << " " <<
5346 bodySurface->m_noCutPoints << " (" << cutCellData[cutc].noCutPoints << ")" << endl; for ( MInt f = 0; f < 2*nDim;
5347 f++ ) { if ( cutCellData[cutc].externalFaces[f] != cutcbak.externalFaces[f] ) cerr <<
5348 grid().tree().globalId(cellId) << ": diff13 " << cutc << " " << noSplitChilds << " " << splitParentId << endl;
5349 }
5350 for ( MInt c = 0; c < IPOW2(nDim); c++ ) {
5351 if ( cutcbak.cornerIsInsideGeometry[0][c] != cutCellData[cutc].cornerIsInsideGeometry[0][c] )
5352 cerr << grid().tree().globalId(cellId) << ": diff14 " << cutc << " " << noSplitChilds << " " << splitParentId <<
5353 endl;
5354 }
5355
5356 }
5357
5358 if ( cutcbak.noCartesianSurfaces != cutCellData[cutc].noCartesianSurfaces ) {
5359 cerr << grid().tree().globalId(cellId) << ": diff15 " << cutc << " " << noSplitChilds << " " <<
5360 splitParentId << endl;
5361 }
5362 for ( MInt cs = 0; cs < cutCellData[cutc].noCartesianSurfaces; cs++ ) {
5363 MBool match = false;
5364 for ( MInt cs1 = 0; cs1 < cutcbak.noCartesianSurfaces; cs1++ ) {
5365
5366 if ( cutcbak.cartFaceDir[cs1] != cutCellData[cutc].cartFaceDir[cs] ) continue;
5367
5368 match = true;
5369
5370 if ( cutcbak.cartFaceDir[cs1] != cutCellData[cutc].cartFaceDir[cs] ) {
5371 cerr << grid().tree().globalId(cellId) << ": diff16 " << cutc << " " << noSplitChilds << " "
5372 << splitParentId << endl;
5373 }
5374 if ( fabs(cutcbak.cartFaceArea[cs1] - cutCellData[cutc].cartFaceArea[cs]) > 1e-15 ) {
5375 cerr << grid().tree().globalId(cellId) << ": diff17 " << cutc << " " << noSplitChilds << " "
5376 << splitParentId
5377 << " " << cutcbak.cartFaceArea[cs1] << " " << cutCellData[cutc].cartFaceArea[cs] << endl;
5378 }
5379 for( MInt i = 0; i < nDim; i++ ) {
5380 if ( fabs( cutcbak.cartFaceCentroid[cs1][i] - cutCellData[cutc].cartFaceCentroid[cs][i] ) >
5381 1e-15 ) { cerr << grid().tree().globalId(cellId) << ": diff18 " << cutc << " " << noSplitChilds << " " <<
5382 splitParentId
5383 << " " << i << " " << cutcbak.cartFaceCentroid[cs1][i] << " "
5384 <<cutCellData[cutc].cartFaceCentroid[cs][i] << endl;
5385 }
5386 }
5387
5388 }
5389 if ( !match ) cerr << grid().tree().globalId(cellId) << ": diff16 " << endl;
5390 }
5391 for ( MInt cs = 0; cs < cutCellData[cutc].noCartesianSurfaces; cs++ ) {
5392 cerr << cs << " " << cutcbak.cartFaceDir[cs] << " " << cutCellData[cutc].cartFaceDir[cs]
5393 << " " << cutcbak.cartFaceArea[cs] << " " << cutCellData[cutc].cartFaceArea[cs]
5394 << " " << cutcbak.cartFaceCentroid[cs][0] << " " << cutCellData[cutc].cartFaceCentroid[cs][0]
5395 << " " << cutcbak.cartFaceCentroid[cs][1] << " " << cutCellData[cutc].cartFaceCentroid[cs][1]
5396 << " " << cutcbak.cartFaceCentroid[cs][2] << " " << cutCellData[cutc].cartFaceCentroid[cs][2]
5397 << endl;
5398 }
5399
5400
5401
5402 //if ( grid().tree().globalId(cellId) == 205407 || grid().tree().globalId(cellId) == 205408 ||
5403 grid().tree().globalId(cellId) == 205411 || grid().tree().globalId(cellId) == 205418 ) {
5404 //if ( grid().tree().globalId(cellId) == 205407 ) {
5405 // cutCellData[cutc] = cutcbak;
5406 //}
5407 }
5408 */
5409
5410
5411 /*
5412 const MInt faceCornerMapping[6][4] =
5413 {{2,6,4,0},{1,5,7,3},{0,4,5,1},{3,7,6,2},{2,3,1,0},{6,7,5,4}};
5414 // for( MInt set = 0; set < m_noLevelSetsUsedForMb; set++ ){
5415 { MInt set = 0;
5416 MBool hasSplitFace = false;
5417 MInt noPartiallyOutsideFaces = 0;
5418 MInt noOutsideNodes = 0;
5419 MInt maxCutsPerFace = 0;
5420 MInt cutsPerFace[m_noCorners] = {0,0,0,0,0,0};
5421 for( MInt c = 0; c < m_noCorners; c++){
5422 if ( cutCellData[cutc].cornerIsInsideGeometry[set][c] ) noOutsideNodes++;
5423 }
5424 for ( MInt k = 0; k < CC::noFaces; k++ ) {
5425 if ( noFacesPerCartesianFaceAll[k] > 1 ) hasSplitFace = true;
5426 for ( MInt j = 0; j < 4; j++ ) {
5427 if ( cutCellData[cutc].cornerIsInsideGeometry[set][faceCornerMapping[k][j]] ) {
5428 noPartiallyOutsideFaces++;
5429 break;
5430 }
5431 }
5432 }
5433 for( MInt cutPoint = 0; cutPoint < cutCellData[cutc].noCutPoints; cutPoint++){
5434 MInt edge = cutCellData[cutc].cutEdges[cutPoint];
5435 cutsPerFace[ edgeFaceCode[edge][0] ]++;
5436 cutsPerFace[ edgeFaceCode[edge][1] ]++;
5437 }
5438 for ( MInt k = 0; k < CC::noFaces; k++ ) {
5439 maxCutsPerFace = mMax(maxCutsPerFace, cutsPerFace[k] );
5440 }
5441 if( noSplitChildren > 1 || hasSplitFace ) {
5442 cerr << "test_npof " << maxCutsPerFace << " " << hasAmbiguousFaces << " " <<
5443 cutCellData[cutc].noCutPoints << " " << noOutsideNodes << endl; } else { cerr << "tset_npof " << maxCutsPerFace <<
5444 " " << hasAmbiguousFaces << " " << cutCellData[cutc].noCutPoints << " " << noOutsideNodes << endl;
5445 }
5446 if ( !( noSplitChildren > 1 || hasSplitFace ) && hasAmbiguousFaces ) cerr << "case_0" << endl;
5447 if ( ( noSplitChildren > 1 || hasSplitFace ) && !hasAmbiguousFaces ) cerr << "case_1" << endl;
5448 }*/
5449
5450 //=================================================
5451
5452#ifdef CutCell_DEBUG
5453 if(globalTimeStep == debugTimeStep && cellId == debugCellId && grid().domainId() == debugDomainId) {
5454 writeVTKFileOfCell(cellId, &faces[startSetIndex], &vertices[startSetIndex], -2);
5455
5456 const MChar* fileName = "cell-Info_";
5457 stringstream fileName2;
5458 fileName2 << fileName << grid().tree().globalId(cellId) << ".txt";
5459
5460 ofstream ofl;
5461 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
5462
5463 if(ofl) {
5464 ofl.setf(ios::fixed);
5465 ofl.precision(12);
5466
5467 ofl << "Writing Cell " << grid().tree().globalId(cellId) << " " << cellId << " " << cutc << " noCuts "
5468 << noIndividualCuts << " noCutCells " << cutCells.size() << " vol " << cutCellData[cutc].volume
5469 << " SplitChilds " << cutCellData[cutc].noSplitChilds << " " << cutCellData[cutc].splitParentId << endl
5470 << endl;
5471 for(MInt dir = 0; dir < m_noDirs; dir++) {
5472 ofl << "Dir " << dir << " external " << cutCellData[cutc].externalFaces[dir] << " faces "
5473 << cutCellData[cutc].noFacesPerCartesianDir[dir] << endl
5474 << endl;
5475 }
5476
5477 ofl << " Cartesian-Surf: " << cutCellData[cutc].noCartesianSurfaces << endl << endl;
5478
5479 for(MInt id = 0; id < cutCellData[cutc].noCartesianSurfaces; id++) {
5480 ofl << "Id " << id << " dir " << cutCellData[cutc].cartFaceDir[id] << " area "
5481 << cutCellData[cutc].cartFaceArea[id] << " coord " << cutCellData[cutc].cartFaceCentroid[id][0]
5482 << cutCellData[cutc].cartFaceCentroid[id][1] << cutCellData[cutc].cartFaceCentroid[id][2] << endl
5483 << endl;
5484 }
5485
5486 ofl << " Bndry-Surfaces: " << cutCellData[cutc].noBoundarySurfaces << endl << endl;
5487
5488 for(MInt id = 0; id < cutCellData[cutc].noBoundarySurfaces; id++) {
5489 ofl << "Id " << id << " normal " << cutCellData[cutc].boundarySurfaceNormal[id][0]
5490 << cutCellData[cutc].boundarySurfaceNormal[id][1] << cutCellData[cutc].boundarySurfaceNormal[id][2]
5491 << " center " << cutCellData[cutc].boundarySurfaceCentroid[id][0]
5492 << cutCellData[cutc].boundarySurfaceCentroid[id][1] << cutCellData[cutc].boundarySurfaceCentroid[id][2]
5493 << " area " << cutCellData[cutc].boundarySurfaceArea[id] << endl
5494 << endl;
5495 }
5496 }
5497 }
5498#endif
5499 }
5500
5501
5502#ifdef CutCell_DEBUG
5503 if(globalTimeStep == (g_timeSteps + g_restartTimeStep)) returnDebugInfo();
5504#endif
5505}
5506
5507
5508//-----------------------------------------------------------------------------------------------------
5509
5510// template <MInt nDim_>
5511// void GeometryIntersection<nDim_>::designateCutCellCandidates( std::vector< CutCell<nDim> >& cutCellData )
5512//{
5513// clearCutCellData();
5514// cutCellData.clear();
5515//
5516// // loop over all cells
5517// // --stl: check if neighbor exists or not in all 27 directions!
5518// // --ls/analytical: check level set value vs threshold
5519//
5520// //or stl: compute distance and then uniform scheme for all boundary types
5521//
5522// //better stl: hierarchical, check minLevel...maxLevel, exclude children whose parent already too far from
5523// boundary/not cut by boundary
5524//}
5525
5533template <MInt nDim_>
5535 const MInt* candidateIds,
5536 std::vector<MInt>& candidatesOrder) {
5537 TRACE();
5538
5539 const MInt edgesPerDim = IPOW2(nDim_ - 1);
5540
5541 const MInt DOFStencil[12] = {1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2};
5542
5543 // returns the two faces of any edge
5544 const MInt faceStencil[2][12] = {{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 0, 1}, {4, 4, 4, 4, 5, 5, 5, 5, 2, 2, 3, 3}};
5545
5546 // edege -> opposing edge
5547 // 1: oppsing edge on the same higher face count
5548 // 2: opposing edge on the same lower face count
5549 // 3: oppsong edge accros the cube
5550 // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
5551 const MInt reverseEdgeStencil[3][12] = {{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10},
5552 {4, 5, 6, 7, 0, 1, 2, 3, 10, 11, 8, 9},
5553 {5, 4, 7, 6, 1, 0, 3, 2, 11, 10, 9, 8}};
5554
5555 const MInt signStencil[3][12] = {{-1, 1, 0, 0, -1, 1, 0, 0, -1, 1, -1, 1},
5556 {0, 0, -1, 1, 0, 0, -1, 1, -1, -1, 1, 1},
5557 {-1, -1, -1, -1, 1, 1, 1, 1, 0, 0, 0, 0}};
5558
5559 // edeg -> corner: returns the two corners for any edge
5560 // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11
5561 const MInt nodeStencil[2][12] = {{0, 1, 0, 2, 4, 5, 4, 6, 0, 1, 2, 3}, {2, 3, 1, 3, 6, 7, 5, 7, 4, 5, 6, 7}};
5562
5563 //----------------------------------------------------------
5564
5565
5566 const MFloat eps = m_multiCutCell ? 10 * m_eps : m_eps;
5567
5568 MInt errorFlag = 0;
5569
5570 //----------------------------------------------------------
5571
5572 // loop over candidates, determine cutpoints, store cutCandidates properties
5573 for(MInt cndt = 0; cndt < (signed)candidates.size(); cndt++) {
5574 const MInt cellId = candidates[cndt].cellId;
5575 const MFloat cellLength = a_cellLengthAtCell(cellId);
5576 const MFloat cellHalfLength = F1B2 * cellLength;
5577 for(MInt edge = 0; edge < m_noEdges; edge++) {
5578 if(candidates[cndt].edgeChecked[edge]) continue;
5579
5580 // first do some data structure related stuff
5581 MInt face[2]{-1, -1};
5582 // in 2D: face == edge
5583 face[0] = faceStencil[0][edge];
5584
5585 IF_CONSTEXPR(nDim_ == 3) {
5586 // in 3D: each edge is connected to two faces
5587 face[1] = faceStencil[1][edge];
5588 }
5589
5590 // edge's degree of freedom
5591 const MInt edgeDOF = DOFStencil[edge];
5592
5593 // direct neighbours of each edge -> requires that neighboring cells are on same level!
5594 MInt directNeighbourIds[4]{-1, -1, -1, -1};
5595 directNeighbourIds[0] = cellId;
5596
5597 if(grid().tree().hasNeighbor(cellId, face[0]) > 0) {
5598 directNeighbourIds[1] = grid().tree().neighbor(cellId, face[0]);
5599 }
5600 MInt reverseEdge[edgesPerDim];
5601 reverseEdge[0] = edge;
5602 reverseEdge[1] = reverseEdgeStencil[0][edge];
5603
5604 IF_CONSTEXPR(nDim_ == 3) {
5605 if(grid().tree().hasNeighbor(cellId, face[1]) > 0) {
5606 directNeighbourIds[2] = grid().tree().neighbor(cellId, face[1]);
5607 }
5608
5609 if(grid().tree().hasNeighbor(cellId, face[0]) > 0) {
5610 if(grid().tree().hasNeighbor(grid().tree().neighbor(cellId, face[0]), face[1]) > 0) {
5611 directNeighbourIds[3] = grid().tree().neighbor(grid().tree().neighbor(cellId, face[0]), face[1]);
5612 }
5613 }
5614 if(directNeighbourIds[3] < 0) {
5615 if(grid().tree().hasNeighbor(cellId, face[1]) > 0) {
5616 if(grid().tree().hasNeighbor(grid().tree().neighbor(cellId, face[1]), face[0]) > 0) {
5617 directNeighbourIds[3] = grid().tree().neighbor(grid().tree().neighbor(cellId, face[1]), face[0]);
5618 }
5619 }
5620 }
5621 reverseEdge[2] = reverseEdgeStencil[1][edge];
5622 reverseEdge[3] = reverseEdgeStencil[2][edge];
5623 }
5624
5625
5626 MInt startSet = 0;
5627 MInt endSet = 1;
5628
5629 const MBool isGapCell = candidates[cndt].isGapCell;
5630 if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (!isGapCell)) {
5631 startSet = 1;
5632 endSet = m_noLevelSetsUsedForMb;
5633 }
5634
5635
5636 for(MInt set = startSet; set < endSet; set++) {
5637 MFloat phi[2]{-99, -99}; // signed-distance value on both vertices defining an edge
5638
5639 phi[0] = candidates[cndt].nodalValues[set][nodeStencil[0][edge]];
5640 phi[1] = candidates[cndt].nodalValues[set][nodeStencil[1][edge]];
5641
5642 ASSERT(candidates[cndt].nodeValueSet[nodeStencil[0][edge]], "");
5643 ASSERT(candidates[cndt].nodeValueSet[nodeStencil[1][edge]], "");
5644
5645 // prevent zero-volume cells
5646 if(fabs(phi[0]) < eps) {
5647 if(phi[0] < F0)
5648 phi[0] = -eps;
5649 else
5650 phi[0] = eps;
5651 }
5652 if(fabs(phi[1]) < eps) {
5653 if(phi[1] < F0)
5654 phi[1] = -eps;
5655 else
5656 phi[1] = eps;
5657 }
5658
5659 // limit the distance of a cutPoint to any corner:
5660 // together with the above, this ensure that the CP
5661 // is always 2 eps appart from the corner!
5662 if(m_multiCutCell) {
5663 if(approx(fabs(phi[0]), cellHalfLength, eps)) {
5664 if(phi[0] > F0)
5665 phi[0] = cellHalfLength - eps;
5666 else
5667 phi[0] = -cellHalfLength + eps;
5668 }
5669 if(approx(fabs(phi[1]), cellHalfLength, eps)) {
5670 if(phi[1] > F0)
5671 phi[1] = cellHalfLength - eps;
5672 else
5673 phi[1] = -cellHalfLength + eps;
5674 }
5675 }
5676
5677 // found a cutpoint if sign differs
5678 if(phi[0] * phi[1] < 0) {
5679 MFloat cutpoint[nDim_];
5680 // determine cutpoint coordinates
5681 const MFloat deltaCutpoint = (phi[0] + phi[1]) / (phi[0] - phi[1]);
5682 ASSERT(deltaCutpoint < F1 && deltaCutpoint > -F1, "");
5683 for(MInt dim = 0; dim < nDim_; dim++) {
5684 if(dim == edgeDOF) continue;
5685 cutpoint[dim] = a_coordinate(cellId, dim) + signStencil[dim][edge] * cellHalfLength;
5686 }
5687 cutpoint[edgeDOF] = a_coordinate(cellId, edgeDOF) + cellHalfLength * deltaCutpoint;
5688
5689 // store this cutpoint at all direct neighbours
5690 for(MInt nb = 0; nb < edgesPerDim; nb++) {
5691 const MInt nbCell = directNeighbourIds[nb];
5692 if(nbCell < 0) continue;
5693 const MInt nbCandidate = candidateIds[nbCell];
5694 // IF_CONSTEXPR(nDim_ == 3) {
5695 // ASSERT(nbCandidate >= 0 , "ERROR: future cutCell has no valid cutCandidate-neighbor!");
5696 //} else {
5697 if(nbCandidate < 0) continue;
5698 //}
5699
5700 ASSERT(!candidates[nbCandidate].edgeChecked[reverseEdge[nb]], "");
5701
5702 // store the ordering in which bndryCells are added
5703 // the order appears to change the result for gapClosing-testcases!
5704 candidatesOrder.push_back(nbCandidate);
5705
5706 // store relevant information
5707 const MInt noCPs = candidates[nbCandidate].noCutPoints;
5708 if(noCPs == 2 * m_noEdges) {
5709 mTerm(1, AT_, "Error: too many cut points, can't store more!");
5710 }
5711 if(candidates[nbCandidate].noCutPointsOnEdge[reverseEdge[nb]] == 2) {
5712 // check your geometry and gap-Cell!
5713 mTerm(1, AT_, "Error: already two cut points on edge, can't store more!");
5714 }
5715
5716
5717 if(set >= 1) {
5718 // ASSERT( candidates[ nbCandidate ].associatedBodyIds[set] ==
5719 // candidates[ cndt ].associatedBodyIds[set] , "");
5720 }
5721
5722 for(MInt dim = 0; dim < nDim_; dim++) {
5723 candidates[nbCandidate].cutPoints[noCPs][dim] = cutpoint[dim];
5724 }
5725
5726 // check your geometry and gap-Cell!
5727 ASSERT(candidates[nbCandidate].associatedBodyIds[set] > -1, "cutPoint with invalid bodyId! ");
5728
5729 candidates[nbCandidate].cutBodyIds[noCPs] = candidates[nbCandidate].associatedBodyIds[set];
5730 candidates[nbCandidate].cutEdges[noCPs] = reverseEdge[nb];
5731 candidates[nbCandidate].noCutPoints++;
5732 candidates[nbCandidate].noCutPointsOnEdge[reverseEdge[nb]]++;
5733
5734 } // for nb
5735 } // phi1*phi2<0
5736 } // for sets
5737
5738 // flag direct neighbours so that this edge is only checked once
5739 for(MInt nb = 0; nb < edgesPerDim; nb++) {
5740 if(directNeighbourIds[nb] < 0) continue;
5741 const MInt nbCndt = candidateIds[directNeighbourIds[nb]];
5742 if(nbCndt < 0) continue;
5743 candidates[nbCndt].edgeChecked[reverseEdge[nb]] = true;
5744 }
5745 } // for edge
5746 } // for cndt
5747
5748#ifdef CutCell_DEBUG
5749 MPI_Allreduce(MPI_IN_PLACE, &errorFlag, 1, MPI_INT, MPI_MAX, grid().mpiComm(), AT_, "MPI_IN_PLACE", "errorFlag");
5750#endif
5751 if(errorFlag) {
5752 mTerm(1, AT_, "Critical error in computeCutPoints! Quit.");
5753 }
5754}
5755
5756
5767template <MInt nDim_>
5769 const MFloat* scalarField, const MInt* bodyIdField,
5770 const MBool* const gapPropertyField, const MBool gapClosure) {
5771 TRACE();
5772
5773#ifdef CutCell_DEBUG
5774 const MInt debugTimeStep = -2;
5775 const MInt debugGlobalId = 216221;
5776#endif
5777
5778 m_cutLvlJumpCandidates.clear();
5779
5780 if(candidates.empty()) return;
5781
5782 const MInt noCandidates = (signed)candidates.size();
5783
5784 // add bndryLvlJump cell parents to the candidates and fill m_cutLvlJumpCandidates info
5785 if(m_bndryLvlJumps) {
5786 vector<std::pair<MInt, MInt>> diagonalJumpCells;
5787 for(MInt cnd = 0; cnd < noCandidates; cnd++) {
5788 const MInt cellId = candidates[cnd].cellId;
5789#ifdef CutCell_DEBUG
5790 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
5791 cerr << "Cell is candidate!" << endl;
5792 }
5793#endif
5794 ASSERT(!candidates[cnd].isbndryLvlJumpParent, "");
5795 MInt id = -1;
5796 diagonalJumpCells.clear();
5797 const MInt parentId = grid().tree().parent(cellId);
5798 if(parentId < 0) continue;
5799 for(MInt dir = 0; dir < m_noDirs; dir++) {
5800 // check if the cell is a direct bndryLvlJumpCell:
5801 if(!grid().tree().hasNeighbor(cellId, dir) && grid().tree().hasNeighbor(parentId, dir)) {
5802 if(id < 0) {
5803 // added new as levelJump-candidate:
5804 id = m_cutLvlJumpCandidates.size();
5805 m_cutLvlJumpCandidates.emplace_back();
5806 m_cutLvlJumpCandidates[id].candId = cnd;
5807 // find childId of the cell in relation to its parent
5808 MInt child = -1;
5809 for(child = 0; child < m_maxNoChilds; child++) {
5810 const MInt childCellId = grid().tree().child(parentId, child);
5811 if(childCellId == cellId) break;
5812 }
5813 m_cutLvlJumpCandidates[id].childId = child;
5814 // add parent as additional cutCandidate once
5815 if(candidateIds[parentId] < 0) {
5816 const MInt newId = candidates.size();
5817 candidates.emplace_back();
5818 candidates[newId].cellId = parentId;
5819 candidates[newId].isbndryLvlJumpParent = true;
5820 candidateIds[parentId] = newId;
5821 } else {
5822 if(!candidates[candidateIds[parentId]].isbndryLvlJumpParent) {
5823 candidates[candidateIds[parentId]].isbndryLvlJumpParent = true;
5824 }
5825 }
5826 const MInt parentCandId = candidateIds[parentId];
5827 ASSERT(parentCandId > -1, "");
5828 m_cutLvlJumpCandidates[id].parentCandId = parentCandId;
5829 }
5830 // add jump-related information:
5831 const MInt noJumps = m_cutLvlJumpCandidates[id].noJumps;
5832
5833#ifdef CutCell_DEBUG
5834 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
5835 cerr << "Direct nieghbor Jump!" << dir << endl;
5836 }
5837#endif
5838
5839 m_cutLvlJumpCandidates[id].dirs[noJumps] = dir;
5840 m_cutLvlJumpCandidates[id].diagonalDirs[noJumps] = -2;
5841 m_cutLvlJumpCandidates[id].neighborType[noJumps] = 0;
5842
5843 m_cutLvlJumpCandidates[id].noJumps++;
5844
5845 } else { // 2D-diagonal check
5846 const MInt nghbrId1 = grid().tree().neighbor(cellId, dir);
5847 if(nghbrId1 < 0) continue;
5848 if(!grid().tree().isLeafCell(nghbrId1)) continue;
5849 const MInt ngbParent1 = grid().tree().parent(nghbrId1);
5850 if(ngbParent1 < 0) continue;
5851 if(ngbParent1 == parentId) continue;
5852 for(MInt dir1 = 0; dir1 < m_noDirs; dir1++) {
5853 if((dir1 / 2) == (dir / 2)) continue;
5854 // if(dir1 == dir ) continue;
5855 if(!grid().tree().hasNeighbor(nghbrId1, dir1) && grid().tree().hasNeighbor(ngbParent1, dir1)) {
5856 // don't add the same neighbor twice!
5857 MBool alreadyAdded = false;
5858 MUint i = 0;
5859 for(i = 0; i < diagonalJumpCells.size(); i++) {
5860 if(diagonalJumpCells[i].first == grid().tree().neighbor(ngbParent1, dir1)
5861 && diagonalJumpCells[i].second == 1) {
5862 alreadyAdded = true;
5863 break;
5864 } else if(diagonalJumpCells[i].first == grid().tree().neighbor(ngbParent1, dir1)) {
5865 break;
5866 }
5867 }
5868
5869 if(alreadyAdded) {
5870#ifdef CutCell_DEBUG
5871 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
5872 cerr << "Already found: " << dir << " " << dir1 << " "
5873 << grid().tree().globalId(grid().tree().neighbor(ngbParent1, dir1)) << endl;
5874 }
5875#endif
5876
5877 ASSERT(id > -1, "");
5878 continue;
5879 }
5880
5881 // add diagonal neighbor to the list
5882 diagonalJumpCells.emplace_back(make_pair(grid().tree().neighbor(ngbParent1, dir1), 1));
5883
5884 if(id < 0) {
5885 // added new as levelJump-candidate:
5886 id = m_cutLvlJumpCandidates.size();
5887 m_cutLvlJumpCandidates.emplace_back();
5888 m_cutLvlJumpCandidates[id].candId = cnd;
5889 // find childId of the cell in relation to its parent
5890 MInt child = -1;
5891 for(child = 0; child < m_maxNoChilds; child++) {
5892 const MInt childCellId = grid().tree().child(parentId, child);
5893 if(childCellId == cellId) break;
5894 }
5895 m_cutLvlJumpCandidates[id].childId = child;
5896 // add parent as additional cutCandidate once
5897 if(candidateIds[parentId] < 0) {
5898 const MInt newId = candidates.size();
5899 candidates.emplace_back();
5900 candidates[newId].cellId = parentId;
5901 candidates[newId].isbndryLvlJumpParent = true;
5902 candidateIds[parentId] = newId;
5903 } else {
5904 if(!candidates[candidateIds[parentId]].isbndryLvlJumpParent) {
5905 candidates[candidateIds[parentId]].isbndryLvlJumpParent = true;
5906 }
5907 }
5908 const MInt parentCandId = candidateIds[parentId];
5909 ASSERT(parentCandId > -1, "");
5910 m_cutLvlJumpCandidates[id].parentCandId = parentCandId;
5911 }
5912 const MInt noJumps = m_cutLvlJumpCandidates[id].noJumps;
5913
5914#ifdef CutCell_DEBUG
5915 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
5916 cerr << "Adding type1: " << dir << " " << dir1 << " "
5917 << grid().tree().globalId(grid().tree().neighbor(ngbParent1, dir1)) << " " << noJumps << " "
5918 << endl;
5919 }
5920#endif
5921
5922 m_cutLvlJumpCandidates[id].neighborType[noJumps] = 1;
5923 // store diagonal relation
5924 m_cutLvlJumpCandidates[id].dirs[noJumps] = dir;
5925 m_cutLvlJumpCandidates[id].diagonalDirs[noJumps] = dir1;
5926
5927 m_cutLvlJumpCandidates[id].noJumps++;
5928
5929 } else
5930 IF_CONSTEXPR(nDim == 3) { // check for 3D-diagonals
5931 const MInt nghbrId2 = grid().tree().neighbor(nghbrId1, dir1);
5932 if(nghbrId2 < 0) continue;
5933 if(!grid().tree().isLeafCell(nghbrId2)) continue;
5934 const MInt ngbParent2 = grid().tree().parent(nghbrId2);
5935 if(ngbParent2 < 0) continue;
5936 if(ngbParent2 == parentId) continue;
5937 for(MInt dir2 = 0; dir2 < 2 * nDim; dir2++) {
5938 if(((dir2 / 2) == (dir / 2)) || ((dir2 / 2) == (dir1 / 2))) continue;
5939
5940 if(!grid().tree().hasNeighbor(nghbrId2, dir2) && grid().tree().hasNeighbor(ngbParent2, dir2)) {
5941 // don't add the same neighbor twice!
5942 MBool alreadyAdded = false;
5943 for(MUint i = 0; i < diagonalJumpCells.size(); i++) {
5944 if(diagonalJumpCells[i].first == grid().tree().neighbor(ngbParent2, dir2)) {
5945 alreadyAdded = true;
5946 break;
5947 }
5948 }
5949 if(alreadyAdded) {
5950 ASSERT(id > -1, "");
5951 continue;
5952 }
5953 // add diagonal neighbor to the list
5954 diagonalJumpCells.emplace_back(make_pair(grid().tree().neighbor(ngbParent2, dir2), 2));
5955 if(id < 0) {
5956 // added new as levelJump-candidate:
5957 id = m_cutLvlJumpCandidates.size();
5958 m_cutLvlJumpCandidates.emplace_back();
5959 m_cutLvlJumpCandidates[id].candId = cnd;
5960 // find childId of the cell in relation to its parent
5961 MInt child = -1;
5962 for(child = 0; child < m_maxNoChilds; child++) {
5963 const MInt childCellId = grid().tree().child(parentId, child);
5964 if(childCellId == cellId) break;
5965 }
5966 m_cutLvlJumpCandidates[id].childId = child;
5967 // add parent as additional cutCandidate once
5968 if(candidateIds[parentId] < 0) {
5969 const MInt newId = candidates.size();
5970 candidates.emplace_back();
5971 candidates[newId].cellId = parentId;
5972 candidates[newId].isbndryLvlJumpParent = true;
5973 candidateIds[parentId] = newId;
5974 } else {
5975 if(!candidates[candidateIds[parentId]].isbndryLvlJumpParent) {
5976 candidates[candidateIds[parentId]].isbndryLvlJumpParent = true;
5977 }
5978 }
5979 const MInt parentCandId = candidateIds[parentId];
5980 ASSERT(parentCandId > -1, "");
5981 m_cutLvlJumpCandidates[id].parentCandId = parentCandId;
5982 }
5983 const MInt noJumps = m_cutLvlJumpCandidates[id].noJumps;
5984 m_cutLvlJumpCandidates[id].neighborType[noJumps] = 2;
5985 // store diagonal relation
5986 m_cutLvlJumpCandidates[id].dirs[noJumps] = dir;
5987 m_cutLvlJumpCandidates[id].diagonalDirs[noJumps] = dir1;
5988 m_cutLvlJumpCandidates[id].noJumps++;
5989
5990#ifdef CutCell_DEBUG
5991 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
5992 cerr << "Adding type2: " << dir << " " << dir1 << " " << dir2 << " "
5993 << grid().tree().globalId(grid().tree().neighbor(ngbParent2, dir1)) << " " << noJumps
5994 << endl;
5995 }
5996#endif
5997 }
5998 }
5999 }
6000 }
6001 }
6002 }
6003 }
6004 }
6005
6006 ASSERT(noCandidates <= (signed)candidates.size(), "");
6007
6008 const MInt nodeStencil[3][8] = {{0, 1, 0, 1, 0, 1, 0, 1}, {2, 2, 3, 3, 2, 2, 3, 3}, {4, 4, 4, 4, 5, 5, 5, 5}};
6009
6010 const MInt reverseNode[3][8] = {{1, 0, 3, 2, 5, 4, 7, 6}, {2, 3, 0, 1, 6, 7, 4, 5}, {4, 5, 6, 7, 0, 1, 2, 3}};
6011
6012 MInt nghbrIds[m_noCorners]{};
6013 MInt nghbrNodes[m_noCorners]{};
6014
6015 for(MInt cnd = 0; cnd < (signed)candidates.size(); cnd++) {
6016 const MInt cellId = candidates[cnd].cellId;
6017
6018 // setCandidate-properties:
6019 candidates[cnd].isGapCell = gapPropertyField[cellId];
6020 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6021 if(bodyIdField != nullptr) {
6022 candidates[cnd].associatedBodyIds[set] = bodyIdField[IDX_LSSETMB(cellId, set)];
6023 }
6024 }
6025
6026 for(MInt node = 0; node < m_noCorners; node++) {
6027 if(candidates[cnd].nodeValueSet[node]) continue;
6028 // b) Add all neighbors and the corresponding nodes from the node-loop to the list
6029
6030 MInt noNeighborsPerNode = 0;
6031
6032 nghbrIds[noNeighborsPerNode] = cellId;
6033 nghbrNodes[noNeighborsPerNode] = node;
6034 noNeighborsPerNode++;
6035
6036 for(MInt i = 0; i < nDim; i++) {
6037 const MInt firstDir = nodeStencil[i][node];
6038 const MInt firstNghbrNode = reverseNode[i][node];
6039 const MInt firstNghbrId = grid().tree().neighbor(cellId, firstDir);
6040 if(firstNghbrId > -1) {
6041 nghbrIds[noNeighborsPerNode] = firstNghbrId;
6042 nghbrNodes[noNeighborsPerNode] = firstNghbrNode;
6043 noNeighborsPerNode++;
6044 for(MInt j = i + 1; j < nDim; j++) {
6045 const MInt secondDir = nodeStencil[j][node];
6046 if(secondDir == firstDir) continue;
6047 const MInt secondNghbrNode = reverseNode[j][firstNghbrNode];
6048 const MInt secondNghbrId = grid().tree().neighbor(firstNghbrId, secondDir);
6049 if(secondNghbrId > -1) {
6050 nghbrIds[noNeighborsPerNode] = secondNghbrId;
6051 nghbrNodes[noNeighborsPerNode] = secondNghbrNode;
6052 noNeighborsPerNode++;
6053 IF_CONSTEXPR(nDim == 3) {
6054 for(MInt k = j + 1; k < nDim; k++) {
6055 const MInt thirdDir = nodeStencil[k][node];
6056 if(thirdDir == firstDir || thirdDir == secondDir) continue;
6057 const MInt thirdNghbrNode = reverseNode[k][secondNghbrNode];
6058 const MInt thirdNghbrId = grid().tree().neighbor(secondNghbrId, thirdDir);
6059 if(thirdNghbrId > -1) {
6060 nghbrIds[noNeighborsPerNode] = thirdNghbrId;
6061 nghbrNodes[noNeighborsPerNode] = thirdNghbrNode;
6062 noNeighborsPerNode++;
6063 }
6064 }
6065 }
6066 }
6067 }
6068 }
6069 }
6070
6071 MBool gapBoundary = false;
6072 MBool setBoundary = false;
6073
6074 // ensure the same NodeValues at Gap-NoGap-Node-Boundaries!
6075 // important for 3D-CutCells!
6076 // Otherwise, the number of CutPoints doesn't match the nodalLSValues!
6077 // however, this means that nodes of cells, which are not a gapCell but a gapBoundary node
6078 // will still be using the effective G0-set!
6079 if(gapClosure) {
6080 const MBool isGapCell = gapPropertyField[cellId];
6081 for(MInt nghbrNode = 0; nghbrNode < noNeighborsPerNode; nghbrNode++) {
6082 const MBool isGapNghbr = gapPropertyField[nghbrIds[nghbrNode]];
6083
6084 if(isGapCell != isGapNghbr) {
6085 gapBoundary = true;
6086 }
6087 }
6088 const MInt bodyId = bodyIdField[IDX_LSSETMB(cellId, 0)];
6089 for(MInt nghbrNode = 0; nghbrNode < noNeighborsPerNode; nghbrNode++) {
6090 const MInt bodyIdNghbr = bodyIdField[IDX_LSSETMB(nghbrIds[nghbrNode], 0)];
6091 if(bodyId != bodyIdNghbr) setBoundary = true;
6092 }
6093 }
6094
6095 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6096 // interpolate scalar field value
6097 MFloat phi = F0;
6098 for(MInt nghbrNode = 0; nghbrNode < noNeighborsPerNode; nghbrNode++) {
6099 MInt usedSet = set;
6100
6101 if(gapBoundary) {
6102 const MInt bodyIdNghbr = bodyIdField[IDX_LSSETMB(nghbrIds[nghbrNode], 0)];
6103 // const MInt bodyId = bodyIdField[IDX_LSSETMB( cellId, 0) ];
6104 if(!setBoundary) {
6105 // if a gapBoundary: use the G0-Set for the set matching the associated body!
6106 if(m_bodyToSetTable[bodyIdNghbr] == set) usedSet = 0;
6107 } else {
6108 // if a gap- and setBoundary-Node:
6109 // the node-values must use the G0-Set for any of the two bodies!
6110 // if(m_bodyToSetTable[bodyIdNghbr] == set || m_bodyToSetTable[bodyId] == set ) {
6111 usedSet = 0;
6112 //}
6113 }
6114 }
6115
6116 phi += scalarField[IDX_LSSETMB(nghbrIds[nghbrNode], usedSet)];
6117 }
6118
6119 phi /= noNeighborsPerNode;
6120
6121 for(MInt nghbrNode = 0; nghbrNode < noNeighborsPerNode; nghbrNode++) {
6122 const MInt nghbrCand = candidateIds[nghbrIds[nghbrNode]];
6123 if(nghbrCand < 0) continue;
6124 candidates[nghbrCand].nodeValueSet[nghbrNodes[nghbrNode]] = true;
6125 candidates[nghbrCand].nodalValues[set][nghbrNodes[nghbrNode]] = phi;
6126 }
6127 }
6128
6129#ifdef CutCell_DEBUG
6130 for(MInt nghbrNode = 0; nghbrNode < noNeighborsPerNode; nghbrNode++) {
6131 if(gapBoundary) {
6132 const MInt candidateId = candidateIds[nghbrIds[nghbrNode]];
6133 if(candidateId < 0) continue;
6134 const MInt cellId2 = candidates[candidateId].cellId;
6135 ASSERT(cellId2 == nghbrIds[nghbrNode], "");
6136 const MInt set = m_bodyToSetTable[bodyIdField[IDX_LSSETMB(cellId2, 0)]];
6137 if(abs(candidates[candidateId].nodalValues[0][nghbrNodes[nghbrNode]]
6138 - candidates[candidateId].nodalValues[set][nghbrNodes[nghbrNode]])
6139 > 0.0000008)
6140 cerr << "ERROR in Node-LS-Values " << cellId2 << " globalId " << grid().tree().globalId(cellId2) << " "
6141 << grid().tree().globalId(cellId) << " "
6142 << candidateId /*<< " isHalo " << a_isHalo(cellId2) << " " << a_isHalo(cellId) */
6143 << " Gap " << candidates[cnd].isGapCell << " " << candidates[candidateId].isGapCell << " BodyId "
6144 << candidates[cnd].associatedBodyIds[0] << " " << candidates[candidateId].associatedBodyIds[0] << " "
6145 << nghbrNode << endl;
6146 }
6147 }
6148#endif
6149 }
6150 }
6151
6152 if(m_bndryLvlJumps && !m_cutLvlJumpCandidates.empty()) {
6153 correctNodalValuesAtLevelJump(candidates, candidateIds);
6154 }
6155
6156 // remove bndryJumpCellParents
6157 for(MInt cnd = noCandidates; cnd < (signed)candidates.size(); cnd++) {
6158 const MInt parentId = candidates[cnd].cellId;
6159 ASSERT(candidates[cnd].isbndryLvlJumpParent, "");
6160 candidateIds[parentId] = -1;
6161 }
6162
6163 candidates.resize(noCandidates);
6164}
6165
6166
6171template <MInt nDim_>
6173 const MInt* noMaxLevelWindowCells,
6174 const MInt** maxLevelHaloCells,
6175 std::vector<CutCandidate<nDim>>& candidates,
6176 MInt* candidateIds) {
6177 TRACE();
6178
6179 auto* mpi_send_req = new MPI_Request[grid().noNeighborDomains()];
6180 auto* mpi_recv_req = new MPI_Request[grid().noNeighborDomains()];
6181
6182 MIntScratchSpace sendBufferSize(grid().noNeighborDomains(), AT_, "sendBufferSize");
6183 MIntScratchSpace receiveBufferSize(grid().noNeighborDomains(), AT_, "receiveBufferSize");
6184
6185 MIntScratchSpace sendBuffersInt(grid().noNeighborDomains(), AT_, "sendBuffersInt");
6186 MIntScratchSpace receiveBuffersInt(grid().noNeighborDomains(), AT_, "receiveBuffersInt");
6187
6188 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6189 mpi_send_req[i] = MPI_REQUEST_NULL;
6190 mpi_recv_req[i] = MPI_REQUEST_NULL;
6191 }
6192
6193 // 0. gather information about the number of values to be exchanged:
6194 MInt sendBufferCounter;
6195 MInt sendBufferCounterOverall = 0;
6196 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6197 sendBufferCounter = 0;
6198 sendBufferCounter++;
6199 for(MInt j = 0; j < noMaxLevelWindowCells[i]; j++) {
6200 const MInt cellId = maxLevelWindowCells[i][j];
6201 const MInt cndId = candidateIds[cellId];
6202 if(cndId < 0) continue;
6203 for(MInt node = 0; node < m_noCorners; node++) {
6204 ASSERT(candidates[cndId].nodeValueSet[node], "");
6205 }
6206
6207 //+check
6208 sendBufferCounter++;
6209
6210 //+nodalvalues
6211 sendBufferCounter += m_noLevelSetsUsedForMb * m_noCorners;
6212
6213 //+isGapCell
6214 sendBufferCounter++;
6215
6216 //+associatedBodyIds
6217 sendBufferCounter += m_noLevelSetsUsedForMb;
6218 }
6219 sendBufferSize[i] = sendBufferCounter;
6220 sendBuffersInt[i] = sendBufferCounter;
6221 sendBufferCounterOverall += sendBufferCounter;
6222 }
6223
6224 // 0.a. exchange number data solvers to be exchanged:
6225 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6226 MPI_Irecv(&receiveBuffersInt[i], 1, MPI_INT, grid().neighborDomain(i), 2, grid().mpiComm(), &mpi_recv_req[i], AT_,
6227 "receiveBuffers[i]");
6228 }
6229 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6230 MPI_Isend(&sendBuffersInt[i], 1, MPI_INT, grid().neighborDomain(i), 2, grid().mpiComm(), &mpi_send_req[i], AT_,
6231 "sendBuffersInt[i]");
6232 }
6233 MPI_Waitall(grid().noNeighborDomains(), mpi_recv_req, MPI_STATUSES_IGNORE, AT_);
6234 MPI_Waitall(grid().noNeighborDomains(), mpi_send_req, MPI_STATUSES_IGNORE, AT_);
6235
6236 // 0.b setup real exchange framework:
6237 MInt receiveBufferCounterOverall = 0;
6238 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6239 receiveBufferCounterOverall += receiveBuffersInt[i];
6240 receiveBufferSize[i] = receiveBuffersInt[i];
6241 }
6242
6243 MFloatScratchSpace sendBuffersOverall(sendBufferCounterOverall, AT_, "sendBuffersOverall");
6244 MFloatScratchSpace receiveBuffersOverall(receiveBufferCounterOverall, AT_, "receiveBuffersOverall");
6245 MFloatPointerScratchSpace sendBuffers(grid().noNeighborDomains(), AT_, "sendBuffers");
6246 MFloatPointerScratchSpace receiveBuffers(grid().noNeighborDomains(), AT_, "receiveBuffers");
6247 MInt counterSend = 0;
6248 MInt counterReceive = 0;
6249 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6250 sendBuffers.p[i] = &sendBuffersOverall.p[counterSend];
6251 counterSend += sendBufferSize[i];
6252 receiveBuffers.p[i] = &receiveBuffersOverall.p[counterReceive];
6253 counterReceive += receiveBufferSize[i];
6254 }
6255
6256 // sicherheitshalber zuruecksetzen
6257 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6258 mpi_send_req[i] = MPI_REQUEST_NULL;
6259 mpi_recv_req[i] = MPI_REQUEST_NULL;
6260 }
6261 // 1. gather relevant information
6262 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6263 sendBufferCounter = 0;
6264 sendBuffers[i][0] = (MFloat)(-1);
6265 sendBufferCounter++;
6266 for(MInt j = 0; j < noMaxLevelWindowCells[i]; j++) {
6267 const MInt cellId = maxLevelWindowCells[i][j];
6268 const MInt cndId = candidateIds[cellId];
6269 if(cndId < 0) continue;
6270 // check
6271 sendBuffers[i][sendBufferCounter] = (MFloat)j;
6272 sendBufferCounter++;
6273 // nodalValues
6274 for(MInt node = 0; node < m_noCorners; node++) {
6275 ASSERT(candidates[cndId].nodeValueSet[node], "");
6276 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6277 sendBuffers[i][sendBufferCounter] = candidates[cndId].nodalValues[set][node];
6278 sendBufferCounter++;
6279 }
6280 }
6281 // isGapCell
6282 sendBuffers[i][sendBufferCounter] = (MFloat)candidates[cndId].isGapCell;
6283 sendBufferCounter++;
6284 // associatedBodyIds
6285 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6286 sendBuffers[i][sendBufferCounter] = (MFloat)candidates[cndId].associatedBodyIds[set];
6287 sendBufferCounter++;
6288 }
6289 }
6290 sendBufferSize[i] = sendBufferCounter;
6291 sendBuffers[i][0] = (MFloat)(sendBufferCounter);
6292 }
6293
6294
6295 // 2. receive data
6296 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6297 MInt bufSize = receiveBufferSize[i];
6298 MPI_Irecv(receiveBuffers[i], bufSize, MPI_DOUBLE, grid().neighborDomain(i), 2, grid().mpiComm(), &mpi_recv_req[i],
6299 AT_, "receiveBuffers[i]");
6300 }
6301
6302 // 3. send data
6303 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6304 MInt bufSize = sendBufferSize[i];
6305 MPI_Isend(sendBuffers[i], bufSize, MPI_DOUBLE, grid().neighborDomain(i), 2, grid().mpiComm(), &mpi_send_req[i], AT_,
6306 "sendBuffers[i]");
6307 }
6308 MPI_Waitall(grid().noNeighborDomains(), mpi_recv_req, MPI_STATUSES_IGNORE, AT_);
6309 MPI_Waitall(grid().noNeighborDomains(), mpi_send_req, MPI_STATUSES_IGNORE, AT_);
6310
6311
6312 // 4. store recieved data
6313 MInt receiveBufferCounter = 0;
6314 MInt j = -1;
6315 for(MInt i = 0; i < grid().noNeighborDomains(); i++) {
6316 receiveBufferCounter = 0;
6317 if(receiveBufferSize[i] != receiveBuffersInt[i]) {
6318 mTerm(1, AT_, " receiveBufferSize doesn't match expected size from previous communication! ");
6319 }
6320 if(receiveBufferSize[i] == 0) {
6321 m_log << "Warning: empty message from rank " << grid().neighborDomain(i) << endl;
6322 }
6323 receiveBufferCounter++;
6324 while(receiveBufferCounter < receiveBufferSize[i]) {
6325 j = (MInt)receiveBuffers[i][receiveBufferCounter];
6326 receiveBufferCounter++;
6327 const MInt cellId = maxLevelHaloCells[i][j];
6328 MBool skip = false;
6329
6330 if(cellId > grid().tree().size()) skip = true;
6331 if(!skip) {
6332 // add halo-cutCandidate
6333 const MInt candId = candidates.size();
6334 candidates.emplace_back();
6335 candidates[candId].cellId = cellId;
6336
6337 // add infomation from computeNodalvalues:
6338 for(MInt node = 0; node < m_noCorners; node++) {
6339 candidates[candId].nodeValueSet[node] = true;
6340 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6341 candidates[candId].nodalValues[set][node] = receiveBuffers[i][receiveBufferCounter];
6342 receiveBufferCounter++;
6343 }
6344 }
6345
6346 candidates[candId].isGapCell = (MInt)receiveBuffers[i][receiveBufferCounter];
6347 receiveBufferCounter++;
6348
6349 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6350 candidates[candId].associatedBodyIds[set] = (MInt)receiveBuffers[i][receiveBufferCounter];
6351 receiveBufferCounter++;
6352 }
6353
6354 candidateIds[cellId] = candId;
6355
6356
6357 } else {
6358 receiveBufferCounter += m_noLevelSetsUsedForMb * m_noCorners;
6359 }
6360 }
6361 }
6362
6363 delete[] mpi_send_req;
6364 delete[] mpi_recv_req;
6365}
6366
6373template <>
6375 std::vector<CutCell<nDim>>& cutCellData,
6376 std::vector<MInt>
6377 cutCellIdMapping) {
6378 TRACE();
6379
6380 const MInt faceCornerMapping[6][4] = {{2, 6, 4, 0}, {1, 5, 7, 3}, {0, 4, 5, 1},
6381 {3, 7, 6, 2}, {2, 3, 1, 0}, {6, 7, 5, 4}};
6382 using CC = CutCell<nDim>;
6383
6384 ASSERT(m_noLevelSetsUsedForMb <= CC::maxNoSets, "");
6385
6386 for(MInt cndt = 0; cndt < (signed)candidates.size(); cndt++) {
6387 if(candidates[cndt].noCutPoints < nDim) continue;
6388
6389 const MInt cutCell = cutCellData.size();
6390 const MInt cellId = candidates[cndt].cellId;
6391
6392 cutCellIdMapping[cellId] = cndt;
6393
6394 cutCellData.emplace_back();
6395 cutCellData[cutCell].cellId = cellId;
6396 cutCellData[cutCell].isGapCell = candidates[cndt].isGapCell;
6397 ASSERT(candidates[cndt].noCutPoints <= CC::maxNoCutPoints, "");
6398 cutCellData[cutCell].noCutPoints = candidates[cndt].noCutPoints;
6399 for(MInt cp = 0; cp < candidates[cndt].noCutPoints; cp++) {
6400 for(MInt i = 0; i < nDim; i++) {
6401 cutCellData[cutCell].cutPoints[cp][i] = candidates[cndt].cutPoints[cp][i];
6402 }
6403 cutCellData[cutCell].cutBodyIds[cp] = candidates[cndt].cutBodyIds[cp];
6404 cutCellData[cutCell].cutEdges[cp] = candidates[cndt].cutEdges[cp];
6405 }
6406
6407 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6408 cutCellData[cutCell].associatedBodyIds[set] = candidates[cndt].associatedBodyIds[set];
6409
6410 for(MInt k = 0; k < CC::noFaces; k++) {
6411 MFloat phi = F0;
6412 for(MInt j = 0; j < 4; j++) {
6413 phi += F1B4 * candidates[cndt].nodalValues[set][faceCornerMapping[k][j]];
6414 }
6415 cutCellData[cutCell].faceCentroidIsInsideGeometry[set][k] = (phi < F0);
6416 }
6417 }
6418
6419 MInt startSet = 0;
6420 MInt endSet = 1;
6421 if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (!cutCellData[cutCell].isGapCell)) {
6422 startSet = 1;
6423 endSet = m_noLevelSetsUsedForMb;
6424 }
6425
6426 for(MInt node = 0; node < m_noCorners; node++) {
6427 ASSERT(candidates[cndt].nodeValueSet[node], "");
6428 MBool isInside = false;
6429 for(MInt set = startSet; set < endSet; set++) {
6430 const MBool isInsideSet = candidates[cndt].nodalValues[set][node] < F0;
6431 isInside = isInside || isInsideSet;
6432 cutCellData[cutCell].cornerIsInsideGeometry[set][node] = isInsideSet;
6433 }
6434 cutCellData[cutCell].cornerIsInsideGeometry[0][node] = isInside;
6435 }
6436 }
6437}
6438
6439
6447template <MInt nDim_>
6449 TRACE();
6450
6451 if(candidates.empty()) return;
6452
6453 // NOTE: as this is stl-dependand, the unscaled regular cutCells need to be used!
6454 m_scaledCutCell = false;
6455
6456 const MInt DOFStencil[12] = {1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2};
6457
6458 const MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
6459 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
6460
6461 const MInt nodeStencil[2][12] = {{0, 1, 0, 2, 4, 5, 4, 6, 0, 1, 2, 3}, {2, 3, 1, 3, 6, 7, 5, 7, 4, 5, 6, 7}};
6462
6463 const MFloat epsilon = 0.00000000001;
6464 const MInt maxNoCutPointsPerEdge = 10;
6465 std::array<MFloat, nDim> a;
6466 std::array<MFloat, nDim> b;
6467 std::array<MFloat, nDim> c;
6468 std::array<MFloat, nDim> d;
6469 std::array<MFloat, nDim> e;
6470 std::array<MFloat, nDim> pP;
6471
6472 MFloat target[nDim * 2];
6473 MFloat corners[m_noCorners][nDim];
6474
6475 MFloatScratchSpace cutPointsEdge(maxNoCutPointsPerEdge, nDim, AT_, "cutPointsEdge");
6476
6477
6478 //--- end of initialization
6479 const MInt m_maxNoBndryCndIds = 100;
6480
6481 MInt noBndryCndIds = 0;
6482 MInt bndryCndIds[m_maxNoBndryCndIds]{};
6483
6484
6485 // first loop over all bndry cells
6486 for(MInt cndt = 0; cndt < (signed)candidates.size(); cndt++) {
6487 ASSERT(candidates[cndt].noCutPoints == 0, "");
6488 const MInt cellId = candidates[cndt].cellId;
6489 // assiciatedBodyId[0] corresponds with bndryCndId and is initialised!
6490 candidates[cndt].associatedBodyIds[0] = std::numeric_limits<MInt>::max();
6491
6492 ASSERT(cellId < grid().tree().size(), "");
6493 // if(!grid().tree().isLeafCell(cellId)) continue;
6494 if(grid().tree().noChildren(cellId) > 0) continue;
6495 const MFloat cellLength = a_cellLengthAtCell(cellId);
6496 const MFloat cellHalfLength = F1B2 * cellLength;
6497
6498 const MFloat eps = cellLength / 10000000.0;
6499
6500 // compute cell corners -> will be used for cut point computation
6501 for(MInt node = 0; node < m_noCorners; node++) {
6502 for(MInt i = 0; i < nDim; i++) {
6503 corners[node][i] = grid().tree().coordinate(cellId, i) + signStencil[node][i] * cellHalfLength;
6504 }
6505 }
6506
6507 // define target around corners of current cell
6508 for(MInt i = 0; i < nDim; i++) {
6509 target[i] = grid().tree().coordinate(cellId, i) - cellHalfLength * 1.05;
6510 target[i + nDim] = grid().tree().coordinate(cellId, i) + cellHalfLength * 1.05;
6511 }
6512
6513 // get all triangles in currentCell (target)
6514 std::vector<MInt> nodeList;
6515 if(m_gridCutTest == "SAT") {
6516 geometry().getIntersectionElements(target, nodeList, cellHalfLength, &a_coordinate(cellId, 0));
6517 } else {
6518 geometry().getIntersectionElements(target, nodeList);
6519 }
6520
6521
6522 // loop over all edges
6523 for(MInt edge = 0; edge < m_noEdges; edge++) {
6524 const MInt edgeDOF = DOFStencil[edge]; // edge's degree of freedom
6525
6526 ASSERT(candidates[cndt].noCutPointsOnEdge[edge] == 0, "");
6527
6528 MBool edgeCut = false;
6529
6530 // compute end points of edge
6531 for(MInt i = 0; i < nDim; i++) {
6532 d[i] = corners[nodeStencil[0][edge]][i];
6533 e[i] = corners[nodeStencil[1][edge]][i];
6534 }
6535
6536 // check for edge-triangle intersection
6537 for(MInt n = 0; n < (signed)nodeList.size(); n++) {
6538 MBool cutsEdge = false;
6539
6540 IF_CONSTEXPR(nDim == 3) {
6541 const MInt spaceId = (edgeDOF + 1) % nDim;
6542 const MInt spaceId1 = (edgeDOF + 2) % nDim;
6543 const MInt spaceId2 = edgeDOF;
6544 // find out if element cuts edge; if yes, compute cut point -> 3D part
6545 MFloat p = F0;
6546 MFloat q = F0;
6547 for(MInt k = 0; k < nDim; k++) {
6548 a[k] = m_geometry->elements[nodeList[n]].m_vertices[0][k];
6549 b[k] = m_geometry->elements[nodeList[n]].m_vertices[1][k];
6550 c[k] = m_geometry->elements[nodeList[n]].m_vertices[2][k];
6551 }
6552 if(approx(a[spaceId1], b[spaceId1], MFloatEps) && !approx(a[spaceId1], c[spaceId1], MFloatEps)) {
6553 // aspaceId != bspaceId, otherwise a and b would be the same point
6554 q = (d[spaceId1] - a[spaceId1]) / (c[spaceId1] - a[spaceId1]);
6555 p = (d[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
6556 } else {
6557 if(!approx(a[spaceId1], b[spaceId1], MFloatEps) && approx(a[spaceId1], c[spaceId1], MFloatEps)) {
6558 // aspaceId != cspaceId, otherwise a and c would be the same point
6559 p = (d[spaceId1] - a[spaceId1]) / (b[spaceId1] - a[spaceId1]);
6560 q = (d[spaceId] - a[spaceId] - p * (b[spaceId] - a[spaceId])) / (c[spaceId] - a[spaceId]);
6561 } else {
6562 if(approx(a[spaceId], b[spaceId], MFloatEps) && !approx(a[spaceId], c[spaceId], MFloatEps)) {
6563 // aspaceId1 != bspaceId1, otherwise a and b would be the same point
6564 q = (d[spaceId] - a[spaceId]) / (c[spaceId] - a[spaceId]);
6565 p = (d[spaceId1] - a[spaceId1] - q * (c[spaceId1] - a[spaceId1])) / (b[spaceId1] - a[spaceId1]);
6566 } else {
6567 if(!approx(a[spaceId], b[spaceId], MFloatEps) && approx(a[spaceId], c[spaceId], MFloatEps)) {
6568 // aspaceId1 != cspaceId1, otherwise a and c would be the same point
6569 p = (d[spaceId] - a[spaceId]) / (b[spaceId] - a[spaceId]);
6570 q = (d[spaceId1] - a[spaceId1] - p * (b[spaceId1] - a[spaceId1])) / (c[spaceId1] - a[spaceId1]);
6571 } else {
6572 // aspaceId1 != bspaceId1 && aspaceId1 != cspaceId1 && aspaceId != bspaceId && aspaceId != cspaceId
6573 q = ((d[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
6574 - (b[spaceId1] - a[spaceId1]) * (d[spaceId] - a[spaceId]))
6575 / ((c[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
6576 - (b[spaceId1] - a[spaceId1]) * (c[spaceId] - a[spaceId]));
6577 p = (d[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
6578 }
6579 }
6580 }
6581 }
6582
6583
6584 if(p * q >= 0 || p * q < 0) {
6585 // compute s
6586 MFloat gamma = a[spaceId2] + p * (b[spaceId2] - a[spaceId2]) + q * (c[spaceId2] - a[spaceId2]);
6587 MFloat s = (gamma - d[spaceId2]) / (e[spaceId2] - d[spaceId2]);
6588
6589 if(s < -epsilon || s > F1 + epsilon || p < -epsilon || q < -epsilon || (p + q) > F1 + epsilon) {
6590 } else {
6591 cutsEdge = true;
6592 // cut point pP
6593 if(candidates[cndt].noCutPointsOnEdge[edge] < maxNoCutPointsPerEdge) {
6594 for(MInt k = 0; k < nDim; k++) {
6595 pP[k] = d[k] + s * (e[k] - d[k]);
6596 cutPointsEdge(candidates[cndt].noCutPointsOnEdge[edge], k) = pP[k];
6597 }
6598 } else {
6599 mTerm(1, AT_, " Too many cut points on edge...");
6600 }
6601 }
6602 }
6603 }
6604 else { // 2D code
6605 if(geometry().edgeTriangleIntersection(geometry().elements[nodeList[n]].m_vertices[0],
6606 geometry().elements[nodeList[n]].m_vertices[1], nullptr, d.data(),
6607 e.data())) {
6608 for(MInt k = 0; k < nDim; k++) {
6609 a[k] = geometry().elements[nodeList[n]].m_vertices[0][k];
6610 b[k] = geometry().elements[nodeList[n]].m_vertices[1][k];
6611 }
6612
6613 MFloat gamma = (b[0] - a[0]) * (d[1] - e[1]) - (d[0] - e[0]) * (b[1] - a[1]);
6614 if(ABS(gamma) < 0.0000000000001) continue;
6615 MFloat s1 = ((d[0] - e[0]) * (a[1] - d[1]) - (d[1] - e[1]) * (a[0] - d[0])) / gamma;
6616 MFloat s2 = ((b[0] - a[0]) * (d[1] - a[1]) - (d[0] - a[0]) * (b[1] - a[1])) / gamma;
6617
6618 cutsEdge = true;
6619
6620 // cut point pP
6621 if(candidates[cndt].noCutPointsOnEdge[edge] < maxNoCutPointsPerEdge) {
6622 for(MInt k = 0; k < nDim; k++) {
6623 if(s1 * s1 < s2 * s2)
6624 pP[k] = d[k] + s2 * (e[k] - d[k]);
6625 else
6626 pP[k] = a[k] + s1 * (b[k] - a[k]);
6627 cutPointsEdge(candidates[cndt].noCutPointsOnEdge[edge], k) = pP[k];
6628 }
6629 } else {
6630 mTerm(1, AT_, " Too many cut points on edge...");
6631 }
6632 }
6633 }
6634
6635 if(cutsEdge) {
6636 // store cut point
6637 if(candidates[cndt].noCutPoints < m_noEdges) {
6638 // set boundary condition (the one with the lowest Id)!
6639 const MInt bndCndId = geometry().elements[nodeList[n]].m_bndCndId;
6640 if(bndCndId < candidates[cndt].associatedBodyIds[0]) {
6641 candidates[cndt].associatedBodyIds[0] = bndCndId;
6642 MBool newBndryCnd = true;
6643 for(MInt j = 0; j < noBndryCndIds; j++) {
6644 if(bndryCndIds[j] == bndCndId) {
6645 newBndryCnd = false;
6646 break;
6647 }
6648 }
6649 if(newBndryCnd) {
6650 ASSERT(noBndryCndIds < m_maxNoBndryCndIds, "Too many different boundary conditions...");
6651 bndryCndIds[noBndryCndIds] = bndCndId;
6652 noBndryCndIds++;
6653 }
6654 }
6655 if(edgeCut) {
6656 // if this edge has already one cut point, check if the new cut point is a different one
6657 // if the cut point is identical to onother one, special treatment is needed
6658
6659 MBool newCutPoint = true;
6660 for(MInt i = 0; i < candidates[cndt].noCutPointsOnEdge[edge]; i++) {
6661 MBool equal = (ABS(pP[0] - cutPointsEdge(i, 0)) < eps && ABS(pP[1] - cutPointsEdge(i, 1)) < eps);
6662 IF_CONSTEXPR(nDim == 3) equal = (equal && (ABS(pP[2] - cutPointsEdge(i, 2)) < eps));
6663 if(equal) {
6664 newCutPoint = false;
6665 break;
6666 }
6667 }
6668
6669 if(newCutPoint) {
6670 candidates[cndt].noCutPoints--;
6671 m_log << "removing two cut points, cell " << cellId << " edge " << edge << endl;
6672 m_log << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " ";
6673 IF_CONSTEXPR(nDim == 3) m_log << a_coordinate(cellId, 2) << endl;
6674 edgeCut = false;
6675 candidates[cndt].noCutPointsOnEdge[edge]++;
6676 } else {
6677 // coinciding cut points
6678 // ignoring one cut point
6679 }
6680 } else {
6681 // check, if cut point is really new!
6682 MBool newCutPoint = true;
6683 for(MInt i = 0; i < candidates[cndt].noCutPointsOnEdge[edge]; i++) {
6684 MBool equal = (ABS(pP[0] - cutPointsEdge(i, 0)) <= eps && ABS(pP[1] - cutPointsEdge(i, 1)) <= eps);
6685 IF_CONSTEXPR(nDim == 3) equal = (equal && (ABS(pP[2] - cutPointsEdge(i, 2)) <= eps));
6686 if(equal) {
6687 newCutPoint = false;
6688 }
6689 }
6690 if(newCutPoint) {
6691 edgeCut = true;
6692 // store cut points in the data structure
6693 const MInt cutPointNo = candidates[cndt].noCutPoints;
6694 candidates[cndt].cutEdges[cutPointNo] = edge;
6695 candidates[cndt].cutBodyIds[cutPointNo] = 0;
6696 for(MInt i = 0; i < nDim; i++) {
6697 candidates[cndt].cutPoints[cutPointNo][i] = pP[i];
6698 }
6699 candidates[cndt].noCutPoints++;
6700 candidates[cndt].noCutPointsOnEdge[edge]++;
6701 }
6702 }
6703 } else {
6704 cerr << "** Warning fvbndrycndxd: " << endl;
6705 cerr << "cell " << cellId << endl;
6706 cerr << " -> Boundary candidate " << cndt << " has more than " << m_noEdges << " cut points" << endl;
6707 cerr << " -> Additional cut points are neglected" << endl;
6708 cerr << cellId << " " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " ";
6709 IF_CONSTEXPR(nDim == 3) cerr << a_coordinate(cellId, 2) << " ";
6710 cerr << grid().tree().level(cellId) << endl;
6711 mTerm(1, AT_, "Boundary cell has more than m_noEdges cut points");
6712 }
6713 }
6714 } // loop over entity-nodes
6715 } // loop over all edges
6716 } // loop over all cut candidates
6717
6718 m_scaledCutCell = true;
6719}
6720
6726template <MInt nDim_>
6728 const MInt* candidateIds) {
6729 // NOTE: it is not possible to copy node values from a neighbor!
6730 // the neighbor might be a halo-cell and thus its node value not set on this rank before
6731 // the exchange, only its cell-centered value is available!
6732 // => only copy values from the parent-node!
6733
6734#ifdef CutCell_DEBUG
6735 const MInt debugTimeStep = -2;
6736 const MInt debugGlobalId = 216221;
6737
6738 for(MInt cellId = 0; cellId < grid().tree().size(); cellId++) {
6739 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
6740 const MInt cand = candidateIds[cellId];
6741 if(cand < 0) break;
6742 cerr << " Original node-values: ";
6743 for(MInt node = 0; node < m_noCorners; node++) {
6744 cerr << candidates[cand].nodalValues[0][node] << " ";
6745 }
6746 cerr << endl;
6747 }
6748 }
6749#else
6750 std::ignore = candidateIds[0];
6751#endif
6752
6753 ASSERT(nDim == 3 && nDim_ == 3, "Intended otherwise!");
6754
6755 // returns node which matches for child and parent for the specified childPosition
6756 //{7, 6, 5, 4, 3, 2, 1, 0}
6757 const constexpr MInt childParentNode[8] = {0, 1, 2, 3, 4, 5, 6, 7};
6758
6759 const constexpr MInt faceCornerCode[6][4] = {{0, 2, 6, 4}, {3, 1, 5, 7}, {1, 0, 4, 5},
6760 {2, 3, 7, 6}, {0, 1, 3, 2}, {5, 4, 6, 7}};
6761
6762 // number of nodes which need to be corrected for each jump-direction!
6763 const constexpr MInt noCorrectNodes = nDim == 2 ? 2 : 4;
6764
6765 // returns the 2 corners of a edge
6766 const constexpr MInt edge2Corner[12][2] = {{0, 2}, {1, 3}, {0, 1}, {2, 3}, {4, 6}, {5, 7},
6767 {4, 5}, {6, 7}, {0, 4}, {1, 5}, {2, 6}, {3, 7}};
6768
6769 // returns the 3 edges of a corner 0 1 2 3 4 5 6 7
6770 const constexpr MInt corner2Edge[3][8] = {
6771 {0, 1, 0, 1, 4, 5, 4, 5}, {2, 2, 3, 3, 6, 6, 7, 7}, {8, 9, 10, 11, 8, 9, 10, 11}};
6772
6773 // recompute node values for nodes at the lvlJump interface
6774 for(MInt id = 0; id < (MInt)m_cutLvlJumpCandidates.size(); id++) {
6775 const MInt parentCand = m_cutLvlJumpCandidates[id].parentCandId;
6776 const MInt candId = m_cutLvlJumpCandidates[id].candId;
6777 const MInt cellId = candidates[candId].cellId;
6778 ASSERT(grid().tree().parent(cellId) == candidates[parentCand].cellId, "");
6779 ASSERT(candidates[parentCand].isbndryLvlJumpParent, "");
6780
6781 for(MInt node = 0; node < m_noCorners; node++) {
6782 ASSERT(candidates[parentCand].nodeValueSet[node], "");
6783 }
6784
6785 const MInt noJumps = m_cutLvlJumpCandidates[id].noJumps;
6786 ASSERT(noJumps <= 7 && noJumps > 0, to_string(noJumps));
6787
6788 const MInt childPos = m_cutLvlJumpCandidates[id].childId;
6789
6790#ifdef CutCell_DEBUG
6791 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
6792 cerr << "Cell-Info: noJumps" << noJumps << endl;
6793 for(MInt j = 0; j < noJumps; j++) {
6794 cerr << "dir " << m_cutLvlJumpCandidates[id].dirs[j] << " type " << m_cutLvlJumpCandidates[id].neighborType[j];
6795 }
6796 cerr << endl;
6797 }
6798#endif
6799
6800 // copy values from matching parent node (node == parentNode)
6801 const MInt parentNode = childParentNode[childPos];
6802 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6803 candidates[candId].nodalValues[set][parentNode] = candidates[parentCand].nodalValues[set][parentNode];
6804 }
6805
6806 const MInt parentEdgeIds[3] = {corner2Edge[0][parentNode], corner2Edge[1][parentNode], corner2Edge[2][parentNode]};
6807
6808#ifdef CutCell_DEBUG
6809 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
6810 cerr << " Child-Pos " << childPos << " setting (1) node " << parentNode << " to "
6811 << candidates[parentCand].nodalValues[0][parentNode] << endl;
6812 }
6813#endif
6814
6815 // loop over all jumps and correct the remaining nodal values in each jump-dir
6816 for(MInt j = 0; j < noJumps; j++) {
6817 const MInt jumpDir = m_cutLvlJumpCandidates[id].dirs[j];
6818 const MInt type = m_cutLvlJumpCandidates[id].neighborType[j];
6819
6820#ifdef CutCell_DEBUG
6821 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
6822 cerr << childPos << " " << noJumps << type << endl;
6823 }
6824#endif
6825
6826 // for 3D-diagonal neighbors nothing else is necessary
6827 if(type == 2) {
6828 continue;
6829 }
6830
6831 for(MInt i = 0; i < noCorrectNodes; i++) {
6832 const MInt node = faceCornerCode[jumpDir][i];
6833 // already correct above(directly copied!)
6834 if(node == parentNode) continue;
6835
6836 MBool isDiagonalNode = false;
6837 // only correct if the node is also on the face of the second-diagonal direction!
6838 if(type == 1) {
6839 const MInt secondDir = m_cutLvlJumpCandidates[id].diagonalDirs[j];
6840 for(MInt l = 0; l < noCorrectNodes; l++) {
6841 if(node == faceCornerCode[secondDir][l]) {
6842 isDiagonalNode = true;
6843 break;
6844 }
6845 }
6846 if(!isDiagonalNode) continue;
6847 }
6848
6849 MInt edgeInterpolation = -1;
6850 for(MInt k = 0; k < 3; k++) {
6851 MInt parentEdgeCorner = edge2Corner[parentEdgeIds[k]][0];
6852 if(parentEdgeCorner == parentNode) {
6853 parentEdgeCorner = edge2Corner[parentEdgeIds[k]][1];
6854 }
6855 if(parentEdgeCorner == node) {
6856 edgeInterpolation = k;
6857 break;
6858 }
6859 }
6860
6861 if(edgeInterpolation > -1) { // edge interpolation for node
6862 const MInt parentEdgeId = parentEdgeIds[edgeInterpolation];
6863 const MInt parentNodes[2] = {edge2Corner[parentEdgeId][0], edge2Corner[parentEdgeId][1]};
6864 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6865 const MFloat phi = 0.5
6866 * (candidates[parentCand].nodalValues[set][parentNodes[0]]
6867 + candidates[parentCand].nodalValues[set][parentNodes[1]]);
6868 candidates[candId].nodalValues[set][node] = phi;
6869 }
6870
6871#ifdef CutCell_DEBUG
6872 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
6873 cerr << " (2 ) Setting node " << node << " to " << candidates[candId].nodalValues[0][node] << endl;
6874 }
6875#endif
6876
6877 } else { // corner interpolation for node (node is on cell-face)
6878 ASSERT(type == 0, "");
6879 const MInt parentNodes[4] = {faceCornerCode[jumpDir][0], faceCornerCode[jumpDir][1],
6880 faceCornerCode[jumpDir][2], faceCornerCode[jumpDir][3]};
6881 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6882 const MFloat phi = 0.25
6883 * (candidates[parentCand].nodalValues[set][parentNodes[0]]
6884 + candidates[parentCand].nodalValues[set][parentNodes[1]]
6885 + candidates[parentCand].nodalValues[set][parentNodes[2]]
6886 + candidates[parentCand].nodalValues[set][parentNodes[3]]);
6887 candidates[candId].nodalValues[set][node] = phi;
6888 }
6889
6890#ifdef CutCell_DEBUG
6891 if(globalTimeStep > debugTimeStep && grid().tree().globalId(cellId) == debugGlobalId) {
6892 cerr << " (3 ) Setting node " << node << " to " << candidates[candId].nodalValues[0][node] << endl;
6893 }
6894#endif
6895 }
6896 }
6897 }
6898 }
6899
6900#ifdef CutCell_DEBUG
6901 const MInt reverseNode[3][8] = {{1, 0, 3, 2, 5, 4, 7, 6}, {2, 3, 0, 1, 6, 7, 4, 5}, {4, 5, 6, 7, 0, 1, 2, 3}};
6902
6903
6904 // check nodal values:
6905 std::set<std::pair<MInt, MInt>> nghbrSet;
6906
6907 MInt nghbrIds[m_noCorners]{};
6908 MInt nghbrNodes[m_noCorners]{};
6909
6910 const MInt nodeStencil[3][8] = {{0, 1, 0, 1, 0, 1, 0, 1}, {2, 2, 3, 3, 2, 2, 3, 3}, {4, 4, 4, 4, 5, 5, 5, 5}};
6911
6912
6913 for(MInt cnd = 0; cnd < (signed)candidates.size(); cnd++) {
6914 const MInt cellId = candidates[cnd].cellId;
6915 for(MInt node = 0; node < m_noCorners; node++) {
6916 nghbrSet.clear();
6917 nghbrSet.insert(std::make_pair(cellId, node));
6918
6919 for(MInt i = 0; i < nDim; i++) {
6920 const MInt firstDir = nodeStencil[i][node];
6921 const MInt firstNghbrNode = reverseNode[i][node];
6922 const MInt firstNghbrId = grid().tree().neighbor(cellId, firstDir);
6923 if(firstNghbrId > -1) {
6924 nghbrSet.insert(make_pair(firstNghbrId, firstNghbrNode));
6925 for(MInt j = 0; j < nDim; j++) {
6926 const MInt secondDir = nodeStencil[j][node];
6927 if(secondDir == firstDir) continue;
6928 const MInt secondNghbrNode = reverseNode[j][firstNghbrNode];
6929 const MInt secondNghbrId = grid().tree().neighbor(firstNghbrId, secondDir);
6930 if(secondNghbrId > -1) {
6931 nghbrSet.insert(make_pair(secondNghbrId, secondNghbrNode));
6932 IF_CONSTEXPR(nDim == 3) {
6933 for(MInt k = 0; k < nDim; k++) {
6934 const MInt thirdDir = nodeStencil[k][node];
6935 if(thirdDir == firstDir || thirdDir == secondDir) continue;
6936 const MInt thirdNghbrNode = reverseNode[k][secondNghbrNode];
6937 const MInt thirdNghbrId = grid().tree().neighbor(secondNghbrId, thirdDir);
6938 if(thirdNghbrId > -1) {
6939 nghbrSet.insert(make_pair(thirdNghbrId, thirdNghbrNode));
6940 }
6941 }
6942 }
6943 }
6944 }
6945 }
6946 }
6947
6948 // c) reorder list by nodes, and calculate noNeighborsPerNode
6949 // note: previously determined neighbors might be added multiple-times to the map
6950 // and overwrite existing and identical information...
6951 MInt noNeighborsPerNode = 0;
6952 for(auto it = nghbrSet.begin(); it != nghbrSet.end(); it++) {
6953 nghbrIds[noNeighborsPerNode] = it->first;
6954 nghbrNodes[noNeighborsPerNode] = it->second;
6955 noNeighborsPerNode++;
6956 }
6957
6958 for(MInt nghbrNode = 0; nghbrNode < noNeighborsPerNode; nghbrNode++) {
6959 const MInt nghbrCand = candidateIds[nghbrIds[nghbrNode]];
6960 if(nghbrCand < 0) continue;
6961 if(fabs(candidates[nghbrCand].nodalValues[0][nghbrNodes[nghbrNode]] - candidates[cnd].nodalValues[0][node])
6962 > 0.00000000001) {
6963 cerr << "Nodal-value missmatch " << cellId << " " << grid().tree().globalId(cellId) << " " << node << " "
6964 << candidates[cnd].nodalValues[0][node] << " " << nghbrIds[nghbrNode] << " "
6965 << grid().tree().globalId(nghbrIds[nghbrNode]) << " " << nghbrNodes[nghbrNode] << " "
6966 << candidates[nghbrCand].nodalValues[0][nghbrNodes[nghbrNode]] << endl;
6967 }
6968 }
6969 }
6970 }
6971#endif
6972}
6973
6979template <MInt nDim_>
6980void GeometryIntersection<nDim_>::getNeighborNodes(const MInt cellId, const MInt node, MInt noNeighborsPerNode,
6981 MInt* nghbrIds, MInt* nghbrNodes) {
6982 TRACE();
6983
6984 const MInt nodeStencil[3][8] = {{0, 1, 0, 1, 0, 1, 0, 1}, {2, 2, 3, 3, 2, 2, 3, 3}, {4, 4, 4, 4, 5, 5, 5, 5}};
6985
6986 const MInt reverseNode[3][8] = {{1, 0, 3, 2, 5, 4, 7, 6}, {2, 3, 0, 1, 6, 7, 4, 5}, {4, 5, 6, 7, 0, 1, 2, 3}};
6987
6988 std::set<std::pair<MInt, MInt>> nghbrSet;
6989
6990 // b) Add all neighbors and the corresponding nodes to the list
6991 nghbrSet.clear();
6992 nghbrSet.insert(std::make_pair(cellId, node));
6993
6994 for(MInt i = 0; i < nDim; i++) {
6995 const MInt firstDir = nodeStencil[i][node];
6996 const MInt firstNghbrNode = reverseNode[i][node];
6997 const MInt firstNghbrId = grid().tree().neighbor(cellId, firstDir);
6998 if(firstNghbrId > -1) {
6999 nghbrSet.insert(make_pair(firstNghbrId, firstNghbrNode));
7000 for(MInt j = 0; j < nDim; j++) {
7001 const MInt secondDir = nodeStencil[j][node];
7002 if(secondDir == firstDir) continue;
7003 const MInt secondNghbrNode = reverseNode[j][firstNghbrNode];
7004 const MInt secondNghbrId = grid().tree().neighbor(firstNghbrId, secondDir);
7005 if(secondNghbrId > -1) {
7006 nghbrSet.insert(make_pair(secondNghbrId, secondNghbrNode));
7007 IF_CONSTEXPR(nDim == 3) {
7008 for(MInt k = 0; k < nDim; k++) {
7009 const MInt thirdDir = nodeStencil[k][node];
7010 if(thirdDir == firstDir || thirdDir == secondDir) continue;
7011 const MInt thirdNghbrNode = reverseNode[k][secondNghbrNode];
7012 const MInt thirdNghbrId = grid().tree().neighbor(secondNghbrId, thirdDir);
7013 if(thirdNghbrId > -1) {
7014 nghbrSet.insert(make_pair(thirdNghbrId, thirdNghbrNode));
7015 }
7016 }
7017 }
7018 }
7019 }
7020 }
7021 }
7022 // c) reorder list by nodes, and calculate noNeighborsPerNode
7023 // note: previously determined neighbors might be added multiple-times to the map
7024 // and overwrite existing and identical information...
7025 noNeighborsPerNode = 0;
7026 for(auto it = nghbrSet.begin(); it != nghbrSet.end(); it++) {
7027 nghbrIds[noNeighborsPerNode] = it->first;
7028 nghbrNodes[noNeighborsPerNode] = it->second;
7029 noNeighborsPerNode++;
7030 }
7031}
7032template class GeometryIntersection<2>;
7033template class GeometryIntersection<3>;
std::array< MInt, maxNoCutPoints > cutBodyIds
std::array< MFloat, maxNoCartesianSurfaces > cartFaceArea
std::array< std::array< MInt, maxNoFaceVertices >, maxNoTotalSurfaces > allFacesPointIds
std::array< MInt, noFaces > noFacesPerCartesianDir
std::array< MInt, maxNoTotalSurfaces > allFacesNoPoints
std::array< MInt, maxNoCutPoints > cutEdges
std::array< MInt, maxNoBoundarySurfaces > boundarySurfaceBodyId
std::array< MFloat, nDim > volumetricCentroid
std::array< MBool, noFaces > externalFaces
std::array< MInt, maxNoBoundarySurfaces > boundarySurfaceBndryCndId
std::array< std::array< MFloat, nDim >, maxNoBoundarySurfaces > boundarySurfaceCentroid
std::array< std::array< MFloat, nDim >, maxNoBoundarySurfaces > boundarySurfaceNormal
std::array< std::array< MFloat, nDim >, maxNoCartesianSurfaces > cartFaceCentroid
std::array< MInt, maxNoCartesianSurfaces > cartFaceDir
std::array< MFloat, maxNoBoundarySurfaces > boundarySurfaceArea
std::array< std::array< MBool, noCorners >, maxNoSets > cornerIsInsideGeometry
std::array< MInt, maxNoSets > associatedBodyIds
std::array< MInt, maxNoTotalSurfaces > allFacesBodyId
std::array< std::array< MFloat, nDim >, maxNoCutPoints > cutPoints
std::array< MFloat, nDim > center
std::array< MFloat, nDim > normal
void compVolumeIntegrals_pyraBased3(std::vector< polyCutCell > *, std::vector< polyFace > *, const std::vector< polyVertex > *)
void writeVTKFileOfCell(MInt cellId, std::vector< polyFace > *faces, const std::vector< polyVertex > *vertices, MInt set)
void addPoint(const std::vector< polyVertex > *, const MInt *, const MInt, std::array< MFloat, nDim >)
adds an additional MC point in the cell sums up all n points passed in indices. points have to be sto...
void writeInfo(std::vector< CutCell< nDim > > &cutCellData, MUint, MInt)
void computeCutFaces(std::vector< CutCell< nDim > > &cutCellData, const MInt maxNoSurfaces, const MInt tCutGroup)
void exchangeNodalValues(const MInt **maxLevelWindowCells, const MInt *noMaxLevelWindowCells, const MInt **maxLevelHaloCells, std::vector< CutCandidate< nDim > > &candidates, MInt *candidateIds)
halo cell - window cell exchange of nodal scalar field data
void fillCutCellData(std::vector< CutCandidate< nDim > > &candidates, std::vector< CutCell< nDim > > &cutCellData, std::vector< MInt > cutCellIdMapping)
void getNeighborNodes(const MInt, const MInt, MInt, MInt *, MInt *)
gets all neighbor cellIds and matching nodes for a given cell and node
void computeNodalValues(std::vector< CutCandidate< nDim > > &candidates, MInt *candidateIds, const MFloat *scalarField, const MInt *bodyIdField, const MBool *const gapPropertyField, const MBool gapClosure)
1) add cutCandidates based on the solver m_bndryCandidates 2) set cutCandidate information 3) set the...
void compFaceIntegrals_pyraBased3(polyFace *face, const std::vector< polyVertex > *vertices, MFloat *MC, MFloat *VC, MFloat *XC)
void correctNodalValuesAtLevelJump(std::vector< CutCandidate< nDim > > &candidates, const MInt *)
corrects the nodal values at bndry level jumps for ls-based geometries
std::conditional< nDim_==3, polyCutCell3D, polyCutCell2D >::type polyCutCell
void computeCutPointsFromSTL(std::vector< CutCandidate< nDim > > &candidates)
computes cut points where candidate intersects with the geometry note: can not handle bndryRefinement...
void computeCutPoints(std::vector< CutCandidate< nDim > > &candidates, const MInt *candidateIds, std::vector< MInt > &candidatesOrder)
Computes cutpoints for the scalar-Field with grid edges and updates cutPoint-Info in the cutCandidate...
MBool computeCutFaceSimple(CutCell< nDim > &cutCell)
This class is a ScratchSpace.
Definition: scratch.h:758
size_type size() const
Definition: scratch.h:302
void fill(T val)
fill the scratch with a given value
Definition: scratch.h:311
pointer p
Deprecated: use [] instead!
Definition: scratch.h:315
iterator end()
Definition: scratch.h:281
iterator begin()
Definition: scratch.h:273
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr Real POW2(const Real x)
Definition: functions.h:119
Real ABS(const Real x)
Definition: functions.h:85
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
constexpr T mMin(const T &x, const T &y)
Definition: functions.h:90
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
MInt globalTimeStep
MInt g_timeSteps
MInt g_restartTimeStep
InfoOutFile m_log
constexpr MLong IPOW2(MInt x)
int32_t MInt
Definition: maiatypes.h:62
uint32_t MUint
Definition: maiatypes.h:63
double MFloat
Definition: maiatypes.h:52
bool MBool
Definition: maiatypes.h:58
char MChar
Definition: maiatypes.h:56
MInt id
Definition: maiatypes.h:71
int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Isend
int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Irecv
int MPI_Waitall(int count, MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Waitall
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
void const MInt cellId
Definition: collector.h:239
constexpr std::underlying_type< FcCell >::type p(const FcCell property)
Converts property name to underlying integer value.
Namespace for auxiliary functions/classes.
Definition: contexttypes.h:19