1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 Calculating cut faces of the enriched patch, together with the addressing
26 into master and slave patch.
28 \*---------------------------------------------------------------------------*/
30 #include "enrichedPatch.H"
32 #include "DynamicList.H"
33 #include "labelPair.H"
34 #include "primitiveMesh.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 // If the cut face gets more than this number of points, it will be checked
40 const Foam::label Foam::enrichedPatch::maxFaceSizeDebug_ = 100;
43 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 // Index of debug signs:
50 void Foam::enrichedPatch::calcCutFaces() const
52 if (cutFacesPtr_ || cutFaceMasterPtr_ || cutFaceSlavePtr_)
54 FatalErrorIn("void enrichedPatch::calcCutFaces() const")
55 << "Cut faces addressing already calculated."
59 const faceList& enFaces = enrichedFaces();
60 const labelList& mp = meshPoints();
61 const faceList& lf = localFaces();
62 const pointField& lp = localPoints();
63 const labelListList& pp = pointPoints();
64 // Pout<< "enFaces: " << enFaces << endl;
65 // Pout<< "lf: " << lf << endl;
66 // Pout<< "lp: " << lp << endl;
67 // Pout<< "pp: " << pp << endl;
68 const Map<labelList>& masterPointFaceAddr = masterPointFaces();
70 // Prepare the storage
71 DynamicList<face> cf(2*lf.size());
72 DynamicList<label> cfMaster(2*lf.size());
73 DynamicList<label> cfSlave(2*lf.size());
76 // Go through all the faces
77 // 1) For each face, start at point zero and grab the edge zero.
78 // Both points are added into the cut face. Mark the first edge
79 // as used and position the current point as the end of the first
80 // edge and previous point as point zero.
81 // 2) Grab all possible points from the current point. Excluding
82 // the previous point find the point giving the biggest right
83 // turn. Add the point to the face and mark the edges as used.
84 // Continue doing this until the face is complete, i.e. the next point
85 // to add is the first point of the face.
86 // 3) Once the facet is completed, register its owner from the face
87 // it has been created from (remember that the first lot of faces
88 // inserted into the enriched faces list are the slaves, to allow
89 // matching of the other side).
90 // 4) If the facet is created from an original slave face, go
91 // through the master patch and try to identify the master face
92 // this facet belongs to. This is recognised by the fact that the
93 // faces consists exclusively of the points of the master face and
94 // the points projected onto the face.
96 // Create a set of edge usage parameters
97 HashSet<edge, Hash<edge> > edgesUsedOnce(pp.size());
98 HashSet<edge, Hash<edge> > edgesUsedTwice
99 (pp.size()*primitiveMesh::edgesPerPoint_);
104 const face& curLocalFace = lf[faceI];
105 const face& curGlobalFace = enFaces[faceI];
107 // Pout<< "Doing face " << faceI
108 // << " local: " << curLocalFace
109 // << " or " << curGlobalFace
112 // if (faceI < slavePatch_.size())
114 // Pout<< "original slave: " << slavePatch_[faceI]
115 // << " local: " << slavePatch_.localFaces()[faceI] << endl;
119 // Pout<< "original master: "
120 // << masterPatch_[faceI - slavePatch_.size()] << " "
121 // << masterPatch_.localFaces()[faceI - slavePatch_.size()]
125 // pointField facePoints = curLocalFace.points(lp);
126 // forAll(curLocalFace, pointI)
128 // Pout<< "v " << facePoints[pointI].x() << " "
129 // << facePoints[pointI].y() << " "
130 // << facePoints[pointI].z() << endl;
134 // Track the usage of face edges. When all edges are used, the
135 // face decomposition is complete.
136 // The seed edges include all the edges of the original face + all edges
137 // of other faces that have been used in the construction of the
138 // facet. Edges from other faces can be considered as
139 // internal to the current face if used only once.
141 // Track the edge usage to avoid duplicate faces and reset it to unused
142 boolList usedFaceEdges(curLocalFace.size(), false);
144 SLList<edge> edgeSeeds;
146 // Insert the edges of current face into the seed list.
147 edgeList cfe = curLocalFace.edges();
148 forAll(curLocalFace, edgeI)
150 edgeSeeds.append(cfe[edgeI]);
154 vector normal = curLocalFace.normal(lp);
155 normal /= mag(normal);
157 while (edgeSeeds.size())
159 // Pout<< "edgeSeeds.size(): "
160 // << edgeSeeds.size()
163 const edge curEdge = edgeSeeds.removeHead();
165 // Locate the edge in current face
166 const label curEdgeWhich = curLocalFace.which(curEdge.start());
168 // Check if the edge is in current face and if it has been
169 // used already. If so, skip it
173 && curLocalFace.nextLabel(curEdgeWhich) == curEdge.end()
176 // Edge is in the starting face.
177 // If unused, mark it as used; if used, skip it
178 if (usedFaceEdges[curEdgeWhich]) continue;
180 usedFaceEdges[curEdgeWhich] = true;
183 // If the edge has already been used twice, skip it
184 if (edgesUsedTwice.found(curEdge)) continue;
186 // Pout<< "Trying new edge (" << mp[curEdge.start()]
187 // << ", " << mp[curEdge.end()]
188 // << ") seed: " << curEdge
189 // << " used: " << edgesUsedTwice.found(curEdge)
192 // Estimate the size of cut face as twice the size of original face
193 DynamicList<label> cutFaceGlobalPoints(2*curLocalFace.size());
194 DynamicList<label> cutFaceLocalPoints(2*curLocalFace.size());
196 // Found unused edge.
197 label prevPointLabel = curEdge.start();
198 cutFaceGlobalPoints.append(mp[prevPointLabel]);
199 cutFaceLocalPoints.append(prevPointLabel);
200 // Pout<< "prevPointLabel: " << mp[prevPointLabel] << endl;
201 // Grab current point and append it to the list
202 label curPointLabel = curEdge.end();
203 point curPoint = lp[curPointLabel];
204 cutFaceGlobalPoints.append(mp[curPointLabel]);
205 cutFaceLocalPoints.append(curPointLabel);
207 bool completedCutFace = false;
209 label faceSizeDebug = maxFaceSizeDebug_;
213 // Grab the next point options
215 // Pout<< "curPointLabel: " << mp[curPointLabel] << endl;
217 const labelList& nextPoints = pp[curPointLabel];
219 // Pout<< "nextPoints: "
220 // << UIndirectList<label>(mp, nextPoints)
223 // Get the vector along the edge and the right vector
224 vector ahead = curPoint - lp[prevPointLabel];
225 ahead -= normal*(normal & ahead);
228 vector right = normal ^ ahead;
231 // Pout<< "normal: " << normal
232 // << " ahead: " << ahead
233 // << " right: " << right
236 scalar atanTurn = -GREAT;
237 label bestAtanPoint = -1;
239 forAll(nextPoints, nextI)
241 // Exclude the point we are coming from; there will always
242 // be more than one edge, so this is safe
243 if (nextPoints[nextI] != prevPointLabel)
245 // Pout<< "cur point: " << curPoint
246 // << " trying for point: "
247 // << mp[nextPoints[nextI]]
248 // << " " << lp[nextPoints[nextI]];
249 vector newDir = lp[nextPoints[nextI]] - curPoint;
250 // Pout<< " newDir: " << newDir
251 // << " mag: " << mag(newDir) << flush;
252 newDir -= normal*(normal & newDir);
253 scalar magNewDir = mag(newDir);
254 // Pout<< " corrected: " << newDir
255 // << " mag: " << mag(newDir) << flush;
257 if (magNewDir < SMALL)
261 "void enrichedPatch::"
262 "calcCutFaces() const"
263 ) << "Zero length edge detected. Probable "
264 << "projection error: slave patch probably "
265 << "does not project onto master. "
266 << "Please switch on "
267 << "enriched patch debug for more info"
268 << abort(FatalError);
274 atan2(newDir & right, newDir & ahead);
276 // Pout<< " atan: " << curAtanTurn << endl;
278 if (curAtanTurn > atanTurn)
280 bestAtanPoint = nextPoints[nextI];
281 atanTurn = curAtanTurn;
283 } // end of prev point skip
284 } // end of next point selection
286 // Pout<< " bestAtanPoint: " << bestAtanPoint << " or "
287 // << mp[bestAtanPoint]
290 // Selected next best point.
292 // Pout<< "cutFaceGlobalPoints: "
293 // << cutFaceGlobalPoints
296 // Check if the edge about to be added has been used
297 // in the current face or twice in other faces. If
298 // so, the face is bad.
299 const label whichNextPoint = curLocalFace.which(curPointLabel);
304 && curLocalFace.nextLabel(whichNextPoint) == bestAtanPoint
305 && usedFaceEdges[whichNextPoint]
308 // This edge is already used in current face
309 // face cannot be good; start on a new one
311 // Pout<< "Double usage in current face, cannot be good"
314 completedCutFace = true;
318 if (edgesUsedTwice.found(edge(curPointLabel, bestAtanPoint)))
320 // This edge is already used -
321 // face cannot be good; start on a new one
322 completedCutFace = true;
324 // Pout<< "Double usage elsewhere, cannot be good" << endl;
327 if (completedCutFace) continue;
329 // Insert the next best point into the list
330 if (mp[bestAtanPoint] == cutFaceGlobalPoints[0])
332 // Face is completed. Save it and move on to the next
334 completedCutFace = true;
338 Pout<< " local: " << cutFaceLocalPoints
339 << " one side: " << faceI;
344 cutFaceGlobal.transfer(cutFaceGlobalPoints);
346 cf.append(cutFaceGlobal);
349 cutFaceLocal.transfer(cutFaceLocalPoints);
351 // Pout<< "\ncutFaceLocal: "
352 // << cutFaceLocal.points(lp)
355 // Go through all edges of the cut faces.
356 // If the edge corresponds to a starting face edge,
357 // mark the starting face edge as true
359 forAll(cutFaceLocal, cutI)
361 const edge curCutFaceEdge
364 cutFaceLocal.nextLabel(cutI)
367 // Increment the usage count using two hash sets
368 HashSet<edge, Hash<edge> >::iterator euoIter =
369 edgesUsedOnce.find(curCutFaceEdge);
371 if (euoIter == edgesUsedOnce.end())
373 // Pout<< "Found edge not used before: "
376 edgesUsedOnce.insert(curCutFaceEdge);
380 // Pout<< "Found edge used once: "
383 edgesUsedOnce.erase(euoIter);
384 edgesUsedTwice.insert(curCutFaceEdge);
387 const label curCutFaceEdgeWhich = curLocalFace.which
389 curCutFaceEdge.start()
394 curCutFaceEdgeWhich > -1
395 && curLocalFace.nextLabel(curCutFaceEdgeWhich)
396 == curCutFaceEdge.end()
399 // Found edge in original face
401 // Pout<< "Found edge in orig face: "
402 // << curCutFaceEdge << ": "
403 // << curCutFaceEdgeWhich
406 usedFaceEdges[curCutFaceEdgeWhich] = true;
410 // Edge not in original face. Add it to seeds
412 // Pout<< "Found new edge seed: "
416 edgeSeeds.append(curCutFaceEdge.reverseEdge());
420 // Find out what the other side is
424 // If the face is in the slave half of the
425 // enrichedFaces lists, it may be matched against
426 // the master face. It can be recognised by the
427 // fact that all its points belong to one master
428 // face. For this purpose:
429 // 1) Grab the master faces around the point zero
430 // of the cut face and collect all master faces
432 // 2) Loop through the rest of cut face points and
433 // if the point refers to one of the faces marked
434 // by point zero, increment its count.
435 // 3) When completed, the face whose count is
436 // equal to the number of points in the cut face
437 // is the other side. If this is not the case, there is no
438 // face on the other side.
440 if (faceI < slavePatch_.size())
442 Map<labelList>::const_iterator mpfAddrIter =
443 masterPointFaceAddr.find(cutFaceGlobal[0]);
445 bool otherSideFound = false;
447 if (mpfAddrIter != masterPointFaceAddr.end())
451 // Create the label count using point zero
452 const labelList& masterFacesOfPZero = mpfAddrIter();
454 labelList hits(masterFacesOfPZero.size(), 1);
459 pointI < cutFaceGlobal.size();
463 Map<labelList>::const_iterator
465 masterPointFaceAddr.find
467 cutFaceGlobal[pointI]
473 == masterPointFaceAddr.end()
476 // Point is off the master patch. Skip
481 const labelList& curMasterFaces =
484 // For every current face, try to find it in the
486 forAll(curMasterFaces, i)
488 forAll(masterFacesOfPZero, j)
493 == masterFacesOfPZero[j]
503 // If all point are found attempt matching
508 if (hits[pointI] == cutFaceGlobal.size())
511 otherSideFound = true;
515 masterFacesOfPZero[pointI]
518 cfSlave.append(faceI);
520 // Reverse the face such that it
521 // points out of the master patch
526 Pout<< " other side: "
527 << masterFacesOfPZero[pointI]
531 } // end of for all hits
535 if (!otherSideFound || miss)
539 Pout<< " solo slave A" << endl;
543 cfSlave.append(faceI);
548 // First point not in master patch
551 Pout<< " solo slave B" << endl;
555 cfSlave.append(faceI);
562 Pout<< " master side" << endl;
565 cfMaster.append(faceI - slavePatch_.size());
571 // Face not completed. Prepare for the next point search
572 prevPointLabel = curPointLabel;
573 curPointLabel = bestAtanPoint;
574 curPoint = lp[curPointLabel];
575 cutFaceGlobalPoints.append(mp[curPointLabel]);
576 cutFaceLocalPoints.append(curPointLabel);
578 if (debug || cutFaceGlobalPoints.size() > faceSizeDebug)
582 // Check for duplicate points in the face
583 forAll(cutFaceGlobalPoints, checkI)
587 label checkJ = checkI + 1;
588 checkJ < cutFaceGlobalPoints.size();
594 cutFaceGlobalPoints[checkI]
595 == cutFaceGlobalPoints[checkJ]
598 // Shrink local points for debugging
599 cutFaceLocalPoints.shrink();
603 if (faceI < slavePatch_.size())
605 origFace = slavePatch_[faceI];
607 slavePatch_.localFaces()[faceI];
613 [faceI - slavePatch_.size()];
616 masterPatch_.localFaces()
617 [faceI - slavePatch_.size()];
622 "void enrichedPatch::"
623 "calcCutFaces() const"
624 ) << "Duplicate point found in cut face. "
625 << "Error in the face cutting "
626 << "algorithm for global face "
627 << origFace << " local face "
628 << origFaceLocal << nl
629 << "Slave size: " << slavePatch_.size()
631 << masterPatch_.size()
632 << " index: " << faceI << ".\n"
633 << "Face: " << curGlobalFace << nl
634 << "Cut face: " << cutFaceGlobalPoints
635 << " local: " << cutFaceLocalPoints
637 << face(cutFaceLocalPoints).points(lp)
638 << abort(FatalError);
644 } while (!completedCutFace);
645 } // end of used edges
649 Pout<< " Finished face " << faceI << endl;
652 } // end of local faces
654 // Re-pack the list into compact storage
655 cutFacesPtr_ = new faceList();
656 cutFacesPtr_->transfer(cf);
658 cutFaceMasterPtr_ = new labelList();
659 cutFaceMasterPtr_->transfer(cfMaster);
661 cutFaceSlavePtr_ = new labelList();
662 cutFaceSlavePtr_->transfer(cfSlave);
666 void Foam::enrichedPatch::clearCutFaces()
668 deleteDemandDrivenData(cutFacesPtr_);
669 deleteDemandDrivenData(cutFaceMasterPtr_);
670 deleteDemandDrivenData(cutFaceSlavePtr_);
674 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
676 const Foam::faceList& Foam::enrichedPatch::cutFaces() const
683 return *cutFacesPtr_;
687 const Foam::labelList& Foam::enrichedPatch::cutFaceMaster() const
689 if (!cutFaceMasterPtr_)
694 return *cutFaceMasterPtr_;
698 const Foam::labelList& Foam::enrichedPatch::cutFaceSlave() const
700 if (!cutFaceSlavePtr_)
705 return *cutFaceSlavePtr_;
709 // ************************************************************************* //