MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
GeometryIntersection< nDim_ > Class Template Reference

#include <geometryintersection.h>

Inheritance diagram for GeometryIntersection< nDim_ >:
[legend]
Collaboration diagram for GeometryIntersection< nDim_ >:
[legend]

Classes

class  cellWithSplitFace
 
class  Csg
 
class  CsgNode
 
class  CsgPlane
 
class  CsgPolygon
 
class  CsgVector
 
class  CsgVertex
 
class  polyCutCell2D
 
class  polyCutCell3D
 
class  polyCutCellBase
 
class  polyEdge2D
 
class  polyEdge3D
 
class  polyEdgeBase
 
class  polyFace
 
class  polyMultiFace
 
class  polyVertex
 
class  splitCartesianFace
 
class  surfBase
 

Public Member Functions

 GeometryIntersection (GridProxy *gridProxy_, Geom *geometry_)
 
 ~GeometryIntersection ()
 
const std::vector< CutCell< nDim > > & cutCellData_ ()
 
const std::vector< CutCandidate< nDim > > & cutCandidates_ ()
 
void computeCutFaces (std::vector< CutCell< nDim > > &cutCellData, const MInt maxNoSurfaces, const MInt tCutGroup)
 
void fillCutCellData (std::vector< CutCandidate< nDim > > &candidates, std::vector< CutCell< nDim > > &cutCellData, std::vector< MInt > cutCellIdMapping)
 
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 cutCandidates data! More...
 
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 scalar-nodal values at the mesh vertices for the cutCandidates More...
 
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 More...
 
void computeCutPointsFromSTL (std::vector< CutCandidate< nDim > > &candidates)
 computes cut points where candidate intersects with the geometry note: can not handle bndryRefinement jumps yet! More...
 
void clearCutCellData ()
 
void resetCutCellData ()
 
void returnDebugInfo ()
 
void computeCutFaces (std::vector< CutCell< nDim > > &cutCellData, const MInt maxNoSurfaces, const MInt tCutGroup)
 
void fillCutCellData (std::vector< CutCandidate< nDim > > &candidates, std::vector< CutCell< nDim > > &cutCellData, std::vector< MInt > cutCellIdMapping)
 set cutCellData based on cutCellCandidates note: not all candidates will become a cutCell! More...
 

Public Attributes

const MFloat m_eps
 
MBool m_complexBoundary = true
 
MInt m_noEmbeddedBodies {}
 
MInt m_noLevelSetsUsedForMb {}
 
MIntm_bodyToSetTable {}
 
MInt ** m_setToBodiesTable {}
 
MIntm_noBodiesInSet {}
 
MFloatm_scaledCoordinate = nullptr
 
MBool m_scaledCutCell = true
 
MBool m_multiCutCell = false
 

Private Types

using GridProxy = typename maia::grid::Proxy< nDim >
 
using Geom = Geometry< nDim >
 
typedef std::conditional< nDim_==3, polyEdge3D, polyEdge2D >::type polyEdge
 
typedef std::conditional< nDim_==3, polyCutCell3D, polyCutCell2D >::type polyCutCell
 

Private Member Functions

MFloata_coordinate (const MInt cellId, const MInt dir)
 Returns the coordinate of the cell cellId for dimension dir. More...
 
MFloat a_cellLengthAtCell (const MInt cellId) const
 Returns the cellLength of the cell cellId. More...
 
MFloat a_gridCellVolume (const MInt cellId) const
 Returns the volume of the cell cellId. More...
 
GridProxygrid ()
 
const GridProxygrid () const
 
Geomgeometry ()
 
const Geomgeometry () const
 
GeometryContextgeometryContext ()
 
MBool computeCutFaceSimple (CutCell< nDim > &cutCell)
 
void crossProduct (MFloat *c, const MFloat *a, const MFloat *b)
 
void correctNodalValuesAtLevelJump (std::vector< CutCandidate< nDim > > &candidates, const MInt *)
 corrects the nodal values at bndry level jumps for ls-based geometries More...
 
