comment
[OpenFOAM-1.5.x.git] / src / dynamicMesh / polyMeshAdder / faceCoupleInfo.C
blob6d97285d738b7ef16bf8c784c50634c7fa67d644
1 /*---------------------------------------------------------------------------*  \
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
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 the
13     Free Software Foundation; either version 2 of the License, or (at your
14     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
19     for more details.
21     You should have received a copy of the GNU General Public License
22     along with OpenFOAM; if not, write to the Free Software Foundation,
23     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*----------------------------------------------------------------------------*/
27 #include "faceCoupleInfo.H"
28 #include "polyMesh.H"
29 #include "matchPoints.H"
30 #include "indirectPrimitivePatch.H"
31 #include "meshTools.H"
32 #include "octreeDataFace.H"
33 #include "octree.H"
34 #include "OFstream.H"
35 #include "IndirectList.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 namespace Foam
42 defineTypeNameAndDebug(faceCoupleInfo, 0);
46 const Foam::scalar Foam::faceCoupleInfo::angleTol_ = 1E-3;
49 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
51 //- Write edges
52 void Foam::faceCoupleInfo::writeOBJ
54     const fileName& fName,
55     const edgeList& edges,
56     const pointField& points,
57     const bool compact
60     OFstream str(fName);
62     labelList pointMap(points.size(), -1);
64     if (compact)
65     {
66         label newPointI = 0;
68         forAll(edges, edgeI)
69         {
70             const edge& e = edges[edgeI];
72             forAll(e, eI)
73             {
74                 label pointI = e[eI];
76                 if (pointMap[pointI] == -1)
77                 {
78                     pointMap[pointI] = newPointI++;
80                     meshTools::writeOBJ(str, points[pointI]);
81                 }
82             }
83         }
84     }
85     else
86     {
87         forAll(points, pointI)
88         {
89             meshTools::writeOBJ(str, points[pointI]);
90         }
92         pointMap = identity(points.size());
93     }
95     forAll(edges, edgeI)
96     {
97         const edge& e = edges[edgeI];
99         str<< "l " << pointMap[e[0]]+1 << ' ' << pointMap[e[1]]+1 << nl;
100     }
104 //- Writes edges.
105 void Foam::faceCoupleInfo::writeOBJ
107     const fileName& fName,
108     const pointField& points0,
109     const pointField& points1
112     Pout<< "Writing connections as edges to " << fName << endl;
114     OFstream str(fName);
116     label vertI = 0;
118     forAll(points0, i)
119     {
120         meshTools::writeOBJ(str, points0[i]);
121         vertI++;
122         meshTools::writeOBJ(str, points1[i]);
123         vertI++;
124         str << "l " << vertI-1 << ' ' << vertI << nl;
125     }
129 //- Writes face and point connectivity as .obj files.
130 void Foam::faceCoupleInfo::writePointsFaces() const
132     const indirectPrimitivePatch& m = masterPatch();
133     const indirectPrimitivePatch& s = slavePatch();
134     const primitiveFacePatch& c = cutFaces();
136     // Patches
137     {
138         OFstream str("masterPatch.obj");
139         Pout<< "Writing masterPatch to " << str.name() << endl;
140         meshTools::writeOBJ(str, m.localFaces(), m.localPoints());
141     }
142     {
143         OFstream str("slavePatch.obj");
144         Pout<< "Writing slavePatch to " << str.name() << endl;
145         meshTools::writeOBJ(str, s.localFaces(), s.localPoints());
146     }
147     {
148         OFstream str("cutFaces.obj");
149         Pout<< "Writing cutFaces to " << str.name() << endl;
150         meshTools::writeOBJ(str, c.localFaces(), c.localPoints());
151     }
153     // Point connectivity
154     {
155         Pout<< "Writing cutToMasterPoints to cutToMasterPoints.obj" << endl;
157         writeOBJ
158         (
159             "cutToMasterPoints.obj",
160             m.localPoints(),
161             pointField
162             (
163                 IndirectList<point>(c.localPoints(), masterToCutPoints_)()
164             )
165         );
166     }
167     {
168         Pout<< "Writing cutToSlavePoints to cutToSlavePoints.obj" << endl;
170         writeOBJ
171         (
172             "cutToSlavePoints.obj",
173             s.localPoints(),
174             pointField
175             (
176                 IndirectList<point>(c.localPoints(), slaveToCutPoints_)()
177             )
178         );
179     }
181     // Face connectivity
182     {
183         Pout<< "Writing cutToMasterFaces to cutToMasterFaces.obj" << endl;
185         pointField equivMasterFaces(c.size());
187         forAll(cutToMasterFaces(), cutFaceI)
188         {
189             label masterFaceI = cutToMasterFaces()[cutFaceI];
191             if (masterFaceI != -1)
192             {
193                 equivMasterFaces[cutFaceI] = m[masterFaceI].centre(m.points());
194             }
195             else
196             {
197                 WarningIn("writePointsFaces()")
198                     << "No master face for cut face " << cutFaceI
199                     << " at position " << c[cutFaceI].centre(c.points())
200                     << endl;
202                 equivMasterFaces[cutFaceI] = vector::zero;
203             }
204         }
206         writeOBJ
207         (
208             "cutToMasterFaces.obj",
209             calcFaceCentres<List>(c, cutPoints(), 0, c.size()),
210             equivMasterFaces
211         );
212     }
214     {
215         Pout<< "Writing cutToSlaveFaces to cutToSlaveFaces.obj" << endl;
217         pointField equivSlaveFaces(c.size());
219         forAll(cutToSlaveFaces(), cutFaceI)
220         {
221             label slaveFaceI = cutToSlaveFaces()[cutFaceI];
223             equivSlaveFaces[cutFaceI] = s[slaveFaceI].centre(s.points());
224         }
226         writeOBJ
227         (
228             "cutToSlaveFaces.obj",
229             calcFaceCentres<List>(c, cutPoints(), 0, c.size()),
230             equivSlaveFaces
231         );
232     }
234     Pout<< endl;
238 void Foam::faceCoupleInfo::writeEdges
240     const labelList& cutToMasterEdges,
241     const labelList& cutToSlaveEdges
242 ) const
244     const indirectPrimitivePatch& m = masterPatch();
245     const indirectPrimitivePatch& s = slavePatch();
246     const primitiveFacePatch& c = cutFaces();
248     // Edge connectivity
249     {
250         OFstream str("cutToMasterEdges.obj");
251         Pout<< "Writing cutToMasterEdges to " << str.name() << endl;
253         label vertI = 0;
255         forAll(cutToMasterEdges, cutEdgeI)
256         {
257             if (cutToMasterEdges[cutEdgeI] != -1)
258             {
259                 const edge& masterEdge =
260                     m.edges()[cutToMasterEdges[cutEdgeI]];
261                 const edge& cutEdge = c.edges()[cutEdgeI];
263                 meshTools::writeOBJ(str, m.localPoints()[masterEdge[0]]);
264                 vertI++;
265                 meshTools::writeOBJ(str, m.localPoints()[masterEdge[1]]);
266                 vertI++;
267                 meshTools::writeOBJ(str, c.localPoints()[cutEdge[0]]);
268                 vertI++;
269                 meshTools::writeOBJ(str, c.localPoints()[cutEdge[1]]);
270                 vertI++;
271                 str << "l " << vertI-3 << ' ' << vertI-2 << nl;
272                 str << "l " << vertI-3 << ' ' << vertI-1 << nl;
273                 str << "l " << vertI-3 << ' ' << vertI << nl;
274                 str << "l " << vertI-2 << ' ' << vertI-1 << nl;
275                 str << "l " << vertI-2 << ' ' << vertI << nl;
276                 str << "l " << vertI-1 << ' ' << vertI << nl;
277             }
278         }
279     }
280     {
281         OFstream str("cutToSlaveEdges.obj");
282         Pout<< "Writing cutToSlaveEdges to " << str.name() << endl;
284         label vertI = 0;
286         labelList slaveToCut(invert(s.nEdges(), cutToSlaveEdges));
288         forAll(slaveToCut, edgeI)
289         {
290             if (slaveToCut[edgeI] != -1)
291             {
292                 const edge& slaveEdge = s.edges()[edgeI];
293                 const edge& cutEdge = c.edges()[slaveToCut[edgeI]];
295                 meshTools::writeOBJ(str, s.localPoints()[slaveEdge[0]]);
296                 vertI++;
297                 meshTools::writeOBJ(str, s.localPoints()[slaveEdge[1]]);
298                 vertI++;
299                 meshTools::writeOBJ(str, c.localPoints()[cutEdge[0]]);
300                 vertI++;
301                 meshTools::writeOBJ(str, c.localPoints()[cutEdge[1]]);
302                 vertI++;
303                 str << "l " << vertI-3 << ' ' << vertI-2 << nl;
304                 str << "l " << vertI-3 << ' ' << vertI-1 << nl;
305                 str << "l " << vertI-3 << ' ' << vertI << nl;
306                 str << "l " << vertI-2 << ' ' << vertI-1 << nl;
307                 str << "l " << vertI-2 << ' ' << vertI << nl;
308                 str << "l " << vertI-1 << ' ' << vertI << nl;
309             }
310         }
311     }
313     Pout<< endl;
317 // Given an edgelist and a map for the points on the edges it tries to find
318 // the corresponding patch edges.
319 Foam::labelList Foam::faceCoupleInfo::findMappedEdges
321     const edgeList& edges,
322     const labelList& pointMap,
323     const indirectPrimitivePatch& patch
326     labelList toPatchEdges(edges.size());
328     forAll(toPatchEdges, edgeI)
329     {
330         const edge& e = edges[edgeI];
332         label v0 = pointMap[e[0]];
333         label v1 = pointMap[e[1]];
335         toPatchEdges[edgeI] =
336             meshTools::findEdge
337             (
338                 patch.edges(),
339                 patch.pointEdges()[v0],
340                 v0,
341                 v1
342             );
343     }
344     return toPatchEdges;
348 // Detect a cut edge which originates from two boundary faces having different
349 // polyPatches.
350 bool Foam::faceCoupleInfo::regionEdge
352     const polyMesh& slaveMesh,
353     const label slaveEdgeI
354 ) const
356     const labelList& eFaces = slavePatch().edgeFaces()[slaveEdgeI];
358     if (eFaces.size() == 1)
359     {
360         return true;
361     }
362     else
363     {
364         // Count how many different patches connected to this edge.
366         label patch0 = -1;
368         forAll(eFaces, i)
369         {
370             label faceI = eFaces[i];
372             label meshFaceI = slavePatch().addressing()[faceI];
374             label patchI = slaveMesh.boundaryMesh().whichPatch(meshFaceI);
376             if (patch0 == -1)
377             {
378                 patch0 = patchI;
379             }
380             else if (patchI != patch0)
381             {
382                 // Found two different patches connected to this edge.
383                 return true;
384             }
385         }
386         return false;
387     }
391 // Find edge using pointI that is most aligned with vector between
392 // master points. Patchdivision tells us whether or not to use
393 // patch information to match edges.
394 Foam::label Foam::faceCoupleInfo::mostAlignedCutEdge
396     const bool report,
397     const polyMesh& slaveMesh,
398     const bool patchDivision,
399     const labelList& cutToMasterEdges,
400     const labelList& cutToSlaveEdges,
401     const label pointI,
402     const label edgeStart,
403     const label edgeEnd
404 ) const
406     const pointField& localPoints = cutFaces().localPoints();
408     const labelList& pEdges = cutFaces().pointEdges()[pointI];
410     if (report)
411     {
412         Pout<< "mostAlignedEdge : finding nearest edge among "
413             << IndirectList<edge>(cutFaces().edges(), pEdges)()
414             << " connected to point " << pointI
415             << " coord:" << localPoints[pointI]
416             << " running between " << edgeStart << " coord:"
417             << localPoints[edgeStart]
418             << " and " << edgeEnd << " coord:"
419             << localPoints[edgeEnd]
420             << endl;
421     }
423     // Find the edge that gets us nearest end.
425     label maxEdgeI = -1;
426     scalar maxCos = -GREAT;
428     forAll(pEdges, i)
429     {
430         label edgeI = pEdges[i];
432         if
433         (
434            !(
435                 patchDivision
436              && cutToMasterEdges[edgeI] == -1
437             )
438          || (
439                 patchDivision
440              && regionEdge(slaveMesh, cutToSlaveEdges[edgeI])
441             )
442         )
443         {
444             const edge& e = cutFaces().edges()[edgeI];
446             label otherPointI = e.otherVertex(pointI);
448             if (otherPointI == edgeEnd)
449             {
450                 // Shortcut: found edge end point.
451                 if (report)
452                 {
453                     Pout<< "    mostAlignedEdge : found end point " << edgeEnd
454                         << endl;
455                 }
456                 return edgeI;
457             }
459             // Get angle between edge and edge to masterEnd
461             vector eVec(localPoints[otherPointI] - localPoints[pointI]);
463             scalar magEVec = mag(eVec);
465             if (magEVec < VSMALL)
466             {
467                 WarningIn("faceCoupleInfo::mostAlignedEdge")
468                     << "Crossing zero sized edge " << edgeI
469                     << " coords:" << localPoints[otherPointI]
470                     << localPoints[pointI]
471                     << " when walking from " << localPoints[edgeStart]
472                     << " to " << localPoints[edgeEnd]
473                     << endl;
474                 return edgeI;
475             }
477             eVec /= magEVec;
479             vector eToEndPoint(localPoints[edgeEnd] - localPoints[otherPointI]);
480             eToEndPoint /= mag(eToEndPoint);
482             scalar cosAngle = eVec & eToEndPoint;
484             if (report)
485             {
486                 Pout<< "    edge:" << e << " points:" << localPoints[pointI]
487                     << localPoints[otherPointI]
488                     << "  vec:" << eVec
489                     << "  vecToEnd:" << eToEndPoint
490                     << " cosAngle:" << cosAngle
491                     << endl;
492             }
494             if (cosAngle > maxCos)
495             {
496                 maxCos = cosAngle;
497                 maxEdgeI = edgeI;
498             }
499         }
500     }
502     if (maxCos > 1 - angleTol_)
503     {
504         return maxEdgeI;
505     }
506     else
507     {
508         return -1;
509     }
513 // Construct points to split points map (in cut addressing)
514 void Foam::faceCoupleInfo::setCutEdgeToPoints(const labelList& cutToMasterEdges)
516     labelListList masterToCutEdges
517     (
518         invertOneToMany
519         (
520             masterPatch().nEdges(),
521             cutToMasterEdges
522         )
523     );
525     const edgeList& cutEdges = cutFaces().edges();
527     // Size extra big so searching is faster
528     cutEdgeToPoints_.resize
529     (
530         masterPatch().nEdges()
531       + slavePatch().nEdges()
532       + cutEdges.size()
533     );
535     forAll(masterToCutEdges, masterEdgeI)
536     {
537         const edge& masterE = masterPatch().edges()[masterEdgeI];
539         //Pout<< "Master:" << masterPatch().localPoints()[masterE[0]] << ' '
540         //    << masterPatch().localPoints()[masterE[1]] << endl;
542         const labelList& stringedEdges = masterToCutEdges[masterEdgeI];
544         if (stringedEdges.size() == 0)
545         {
546             FatalErrorIn
547             (
548                 "faceCoupleInfo::setCutEdgeToPoints"
549                 "(const labelList&)"
550             )   << "Did not match all of master edges to cutFace edges"
551                 << nl
552                 << "First unmatched edge:" << masterEdgeI << " endPoints:"
553                 << masterPatch().localPoints()[masterE[0]]
554                 << masterPatch().localPoints()[masterE[1]]
555                 << endl
556                 << "This usually means that the slave patch is not a"
557                 << " subdivision of the master patch"
558                 << abort(FatalError);
559         }
560         else if (stringedEdges.size() > 1)
561         {
562             // String up the edges between e[0] and e[1]. Store the points
563             // inbetween e[0] and e[1] (all in cutFaces() labels)
565             DynamicList<label> splitPoints(stringedEdges.size()-1);
567             // Unsplit edge endpoints
568             const edge unsplitEdge
569             (
570                 masterToCutPoints_[masterE[0]],
571                 masterToCutPoints_[masterE[1]]
572             );
574             label startVertI = unsplitEdge[0];
575             label startEdgeI = -1;
577             while (startVertI != unsplitEdge[1])
578             {
579                 // Loop over all string of edges. Update
580                 // - startVertI : previous vertex
581                 // - startEdgeI : previous edge
582                 // and insert any points into splitPoints
584                 // For checking
585                 label oldStart = startVertI;
587                 forAll(stringedEdges, i)
588                 {
589                     label edgeI = stringedEdges[i];
591                     if (edgeI != startEdgeI)
592                     {
593                         const edge& e = cutEdges[edgeI];
595                         //Pout<< "    cut:" << e << " at:"
596                         //    << cutFaces().localPoints()[e[0]]
597                         //    << ' ' << cutFaces().localPoints()[e[1]] << endl;
599                         if (e[0] == startVertI)
600                         {
601                             startEdgeI = edgeI;
602                             startVertI = e[1];
603                             if (e[1] != unsplitEdge[1])
604                             {
605                                 splitPoints.append(e[1]);
606                             }
607                             break;
608                         }
609                         else if (e[1] == startVertI)
610                         {
611                             startEdgeI = edgeI;
612                             startVertI = e[0];
613                             if (e[0] != unsplitEdge[1])
614                             {
615                                 splitPoints.append(e[0]);
616                             }
617                             break;
618                         }
619                     }
620                 }
622                 // Check
623                 if (oldStart == startVertI)
624                 {
625                     FatalErrorIn
626                     (
627                         "faceCoupleInfo::setCutEdgeToPoints"
628                         "(const labelList&)"
629                     )   << " unsplitEdge:" << unsplitEdge
630                         << " does not correspond to split edges "
631                         << IndirectList<edge>(cutEdges, stringedEdges)()
632                         << abort(FatalError);
633                 }
634             }
636             //Pout<< "For master edge:"
637             //    << unsplitEdge
638             //    << " Found stringed points "
639             //    <<  IndirectList<point>
640             //        (
641             //            cutFaces().localPoints(),
642             //            splitPoints.shrink()
643             //        )()
644             //    << endl;
646             cutEdgeToPoints_.insert(unsplitEdge, splitPoints.shrink());
647         }
648     }
652 // Determines rotation for f1 to match up with f0, i.e. the index in f0 of
653 // the first point of f1.
654 Foam::label Foam::faceCoupleInfo::matchFaces
656     const scalar absTol,
657     const pointField& points0,
658     const face& f0,
659     const pointField& points1,
660     const face& f1,
661     const bool sameOrientation
664     if (f0.size() != f1.size())
665     {
666         FatalErrorIn
667         (
668             "faceCoupleInfo::matchFaces"
669             "(const scalar, const face&, const pointField&"
670             ", const face&, const pointField&)"
671         )   << "Different sizes for supposedly matching faces." << nl
672             << "f0:" << f0 << " coords:" << IndirectList<point>(points0, f0)()
673             << nl
674             << "f1:" << f1 << " coords:" << IndirectList<point>(points1, f1)()
675             << abort(FatalError);
676     }
678     const scalar absTolSqr = sqr(absTol);
681     label matchFp = -1;
683     forAll(f0, startFp)
684     {
685         // See -if starting from startFp on f0- the two faces match.
686         bool fullMatch = true;
688         label fp0 = startFp;
689         label fp1 = 0;
691         forAll(f1, i)
692         {
693             scalar distSqr = Foam::magSqr(points0[f0[fp0]] - points1[f1[fp1]]);
695             if (distSqr > absTolSqr)
696             {
697                 fullMatch = false;
698                 break;
699             }
701             fp0 = f0.fcIndex(fp0);  // walk forward
703             if (sameOrientation)
704             {
705                 fp1 = f1.fcIndex(fp1);
706             }
707             else
708             {
709                 fp1 = f1.rcIndex(fp1);
710             }
711         }
713         if (fullMatch)
714         {
715             matchFp = startFp;
716             break;
717         }
718     }
720     if (matchFp == -1)
721     {
722         FatalErrorIn
723         (
724             "faceCoupleInfo::matchFaces"
725             "(const scalar, const face&, const pointField&"
726             ", const face&, const pointField&)"
727         )   << "No unique match between two faces" << nl
728             << "Face " << f0 << " coords "
729             << IndirectList<point>(points0, f0)()
730             << nl
731             << "Face " << f1 << " coords "
732             << IndirectList<point>(points1, f1)()
733             << "when using tolerance " << absTol
734             << " and forwardMatching:" << sameOrientation
735             << abort(FatalError);
736     }
738     return matchFp;
742 // Find correspondence from patch points to cut points. This might
743 // detect shared points so the output is a patch-to-cut point list
744 // and a compaction list for the cut points (which will always be equal or more
745 // connected than the patch).
746 // Returns true if there are any duplicates.
747 bool Foam::faceCoupleInfo::matchPointsThroughFaces
749     const scalar absTol,
750     const pointField& cutPoints,
751     const faceList& cutFaces,
752     const pointField& patchPoints,
753     const faceList& patchFaces,
754     const bool sameOrientation,
756     labelList& patchToCutPoints,    // patch to (uncompacted) cut points
757     labelList& cutToCompact,        // compaction list for cut points
758     labelList& compactToCut         // inverse ,,
762     // From slave to cut point
763     patchToCutPoints.setSize(patchPoints.size());
764     patchToCutPoints = -1;
766     // Compaction list for cut points: either -1 or index into master which
767     // gives the point to compact to.
768     labelList cutPointRegion(cutPoints.size(), -1);
769     DynamicList<label> cutPointRegionMaster;
771     forAll(patchFaces, patchFaceI)
772     {
773         const face& patchF = patchFaces[patchFaceI];
775         //const face& cutF = cutFaces[patchToCutFaces[patchFaceI]];
776         const face& cutF = cutFaces[patchFaceI];
778         // Do geometric matching to get position of cutF[0] in patchF
779         label patchFp = matchFaces
780         (
781             absTol,
782             patchPoints,
783             patchF,
784             cutPoints,
785             cutF,
786             sameOrientation        // orientation
787         );
789         forAll(cutF, cutFp)
790         {
791             label cutPointI = cutF[cutFp];
792             label patchPointI = patchF[patchFp];
794             //const point& cutPt = cutPoints[cutPointI];
795             //const point& patchPt = patchPoints[patchPointI];
796             //if (mag(cutPt - patchPt) > SMALL)
797             //{
798             //    FatalErrorIn("matchPointsThroughFaces")
799             //    << "cutP:" << cutPt
800             //    << " patchP:" << patchPt
801             //    << abort(FatalError);
802             //}
804             if (patchToCutPoints[patchPointI] == -1)
805             {
806                 patchToCutPoints[patchPointI] = cutPointI;
807             }
808             else if (patchToCutPoints[patchPointI] != cutPointI)
809             {
810                 // Multiple cut points connecting to same patch.
811                 // Check if already have region & region master for this set
812                 label otherCutPointI = patchToCutPoints[patchPointI];
814                 //Pout<< "PatchPoint:" << patchPt
815                 //    << " matches to:" << cutPointI
816                 //    << " coord:" << cutPoints[cutPointI]
817                 //    << " and to:" << otherCutPointI
818                 //    << " coord:" << cutPoints[otherCutPointI]
819                 //    << endl;
821                 if (cutPointRegion[otherCutPointI] != -1)
822                 {
823                     // Have region for this set. Copy.
824                     label region = cutPointRegion[otherCutPointI];
825                     cutPointRegion[cutPointI] = region;
827                     // Update region master with min point label
828                     cutPointRegionMaster[region] = min
829                     (
830                         cutPointRegionMaster[region],
831                         cutPointI
832                     );
833                 }
834                 else
835                 {
836                     // Create new region.
837                     label region = cutPointRegionMaster.size();
838                     cutPointRegionMaster.append
839                     (
840                         min(cutPointI, otherCutPointI)
841                     );
842                     cutPointRegion[cutPointI] = region;
843                     cutPointRegion[otherCutPointI] = region;
844                 }
845             }
847             if (sameOrientation)
848             {
849                 patchFp = patchF.fcIndex(patchFp);
850             }
851             else
852             {
853                 patchFp = patchF.rcIndex(patchFp);
854             }
855         }
856     }
858     // Rework region&master into compaction array
859     compactToCut.setSize(cutPointRegion.size());
860     cutToCompact.setSize(cutPointRegion.size());
861     cutToCompact = -1;
862     label compactPointI = 0;
864     forAll(cutPointRegion, i)
865     {
866         if (cutPointRegion[i] == -1)
867         {
868             // Unduplicated point. Allocate new compacted point.
869             cutToCompact[i] = compactPointI;
870             compactToCut[compactPointI] = i;
871             compactPointI++;
872         }
873         else
874         {
875             // Duplicate point. Get master.
877             label masterPointI = cutPointRegionMaster[cutPointRegion[i]];
879             if (cutToCompact[masterPointI] == -1)
880             {
881                 cutToCompact[masterPointI] = compactPointI;
882                 compactToCut[compactPointI] = masterPointI;
883                 compactPointI++;
884             }
885             cutToCompact[i] = cutToCompact[masterPointI];
886         }
887     }
888     compactToCut.setSize(compactPointI);
890     return compactToCut.size() != cutToCompact.size();
894 // Return max distance from any point on cutF to masterF
895 Foam::scalar Foam::faceCoupleInfo::maxDistance
897     const face& cutF,
898     const pointField& cutPoints,
899     const face& masterF,
900     const pointField& masterPoints
903     scalar maxDist = -GREAT;
905     forAll(cutF, fp)
906     {
907         const point& cutPt = cutPoints[cutF[fp]];
909         pointHit pHit = masterF.nearestPoint(cutPt, masterPoints);
911         maxDist = max(maxDist, pHit.distance());
912     }
913     return maxDist;
917 void Foam::faceCoupleInfo::findPerfectMatchingFaces
919     const primitiveMesh& mesh0,
920     const primitiveMesh& mesh1,
921     const scalar absTol,
923     labelList& mesh0Faces,
924     labelList& mesh1Faces
927     // Face centres of external faces (without invoking
928     // mesh.faceCentres since mesh might have been clearedOut)
930     pointField fc0
931     (
932         calcFaceCentres<List>
933         (
934             mesh0.faces(),
935             mesh0.points(),
936             mesh0.nInternalFaces(),
937             mesh0.nFaces() - mesh0.nInternalFaces()
938         )
939     );
941     pointField fc1
942     (
943         calcFaceCentres<List>
944         (
945             mesh1.faces(),
946             mesh1.points(),
947             mesh1.nInternalFaces(),
948             mesh1.nFaces() - mesh1.nInternalFaces()
949         )
950     );
953     if (debug)
954     {
955         Pout<< "Face matching tolerance : " << absTol << endl;
956     }
959     // Match geometrically
960     labelList from1To0;
961     bool matchedAllFaces = matchPoints
962     (
963         fc1,
964         fc0,
965         scalarField(fc1.size(), absTol),
966         false,
967         from1To0
968     );
970     if (matchedAllFaces)
971     {
972         Warning
973             << "faceCoupleInfo::faceCoupleInfo : "
974             << "Matched ALL " << fc1.size()
975             << " boundary faces of mesh0 to boundary faces of mesh1." << endl
976             << "This is only valid if the mesh to add is fully"
977             << " enclosed by the mesh it is added to." << endl;
978     }
981     // Collect matches.
982     label nMatched = 0;
984     mesh0Faces.setSize(fc0.size());
985     mesh1Faces.setSize(fc1.size());
987     forAll(from1To0, i)
988     {
989         if (from1To0[i] != -1)
990         {
991             mesh1Faces[nMatched] = i + mesh1.nInternalFaces();
992             mesh0Faces[nMatched] = from1To0[i] + mesh0.nInternalFaces();
994             nMatched++;
995         }
996     }
998     mesh0Faces.setSize(nMatched);
999     mesh1Faces.setSize(nMatched);
1003 void Foam::faceCoupleInfo::findSlavesCoveringMaster
1005     const primitiveMesh& mesh0,
1006     const primitiveMesh& mesh1,
1007     const scalar absTol,
1009     labelList& mesh0Faces,
1010     labelList& mesh1Faces
1013     // Construct octree from all mesh0 boundary faces
1014     octreeDataFace shapes(mesh0);
1016     treeBoundBox overallBb(mesh0.points());
1018     octree<octreeDataFace> tree
1019     (
1020         overallBb,  // overall search domain
1021         shapes,     // all information needed to do checks on cells
1022         1,          // min levels
1023         20.0,       // maximum ratio of cubes v.s. cells
1024         10.0
1025     );
1028     if (debug)
1029     {
1030         Pout<< "findSlavesCoveringMaster :"
1031             << " constructed octree for mesh0 boundary faces" << endl;
1032     }
1034     // Search nearest face for every mesh1 boundary face.
1036     labelHashSet mesh0Set(mesh0.nFaces() - mesh0.nInternalFaces());
1037     labelHashSet mesh1Set(mesh1.nFaces() - mesh1.nInternalFaces());
1039     for
1040     (
1041         label mesh1FaceI = mesh1.nInternalFaces();
1042         mesh1FaceI < mesh1.nFaces();
1043         mesh1FaceI++
1044     )
1045     {
1046         const face& f1 = mesh1.faces()[mesh1FaceI];
1048         // Generate face centre (prevent cellCentres() reconstruction)
1049         point fc(f1.centre(mesh1.points()));
1051         // Search in bounding box of face only.
1052         treeBoundBox tightest(static_cast<const pointField&>(f1.points(mesh1.points())));
1054         scalar tightestDist = GREAT;
1056         label index = tree.findNearest(fc, tightest, tightestDist);
1059         if (index != -1)
1060         {
1061             label mesh0FaceI = shapes.meshFaces()[index];
1063             // Check if points of f1 actually lie on top of mesh0 face
1064             // This is the bit that might fail since if f0 is severely warped
1065             // and f1's points are not present on f0 (since subdivision)
1066             // then the distance of the points to f0 might be quite large
1067             // and the test will fail. This all should in fact be some kind
1068             // of walk from known corresponding points/edges/faces.
1069             scalar dist =
1070                 maxDistance
1071                 (
1072                     f1,
1073                     mesh1.points(),
1074                     mesh0.faces()[mesh0FaceI],
1075                     mesh0.points()
1076                 );
1078             if (dist < absTol)
1079             {
1080                 mesh0Set.insert(mesh0FaceI);
1081                 mesh1Set.insert(mesh1FaceI);
1082             }
1083         }
1084     }
1086     if (debug)
1087     {
1088         Pout<< "findSlavesCoveringMaster :"
1089             << " matched " << mesh1Set.size() << " mesh1 faces to "
1090             << mesh0Set.size() << " mesh0 faces" << endl;
1091     }
1093     mesh0Faces = mesh0Set.toc();
1094     mesh1Faces = mesh1Set.toc();
1098 // Grow cutToMasterFace across 'internal' edges.
1099 Foam::label Foam::faceCoupleInfo::growCutFaces
1101     const labelList& cutToMasterEdges,
1102     Map<labelList>& candidates
1105     if (debug)
1106     {
1107         Pout<< "growCutFaces :"
1108             << " growing cut faces to masterPatch" << endl;
1109     }
1111     label nTotChanged = 0;
1113     while (true)
1114     {
1115         const labelListList& cutFaceEdges = cutFaces().faceEdges();
1116         const labelListList& cutEdgeFaces = cutFaces().edgeFaces();
1118         label nChanged = 0;
1120         forAll(cutToMasterFaces_, cutFaceI)
1121         {
1122             const label masterFaceI = cutToMasterFaces_[cutFaceI];
1124             if (masterFaceI != -1)
1125             {
1126                 // We now have a cutFace for which we have already found a
1127                 // master face. Grow this masterface across any internal edge
1128                 // (internal: no corresponding master edge)
1130                 const labelList& fEdges = cutFaceEdges[cutFaceI];
1132                 forAll(fEdges, i)
1133                 {
1134                     const label cutEdgeI = fEdges[i];
1136                     if (cutToMasterEdges[cutEdgeI] == -1)
1137                     {
1138                         // So this edge:
1139                         // - internal to the cutPatch (since all region edges
1140                         //   marked before)
1141                         // - on cutFaceI which corresponds to masterFace.
1142                         // Mark all connected faces with this masterFace.
1144                         const labelList& eFaces = cutEdgeFaces[cutEdgeI];
1146                         forAll(eFaces, j)
1147                         {
1148                             const label faceI = eFaces[j];
1150                             if (cutToMasterFaces_[faceI] == -1)
1151                             {
1152                                 cutToMasterFaces_[faceI] = masterFaceI;
1153                                 candidates.erase(faceI);
1154                                 nChanged++;
1155                             }
1156                             else if (cutToMasterFaces_[faceI] != masterFaceI)
1157                             {
1158                                 const pointField& cutPoints =
1159                                     cutFaces().points();
1160                                 const pointField& masterPoints =
1161                                     masterPatch().points();
1163                                 const edge& e = cutFaces().edges()[cutEdgeI];
1165                                 label myMaster = cutToMasterFaces_[faceI];
1166                                 const face& myF = masterPatch()[myMaster];
1168                                 const face& nbrF = masterPatch()[masterFaceI];
1170                                 FatalErrorIn
1171                                 (
1172                                     "faceCoupleInfo::growCutFaces"
1173                                     "(const labelList&, Map<labelList>&)"
1174                                 )   << "Cut face "
1175                                     << cutFaces()[faceI].points(cutPoints)
1176                                     << " has master "
1177                                     << myMaster
1178                                     << " but also connects to nbr face "
1179                                     << cutFaces()[cutFaceI].points(cutPoints)
1180                                     << " with master " << masterFaceI
1181                                     << nl
1182                                     << "myMasterFace:"
1183                                     << myF.points(masterPoints)
1184                                     << "  nbrMasterFace:"
1185                                     << nbrF.points(masterPoints) << nl
1186                                     << "Across cut edge " << cutEdgeI
1187                                     << " coord:"
1188                                     << cutFaces().localPoints()[e[0]]
1189                                     << cutFaces().localPoints()[e[1]]
1190                                     << abort(FatalError);
1191                             }
1192                         }
1193                     }
1194                 }
1195             }
1196         }
1198         if (debug)
1199         {
1200             Pout<< "growCutFaces : Grown an additional " << nChanged
1201                 << " cut to master face" << " correspondence" << endl;
1202         }
1204         nTotChanged += nChanged;
1206         if (nChanged == 0)
1207         {
1208             break;
1209         }
1210     }
1212     return nTotChanged;
1216 void Foam::faceCoupleInfo::checkMatch(const labelList& cutToMasterEdges) const
1218     const pointField& cutLocalPoints = cutFaces().localPoints();
1220     const pointField& masterLocalPoints = masterPatch().localPoints();
1221     const faceList& masterLocalFaces = masterPatch().localFaces();
1223     forAll(cutToMasterEdges, cutEdgeI)
1224     {
1225         const edge& e = cutFaces().edges()[cutEdgeI];
1227         if (cutToMasterEdges[cutEdgeI] == -1)
1228         {
1229             // Internal edge. Check that master face is same on both sides.
1230             const labelList& cutEFaces = cutFaces().edgeFaces()[cutEdgeI];
1232             label masterFaceI = -1;
1234             forAll(cutEFaces, i)
1235             {
1236                 label cutFaceI = cutEFaces[i];
1238                 if (cutToMasterFaces_[cutFaceI] != -1)
1239                 {
1240                     if (masterFaceI == -1)
1241                     {
1242                         masterFaceI = cutToMasterFaces_[cutFaceI];
1243                     }
1244                     else if (masterFaceI != cutToMasterFaces_[cutFaceI])
1245                     {
1246                         label myMaster = cutToMasterFaces_[cutFaceI];
1247                         const face& myF = masterLocalFaces[myMaster];
1249                         const face& nbrF = masterLocalFaces[masterFaceI];
1251                         FatalErrorIn
1252                         (
1253                             "faceCoupleInfo::checkMatch(const labelList&) const"
1254                         )
1255                             << "Internal CutEdge " << e
1256                             << " coord:"
1257                             << cutLocalPoints[e[0]]
1258                             << cutLocalPoints[e[1]]
1259                             << " connects to master " << myMaster
1260                             << " and to master " << masterFaceI << nl
1261                             << "myMasterFace:"
1262                             << myF.points(masterLocalPoints)
1263                             << "  nbrMasterFace:"
1264                             << nbrF.points(masterLocalPoints)
1265                             << abort(FatalError);
1266                     }
1267                 }
1268             }
1269         }
1270     }
1274 // Extends matching information by elimination across cutFaces using more
1275 // than one region edge. Updates cutToMasterFaces_ and sets candidates
1276 // which is for every cutface on a region edge the possible master faces.
1277 Foam::label Foam::faceCoupleInfo::matchEdgeFaces
1279     const labelList& cutToMasterEdges,
1280     Map<labelList>& candidates
1283     // For every unassigned cutFaceI the possible list of master faces.
1284     candidates.clear();
1285     candidates.resize(cutFaces().size());
1287     label nChanged = 0;
1289     forAll(cutToMasterEdges, cutEdgeI)
1290     {
1291         label masterEdgeI = cutToMasterEdges[cutEdgeI];
1293         if (masterEdgeI != -1)
1294         {
1295             // So cutEdgeI is matched to masterEdgeI. For all cut faces using
1296             // the cut edge store the master face as a candidate match.
1298             const labelList& cutEFaces = cutFaces().edgeFaces()[cutEdgeI];
1299             const labelList& masterEFaces =
1300                 masterPatch().edgeFaces()[masterEdgeI];
1302             forAll(cutEFaces, i)
1303             {
1304                 label cutFaceI = cutEFaces[i];
1306                 if (cutToMasterFaces_[cutFaceI] == -1)
1307                 {
1308                     // So this face (cutFaceI) is on an edge (cutEdgeI) that
1309                     // is used by some master faces (masterEFaces). Check if
1310                     // the cutFaceI and some of these masterEFaces share more
1311                     // than one edge (which uniquely defines face)
1313                     // Combine master faces with current set of candidate
1314                     // master faces.
1315                     Map<labelList>::iterator fnd = candidates.find(cutFaceI);
1317                     if (fnd == candidates.end())
1318                     {
1319                         // No info yet for cutFaceI. Add all master faces as
1320                         // candidates
1321                         candidates.insert(cutFaceI, masterEFaces);
1322                     }
1323                     else
1324                     {
1325                         // From some other cutEdgeI there are already some
1326                         // candidate master faces. Check the overlap with
1327                         // the current set of master faces.
1328                         const labelList& masterFaces = fnd();
1330                         DynamicList<label> newCandidates(masterFaces.size());
1332                         forAll(masterEFaces, j)
1333                         {
1334                             if (findIndex(masterFaces, masterEFaces[j]) != -1)
1335                             {
1336                                 newCandidates.append(masterEFaces[j]);
1337                             }
1338                         }
1340                         if (newCandidates.size() == 1)
1341                         {
1342                             // We found a perfect match. Delete entry from
1343                             // candidates map.
1344                             cutToMasterFaces_[cutFaceI] = newCandidates[0];
1345                             candidates.erase(cutFaceI);
1346                             nChanged++;
1347                         }
1348                         else
1349                         {
1350                             // Should not happen?
1351                             //Pout<< "On edge:" << cutEdgeI
1352                             //    << " have connected masterFaces:"
1353                             //    << masterEFaces
1354                             //    << " and from previous edge we have"
1355                             //    << " connected masterFaces" << masterFaces
1356                             //    << " . Overlap:" << newCandidates << endl;
1358                             fnd() = newCandidates.shrink();
1359                         }
1360                     }
1361                 }
1363             }
1364         }
1365     }
1367     if (debug)
1368     {
1369         Pout<< "matchEdgeFaces : Found " << nChanged
1370             << " faces where there was"
1371             << " only one remaining choice for cut-master correspondence"
1372             << endl;
1373     }
1375     return nChanged;
1379 // Gets a list of cutFaces (that use a master edge) and the candidate
1380 // master faces.
1381 // Finds most aligned master face.
1382 Foam::label Foam::faceCoupleInfo::geometricMatchEdgeFaces
1384     Map<labelList>& candidates
1387     const pointField& cutPoints = cutFaces().points();
1389     label nChanged = 0;
1391     // Mark all master faces that have been matched so far.
1393     labelListList masterToCutFaces
1394     (
1395         invertOneToMany
1396         (
1397             masterPatch().size(),
1398             cutToMasterFaces_
1399         )
1400     );
1402     forAllConstIter(Map<labelList>, candidates, iter)
1403     {
1404         label cutFaceI = iter.key();
1406         const face& cutF = cutFaces()[cutFaceI];
1408         if (cutToMasterFaces_[cutFaceI] == -1)
1409         {
1410             const labelList& masterFaces = iter();
1412             // Find the best matching master face.
1413             scalar minDist = GREAT;
1414             label minMasterFaceI = -1;
1416             forAll(masterFaces, i)
1417             {
1418                 label masterFaceI = masterFaces[i];
1420                 if (masterToCutFaces[masterFaces[i]].size() == 0)
1421                 {
1422                     scalar dist =
1423                         maxDistance
1424                         (
1425                             cutF,
1426                             cutPoints,
1427                             masterPatch()[masterFaceI],
1428                             masterPatch().points()
1429                         );
1431                     if (dist < minDist)
1432                     {
1433                         minDist = dist;
1434                         minMasterFaceI = masterFaceI;
1435                     }
1436                 }
1437             }
1439             if (minMasterFaceI != -1)
1440             {
1441                 cutToMasterFaces_[cutFaceI] = minMasterFaceI;
1442                 masterToCutFaces[minMasterFaceI] = cutFaceI;
1443                 nChanged++;
1444             }
1445         }
1446     }
1448     // (inefficiently) force candidates to be uptodate.
1449     forAll(cutToMasterFaces_, cutFaceI)
1450     {
1451         if (cutToMasterFaces_[cutFaceI] != -1)
1452         {
1453             candidates.erase(cutFaceI);
1454         }
1455     }
1458     if (debug)
1459     {
1460         Pout<< "geometricMatchEdgeFaces : Found " << nChanged
1461             << " faces where there was"
1462             << " only one remaining choice for cut-master correspondence"
1463             << endl;
1464     }
1466     return nChanged;
1470 // Calculate the set of cut faces inbetween master and slave patch
1471 // assuming perfect match (and optional face ordering on slave)
1472 void Foam::faceCoupleInfo::perfectPointMatch
1474     const scalar absTol,
1475     const bool slaveFacesOrdered
1478     if (debug)
1479     {
1480         Pout<< "perfectPointMatch :"
1481             << " Matching master and slave to cut."
1482             << " Master and slave faces are identical" << nl;
1484         if (slaveFacesOrdered)
1485         {
1486             Pout<< "and master and slave faces are ordered"
1487                 << " (on coupled patches)" << endl;
1488         }
1489         else
1490         {
1491             Pout<< "and master and slave faces are not ordered"
1492                 << " (on coupled patches)" << endl;
1493         }
1494     }
1496     cutToMasterFaces_ = identity(masterPatch().size());
1497     cutPoints_ = masterPatch().localPoints();
1498     cutFacesPtr_.reset
1499     (
1500         new primitiveFacePatch
1501         (
1502             masterPatch().localFaces(),
1503             cutPoints_
1504         )
1505     );
1506     masterToCutPoints_ = identity(cutPoints_.size());
1509     // Cut faces to slave patch.
1510     bool matchedAllFaces = false;
1512     if (slaveFacesOrdered)
1513     {
1514         cutToSlaveFaces_ = identity(cutFaces().size());
1515         matchedAllFaces = (cutFaces().size() == slavePatch().size());
1516     }
1517     else
1518     {
1519         // Faces do not have to be ordered (but all have
1520         // to match). Note: Faces will be already ordered if we enter here from
1521         // construct from meshes.
1522         matchedAllFaces = matchPoints
1523         (
1524             calcFaceCentres<List>
1525             (
1526                 cutFaces(),
1527                 cutPoints_,
1528                 0,
1529                 cutFaces().size()
1530             ),
1531             calcFaceCentres<IndirectList>
1532             (
1533                 slavePatch(),
1534                 slavePatch().points(),
1535                 0,
1536                 slavePatch().size()
1537             ),
1538             scalarField(slavePatch().size(), absTol),
1539             true,
1540             cutToSlaveFaces_
1541         );
1542     }
1545     if (!matchedAllFaces)
1546     {
1547         FatalErrorIn
1548         (
1549             "faceCoupleInfo::perfectPointMatch"
1550             "(const scalar&, const bool)"
1551         )   << "Did not match all of the master faces to the slave faces"
1552             << endl
1553             << "This usually means that the slave patch and master patch"
1554             << " do not align to within " << absTol << " meter."
1555             << abort(FatalError);
1556     }
1559     // Find correspondence from slave points to cut points. This might
1560     // detect shared points so the output is a slave-to-cut point list
1561     // and a compaction list.
1563     labelList cutToCompact, compactToCut;
1564     matchPointsThroughFaces
1565     (
1566         absTol,
1567         cutFaces().localPoints(),
1568         reorder(cutToSlaveFaces_, cutFaces().localFaces()),
1569         slavePatch().localPoints(),
1570         slavePatch().localFaces(),
1571         false,                      // slave and cut have opposite orientation
1573         slaveToCutPoints_,          // slave to (uncompacted) cut points
1574         cutToCompact,               // compaction map: from cut to compacted
1575         compactToCut                // compaction map: from compacted to cut
1576     );
1579     // Use compaction lists to renumber cutPoints.
1580     cutPoints_ = IndirectList<point>(cutPoints_, compactToCut)();
1581     {
1582         const faceList& cutLocalFaces = cutFaces().localFaces();
1584         faceList compactFaces(cutLocalFaces.size());
1585         forAll(cutLocalFaces, i)
1586         {
1587             compactFaces[i] = renumber(cutToCompact, cutLocalFaces[i]);
1588         }
1589         cutFacesPtr_.reset
1590         (
1591             new primitiveFacePatch
1592             (
1593                 compactFaces,
1594                 cutPoints_
1595             )
1596         );
1597     }
1598     inplaceRenumber(cutToCompact, slaveToCutPoints_);
1599     inplaceRenumber(cutToCompact, masterToCutPoints_);
1603 // Calculate the set of cut faces inbetween master and slave patch
1604 // assuming that slave patch is subdivision of masterPatch.
1605 void Foam::faceCoupleInfo::subDivisionMatch
1607     const polyMesh& slaveMesh,
1608     const bool patchDivision,
1609     const scalar absTol
1612     if (debug)
1613     {
1614         Pout<< "subDivisionMatch :"
1615             << " Matching master and slave to cut."
1616             << " Slave can be subdivision of master but all master edges"
1617             << " have to be covered by slave edges." << endl;
1618     }
1620     // Assume slave patch is subdivision of the master patch so cutFaces is a
1621     // copy of the slave (but reversed since orientation has to be like master).
1622     cutPoints_ = slavePatch().localPoints();
1623     {
1624         faceList cutFaces(slavePatch().size());
1626         forAll(cutFaces, i)
1627         {
1628             cutFaces[i] = slavePatch().localFaces()[i].reverseFace();
1629         }
1630         cutFacesPtr_.reset(new primitiveFacePatch(cutFaces, cutPoints_));
1631     }
1633     // Cut is copy of slave so addressing to slave is trivial.
1634     cutToSlaveFaces_ = identity(cutFaces().size());
1635     slaveToCutPoints_ = identity(slavePatch().nPoints());
1637     // Cut edges to slave patch
1638     labelList cutToSlaveEdges
1639     (
1640         findMappedEdges
1641         (
1642             cutFaces().edges(),
1643             slaveToCutPoints_,  //note:should be cutToSlavePoints but since iden
1644             slavePatch()
1645         )
1646     );
1649     if (debug)
1650     {
1651         OFstream str("regionEdges.obj");
1653         Pout<< "subDivisionMatch :"
1654             << " addressing for slave patch fully done."
1655             << " Dumping region edges to " << str.name() << endl;
1657         label vertI = 0;
1659         forAll(slavePatch().edges(), slaveEdgeI)
1660         {
1661             if (regionEdge(slaveMesh, slaveEdgeI))
1662             {
1663                 const edge& e = slavePatch().edges()[slaveEdgeI];
1665                 meshTools::writeOBJ(str, slavePatch().localPoints()[e[0]]);
1666                 vertI++;
1667                 meshTools::writeOBJ(str, slavePatch().localPoints()[e[1]]);
1668                 vertI++;
1669                 str<< "l " << vertI-1 << ' ' << vertI << nl;
1670             }
1671         }
1672     }
1675     // Addressing from cut to master.
1677     // Cut points to master patch
1678     // - determine master points to cut points. Has to be full!
1679     // - invert to get cut to master
1680     if (debug)
1681     {
1682         Pout<< "subDivisionMatch :"
1683             << " matching master points to cut points" << endl;
1684     }
1686     bool matchedAllPoints = matchPoints
1687     (
1688         masterPatch().localPoints(),
1689         cutPoints_,
1690         scalarField(masterPatch().nPoints(), absTol),
1691         true,
1692         masterToCutPoints_
1693     );
1695     if (!matchedAllPoints)
1696     {
1697         FatalErrorIn
1698         (
1699             "faceCoupleInfo::subDivisionMatch"
1700             "(const polyMesh&, const bool, const scalar)"
1701         )   << "Did not match all of the master points to the slave points"
1702             << endl
1703             << "This usually means that the slave patch is not a"
1704             << " subdivision of the master patch"
1705             << abort(FatalError);
1706     }
1709     // Do masterEdges to cutEdges :
1710     // - mark all edges between two masterEdge endpoints. (geometric test since
1711     //   this is the only distinction)
1712     // - this gives the borders inbetween which all cutfaces come from
1713     //   a single master face.
1714     if (debug)
1715     {
1716         Pout<< "subDivisionMatch :"
1717             << " matching cut edges to master edges" << endl;
1718     }
1720     const edgeList& masterEdges = masterPatch().edges();
1721     const pointField& masterPoints = masterPatch().localPoints();
1723     const edgeList& cutEdges = cutFaces().edges();
1725     labelList cutToMasterEdges(cutFaces().nEdges(), -1);
1727     forAll(masterEdges, masterEdgeI)
1728     {
1729         const edge& masterEdge = masterEdges[masterEdgeI];
1731         label cutPoint0 = masterToCutPoints_[masterEdge[0]];
1732         label cutPoint1 = masterToCutPoints_[masterEdge[1]];
1734         // Find edges between cutPoint0 and cutPoint1.
1736         label cutPointI = cutPoint0;
1737         do
1738         {
1739             // Find edge (starting at pointI on cut), aligned with master
1740             // edge.
1741             label cutEdgeI =
1742                 mostAlignedCutEdge
1743                 (
1744                     false,
1745                     slaveMesh,
1746                     patchDivision,
1747                     cutToMasterEdges,
1748                     cutToSlaveEdges,
1749                     cutPointI,
1750                     cutPoint0,
1751                     cutPoint1
1752                 );
1754             if (cutEdgeI == -1)
1755             {
1756                 // Problem. Report while matching to produce nice error message
1757                 mostAlignedCutEdge
1758                 (
1759                     true,
1760                     slaveMesh,
1761                     patchDivision,
1762                     cutToMasterEdges,
1763                     cutToSlaveEdges,
1764                     cutPointI,
1765                     cutPoint0,
1766                     cutPoint1
1767                 );
1769                 Pout<< "Dumping unmatched pointEdges to errorEdges.obj"
1770                     << endl;
1772                 writeOBJ
1773                 (
1774                     "errorEdges.obj",
1775                     IndirectList<edge>
1776                     (
1777                         cutFaces().edges(),
1778                         cutFaces().pointEdges()[cutPointI]
1779                     )(),
1780                     cutFaces().localPoints(),
1781                     false
1782                 );
1784                 FatalErrorIn
1785                 (
1786                     "faceCoupleInfo::subDivisionMatch"
1787                     "(const polyMesh&, const bool, const scalar)"
1788                 )   << "Problem in finding cut edges corresponding to"
1789                     << " master edge " << masterEdge
1790                     << " points:" << masterPoints[masterEdge[0]]
1791                     << ' ' << masterPoints[masterEdge[1]]
1792                     << " corresponding cut edge: (" << cutPoint0
1793                     << ' ' << cutPoint1
1794                     << abort(FatalError);
1795             }
1797             cutToMasterEdges[cutEdgeI] = masterEdgeI;
1799             cutPointI = cutEdges[cutEdgeI].otherVertex(cutPointI);
1801         } while(cutPointI != cutPoint1);
1802     }
1804     if (debug)
1805     {
1806         // Write all matched edges.
1807         writeEdges(cutToMasterEdges, cutToSlaveEdges);
1808     }
1810     // Rework cutToMasterEdges into list of points inbetween two endpoints
1811     // (cutEdgeToPoints_)
1812     setCutEdgeToPoints(cutToMasterEdges);
1815     // Now that we have marked the cut edges that lie on top of master edges
1816     // we can find cut faces that have two (or more) of these edges.
1817     // Note that there can be multiple faces having two or more matched edges
1818     // since the cut faces can form a non-manifold surface(?)
1819     // So the matching is done as an elimination process where for every
1820     // cutFace on a matched edge we store the possible master faces and
1821     // eliminate more and more until we only have one possible master face
1822     // left.
1824     if (debug)
1825     {
1826         Pout<< "subDivisionMatch :"
1827             << " matching (topological) cut faces to masterPatch" << endl;
1828     }
1830     // For every unassigned cutFaceI the possible list of master faces.
1831     Map<labelList> candidates(cutFaces().size());
1833     cutToMasterFaces_.setSize(cutFaces().size());
1834     cutToMasterFaces_ = -1;
1836     while (true)
1837     {
1838         // See if there are any edges left where there is only one remaining
1839         // candidate.
1840         label nChanged = matchEdgeFaces(cutToMasterEdges, candidates);
1842         checkMatch(cutToMasterEdges);
1845         // Now we should have found a face correspondence for every cutFace
1846         // that uses two or more cutEdges. Floodfill from these across
1847         // 'internal' cutedges (i.e. edges that do not have a master
1848         // equivalent) to determine some more cutToMasterFaces
1849         nChanged += growCutFaces(cutToMasterEdges, candidates);
1851         checkMatch(cutToMasterEdges);
1853         if (nChanged == 0)
1854         {
1855             break;
1856         }
1857     }
1859     if (debug)
1860     {
1861         Pout<< "subDivisionMatch :"
1862             << " matching (geometric) cut faces to masterPatch" << endl;
1863     }
1865     // Above should have matched all cases fully. Cannot prove this yet so
1866     // do any remaining unmatched edges by a geometric test.
1867     while (true)
1868     {
1869         // See if there are any edges left where there is only one remaining
1870         // candidate.
1871         label nChanged = geometricMatchEdgeFaces(candidates);
1873         checkMatch(cutToMasterEdges);
1875         nChanged += growCutFaces(cutToMasterEdges, candidates);
1877         checkMatch(cutToMasterEdges);
1879         if (nChanged == 0)
1880         {
1881             break;
1882         }
1883     }
1886     // All cut faces matched?
1887     forAll(cutToMasterFaces_, cutFaceI)
1888     {
1889         if (cutToMasterFaces_[cutFaceI] == -1)
1890         {
1891             const face& cutF = cutFaces()[cutFaceI];
1893             FatalErrorIn
1894             (
1895                 "faceCoupleInfo::subDivisionMatch"
1896                 "(const polyMesh&, const bool, const scalar)"
1897             )   << "Did not match all of cutFaces to a master face" << nl
1898                 << "First unmatched cut face:" << cutFaceI << " with points:"
1899                 << IndirectList<point>(cutFaces().points(), cutF)()
1900                 << nl
1901                 << "This usually means that the slave patch is not a"
1902                 << " subdivision of the master patch"
1903                 << abort(FatalError);
1904         }
1905     }
1907     if (debug)
1908     {
1909         Pout<< "subDivisionMatch :"
1910             << " finished matching master and slave to cut" << endl;
1911     }
1913     if (debug)
1914     {
1915         writePointsFaces();
1916     }
1920 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
1922 // Construct from mesh data
1923 Foam::faceCoupleInfo::faceCoupleInfo
1925     const polyMesh& masterMesh,
1926     const polyMesh& slaveMesh,
1927     const scalar absTol,
1928     const bool perfectMatch
1931     masterPatchPtr_(NULL),
1932     slavePatchPtr_(NULL),
1933     cutPoints_(0),
1934     cutFacesPtr_(NULL),
1935     cutToMasterFaces_(0),
1936     masterToCutPoints_(0),
1937     cutToSlaveFaces_(0),
1938     slaveToCutPoints_(0),
1939     cutEdgeToPoints_(0)
1941     // Get faces on both meshes that are aligned.
1942     // (not ordered i.e. masterToMesh[0] does
1943     // not couple to slaveToMesh[0]. This ordering is done later on)
1944     labelList masterToMesh;
1945     labelList slaveToMesh;
1947     if (perfectMatch)
1948     {
1949         // Identical faces so use tight face-centre comparison.
1950         findPerfectMatchingFaces
1951         (
1952             masterMesh,
1953             slaveMesh,
1954             absTol,
1955             masterToMesh,
1956             slaveToMesh
1957         );
1958     }
1959     else
1960     {
1961         // Slave subdivision of master so use 'nearest'. Bit dodgy, especially
1962         // with using absTol (which is quite small)
1963         findSlavesCoveringMaster
1964         (
1965             masterMesh,
1966             slaveMesh,
1967             absTol,
1968             masterToMesh,
1969             slaveToMesh
1970         );
1971     }
1973     // Construct addressing engines for both sides
1974     masterPatchPtr_.reset
1975     (
1976         new indirectPrimitivePatch
1977         (
1978             IndirectList<face>(masterMesh.faces(), masterToMesh),
1979             masterMesh.points()
1980         )
1981     );
1983     slavePatchPtr_.reset
1984     (
1985         new indirectPrimitivePatch
1986         (
1987             IndirectList<face>(slaveMesh.faces(), slaveToMesh),
1988             slaveMesh.points()
1989         )
1990     );
1993     if (perfectMatch)
1994     {
1995         // Faces are perfectly aligned but probably not ordered.
1996         perfectPointMatch(absTol, false);
1997     }
1998     else
1999     {
2000         // Slave faces are subdivision of master face. Faces not ordered.
2001         subDivisionMatch(slaveMesh, false, absTol);
2002     }
2004     if (debug)
2005     {
2006         writePointsFaces();
2007     }
2011 // Slave is subdivision of master patch.
2012 // (so -both cover the same area -all of master points are present in slave)
2013 Foam::faceCoupleInfo::faceCoupleInfo
2015     const polyMesh& masterMesh,
2016     const labelList& masterAddressing,
2017     const polyMesh& slaveMesh,
2018     const labelList& slaveAddressing,
2019     const scalar absTol,
2020     const bool perfectMatch,
2021     const bool orderedFaces,
2022     const bool patchDivision
2025     masterPatchPtr_
2026     (
2027         new indirectPrimitivePatch
2028         (
2029             IndirectList<face>(masterMesh.faces(), masterAddressing),
2030             masterMesh.points()
2031         )
2032     ),
2033     slavePatchPtr_
2034     (
2035         new indirectPrimitivePatch
2036         (
2037             IndirectList<face>(slaveMesh.faces(), slaveAddressing),
2038             slaveMesh.points()
2039         )
2040     ),
2041     cutPoints_(0),
2042     cutFacesPtr_(NULL),
2043     cutToMasterFaces_(0),
2044     masterToCutPoints_(0),
2045     cutToSlaveFaces_(0),
2046     slaveToCutPoints_(0),
2047     cutEdgeToPoints_(0)
2049     if (perfectMatch && (masterAddressing.size() != slaveAddressing.size()))
2050     {
2051         FatalErrorIn
2052         (
2053             "faceCoupleInfo::faceCoupleInfo(const primitiveMesh&"
2054             ", const primitiveMesh&, const scalar, const bool"
2055         )   << "Perfect match specified but number of master and slave faces"
2056             << " differ." << endl
2057             << "master:" << masterAddressing.size()
2058             << "  slave:" << slaveAddressing.size()
2059             << abort(FatalError);
2060     }
2062     if
2063     (
2064         masterAddressing.size() > 0
2065      && min(masterAddressing) < masterMesh.nInternalFaces()
2066     )
2067     {
2068         FatalErrorIn
2069         (
2070             "faceCoupleInfo::faceCoupleInfo(const primitiveMesh&"
2071             ", const primitiveMesh&, const scalar, const bool"
2072         )   << "Supplied internal face on master mesh to couple." << nl
2073             << "Faces to be coupled have to be boundary faces."
2074             << abort(FatalError);
2075     }
2076     if
2077     (
2078         slaveAddressing.size() > 0
2079      && min(slaveAddressing) < slaveMesh.nInternalFaces()
2080     )
2081     {
2082         FatalErrorIn
2083         (
2084             "faceCoupleInfo::faceCoupleInfo(const primitiveMesh&"
2085             ", const primitiveMesh&, const scalar, const bool"
2086         )   << "Supplied internal face on slave mesh to couple." << nl
2087             << "Faces to be coupled have to be boundary faces."
2088             << abort(FatalError);
2089     }
2092     if (perfectMatch)
2093     {
2094         perfectPointMatch(absTol, orderedFaces);
2095     }
2096     else
2097     {
2098         // Slave faces are subdivision of master face. Faces not ordered.
2099         subDivisionMatch(slaveMesh, patchDivision, absTol);
2100     }
2102     if (debug)
2103     {
2104         writePointsFaces();
2105     }
2109 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
2111 Foam::faceCoupleInfo::~faceCoupleInfo()
2115 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
2117 Foam::labelList Foam::faceCoupleInfo::faceLabels(const polyPatch& pp)
2119     labelList faces(pp.size());
2121     label faceI = pp.start();
2123     forAll(pp, i)
2124     {
2125         faces[i] = faceI++;
2126     }
2127     return faces;
2131 Foam::Map<Foam::label> Foam::faceCoupleInfo::makeMap(const labelList& lst)
2133     Map<label> map(lst.size());
2135     forAll(lst, i)
2136     {
2137         if (lst[i] != -1)
2138         {
2139             map.insert(i, lst[i]);
2140         }
2141     }
2142     return map;
2146 Foam::Map<Foam::labelList> Foam::faceCoupleInfo::makeMap
2148     const labelListList& lst
2151     Map<labelList> map(lst.size());
2153     forAll(lst, i)
2154     {
2155         if (lst[i].size() > 0)
2156         {
2157             map.insert(i, lst[i]);
2158         }
2159     }
2160     return map;
2164 // ************************************************************************* //