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/>.
24 \*----------------------------------------------------------------------------*/
26 #include "faceCoupleInfo.H"
28 #include "matchPoints.H"
29 #include "indirectPrimitivePatch.H"
30 #include "meshTools.H"
31 #include "treeDataFace.H"
32 #include "indexedOctree.H"
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 defineTypeNameAndDebug(Foam::faceCoupleInfo, 0);
39 const Foam::scalar Foam::faceCoupleInfo::angleTol_ = 1E-3;
42 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 void Foam::faceCoupleInfo::writeOBJ
47 const fileName& fName,
48 const edgeList& edges,
49 const pointField& points,
55 labelList pointMap(points.size(), -1);
63 const edge& e = edges[edgeI];
69 if (pointMap[pointI] == -1)
71 pointMap[pointI] = newPointI++;
73 meshTools::writeOBJ(str, points[pointI]);
80 forAll(points, pointI)
82 meshTools::writeOBJ(str, points[pointI]);
85 pointMap = identity(points.size());
90 const edge& e = edges[edgeI];
92 str<< "l " << pointMap[e[0]]+1 << ' ' << pointMap[e[1]]+1 << nl;
98 void Foam::faceCoupleInfo::writeOBJ
100 const fileName& fName,
101 const pointField& points0,
102 const pointField& points1
105 Pout<< "Writing connections as edges to " << fName << endl;
113 meshTools::writeOBJ(str, points0[i]);
115 meshTools::writeOBJ(str, points1[i]);
117 str << "l " << vertI-1 << ' ' << vertI << nl;
122 //- Writes face and point connectivity as .obj files.
123 void Foam::faceCoupleInfo::writePointsFaces() const
125 const indirectPrimitivePatch& m = masterPatch();
126 const indirectPrimitivePatch& s = slavePatch();
127 const primitiveFacePatch& c = cutFaces();
131 OFstream str("masterPatch.obj");
132 Pout<< "Writing masterPatch to " << str.name() << endl;
133 meshTools::writeOBJ(str, m.localFaces(), m.localPoints());
136 OFstream str("slavePatch.obj");
137 Pout<< "Writing slavePatch to " << str.name() << endl;
138 meshTools::writeOBJ(str, s.localFaces(), s.localPoints());
141 OFstream str("cutFaces.obj");
142 Pout<< "Writing cutFaces to " << str.name() << endl;
143 meshTools::writeOBJ(str, c.localFaces(), c.localPoints());
146 // Point connectivity
148 Pout<< "Writing cutToMasterPoints to cutToMasterPoints.obj" << endl;
152 "cutToMasterPoints.obj",
154 pointField(c.localPoints(), masterToCutPoints_));
157 Pout<< "Writing cutToSlavePoints to cutToSlavePoints.obj" << endl;
161 "cutToSlavePoints.obj",
163 pointField(c.localPoints(), slaveToCutPoints_)
169 Pout<< "Writing cutToMasterFaces to cutToMasterFaces.obj" << endl;
171 pointField equivMasterFaces(c.size());
173 forAll(cutToMasterFaces(), cutFaceI)
175 label masterFaceI = cutToMasterFaces()[cutFaceI];
177 if (masterFaceI != -1)
179 equivMasterFaces[cutFaceI] = m[masterFaceI].centre(m.points());
183 WarningIn("writePointsFaces()")
184 << "No master face for cut face " << cutFaceI
185 << " at position " << c[cutFaceI].centre(c.points())
188 equivMasterFaces[cutFaceI] = vector::zero;
194 "cutToMasterFaces.obj",
195 calcFaceCentres<List>(c, cutPoints(), 0, c.size()),
201 Pout<< "Writing cutToSlaveFaces to cutToSlaveFaces.obj" << endl;
203 pointField equivSlaveFaces(c.size());
205 forAll(cutToSlaveFaces(), cutFaceI)
207 label slaveFaceI = cutToSlaveFaces()[cutFaceI];
209 equivSlaveFaces[cutFaceI] = s[slaveFaceI].centre(s.points());
214 "cutToSlaveFaces.obj",
215 calcFaceCentres<List>(c, cutPoints(), 0, c.size()),
224 void Foam::faceCoupleInfo::writeEdges
226 const labelList& cutToMasterEdges,
227 const labelList& cutToSlaveEdges
230 const indirectPrimitivePatch& m = masterPatch();
231 const indirectPrimitivePatch& s = slavePatch();
232 const primitiveFacePatch& c = cutFaces();
236 OFstream str("cutToMasterEdges.obj");
237 Pout<< "Writing cutToMasterEdges to " << str.name() << endl;
241 forAll(cutToMasterEdges, cutEdgeI)
243 if (cutToMasterEdges[cutEdgeI] != -1)
245 const edge& masterEdge =
246 m.edges()[cutToMasterEdges[cutEdgeI]];
247 const edge& cutEdge = c.edges()[cutEdgeI];
249 meshTools::writeOBJ(str, m.localPoints()[masterEdge[0]]);
251 meshTools::writeOBJ(str, m.localPoints()[masterEdge[1]]);
253 meshTools::writeOBJ(str, c.localPoints()[cutEdge[0]]);
255 meshTools::writeOBJ(str, c.localPoints()[cutEdge[1]]);
257 str << "l " << vertI-3 << ' ' << vertI-2 << nl;
258 str << "l " << vertI-3 << ' ' << vertI-1 << nl;
259 str << "l " << vertI-3 << ' ' << vertI << nl;
260 str << "l " << vertI-2 << ' ' << vertI-1 << nl;
261 str << "l " << vertI-2 << ' ' << vertI << nl;
262 str << "l " << vertI-1 << ' ' << vertI << nl;
267 OFstream str("cutToSlaveEdges.obj");
268 Pout<< "Writing cutToSlaveEdges to " << str.name() << endl;
272 labelList slaveToCut(invert(s.nEdges(), cutToSlaveEdges));
274 forAll(slaveToCut, edgeI)
276 if (slaveToCut[edgeI] != -1)
278 const edge& slaveEdge = s.edges()[edgeI];
279 const edge& cutEdge = c.edges()[slaveToCut[edgeI]];
281 meshTools::writeOBJ(str, s.localPoints()[slaveEdge[0]]);
283 meshTools::writeOBJ(str, s.localPoints()[slaveEdge[1]]);
285 meshTools::writeOBJ(str, c.localPoints()[cutEdge[0]]);
287 meshTools::writeOBJ(str, c.localPoints()[cutEdge[1]]);
289 str << "l " << vertI-3 << ' ' << vertI-2 << nl;
290 str << "l " << vertI-3 << ' ' << vertI-1 << nl;
291 str << "l " << vertI-3 << ' ' << vertI << nl;
292 str << "l " << vertI-2 << ' ' << vertI-1 << nl;
293 str << "l " << vertI-2 << ' ' << vertI << nl;
294 str << "l " << vertI-1 << ' ' << vertI << nl;
303 // Given an edgelist and a map for the points on the edges it tries to find
304 // the corresponding patch edges.
305 Foam::labelList Foam::faceCoupleInfo::findMappedEdges
307 const edgeList& edges,
308 const labelList& pointMap,
309 const indirectPrimitivePatch& patch
312 labelList toPatchEdges(edges.size());
314 forAll(toPatchEdges, edgeI)
316 const edge& e = edges[edgeI];
318 label v0 = pointMap[e[0]];
319 label v1 = pointMap[e[1]];
321 toPatchEdges[edgeI] =
325 patch.pointEdges()[v0],
334 // Detect a cut edge which originates from two boundary faces having different
336 bool Foam::faceCoupleInfo::regionEdge
338 const polyMesh& slaveMesh,
339 const label slaveEdgeI
342 const labelList& eFaces = slavePatch().edgeFaces()[slaveEdgeI];
344 if (eFaces.size() == 1)
350 // Count how many different patches connected to this edge.
356 label faceI = eFaces[i];
358 label meshFaceI = slavePatch().addressing()[faceI];
360 label patchI = slaveMesh.boundaryMesh().whichPatch(meshFaceI);
366 else if (patchI != patch0)
368 // Found two different patches connected to this edge.
377 // Find edge using pointI that is most aligned with vector between
378 // master points. Patchdivision tells us whether or not to use
379 // patch information to match edges.
380 Foam::label Foam::faceCoupleInfo::mostAlignedCutEdge
383 const polyMesh& slaveMesh,
384 const bool patchDivision,
385 const labelList& cutToMasterEdges,
386 const labelList& cutToSlaveEdges,
388 const label edgeStart,
392 const pointField& localPoints = cutFaces().localPoints();
394 const labelList& pEdges = cutFaces().pointEdges()[pointI];
398 Pout<< "mostAlignedEdge : finding nearest edge among "
399 << UIndirectList<edge>(cutFaces().edges(), pEdges)()
400 << " connected to point " << pointI
401 << " coord:" << localPoints[pointI]
402 << " running between " << edgeStart << " coord:"
403 << localPoints[edgeStart]
404 << " and " << edgeEnd << " coord:"
405 << localPoints[edgeEnd]
409 // Find the edge that gets us nearest end.
412 scalar maxCos = -GREAT;
416 label edgeI = pEdges[i];
422 && cutToMasterEdges[edgeI] == -1
426 && regionEdge(slaveMesh, cutToSlaveEdges[edgeI])
430 const edge& e = cutFaces().edges()[edgeI];
432 label otherPointI = e.otherVertex(pointI);
434 if (otherPointI == edgeEnd)
436 // Shortcut: found edge end point.
439 Pout<< " mostAlignedEdge : found end point " << edgeEnd
445 // Get angle between edge and edge to masterEnd
447 vector eVec(localPoints[otherPointI] - localPoints[pointI]);
449 scalar magEVec = mag(eVec);
451 if (magEVec < VSMALL)
453 WarningIn("faceCoupleInfo::mostAlignedEdge")
454 << "Crossing zero sized edge " << edgeI
455 << " coords:" << localPoints[otherPointI]
456 << localPoints[pointI]
457 << " when walking from " << localPoints[edgeStart]
458 << " to " << localPoints[edgeEnd]
465 vector eToEndPoint(localPoints[edgeEnd] - localPoints[otherPointI]);
466 eToEndPoint /= mag(eToEndPoint);
468 scalar cosAngle = eVec & eToEndPoint;
472 Pout<< " edge:" << e << " points:" << localPoints[pointI]
473 << localPoints[otherPointI]
475 << " vecToEnd:" << eToEndPoint
476 << " cosAngle:" << cosAngle
480 if (cosAngle > maxCos)
488 if (maxCos > 1 - angleTol_)
499 // Construct points to split points map (in cut addressing)
500 void Foam::faceCoupleInfo::setCutEdgeToPoints(const labelList& cutToMasterEdges)
502 labelListList masterToCutEdges
506 masterPatch().nEdges(),
511 const edgeList& cutEdges = cutFaces().edges();
513 // Size extra big so searching is faster
514 cutEdgeToPoints_.resize
516 masterPatch().nEdges()
517 + slavePatch().nEdges()
521 forAll(masterToCutEdges, masterEdgeI)
523 const edge& masterE = masterPatch().edges()[masterEdgeI];
525 //Pout<< "Master:" << masterPatch().localPoints()[masterE[0]] << ' '
526 // << masterPatch().localPoints()[masterE[1]] << endl;
528 const labelList& stringedEdges = masterToCutEdges[masterEdgeI];
530 if (stringedEdges.empty())
534 "faceCoupleInfo::setCutEdgeToPoints"
536 ) << "Did not match all of master edges to cutFace edges"
538 << "First unmatched edge:" << masterEdgeI << " endPoints:"
539 << masterPatch().localPoints()[masterE[0]]
540 << masterPatch().localPoints()[masterE[1]]
542 << "This usually means that the slave patch is not a"
543 << " subdivision of the master patch"
544 << abort(FatalError);
546 else if (stringedEdges.size() > 1)
548 // String up the edges between e[0] and e[1]. Store the points
549 // inbetween e[0] and e[1] (all in cutFaces() labels)
551 DynamicList<label> splitPoints(stringedEdges.size()-1);
553 // Unsplit edge endpoints
554 const edge unsplitEdge
556 masterToCutPoints_[masterE[0]],
557 masterToCutPoints_[masterE[1]]
560 label startVertI = unsplitEdge[0];
561 label startEdgeI = -1;
563 while (startVertI != unsplitEdge[1])
565 // Loop over all string of edges. Update
566 // - startVertI : previous vertex
567 // - startEdgeI : previous edge
568 // and insert any points into splitPoints
571 label oldStart = startVertI;
573 forAll(stringedEdges, i)
575 label edgeI = stringedEdges[i];
577 if (edgeI != startEdgeI)
579 const edge& e = cutEdges[edgeI];
581 //Pout<< " cut:" << e << " at:"
582 // << cutFaces().localPoints()[e[0]]
583 // << ' ' << cutFaces().localPoints()[e[1]] << endl;
585 if (e[0] == startVertI)
589 if (e[1] != unsplitEdge[1])
591 splitPoints.append(e[1]);
595 else if (e[1] == startVertI)
599 if (e[0] != unsplitEdge[1])
601 splitPoints.append(e[0]);
609 if (oldStart == startVertI)
613 "faceCoupleInfo::setCutEdgeToPoints"
615 ) << " unsplitEdge:" << unsplitEdge
616 << " does not correspond to split edges "
617 << UIndirectList<edge>(cutEdges, stringedEdges)()
618 << abort(FatalError);
622 //Pout<< "For master edge:"
624 // << " Found stringed points "
625 // << UIndirectList<point>
627 // cutFaces().localPoints(),
628 // splitPoints.shrink()
632 cutEdgeToPoints_.insert(unsplitEdge, splitPoints.shrink());
638 // Determines rotation for f1 to match up with f0, i.e. the index in f0 of
639 // the first point of f1.
640 Foam::label Foam::faceCoupleInfo::matchFaces
643 const pointField& points0,
645 const pointField& points1,
647 const bool sameOrientation
650 if (f0.size() != f1.size())
654 "faceCoupleInfo::matchFaces"
655 "(const scalar, const face&, const pointField&"
656 ", const face&, const pointField&)"
657 ) << "Different sizes for supposedly matching faces." << nl
658 << "f0:" << f0 << " coords:" << UIndirectList<point>(points0, f0)()
660 << "f1:" << f1 << " coords:" << UIndirectList<point>(points1, f1)()
661 << abort(FatalError);
664 const scalar absTolSqr = sqr(absTol);
671 // See -if starting from startFp on f0- the two faces match.
672 bool fullMatch = true;
679 scalar distSqr = Foam::magSqr(points0[f0[fp0]] - points1[f1[fp1]]);
681 if (distSqr > absTolSqr)
687 fp0 = f0.fcIndex(fp0); // walk forward
691 fp1 = f1.fcIndex(fp1);
695 fp1 = f1.rcIndex(fp1);
710 "faceCoupleInfo::matchFaces"
711 "(const scalar, const face&, const pointField&"
712 ", const face&, const pointField&)"
713 ) << "No unique match between two faces" << nl
714 << "Face " << f0 << " coords "
715 << UIndirectList<point>(points0, f0)() << nl
716 << "Face " << f1 << " coords "
717 << UIndirectList<point>(points1, f1)()
718 << "when using tolerance " << absTol
719 << " and forwardMatching:" << sameOrientation
720 << abort(FatalError);
727 // Find correspondence from patch points to cut points. This might
728 // detect shared points so the output is a patch-to-cut point list
729 // and a compaction list for the cut points (which will always be equal or more
730 // connected than the patch).
731 // Returns true if there are any duplicates.
732 bool Foam::faceCoupleInfo::matchPointsThroughFaces
735 const pointField& cutPoints,
736 const faceList& cutFaces,
737 const pointField& patchPoints,
738 const faceList& patchFaces,
739 const bool sameOrientation,
741 labelList& patchToCutPoints, // patch to (uncompacted) cut points
742 labelList& cutToCompact, // compaction list for cut points
743 labelList& compactToCut // inverse ,,
747 // From slave to cut point
748 patchToCutPoints.setSize(patchPoints.size());
749 patchToCutPoints = -1;
751 // Compaction list for cut points: either -1 or index into master which
752 // gives the point to compact to.
753 labelList cutPointRegion(cutPoints.size(), -1);
754 DynamicList<label> cutPointRegionMaster;
756 forAll(patchFaces, patchFaceI)
758 const face& patchF = patchFaces[patchFaceI];
760 //const face& cutF = cutFaces[patchToCutFaces[patchFaceI]];
761 const face& cutF = cutFaces[patchFaceI];
763 // Do geometric matching to get position of cutF[0] in patchF
764 label patchFp = matchFaces
771 sameOrientation // orientation
776 label cutPointI = cutF[cutFp];
777 label patchPointI = patchF[patchFp];
779 //const point& cutPt = cutPoints[cutPointI];
780 //const point& patchPt = patchPoints[patchPointI];
781 //if (mag(cutPt - patchPt) > SMALL)
783 // FatalErrorIn("matchPointsThroughFaces")
784 // << "cutP:" << cutPt
785 // << " patchP:" << patchPt
786 // << abort(FatalError);
789 if (patchToCutPoints[patchPointI] == -1)
791 patchToCutPoints[patchPointI] = cutPointI;
793 else if (patchToCutPoints[patchPointI] != cutPointI)
795 // Multiple cut points connecting to same patch.
796 // Check if already have region & region master for this set
797 label otherCutPointI = patchToCutPoints[patchPointI];
799 //Pout<< "PatchPoint:" << patchPt
800 // << " matches to:" << cutPointI
801 // << " coord:" << cutPoints[cutPointI]
802 // << " and to:" << otherCutPointI
803 // << " coord:" << cutPoints[otherCutPointI]
806 if (cutPointRegion[otherCutPointI] != -1)
808 // Have region for this set. Copy.
809 label region = cutPointRegion[otherCutPointI];
810 cutPointRegion[cutPointI] = region;
812 // Update region master with min point label
813 cutPointRegionMaster[region] = min
815 cutPointRegionMaster[region],
821 // Create new region.
822 label region = cutPointRegionMaster.size();
823 cutPointRegionMaster.append
825 min(cutPointI, otherCutPointI)
827 cutPointRegion[cutPointI] = region;
828 cutPointRegion[otherCutPointI] = region;
834 patchFp = patchF.fcIndex(patchFp);
838 patchFp = patchF.rcIndex(patchFp);
843 // Rework region&master into compaction array
844 compactToCut.setSize(cutPointRegion.size());
845 cutToCompact.setSize(cutPointRegion.size());
847 label compactPointI = 0;
849 forAll(cutPointRegion, i)
851 if (cutPointRegion[i] == -1)
853 // Unduplicated point. Allocate new compacted point.
854 cutToCompact[i] = compactPointI;
855 compactToCut[compactPointI] = i;
860 // Duplicate point. Get master.
862 label masterPointI = cutPointRegionMaster[cutPointRegion[i]];
864 if (cutToCompact[masterPointI] == -1)
866 cutToCompact[masterPointI] = compactPointI;
867 compactToCut[compactPointI] = masterPointI;
870 cutToCompact[i] = cutToCompact[masterPointI];
873 compactToCut.setSize(compactPointI);
875 return compactToCut.size() != cutToCompact.size();
879 // Return max distance from any point on cutF to masterF
880 Foam::scalar Foam::faceCoupleInfo::maxDistance
883 const pointField& cutPoints,
885 const pointField& masterPoints
888 scalar maxDist = -GREAT;
892 const point& cutPt = cutPoints[cutF[fp]];
894 pointHit pHit = masterF.nearestPoint(cutPt, masterPoints);
896 maxDist = max(maxDist, pHit.distance());
902 void Foam::faceCoupleInfo::findPerfectMatchingFaces
904 const primitiveMesh& mesh0,
905 const primitiveMesh& mesh1,
908 labelList& mesh0Faces,
909 labelList& mesh1Faces
912 // Face centres of external faces (without invoking
913 // mesh.faceCentres since mesh might have been clearedOut)
917 calcFaceCentres<List>
921 mesh0.nInternalFaces(),
922 mesh0.nFaces() - mesh0.nInternalFaces()
928 calcFaceCentres<List>
932 mesh1.nInternalFaces(),
933 mesh1.nFaces() - mesh1.nInternalFaces()
940 Pout<< "Face matching tolerance : " << absTol << endl;
944 // Match geometrically
946 bool matchedAllFaces = matchPoints
950 scalarField(fc1.size(), absTol),
958 << "faceCoupleInfo::faceCoupleInfo : "
959 << "Matched ALL " << fc1.size()
960 << " boundary faces of mesh0 to boundary faces of mesh1." << endl
961 << "This is only valid if the mesh to add is fully"
962 << " enclosed by the mesh it is added to." << endl;
969 mesh0Faces.setSize(fc0.size());
970 mesh1Faces.setSize(fc1.size());
974 if (from1To0[i] != -1)
976 mesh1Faces[nMatched] = i + mesh1.nInternalFaces();
977 mesh0Faces[nMatched] = from1To0[i] + mesh0.nInternalFaces();
983 mesh0Faces.setSize(nMatched);
984 mesh1Faces.setSize(nMatched);
988 void Foam::faceCoupleInfo::findSlavesCoveringMaster
990 const primitiveMesh& mesh0,
991 const primitiveMesh& mesh1,
994 labelList& mesh0Faces,
995 labelList& mesh1Faces
998 // Construct octree from all mesh0 boundary faces
999 labelList bndFaces(mesh0.nFaces()-mesh0.nInternalFaces());
1002 bndFaces[i] = mesh0.nInternalFaces() + i;
1005 treeBoundBox overallBb(mesh0.points());
1007 Random rndGen(123456);
1009 indexedOctree<treeDataFace> tree
1011 treeDataFace // all information needed to search faces
1013 false, // do not cache bb
1015 bndFaces // boundary faces only
1017 overallBb.extend(rndGen, 1E-4), // overall search domain
1025 Pout<< "findSlavesCoveringMaster :"
1026 << " constructed octree for mesh0 boundary faces" << endl;
1029 // Search nearest face for every mesh1 boundary face.
1031 labelHashSet mesh0Set(mesh0.nFaces() - mesh0.nInternalFaces());
1032 labelHashSet mesh1Set(mesh1.nFaces() - mesh1.nInternalFaces());
1036 label mesh1FaceI = mesh1.nInternalFaces();
1037 mesh1FaceI < mesh1.nFaces();
1041 const face& f1 = mesh1.faces()[mesh1FaceI];
1043 // Generate face centre (prevent cellCentres() reconstruction)
1044 point fc(f1.centre(mesh1.points()));
1046 pointIndexHit nearInfo = tree.findNearest(fc, Foam::sqr(absTol));
1050 label mesh0FaceI = tree.shapes().faceLabels()[nearInfo.index()];
1052 // Check if points of f1 actually lie on top of mesh0 face
1053 // This is the bit that might fail since if f0 is severely warped
1054 // and f1's points are not present on f0 (since subdivision)
1055 // then the distance of the points to f0 might be quite large
1056 // and the test will fail. This all should in fact be some kind
1057 // of walk from known corresponding points/edges/faces.
1063 mesh0.faces()[mesh0FaceI],
1069 mesh0Set.insert(mesh0FaceI);
1070 mesh1Set.insert(mesh1FaceI);
1077 Pout<< "findSlavesCoveringMaster :"
1078 << " matched " << mesh1Set.size() << " mesh1 faces to "
1079 << mesh0Set.size() << " mesh0 faces" << endl;
1082 mesh0Faces = mesh0Set.toc();
1083 mesh1Faces = mesh1Set.toc();
1087 // Grow cutToMasterFace across 'internal' edges.
1088 Foam::label Foam::faceCoupleInfo::growCutFaces
1090 const labelList& cutToMasterEdges,
1091 Map<labelList>& candidates
1096 Pout<< "growCutFaces :"
1097 << " growing cut faces to masterPatch" << endl;
1100 label nTotChanged = 0;
1104 const labelListList& cutFaceEdges = cutFaces().faceEdges();
1105 const labelListList& cutEdgeFaces = cutFaces().edgeFaces();
1109 forAll(cutToMasterFaces_, cutFaceI)
1111 const label masterFaceI = cutToMasterFaces_[cutFaceI];
1113 if (masterFaceI != -1)
1115 // We now have a cutFace for which we have already found a
1116 // master face. Grow this masterface across any internal edge
1117 // (internal: no corresponding master edge)
1119 const labelList& fEdges = cutFaceEdges[cutFaceI];
1123 const label cutEdgeI = fEdges[i];
1125 if (cutToMasterEdges[cutEdgeI] == -1)
1128 // - internal to the cutPatch (since all region edges
1130 // - on cutFaceI which corresponds to masterFace.
1131 // Mark all connected faces with this masterFace.
1133 const labelList& eFaces = cutEdgeFaces[cutEdgeI];
1137 const label faceI = eFaces[j];
1139 if (cutToMasterFaces_[faceI] == -1)
1141 cutToMasterFaces_[faceI] = masterFaceI;
1142 candidates.erase(faceI);
1145 else if (cutToMasterFaces_[faceI] != masterFaceI)
1147 const pointField& cutPoints =
1148 cutFaces().points();
1149 const pointField& masterPoints =
1150 masterPatch().points();
1152 const edge& e = cutFaces().edges()[cutEdgeI];
1154 label myMaster = cutToMasterFaces_[faceI];
1155 const face& myF = masterPatch()[myMaster];
1157 const face& nbrF = masterPatch()[masterFaceI];
1161 "faceCoupleInfo::growCutFaces"
1162 "(const labelList&, Map<labelList>&)"
1164 << cutFaces()[faceI].points(cutPoints)
1167 << " but also connects to nbr face "
1168 << cutFaces()[cutFaceI].points(cutPoints)
1169 << " with master " << masterFaceI
1172 << myF.points(masterPoints)
1173 << " nbrMasterFace:"
1174 << nbrF.points(masterPoints) << nl
1175 << "Across cut edge " << cutEdgeI
1177 << cutFaces().localPoints()[e[0]]
1178 << cutFaces().localPoints()[e[1]]
1179 << abort(FatalError);
1189 Pout<< "growCutFaces : Grown an additional " << nChanged
1190 << " cut to master face" << " correspondence" << endl;
1193 nTotChanged += nChanged;
1205 void Foam::faceCoupleInfo::checkMatch(const labelList& cutToMasterEdges) const
1207 const pointField& cutLocalPoints = cutFaces().localPoints();
1209 const pointField& masterLocalPoints = masterPatch().localPoints();
1210 const faceList& masterLocalFaces = masterPatch().localFaces();
1212 forAll(cutToMasterEdges, cutEdgeI)
1214 const edge& e = cutFaces().edges()[cutEdgeI];
1216 if (cutToMasterEdges[cutEdgeI] == -1)
1218 // Internal edge. Check that master face is same on both sides.
1219 const labelList& cutEFaces = cutFaces().edgeFaces()[cutEdgeI];
1221 label masterFaceI = -1;
1223 forAll(cutEFaces, i)
1225 label cutFaceI = cutEFaces[i];
1227 if (cutToMasterFaces_[cutFaceI] != -1)
1229 if (masterFaceI == -1)
1231 masterFaceI = cutToMasterFaces_[cutFaceI];
1233 else if (masterFaceI != cutToMasterFaces_[cutFaceI])
1235 label myMaster = cutToMasterFaces_[cutFaceI];
1236 const face& myF = masterLocalFaces[myMaster];
1238 const face& nbrF = masterLocalFaces[masterFaceI];
1242 "faceCoupleInfo::checkMatch(const labelList&) const"
1244 << "Internal CutEdge " << e
1246 << cutLocalPoints[e[0]]
1247 << cutLocalPoints[e[1]]
1248 << " connects to master " << myMaster
1249 << " and to master " << masterFaceI << nl
1251 << myF.points(masterLocalPoints)
1252 << " nbrMasterFace:"
1253 << nbrF.points(masterLocalPoints)
1254 << abort(FatalError);
1263 // Extends matching information by elimination across cutFaces using more
1264 // than one region edge. Updates cutToMasterFaces_ and sets candidates
1265 // which is for every cutface on a region edge the possible master faces.
1266 Foam::label Foam::faceCoupleInfo::matchEdgeFaces
1268 const labelList& cutToMasterEdges,
1269 Map<labelList>& candidates
1272 // For every unassigned cutFaceI the possible list of master faces.
1274 candidates.resize(cutFaces().size());
1278 forAll(cutToMasterEdges, cutEdgeI)
1280 label masterEdgeI = cutToMasterEdges[cutEdgeI];
1282 if (masterEdgeI != -1)
1284 // So cutEdgeI is matched to masterEdgeI. For all cut faces using
1285 // the cut edge store the master face as a candidate match.
1287 const labelList& cutEFaces = cutFaces().edgeFaces()[cutEdgeI];
1288 const labelList& masterEFaces =
1289 masterPatch().edgeFaces()[masterEdgeI];
1291 forAll(cutEFaces, i)
1293 label cutFaceI = cutEFaces[i];
1295 if (cutToMasterFaces_[cutFaceI] == -1)
1297 // So this face (cutFaceI) is on an edge (cutEdgeI) that
1298 // is used by some master faces (masterEFaces). Check if
1299 // the cutFaceI and some of these masterEFaces share more
1300 // than one edge (which uniquely defines face)
1302 // Combine master faces with current set of candidate
1304 Map<labelList>::iterator fnd = candidates.find(cutFaceI);
1306 if (fnd == candidates.end())
1308 // No info yet for cutFaceI. Add all master faces as
1310 candidates.insert(cutFaceI, masterEFaces);
1314 // From some other cutEdgeI there are already some
1315 // candidate master faces. Check the overlap with
1316 // the current set of master faces.
1317 const labelList& masterFaces = fnd();
1319 DynamicList<label> newCandidates(masterFaces.size());
1321 forAll(masterEFaces, j)
1323 if (findIndex(masterFaces, masterEFaces[j]) != -1)
1325 newCandidates.append(masterEFaces[j]);
1329 if (newCandidates.size() == 1)
1331 // We found a perfect match. Delete entry from
1333 cutToMasterFaces_[cutFaceI] = newCandidates[0];
1334 candidates.erase(cutFaceI);
1339 // Should not happen?
1340 //Pout<< "On edge:" << cutEdgeI
1341 // << " have connected masterFaces:"
1343 // << " and from previous edge we have"
1344 // << " connected masterFaces" << masterFaces
1345 // << " . Overlap:" << newCandidates << endl;
1347 fnd() = newCandidates.shrink();
1358 Pout<< "matchEdgeFaces : Found " << nChanged
1359 << " faces where there was"
1360 << " only one remaining choice for cut-master correspondence"
1368 // Gets a list of cutFaces (that use a master edge) and the candidate
1370 // Finds most aligned master face.
1371 Foam::label Foam::faceCoupleInfo::geometricMatchEdgeFaces
1373 Map<labelList>& candidates
1376 const pointField& cutPoints = cutFaces().points();
1380 // Mark all master faces that have been matched so far.
1382 labelListList masterToCutFaces
1386 masterPatch().size(),
1391 forAllConstIter(Map<labelList>, candidates, iter)
1393 label cutFaceI = iter.key();
1395 const face& cutF = cutFaces()[cutFaceI];
1397 if (cutToMasterFaces_[cutFaceI] == -1)
1399 const labelList& masterFaces = iter();
1401 // Find the best matching master face.
1402 scalar minDist = GREAT;
1403 label minMasterFaceI = -1;
1405 forAll(masterFaces, i)
1407 label masterFaceI = masterFaces[i];
1409 if (masterToCutFaces[masterFaces[i]].empty())
1411 scalar dist = maxDistance
1415 masterPatch()[masterFaceI],
1416 masterPatch().points()
1422 minMasterFaceI = masterFaceI;
1427 if (minMasterFaceI != -1)
1429 cutToMasterFaces_[cutFaceI] = minMasterFaceI;
1430 masterToCutFaces[minMasterFaceI] = cutFaceI;
1436 // (inefficiently) force candidates to be uptodate.
1437 forAll(cutToMasterFaces_, cutFaceI)
1439 if (cutToMasterFaces_[cutFaceI] != -1)
1441 candidates.erase(cutFaceI);
1448 Pout<< "geometricMatchEdgeFaces : Found " << nChanged
1449 << " faces where there was"
1450 << " only one remaining choice for cut-master correspondence"
1458 // Calculate the set of cut faces inbetween master and slave patch
1459 // assuming perfect match (and optional face ordering on slave)
1460 void Foam::faceCoupleInfo::perfectPointMatch
1462 const scalar absTol,
1463 const bool slaveFacesOrdered
1468 Pout<< "perfectPointMatch :"
1469 << " Matching master and slave to cut."
1470 << " Master and slave faces are identical" << nl;
1472 if (slaveFacesOrdered)
1474 Pout<< "and master and slave faces are ordered"
1475 << " (on coupled patches)" << endl;
1479 Pout<< "and master and slave faces are not ordered"
1480 << " (on coupled patches)" << endl;
1484 cutToMasterFaces_ = identity(masterPatch().size());
1485 cutPoints_ = masterPatch().localPoints();
1488 new primitiveFacePatch
1490 masterPatch().localFaces(),
1494 masterToCutPoints_ = identity(cutPoints_.size());
1497 // Cut faces to slave patch.
1498 bool matchedAllFaces = false;
1500 if (slaveFacesOrdered)
1502 cutToSlaveFaces_ = identity(cutFaces().size());
1503 matchedAllFaces = (cutFaces().size() == slavePatch().size());
1507 // Faces do not have to be ordered (but all have
1508 // to match). Note: Faces will be already ordered if we enter here from
1509 // construct from meshes.
1510 matchedAllFaces = matchPoints
1512 calcFaceCentres<List>
1519 calcFaceCentres<IndirectList>
1522 slavePatch().points(),
1526 scalarField(slavePatch().size(), absTol),
1533 if (!matchedAllFaces)
1537 "faceCoupleInfo::perfectPointMatch"
1538 "(const scalar, const bool)"
1539 ) << "Did not match all of the master faces to the slave faces"
1541 << "This usually means that the slave patch and master patch"
1542 << " do not align to within " << absTol << " meter."
1543 << abort(FatalError);
1547 // Find correspondence from slave points to cut points. This might
1548 // detect shared points so the output is a slave-to-cut point list
1549 // and a compaction list.
1551 labelList cutToCompact, compactToCut;
1552 matchPointsThroughFaces
1555 cutFaces().localPoints(),
1556 reorder(cutToSlaveFaces_, cutFaces().localFaces()),
1557 slavePatch().localPoints(),
1558 slavePatch().localFaces(),
1559 false, // slave and cut have opposite orientation
1561 slaveToCutPoints_, // slave to (uncompacted) cut points
1562 cutToCompact, // compaction map: from cut to compacted
1563 compactToCut // compaction map: from compacted to cut
1567 // Use compaction lists to renumber cutPoints.
1568 cutPoints_ = UIndirectList<point>(cutPoints_, compactToCut)();
1570 const faceList& cutLocalFaces = cutFaces().localFaces();
1572 faceList compactFaces(cutLocalFaces.size());
1573 forAll(cutLocalFaces, i)
1575 compactFaces[i] = renumber(cutToCompact, cutLocalFaces[i]);
1579 new primitiveFacePatch
1586 inplaceRenumber(cutToCompact, slaveToCutPoints_);
1587 inplaceRenumber(cutToCompact, masterToCutPoints_);
1591 // Calculate the set of cut faces inbetween master and slave patch
1592 // assuming that slave patch is subdivision of masterPatch.
1593 void Foam::faceCoupleInfo::subDivisionMatch
1595 const polyMesh& slaveMesh,
1596 const bool patchDivision,
1602 Pout<< "subDivisionMatch :"
1603 << " Matching master and slave to cut."
1604 << " Slave can be subdivision of master but all master edges"
1605 << " have to be covered by slave edges." << endl;
1608 // Assume slave patch is subdivision of the master patch so cutFaces is a
1609 // copy of the slave (but reversed since orientation has to be like master).
1610 cutPoints_ = slavePatch().localPoints();
1612 faceList cutFaces(slavePatch().size());
1616 cutFaces[i] = slavePatch().localFaces()[i].reverseFace();
1618 cutFacesPtr_.reset(new primitiveFacePatch(cutFaces, cutPoints_));
1621 // Cut is copy of slave so addressing to slave is trivial.
1622 cutToSlaveFaces_ = identity(cutFaces().size());
1623 slaveToCutPoints_ = identity(slavePatch().nPoints());
1625 // Cut edges to slave patch
1626 labelList cutToSlaveEdges
1631 slaveToCutPoints_, //note:should be cutToSlavePoints but since iden
1639 OFstream str("regionEdges.obj");
1641 Pout<< "subDivisionMatch :"
1642 << " addressing for slave patch fully done."
1643 << " Dumping region edges to " << str.name() << endl;
1647 forAll(slavePatch().edges(), slaveEdgeI)
1649 if (regionEdge(slaveMesh, slaveEdgeI))
1651 const edge& e = slavePatch().edges()[slaveEdgeI];
1653 meshTools::writeOBJ(str, slavePatch().localPoints()[e[0]]);
1655 meshTools::writeOBJ(str, slavePatch().localPoints()[e[1]]);
1657 str<< "l " << vertI-1 << ' ' << vertI << nl;
1663 // Addressing from cut to master.
1665 // Cut points to master patch
1666 // - determine master points to cut points. Has to be full!
1667 // - invert to get cut to master
1670 Pout<< "subDivisionMatch :"
1671 << " matching master points to cut points" << endl;
1674 bool matchedAllPoints = matchPoints
1676 masterPatch().localPoints(),
1678 scalarField(masterPatch().nPoints(), absTol),
1683 if (!matchedAllPoints)
1687 "faceCoupleInfo::subDivisionMatch"
1688 "(const polyMesh&, const bool, const scalar)"
1689 ) << "Did not match all of the master points to the slave points"
1691 << "This usually means that the slave patch is not a"
1692 << " subdivision of the master patch"
1693 << abort(FatalError);
1697 // Do masterEdges to cutEdges :
1698 // - mark all edges between two masterEdge endpoints. (geometric test since
1699 // this is the only distinction)
1700 // - this gives the borders inbetween which all cutfaces come from
1701 // a single master face.
1704 Pout<< "subDivisionMatch :"
1705 << " matching cut edges to master edges" << endl;
1708 const edgeList& masterEdges = masterPatch().edges();
1709 const pointField& masterPoints = masterPatch().localPoints();
1711 const edgeList& cutEdges = cutFaces().edges();
1713 labelList cutToMasterEdges(cutFaces().nEdges(), -1);
1715 forAll(masterEdges, masterEdgeI)
1717 const edge& masterEdge = masterEdges[masterEdgeI];
1719 label cutPoint0 = masterToCutPoints_[masterEdge[0]];
1720 label cutPoint1 = masterToCutPoints_[masterEdge[1]];
1722 // Find edges between cutPoint0 and cutPoint1.
1724 label cutPointI = cutPoint0;
1727 // Find edge (starting at pointI on cut), aligned with master
1744 // Problem. Report while matching to produce nice error message
1757 Pout<< "Dumping unmatched pointEdges to errorEdges.obj"
1768 cutFaces().pointEdges()[cutPointI]
1771 cutFaces().localPoints(),
1777 "faceCoupleInfo::subDivisionMatch"
1778 "(const polyMesh&, const bool, const scalar)"
1779 ) << "Problem in finding cut edges corresponding to"
1780 << " master edge " << masterEdge
1781 << " points:" << masterPoints[masterEdge[0]]
1782 << ' ' << masterPoints[masterEdge[1]]
1783 << " corresponding cut edge: (" << cutPoint0
1785 << abort(FatalError);
1788 cutToMasterEdges[cutEdgeI] = masterEdgeI;
1790 cutPointI = cutEdges[cutEdgeI].otherVertex(cutPointI);
1792 } while (cutPointI != cutPoint1);
1797 // Write all matched edges.
1798 writeEdges(cutToMasterEdges, cutToSlaveEdges);
1801 // Rework cutToMasterEdges into list of points inbetween two endpoints
1802 // (cutEdgeToPoints_)
1803 setCutEdgeToPoints(cutToMasterEdges);
1806 // Now that we have marked the cut edges that lie on top of master edges
1807 // we can find cut faces that have two (or more) of these edges.
1808 // Note that there can be multiple faces having two or more matched edges
1809 // since the cut faces can form a non-manifold surface(?)
1810 // So the matching is done as an elimination process where for every
1811 // cutFace on a matched edge we store the possible master faces and
1812 // eliminate more and more until we only have one possible master face
1817 Pout<< "subDivisionMatch :"
1818 << " matching (topological) cut faces to masterPatch" << endl;
1821 // For every unassigned cutFaceI the possible list of master faces.
1822 Map<labelList> candidates(cutFaces().size());
1824 cutToMasterFaces_.setSize(cutFaces().size());
1825 cutToMasterFaces_ = -1;
1829 // See if there are any edges left where there is only one remaining
1831 label nChanged = matchEdgeFaces(cutToMasterEdges, candidates);
1833 checkMatch(cutToMasterEdges);
1836 // Now we should have found a face correspondence for every cutFace
1837 // that uses two or more cutEdges. Floodfill from these across
1838 // 'internal' cutedges (i.e. edges that do not have a master
1839 // equivalent) to determine some more cutToMasterFaces
1840 nChanged += growCutFaces(cutToMasterEdges, candidates);
1842 checkMatch(cutToMasterEdges);
1852 Pout<< "subDivisionMatch :"
1853 << " matching (geometric) cut faces to masterPatch" << endl;
1856 // Above should have matched all cases fully. Cannot prove this yet so
1857 // do any remaining unmatched edges by a geometric test.
1860 // See if there are any edges left where there is only one remaining
1862 label nChanged = geometricMatchEdgeFaces(candidates);
1864 checkMatch(cutToMasterEdges);
1866 nChanged += growCutFaces(cutToMasterEdges, candidates);
1868 checkMatch(cutToMasterEdges);
1877 // All cut faces matched?
1878 forAll(cutToMasterFaces_, cutFaceI)
1880 if (cutToMasterFaces_[cutFaceI] == -1)
1882 const face& cutF = cutFaces()[cutFaceI];
1886 "faceCoupleInfo::subDivisionMatch"
1887 "(const polyMesh&, const bool, const scalar)"
1888 ) << "Did not match all of cutFaces to a master face" << nl
1889 << "First unmatched cut face:" << cutFaceI << " with points:"
1890 << UIndirectList<point>(cutFaces().points(), cutF)()
1892 << "This usually means that the slave patch is not a"
1893 << " subdivision of the master patch"
1894 << abort(FatalError);
1900 Pout<< "subDivisionMatch :"
1901 << " finished matching master and slave to cut" << endl;
1911 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1913 // Construct from mesh data
1914 Foam::faceCoupleInfo::faceCoupleInfo
1916 const polyMesh& masterMesh,
1917 const polyMesh& slaveMesh,
1918 const scalar absTol,
1919 const bool perfectMatch
1922 masterPatchPtr_(NULL),
1923 slavePatchPtr_(NULL),
1926 cutToMasterFaces_(0),
1927 masterToCutPoints_(0),
1928 cutToSlaveFaces_(0),
1929 slaveToCutPoints_(0),
1932 // Get faces on both meshes that are aligned.
1933 // (not ordered i.e. masterToMesh[0] does
1934 // not couple to slaveToMesh[0]. This ordering is done later on)
1935 labelList masterToMesh;
1936 labelList slaveToMesh;
1940 // Identical faces so use tight face-centre comparison.
1941 findPerfectMatchingFaces
1952 // Slave subdivision of master so use 'nearest'. Bit dodgy, especially
1953 // with using absTol (which is quite small)
1954 findSlavesCoveringMaster
1964 // Construct addressing engines for both sides
1965 masterPatchPtr_.reset
1967 new indirectPrimitivePatch
1969 IndirectList<face>(masterMesh.faces(), masterToMesh),
1974 slavePatchPtr_.reset
1976 new indirectPrimitivePatch
1978 IndirectList<face>(slaveMesh.faces(), slaveToMesh),
1986 // Faces are perfectly aligned but probably not ordered.
1987 perfectPointMatch(absTol, false);
1991 // Slave faces are subdivision of master face. Faces not ordered.
1992 subDivisionMatch(slaveMesh, false, absTol);
2002 // Slave is subdivision of master patch.
2003 // (so -both cover the same area -all of master points are present in slave)
2004 Foam::faceCoupleInfo::faceCoupleInfo
2006 const polyMesh& masterMesh,
2007 const labelList& masterAddressing,
2008 const polyMesh& slaveMesh,
2009 const labelList& slaveAddressing,
2010 const scalar absTol,
2011 const bool perfectMatch,
2012 const bool orderedFaces,
2013 const bool patchDivision
2018 new indirectPrimitivePatch
2020 IndirectList<face>(masterMesh.faces(), masterAddressing),
2026 new indirectPrimitivePatch
2028 IndirectList<face>(slaveMesh.faces(), slaveAddressing),
2034 cutToMasterFaces_(0),
2035 masterToCutPoints_(0),
2036 cutToSlaveFaces_(0),
2037 slaveToCutPoints_(0),
2040 if (perfectMatch && (masterAddressing.size() != slaveAddressing.size()))
2044 "faceCoupleInfo::faceCoupleInfo(const primitiveMesh&"
2045 ", const primitiveMesh&, const scalar, const bool"
2046 ) << "Perfect match specified but number of master and slave faces"
2047 << " differ." << endl
2048 << "master:" << masterAddressing.size()
2049 << " slave:" << slaveAddressing.size()
2050 << abort(FatalError);
2055 masterAddressing.size()
2056 && min(masterAddressing) < masterMesh.nInternalFaces()
2061 "faceCoupleInfo::faceCoupleInfo(const primitiveMesh&"
2062 ", const primitiveMesh&, const scalar, const bool"
2063 ) << "Supplied internal face on master mesh to couple." << nl
2064 << "Faces to be coupled have to be boundary faces."
2065 << abort(FatalError);
2069 slaveAddressing.size()
2070 && min(slaveAddressing) < slaveMesh.nInternalFaces()
2075 "faceCoupleInfo::faceCoupleInfo(const primitiveMesh&"
2076 ", const primitiveMesh&, const scalar, const bool"
2077 ) << "Supplied internal face on slave mesh to couple." << nl
2078 << "Faces to be coupled have to be boundary faces."
2079 << abort(FatalError);
2085 perfectPointMatch(absTol, orderedFaces);
2089 // Slave faces are subdivision of master face. Faces not ordered.
2090 subDivisionMatch(slaveMesh, patchDivision, absTol);
2100 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
2102 Foam::faceCoupleInfo::~faceCoupleInfo()
2106 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2108 Foam::labelList Foam::faceCoupleInfo::faceLabels(const polyPatch& pp)
2110 labelList faces(pp.size());
2112 label faceI = pp.start();
2122 Foam::Map<Foam::label> Foam::faceCoupleInfo::makeMap(const labelList& lst)
2124 Map<label> map(lst.size());
2130 map.insert(i, lst[i]);
2137 Foam::Map<Foam::labelList> Foam::faceCoupleInfo::makeMap
2139 const labelListList& lst
2142 Map<labelList> map(lst.size());
2148 map.insert(i, lst[i]);
2155 // ************************************************************************* //