void getNeighborNodes (const MInt, const MInt, MInt, MInt *, MInt *)
 gets all neighbor cellIds and matching nodes for a given cell and node More...
 
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 stored in vertices, result is passed in res. More...
 
void compVolumeIntegrals_pyraBased3 (std::vector< polyCutCell > *, std::vector< polyFace > *, const std::vector< polyVertex > *)
 
void compFaceIntegrals_pyraBased3 (polyFace *face, const std::vector< polyVertex > *vertices, MFloat *MC, MFloat *VC, MFloat *XC)
 
void writeVTKFileOfCell (MInt cellId, std::vector< polyFace > *faces, const std::vector< polyVertex > *vertices, MInt set)
 
void writeInfo (std::vector< CutCell< nDim > > &cutCellData, MUint, MInt)
 
template<class T = void>
std::enable_if< nDim_==2, T >::type computeNormal (const std::array< MFloat, nDim > p0, const std::array< MFloat, nDim > p1, std::array< MFloat, nDim > res, MFloat &w)
 returns the normal corresponding to the triangle abc and returns the result in res More...
 
template<class T = MFloat>
std::enable_if< nDim_==3, T >::type computeNormal (const std::array< MFloat, nDim > p0, const std::array< MFloat, nDim > p1, const std::array< MFloat, nDim > p2, std::array< MFloat, nDim > &res, MFloat &w)
 
void compFaceIntegrals_pyraBased3 (polyFace *face, const std::vector< polyVertex > *vertices, MFloat *MC, MFloat *VC, MFloat *XC)
 
void compVolumeIntegrals_pyraBased3 (std::vector< polyCutCell > *cutCells, std::vector< polyFace > *faces, const std::vector< polyVertex > *vertices)
 
void writeVTKFileOfCell (MInt cellId, std::vector< polyFace > *faces, const std::vector< polyVertex > *vertices, MInt set)
 
MBool computeCutFaceSimple (CutCell< nDim > &cutCell)
 determines the geometric cut-cell data, simple marching cubes version, fast More...
 

Private Attributes

GridProxy *const m_gridProxy
 
Geom *const m_geometry
 
std::vector< CutCell< nDim > > m_cutCellData
 
std::vector< CutCandidate< nDim > > m_cutCandidates
 
MInt m_bodyFaceJoinMode
 
MFloat m_bodyFaceJoinCriterion
 
MString m_gridCutTest
 
MIntm_caseCheckList = nullptr
 
MBool m_bndryLvlJumps = false
 
std::vector< lvlJumpCandidates< nDim > > m_cutLvlJumpCandidates
 

Static Private Attributes

static constexpr MInt nDim = nDim_
 
static constexpr MInt m_noDirs = 2 * nDim
 
static constexpr MInt m_noCorners = IPOW2(nDim)
 
static constexpr MInt m_maxNoChilds = IPOW2(nDim)
 
static constexpr MInt m_noEdges = 2 * nDim * (nDim - 1)
 

Detailed Description

template<MInt nDim_>
class GeometryIntersection< nDim_ >

Definition at line 56 of file geometryintersection.h.

Member Typedef Documentation

◆ Geom

template<MInt nDim_>
using GeometryIntersection< nDim_ >::Geom = Geometry<nDim>
private

Definition at line 66 of file geometryintersection.h.

◆ GridProxy

template<MInt nDim_>
using GeometryIntersection< nDim_ >::GridProxy = typename maia::grid::Proxy<nDim>
private

Definition at line 65 of file geometryintersection.h.

◆ polyCutCell

template<MInt nDim_>
typedef std::conditional<nDim_==3,polyCutCell3D,polyCutCell2D>::type GeometryIntersection< nDim_ >::polyCutCell
private

Definition at line 355 of file geometryintersection.h.

◆ polyEdge

template<MInt nDim_>
typedef std::conditional<nDim_==3,polyEdge3D,polyEdge2D>::type GeometryIntersection< nDim_ >::polyEdge
private

Definition at line 299 of file geometryintersection.h.

Constructor & Destructor Documentation

◆ GeometryIntersection()

template<MInt nDim_>
GeometryIntersection< nDim_ >::GeometryIntersection ( GridProxy gridProxy_,
Geom geometry_ 
)
inline

Definition at line 96 of file geometryintersection.h.

97 : m_eps(std::numeric_limits<MFloat>::epsilon()), m_gridProxy(gridProxy_), m_geometry(geometry_) {
99 if(geometryContext().propertyExists("bodyFaceJoinMode", 0)) { // TODO labels:GEOM simplify
100 m_bodyFaceJoinMode = *(geometryContext().getProperty("bodyFaceJoinMode", 0)->asInt(0));
101 }
102
104 if(geometryContext().propertyExists("bodyFaceJoinCriterion", 0)) {
105 m_bodyFaceJoinCriterion = *(geometryContext().getProperty("bodyFaceJoinCriterion", 0)->asFloat(0));
106 }
107
108 m_gridCutTest = "SAT";
109 if(geometryContext().propertyExists("gridCutTest", 0)) { // TODO labels:GEOM simplify
110 m_gridCutTest = *(geometryContext().getProperty("gridCutTest", 0)->asString(0));
111 }
112
113 m_multiCutCell = false;
114 if(geometryContext().propertyExists("multiCutCell", 0)) { // TODO labels:GEOM simplify
115 m_multiCutCell = (MBool) * (geometryContext().getProperty("multiCutCell", 0)->asInt(0));
116 }
117
118 if(!m_multiCutCell) {
119 m_scaledCutCell = false;
120 } else {
121 m_scaledCutCell = true;
122 }
123
124 m_bndryLvlJumps = false;
125 if(geometryContext().propertyExists("allowBndryLvlJumps", 0)) { // TODO labels:GEOM simplify
126 m_bndryLvlJumps = (MBool) * (geometryContext().getProperty("allowBndryLvlJumps", 0)->asInt(0));
127 }
128
129#ifdef CutCell_DEBUG
130 mAlloc(m_caseCheckList, 256, "m_caseCheckList", 0, AT_);
131#endif
132
133 mAlloc(m_scaledCoordinate, 3, "m_scaledCoordinate", F0, AT_);
134 }
void mAlloc(T *&a, const MLong N, const MString &objectName, MString function)
allocates memory for one-dimensional array 'a' of size N
Definition: alloc.h:173
MBool propertyExists(MString name, MInt solver)
GeometryProperty * getProperty(const MString &name, MInt segment)
GridProxy *const m_gridProxy
GeometryContext & geometryContext()
bool MBool
Definition: maiatypes.h:58

◆ ~GeometryIntersection()

template<MInt nDim_>
GeometryIntersection< nDim_ >::~GeometryIntersection ( )
inline

Definition at line 136 of file geometryintersection.h.

Member Function Documentation

◆ a_cellLengthAtCell()

template<MInt nDim_>
MFloat GeometryIntersection< nDim_ >::a_cellLengthAtCell ( const MInt  cellId) const
inlineprivate

Definition at line 80 of file geometryintersection.h.

80 {
81 if(!m_scaledCutCell) {
82 return grid().cellLengthAtCell(cellId);
83 }
84 return 2;
85 }

◆ a_coordinate()

template<MInt nDim_>
MFloat & GeometryIntersection< nDim_ >::a_coordinate ( const MInt  cellId,
const MInt  dir 
)
inlineprivate

Definition at line 69 of file geometryintersection.h.

69 {
70 // FIXME labels:GEOM avoid pointer-access to the grid-raw-coordinate!!!
71 if(!m_scaledCutCell) {
72 const MInt gridCellId = grid().tree().solver2grid(cellId);
73 return grid().raw().a_coordinate(gridCellId, dir);
74 }
75
76 return m_scaledCoordinate[0];
77 }
int32_t MInt
Definition: maiatypes.h:62

◆ a_gridCellVolume()

template<MInt nDim_>
MFloat GeometryIntersection< nDim_ >::a_gridCellVolume ( const MInt  cellId) const
inlineprivate

Definition at line 88 of file geometryintersection.h.

88 {
89 if(!m_scaledCutCell) {
90 return grid().gridCellVolume(grid().tree().level(cellId));
91 }
92 return 8;
93 }

◆ addPoint()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::addPoint ( const std::vector< polyVertex > *  vertices,
const MInt indices,
const MInt  n,
std::array< MFloat, nDim res 
)
private
Author
Claudia Guenther, September 2013

Definition at line 28 of file geometryintersection.cpp.

29 {
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}
void indices(const MInt i, const MInt n, MInt *const ids)
Calculate the 2D/3D indices for a given scalar id for accessing a field of n^nDim points.

◆ clearCutCellData()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::clearCutCellData ( )
inline

Definition at line 167 of file geometryintersection.h.

167{ std::vector<CutCell<nDim>>().swap(m_cutCellData); }
std::vector< CutCell< nDim > > m_cutCellData
void swap(Tensor< TT > &a, Tensor< TT > &b)
Non-member swap exchanges the contents of two Tensors.
Definition: tensor.h:752

◆ compFaceIntegrals_pyraBased3() [1/2]

void GeometryIntersection< 3 >::compFaceIntegrals_pyraBased3 ( polyFace face,
const std::vector< polyVertex > *  vertices,
MFloat MC,
MFloat VC,
MFloat XC 
)
private

Definition at line 50 of file geometryintersection.cpp.

51 {
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}
static constexpr MInt nDim
double MFloat
Definition: maiatypes.h:52
Definition: contexttypes.h:19

◆ compFaceIntegrals_pyraBased3() [2/2]

template<MInt nDim_>
void GeometryIntersection< nDim_ >::compFaceIntegrals_pyraBased3 ( polyFace face,
const std::vector< polyVertex > *  vertices,
MFloat MC,
MFloat VC,
MFloat XC 
)
private

◆ computeCutFaces() [1/2]

void GeometryIntersection< 3 >::computeCutFaces ( std::vector< CutCell< nDim > > &  cutCellData,
const MInt  maxNoSurfaces,
const MInt  tCutGroup 
)

Definition at line 1292 of file geometryintersection.cpp.

1293 {
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
5504#endif
5505}
static constexpr MInt m_noCorners
static constexpr MInt m_noEdges
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)
MFloat & a_coordinate(const MInt cellId, const MInt dir)
Returns the coordinate of the cell cellId for dimension dir.
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 crossProduct(MFloat *c, const MFloat *a, const MFloat *b)
MFloat a_gridCellVolume(const MInt cellId) const
Returns the volume of the cell cellId.
static constexpr MInt m_noDirs
std::enable_if< nDim_==2, T >::type computeNormal(const std::array< MFloat, nDim > p0, const std::array< MFloat, nDim > p1, std::array< MFloat, nDim > res, MFloat &w)
returns the normal corresponding to the triangle abc and returns the result in res
MFloat a_cellLengthAtCell(const MInt cellId) const
Returns the cellLength of the cell cellId.
MBool computeCutFaceSimple(CutCell< nDim > &cutCell)
This class is a ScratchSpace.
Definition: scratch.h:758
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
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
constexpr MLong IPOW2(MInt x)
uint32_t MUint
Definition: maiatypes.h:63
char MChar
Definition: maiatypes.h:56
MInt id
Definition: maiatypes.h:71
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.

◆ computeCutFaces() [2/2]

template<MInt nDim_>
void GeometryIntersection< nDim_ >::computeCutFaces ( std::vector< CutCell< nDim > > &  cutCellData,
const MInt  maxNoSurfaces,
const MInt  tCutGroup 
)

◆ computeCutFaceSimple() [1/2]

MBool GeometryIntersection< 3 >::computeCutFaceSimple ( CutCell< nDim > &  cutCell)
private
Author
Daniel Hartmann, Claudia Guenther, Lennart Schneiders
Date

Definition at line 352 of file geometryintersection.cpp.

352 {
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}
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

◆ computeCutFaceSimple() [2/2]

template<MInt nDim_>
MBool GeometryIntersection< nDim_ >::computeCutFaceSimple ( CutCell< nDim > &  cutCell)
private

◆ computeCutPoints()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::computeCutPoints ( std::vector< CutCandidate< nDim > > &  candidates,
const MInt candidateIds,
std::vector< MInt > &  candidatesOrder 
)
Note
can handle complex geometries for multiple scalar fields
Author
Claudia Guenther, Update Tim Wegmann
Date
30.07.2013

Definition at line 5534 of file geometryintersection.cpp.

5536 {
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}
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
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

◆ computeCutPointsFromSTL()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::computeCutPointsFromSTL ( std::vector< CutCandidate< nDim > > &  candidates)
Author
Daniel Hartmann, Claudia Guenther, Sohel Herff, Tim Wegmann
Date
2006, 08/2013, 2016, 2019

Definition at line 6448 of file geometryintersection.cpp.

6448 {
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}
element< nDim > * elements
Definition: geometry.h:215
virtual MInt getIntersectionElements(MFloat *, std::vector< MInt > &)
Definition: geometry.h:63
Real ABS(const Real x)
Definition: functions.h:85
InfoOutFile m_log

◆ computeNodalValues()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::computeNodalValues ( std::vector< CutCandidate< nDim > > &  candidates,
MInt candidateIds,
const MFloat scalarField,
const MInt bodyIdField,
const MBool *const  gapPropertyField,
const MBool  gapClosure 
)

NOTE: the nodal-values need to be exchanged afterwards!

Author
Lennart Schneiders, Update Tim Wegmann

Definition at line 5768 of file geometryintersection.cpp.

5770 {
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}
std::vector< lvlJumpCandidates< nDim > > m_cutLvlJumpCandidates
void correctNodalValuesAtLevelJump(std::vector< CutCandidate< nDim > > &candidates, const MInt *)
corrects the nodal values at bndry level jumps for ls-based geometries
static constexpr MInt m_maxNoChilds

◆ computeNormal() [1/2]

template<MInt nDim_>
template<class T = MFloat>
std::enable_if< nDim_==3, T >::type GeometryIntersection< nDim_ >::computeNormal ( const std::array< MFloat, nDim p0,
const std::array< MFloat, nDim p1,
const std::array< MFloat, nDim p2,
std::array< MFloat, nDim > &  res,
MFloat w 
)
inlineprivate

Definition at line 401 of file geometryintersection.h.

402 {
403 const MFloat a0 = p1[0] - p0[0], a1 = p1[1] - p0[1], a2 = p1[2] - p0[2], b0 = p2[0] - p0[0], b1 = p2[1] - p0[1],
404 b2 = p2[2] - p0[2];
405 res[0] = a1 * b2 - a2 * b1;
406 res[1] = a2 * b0 - a0 * b2;
407 res[2] = a0 * b1 - a1 * b0;
408 const MFloat abs = sqrt(res[0] * res[0] + res[1] * res[1] + res[2] * res[2]);
409 res[0] /= abs;
410 res[1] /= abs;
411 res[2] /= abs;
412 w = -res[0] * p0[0] - res[1] * p0[1] - res[2] * p0[2];
413 return abs;
414 }

◆ computeNormal() [2/2]

template<MInt nDim_>
template<class T = void>
std::enable_if< nDim_==2, T >::type GeometryIntersection< nDim_ >::computeNormal ( const std::array< MFloat, nDim p0,
const std::array< MFloat, nDim p1,
std::array< MFloat, nDim res,
MFloat w 
)
inlineprivate
Author
Claudia Guenther, November 2013

Definition at line 388 of file geometryintersection.h.

389 {
390 const MFloat dx = p1[0] - p0[0], dy = p1[1] - p0[1];
391 res[0] = -dy;
392 res[1] = dx;
393 const MFloat abs = sqrt(res[0] * res[0] + res[1] * res[1]);
394 res[0] /= abs;
395 res[1] /= abs;
396 w = -res[0] * p0[0] - res[1] * p0[1];
397 return;
398 }

◆ compVolumeIntegrals_pyraBased3() [1/2]

template<MInt nDim_>
void GeometryIntersection< nDim_ >::compVolumeIntegrals_pyraBased3 ( std::vector< polyCutCell > *  ,
std::vector< polyFace > *  ,
const std::vector< polyVertex > *   
)
private

◆ compVolumeIntegrals_pyraBased3() [2/2]

void GeometryIntersection< 3 >::compVolumeIntegrals_pyraBased3 ( std::vector< polyCutCell > *  cutCells,
std::vector< polyFace > *  faces,
const std::vector< polyVertex > *  vertices 
)
private

Definition at line 134 of file geometryintersection.cpp.

136 {
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;
156 }
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}
void compFaceIntegrals_pyraBased3(polyFace *face, const std::vector< polyVertex > *vertices, MFloat *MC, MFloat *VC, MFloat *XC)
std::conditional< nDim_==3, polyCutCell3D, polyCutCell2D >::type polyCutCell

◆ correctNodalValuesAtLevelJump()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::correctNodalValuesAtLevelJump ( std::vector< CutCandidate< nDim > > &  candidates,
const MInt candidateIds 
)
private
Author
Tim Wegmann
Date
2020

Definition at line 6727 of file geometryintersection.cpp.

6728 {
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}

◆ crossProduct()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::crossProduct ( MFloat c,
const MFloat a,
const MFloat b 
)
inlineprivate

Definition at line 215 of file geometryintersection.h.

215 {
216 c[0] = a[1] * b[2] - a[2] * b[1];
217 c[1] = a[2] * b[0] - a[0] * b[2];
218 c[2] = a[0] * b[1] - a[1] * b[0];
219 }

◆ cutCandidates_()

template<MInt nDim_>
const std::vector< CutCandidate< nDim > > & GeometryIntersection< nDim_ >::cutCandidates_ ( )
inline

Definition at line 142 of file geometryintersection.h.

142{ return m_cutCandidates; }
std::vector< CutCandidate< nDim > > m_cutCandidates

◆ cutCellData_()

template<MInt nDim_>
const std::vector< CutCell< nDim > > & GeometryIntersection< nDim_ >::cutCellData_ ( )
inline

Definition at line 141 of file geometryintersection.h.

141{ return m_cutCellData; }

◆ exchangeNodalValues()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::exchangeNodalValues ( const MInt **  maxLevelWindowCells,
const MInt noMaxLevelWindowCells,
const MInt **  maxLevelHaloCells,
std::vector< CutCandidate< nDim > > &  candidates,
MInt candidateIds 
)
Author
Lennart Schneiders, Update Tim Wegmann

Definition at line 6172 of file geometryintersection.cpp.

6176 {
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}
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

◆ fillCutCellData() [1/2]

void GeometryIntersection< 3 >::fillCutCellData ( std::vector< CutCandidate< nDim > > &  candidates,
std::vector< CutCell< nDim > > &  cutCellData,
std::vector< MInt cutCellIdMapping 
)
Author
Tim Wegmann

Definition at line 6374 of file geometryintersection.cpp.

6377 {
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}

◆ fillCutCellData() [2/2]

template<MInt nDim_>
void GeometryIntersection< nDim_ >::fillCutCellData ( std::vector< CutCandidate< nDim > > &  candidates,
std::vector< CutCell< nDim > > &  cutCellData,
std::vector< MInt cutCellIdMapping 
)

◆ geometry() [1/2]

template<MInt nDim_>
Geom & GeometryIntersection< nDim_ >::geometry ( )
inlineprivate

Definition at line 206 of file geometryintersection.h.

206{ return *m_geometry; }

◆ geometry() [2/2]

template<MInt nDim_>
const Geom & GeometryIntersection< nDim_ >::geometry ( ) const
inlineprivate

Definition at line 207 of file geometryintersection.h.

207{ return *m_geometry; }

◆ geometryContext()

template<MInt nDim_>
GeometryContext & GeometryIntersection< nDim_ >::geometryContext ( )
inlineprivate

Definition at line 210 of file geometryintersection.h.

210{ return geometry().geometryContext(); }
GeometryContext & geometryContext()
Definition: geometry.h:48

◆ getNeighborNodes()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::getNeighborNodes ( const MInt  cellId,
const MInt  node,
MInt  noNeighborsPerNode,
MInt nghbrIds,
MInt nghbrNodes 
)
private
Author
Tim Wegmann
Date
2020

Definition at line 6980 of file geometryintersection.cpp.

6981 {
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}

◆ grid() [1/2]

template<MInt nDim_>
GridProxy & GeometryIntersection< nDim_ >::grid ( )
inlineprivate

Definition at line 202 of file geometryintersection.h.

202{ return *m_gridProxy; }

◆ grid() [2/2]

template<MInt nDim_>
const GridProxy & GeometryIntersection< nDim_ >::grid ( ) const
inlineprivate

Definition at line 203 of file geometryintersection.h.

203{ return *m_gridProxy; }

◆ resetCutCellData()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::resetCutCellData ( )
inline

Definition at line 168 of file geometryintersection.h.

168{ std::vector<CutCell<nDim>>().swap(m_cutCellData); }

◆ returnDebugInfo()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::returnDebugInfo ( )
inline

Definition at line 169 of file geometryintersection.h.

169 {
170#ifdef CutCell_DEBUG_
171
172 MPI_Allreduce(MPI_IN_PLACE, &m_caseCheckList[0], 256, MPI_INT, MPI_MAX, grid().mpiComm());
173
174 if(grid().domainId() == 0) {
175 std::cerr << "Tested cases: " << std::endl;
176 for(MInt i = 0; i < 256; i++) {
177 std::cerr << i << " " << m_caseCheckList[i] << std::endl;
178 }
179 }
180#endif
181 }

◆ writeInfo()

template<MInt nDim_>
void GeometryIntersection< nDim_ >::writeInfo ( std::vector< CutCell< nDim > > &  cutCellData,
MUint  cutc,
MInt  nameId 
)
private

Definition at line 296 of file geometryintersection.cpp.

296 {
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}

◆ writeVTKFileOfCell() [1/2]

void GeometryIntersection< 3 >::writeVTKFileOfCell ( MInt  cellId,
std::vector< polyFace > *  faces,
const std::vector< polyVertex > *  vertices,
MInt  set 
)
private

Definition at line 181 of file geometryintersection.cpp.

182 {
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 }
246
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}

◆ writeVTKFileOfCell() [2/2]

template<MInt nDim_>
void GeometryIntersection< nDim_ >::writeVTKFileOfCell ( MInt  cellId,
std::vector< polyFace > *  faces,
const std::vector< polyVertex > *  vertices,
MInt  set 
)
private

Member Data Documentation

◆ m_bndryLvlJumps

template<MInt nDim_>
MBool GeometryIntersection< nDim_ >::m_bndryLvlJumps = false
private

Definition at line 240 of file geometryintersection.h.

◆ m_bodyFaceJoinCriterion

template<MInt nDim_>
MFloat GeometryIntersection< nDim_ >::m_bodyFaceJoinCriterion
private

Definition at line 235 of file geometryintersection.h.

◆ m_bodyFaceJoinMode

template<MInt nDim_>
MInt GeometryIntersection< nDim_ >::m_bodyFaceJoinMode
private

Definition at line 234 of file geometryintersection.h.

◆ m_bodyToSetTable

template<MInt nDim_>
MInt* GeometryIntersection< nDim_ >::m_bodyToSetTable {}

Definition at line 191 of file geometryintersection.h.

◆ m_caseCheckList

template<MInt nDim_>
MInt* GeometryIntersection< nDim_ >::m_caseCheckList = nullptr
private

Definition at line 238 of file geometryintersection.h.

◆ m_complexBoundary

template<MInt nDim_>
MBool GeometryIntersection< nDim_ >::m_complexBoundary = true

Definition at line 185 of file geometryintersection.h.

◆ m_cutCandidates

template<MInt nDim_>
std::vector<CutCandidate<nDim> > GeometryIntersection< nDim_ >::m_cutCandidates
private

Definition at line 232 of file geometryintersection.h.

◆ m_cutCellData

template<MInt nDim_>
std::vector<CutCell<nDim> > GeometryIntersection< nDim_ >::m_cutCellData
private

Definition at line 231 of file geometryintersection.h.

◆ m_cutLvlJumpCandidates

template<MInt nDim_>
std::vector<lvlJumpCandidates<nDim> > GeometryIntersection< nDim_ >::m_cutLvlJumpCandidates
private

Definition at line 242 of file geometryintersection.h.

◆ m_eps

template<MInt nDim_>
const MFloat GeometryIntersection< nDim_ >::m_eps

Definition at line 184 of file geometryintersection.h.

◆ m_geometry

template<MInt nDim_>
Geom* const GeometryIntersection< nDim_ >::m_geometry
private

Definition at line 208 of file geometryintersection.h.

◆ m_gridCutTest

template<MInt nDim_>
MString GeometryIntersection< nDim_ >::m_gridCutTest
private

Definition at line 236 of file geometryintersection.h.

◆ m_gridProxy

template<MInt nDim_>
GridProxy* const GeometryIntersection< nDim_ >::m_gridProxy
private

Definition at line 204 of file geometryintersection.h.

◆ m_maxNoChilds

template<MInt nDim_>
constexpr MInt GeometryIntersection< nDim_ >::m_maxNoChilds = IPOW2(nDim)
staticconstexprprivate

Definition at line 61 of file geometryintersection.h.

◆ m_multiCutCell

template<MInt nDim_>
MBool GeometryIntersection< nDim_ >::m_multiCutCell = false

Definition at line 198 of file geometryintersection.h.

◆ m_noBodiesInSet

template<MInt nDim_>
MInt* GeometryIntersection< nDim_ >::m_noBodiesInSet {}

Definition at line 194 of file geometryintersection.h.

◆ m_noCorners

template<MInt nDim_>
constexpr MInt GeometryIntersection< nDim_ >::m_noCorners = IPOW2(nDim)
staticconstexprprivate

Definition at line 60 of file geometryintersection.h.

◆ m_noDirs

template<MInt nDim_>
constexpr MInt GeometryIntersection< nDim_ >::m_noDirs = 2 * nDim
staticconstexprprivate

Definition at line 59 of file geometryintersection.h.

◆ m_noEdges

template<MInt nDim_>
constexpr MInt GeometryIntersection< nDim_ >::m_noEdges = 2 * nDim * (nDim - 1)
staticconstexprprivate

Definition at line 62 of file geometryintersection.h.

◆ m_noEmbeddedBodies

template<MInt nDim_>
MInt GeometryIntersection< nDim_ >::m_noEmbeddedBodies {}

Definition at line 187 of file geometryintersection.h.

◆ m_noLevelSetsUsedForMb

template<MInt nDim_>
MInt GeometryIntersection< nDim_ >::m_noLevelSetsUsedForMb {}

Definition at line 188 of file geometryintersection.h.

◆ m_scaledCoordinate

template<MInt nDim_>
MFloat* GeometryIntersection< nDim_ >::m_scaledCoordinate = nullptr

Definition at line 196 of file geometryintersection.h.

◆ m_scaledCutCell

template<MInt nDim_>
MBool GeometryIntersection< nDim_ >::m_scaledCutCell = true

Definition at line 197 of file geometryintersection.h.

◆ m_setToBodiesTable

template<MInt nDim_>
MInt** GeometryIntersection< nDim_ >::m_setToBodiesTable {}

Definition at line 193 of file geometryintersection.h.

◆ nDim

template<MInt nDim_>
constexpr MInt GeometryIntersection< nDim_ >::nDim = nDim_
staticconstexprprivate

Definition at line 58 of file geometryintersection.h.


The documentation for this class was generated from the following files: