faceCoupleInfo.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2019 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "faceCoupleInfo.H"
30 #include "polyMesh.H"
31 #include "matchPoints.H"
32 #include "indirectPrimitivePatch.H"
33 #include "meshTools.H"
34 #include "treeDataFace.H"
35 #include "indexedOctree.H"
36 #include "OFstream.H"
37 
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
42  defineTypeNameAndDebug(faceCoupleInfo, 0);
43  const scalar faceCoupleInfo::angleTol_ = 1e-3;
44 }
45 
46 
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
48 
49 void Foam::faceCoupleInfo::writeOBJ
50 (
51  const fileName& fName,
52  const edgeList& edges,
53  const pointField& points,
54  const bool compact
55 )
56 {
57  OFstream str(fName);
58 
59  labelList pointMap;
60 
61  if (compact)
62  {
63  pointMap.resize(points.size(), -1);
64 
65  label newPointi = 0;
66 
67  forAll(edges, edgeI)
68  {
69  const edge& e = edges[edgeI];
70 
71  forAll(e, eI)
72  {
73  const label pointi = e[eI];
74 
75  if (pointMap[pointi] == -1)
76  {
77  pointMap[pointi] = newPointi++;
78 
79  meshTools::writeOBJ(str, points[pointi]);
80  }
81  }
82  }
83  }
84  else
85  {
86  pointMap = identity(points.size());
87 
88  forAll(points, pointi)
89  {
90  meshTools::writeOBJ(str, points[pointi]);
91  }
92  }
93 
94  forAll(edges, edgeI)
95  {
96  const edge& e = edges[edgeI];
97 
98  str<< "l " << pointMap[e[0]]+1 << ' ' << pointMap[e[1]]+1 << nl;
99  }
100 }
101 
102 
103 void Foam::faceCoupleInfo::writeOBJ
104 (
105  const fileName& fName,
106  const pointField& points0,
107  const pointField& points1
108 )
109 {
110  Pout<< "Writing connections as edges to " << fName << endl;
111 
112  OFstream str(fName);
113 
114  label vertI = 0;
115 
116  forAll(points0, i)
117  {
118  meshTools::writeOBJ(str, points0[i]);
119  vertI++;
120  meshTools::writeOBJ(str, points1[i]);
121  vertI++;
122  str << "l " << vertI-1 << ' ' << vertI << nl;
123  }
124 }
125 
126 
127 void Foam::faceCoupleInfo::writePointsFaces() const
128 {
129  const indirectPrimitivePatch& m = masterPatch();
130  const indirectPrimitivePatch& s = slavePatch();
131  const primitiveFacePatch& c = cutFaces();
132 
133  // Patches
134  {
135  OFstream str("masterPatch.obj");
136  Pout<< "Writing masterPatch to " << str.name() << endl;
137  meshTools::writeOBJ(str, m.localFaces(), m.localPoints());
138  }
139  {
140  OFstream str("slavePatch.obj");
141  Pout<< "Writing slavePatch to " << str.name() << endl;
142  meshTools::writeOBJ(str, s.localFaces(), s.localPoints());
143  }
144  {
145  OFstream str("cutFaces.obj");
146  Pout<< "Writing cutFaces to " << str.name() << endl;
147  meshTools::writeOBJ(str, c.localFaces(), c.localPoints());
148  }
149 
150  // Point connectivity
151  {
152  Pout<< "Writing cutToMasterPoints to cutToMasterPoints.obj" << endl;
153 
154  writeOBJ
155  (
156  "cutToMasterPoints.obj",
157  m.localPoints(),
158  pointField(c.localPoints(), masterToCutPoints_));
159  }
160  {
161  Pout<< "Writing cutToSlavePoints to cutToSlavePoints.obj" << endl;
162 
163  writeOBJ
164  (
165  "cutToSlavePoints.obj",
166  s.localPoints(),
167  pointField(c.localPoints(), slaveToCutPoints_)
168  );
169  }
170 
171  // Face connectivity
172  {
173  Pout<< "Writing cutToMasterFaces to cutToMasterFaces.obj" << endl;
174 
175  pointField equivMasterFaces(c.size());
176 
177  forAll(cutToMasterFaces(), cutFacei)
178  {
179  label masterFacei = cutToMasterFaces()[cutFacei];
180 
181  if (masterFacei != -1)
182  {
183  equivMasterFaces[cutFacei] = m[masterFacei].centre(m.points());
184  }
185  else
186  {
188  << "No master face for cut face " << cutFacei
189  << " at position " << c[cutFacei].centre(c.points())
190  << endl;
191 
192  equivMasterFaces[cutFacei] = Zero;
193  }
194  }
195 
196  writeOBJ
197  (
198  "cutToMasterFaces.obj",
199  calcFaceCentres<List>(c, cutPoints(), 0, c.size()),
200  equivMasterFaces
201  );
202  }
203 
204  {
205  Pout<< "Writing cutToSlaveFaces to cutToSlaveFaces.obj" << endl;
206 
207  pointField equivSlaveFaces(c.size());
208 
209  forAll(cutToSlaveFaces(), cutFacei)
210  {
211  label slaveFacei = cutToSlaveFaces()[cutFacei];
212 
213  equivSlaveFaces[cutFacei] = s[slaveFacei].centre(s.points());
214  }
215 
216  writeOBJ
217  (
218  "cutToSlaveFaces.obj",
219  calcFaceCentres<List>(c, cutPoints(), 0, c.size()),
220  equivSlaveFaces
221  );
222  }
223 
224  Pout<< endl;
225 }
226 
227 
228 void Foam::faceCoupleInfo::writeEdges
229 (
230  const labelList& cutToMasterEdges,
231  const labelList& cutToSlaveEdges
232 ) const
233 {
234  const indirectPrimitivePatch& m = masterPatch();
235  const indirectPrimitivePatch& s = slavePatch();
236  const primitiveFacePatch& c = cutFaces();
237 
238  // Edge connectivity
239  {
240  OFstream str("cutToMasterEdges.obj");
241  Pout<< "Writing cutToMasterEdges to " << str.name() << endl;
242 
243  label vertI = 0;
244 
245  forAll(cutToMasterEdges, cutEdgeI)
246  {
247  if (cutToMasterEdges[cutEdgeI] != -1)
248  {
249  const edge& masterEdge = m.edges()[cutToMasterEdges[cutEdgeI]];
250  const edge& cutEdge = c.edges()[cutEdgeI];
251 
252  meshTools::writeOBJ(str, m.localPoints()[masterEdge[0]]);
253  vertI++;
254  meshTools::writeOBJ(str, m.localPoints()[masterEdge[1]]);
255  vertI++;
256  meshTools::writeOBJ(str, c.localPoints()[cutEdge[0]]);
257  vertI++;
258  meshTools::writeOBJ(str, c.localPoints()[cutEdge[1]]);
259  vertI++;
260  str << "l " << vertI-3 << ' ' << vertI-2 << nl;
261  str << "l " << vertI-3 << ' ' << vertI-1 << nl;
262  str << "l " << vertI-3 << ' ' << vertI << nl;
263  str << "l " << vertI-2 << ' ' << vertI-1 << nl;
264  str << "l " << vertI-2 << ' ' << vertI << nl;
265  str << "l " << vertI-1 << ' ' << vertI << nl;
266  }
267  }
268  }
269  {
270  OFstream str("cutToSlaveEdges.obj");
271  Pout<< "Writing cutToSlaveEdges to " << str.name() << endl;
272 
273  label vertI = 0;
274 
275  labelList slaveToCut(invert(s.nEdges(), cutToSlaveEdges));
276 
277  forAll(slaveToCut, edgeI)
278  {
279  if (slaveToCut[edgeI] != -1)
280  {
281  const edge& slaveEdge = s.edges()[edgeI];
282  const edge& cutEdge = c.edges()[slaveToCut[edgeI]];
283 
284  meshTools::writeOBJ(str, s.localPoints()[slaveEdge[0]]);
285  vertI++;
286  meshTools::writeOBJ(str, s.localPoints()[slaveEdge[1]]);
287  vertI++;
288  meshTools::writeOBJ(str, c.localPoints()[cutEdge[0]]);
289  vertI++;
290  meshTools::writeOBJ(str, c.localPoints()[cutEdge[1]]);
291  vertI++;
292  str << "l " << vertI-3 << ' ' << vertI-2 << nl;
293  str << "l " << vertI-3 << ' ' << vertI-1 << nl;
294  str << "l " << vertI-3 << ' ' << vertI << nl;
295  str << "l " << vertI-2 << ' ' << vertI-1 << nl;
296  str << "l " << vertI-2 << ' ' << vertI << nl;
297  str << "l " << vertI-1 << ' ' << vertI << nl;
298  }
299  }
300  }
301 
302  Pout<< endl;
303 }
304 
305 
306 Foam::labelList Foam::faceCoupleInfo::findMappedEdges
307 (
308  const edgeList& edges,
309  const labelList& pointMap,
311 )
312 {
313  labelList toPatchEdges(edges.size());
314 
315  forAll(toPatchEdges, edgeI)
316  {
317  const edge& e = edges[edgeI];
318 
319  label v0 = pointMap[e[0]];
320  label v1 = pointMap[e[1]];
321 
322  toPatchEdges[edgeI] =
324  (
325  patch.edges(),
326  patch.pointEdges()[v0],
327  v0,
328  v1
329  );
330  }
331  return toPatchEdges;
332 }
333 
334 
335 bool Foam::faceCoupleInfo::regionEdge
336 (
337  const polyMesh& slaveMesh,
338  const label slaveEdgeI
339 ) const
340 {
341  const labelList& eFaces = slavePatch().edgeFaces()[slaveEdgeI];
342 
343  if (eFaces.size() == 1)
344  {
345  return true;
346  }
347  else
348  {
349  // Count how many different patches connected to this edge.
350 
351  label patch0 = -1;
352 
353  forAll(eFaces, i)
354  {
355  label facei = eFaces[i];
356 
357  label meshFacei = slavePatch().addressing()[facei];
358 
359  label patchi = slaveMesh.boundaryMesh().whichPatch(meshFacei);
360 
361  if (patch0 == -1)
362  {
363  patch0 = patchi;
364  }
365  else if (patchi != patch0)
366  {
367  // Found two different patches connected to this edge.
368  return true;
369  }
370  }
371  }
372 
373  return false;
374 }
375 
376 
377 Foam::label Foam::faceCoupleInfo::mostAlignedCutEdge
378 (
379  const bool report,
380  const polyMesh& slaveMesh,
381  const bool patchDivision,
382  const labelList& cutToMasterEdges,
383  const labelList& cutToSlaveEdges,
384  const label pointi,
385  const label edgeStart,
386  const label edgeEnd
387 ) const
388 {
389  // Find edge using pointi that is most aligned with vector between master
390  // points. Patchdivision tells us whether or not to use patch information to
391  // match edges.
392 
393  const pointField& localPoints = cutFaces().localPoints();
394 
395  const labelList& pEdges = cutFaces().pointEdges()[pointi];
396 
397  if (report)
398  {
399  Pout<< "mostAlignedEdge : finding nearest edge among "
400  << UIndirectList<edge>(cutFaces().edges(), pEdges)
401  << " connected to point " << pointi
402  << " coord:" << localPoints[pointi]
403  << " running between " << edgeStart << " coord:"
404  << localPoints[edgeStart]
405  << " and " << edgeEnd << " coord:"
406  << localPoints[edgeEnd]
407  << endl;
408  }
409 
410  // Find the edge that gets us nearest end.
411 
412  label maxEdgeI = -1;
413  scalar maxCos = -GREAT;
414 
415  forAll(pEdges, i)
416  {
417  label edgeI = pEdges[i];
418 
419  if
420  (
421  !(
422  patchDivision
423  && cutToMasterEdges[edgeI] == -1
424  )
425  || (
426  patchDivision
427  && regionEdge(slaveMesh, cutToSlaveEdges[edgeI])
428  )
429  )
430  {
431  const edge& e = cutFaces().edges()[edgeI];
432 
433  label otherPointi = e.otherVertex(pointi);
434 
435  if (otherPointi == edgeEnd)
436  {
437  // Shortcut: found edge end point.
438  if (report)
439  {
440  Pout<< " mostAlignedEdge : found end point " << edgeEnd
441  << endl;
442  }
443  return edgeI;
444  }
445 
446  // Get angle between edge and edge to masterEnd
447 
448  vector eVec(localPoints[otherPointi] - localPoints[pointi]);
449 
450  scalar magEVec = mag(eVec);
451 
452  if (magEVec < VSMALL)
453  {
455  << "Crossing zero sized edge " << edgeI
456  << " coords:" << localPoints[otherPointi]
457  << localPoints[pointi]
458  << " when walking from " << localPoints[edgeStart]
459  << " to " << localPoints[edgeEnd]
460  << endl;
461  return edgeI;
462  }
463 
464  eVec /= magEVec;
465 
466  const vector eToEndPoint =
467  normalised
468  (
469  localPoints[edgeEnd] - localPoints[otherPointi]
470  );
471 
472  scalar cosAngle = eVec & eToEndPoint;
473 
474  if (report)
475  {
476  Pout<< " edge:" << e << " points:" << localPoints[pointi]
477  << localPoints[otherPointi]
478  << " vec:" << eVec
479  << " vecToEnd:" << eToEndPoint
480  << " cosAngle:" << cosAngle
481  << endl;
482  }
483 
484  if (cosAngle > maxCos)
485  {
486  maxCos = cosAngle;
487  maxEdgeI = edgeI;
488  }
489  }
490  }
491 
492  if (maxCos > 1 - angleTol_)
493  {
494  return maxEdgeI;
495  }
496  else
497  {
498  return -1;
499  }
500 }
501 
502 
503 void Foam::faceCoupleInfo::setCutEdgeToPoints(const labelList& cutToMasterEdges)
504 {
505  labelListList masterToCutEdges
506  (
508  (
509  masterPatch().nEdges(),
510  cutToMasterEdges
511  )
512  );
513 
514  const edgeList& cutEdges = cutFaces().edges();
515 
516  // Size extra big so searching is faster
517  cutEdgeToPoints_.resize
518  (
519  masterPatch().nEdges()
520  + slavePatch().nEdges()
521  + cutEdges.size()
522  );
523 
524  forAll(masterToCutEdges, masterEdgeI)
525  {
526  const edge& masterE = masterPatch().edges()[masterEdgeI];
527 
528  //Pout<< "Master:" << masterPatch().localPoints()[masterE[0]] << ' '
529  // << masterPatch().localPoints()[masterE[1]] << endl;
530 
531  const labelList& stringedEdges = masterToCutEdges[masterEdgeI];
532 
533  if (stringedEdges.empty())
534  {
536  << "Did not match all of master edges to cutFace edges"
537  << nl
538  << "First unmatched edge:" << masterEdgeI << " endPoints:"
539  << masterPatch().localPoints()[masterE[0]]
540  << masterPatch().localPoints()[masterE[1]]
541  << endl
542  << "This usually means that the slave patch is not a"
543  << " subdivision of the master patch"
544  << abort(FatalError);
545  }
546  else if (stringedEdges.size() > 1)
547  {
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)
550 
551  DynamicList<label> splitPoints(stringedEdges.size()-1);
552 
553  // Unsplit edge endpoints
554  const edge unsplitEdge
555  (
556  masterToCutPoints_[masterE[0]],
557  masterToCutPoints_[masterE[1]]
558  );
559 
560  label startVertI = unsplitEdge[0];
561  label startEdgeI = -1;
562 
563  while (startVertI != unsplitEdge[1])
564  {
565  // Loop over all string of edges. Update
566  // - startVertI : previous vertex
567  // - startEdgeI : previous edge
568  // and insert any points into splitPoints
569 
570  // For checking
571  label oldStart = startVertI;
572 
573  forAll(stringedEdges, i)
574  {
575  label edgeI = stringedEdges[i];
576 
577  if (edgeI != startEdgeI)
578  {
579  const edge& e = cutEdges[edgeI];
580 
581  //Pout<< " cut:" << e << " at:"
582  // << cutFaces().localPoints()[e[0]]
583  // << ' ' << cutFaces().localPoints()[e[1]] << endl;
584 
585  if (e[0] == startVertI)
586  {
587  startEdgeI = edgeI;
588  startVertI = e[1];
589  if (e[1] != unsplitEdge[1])
590  {
591  splitPoints.append(e[1]);
592  }
593  break;
594  }
595  else if (e[1] == startVertI)
596  {
597  startEdgeI = edgeI;
598  startVertI = e[0];
599  if (e[0] != unsplitEdge[1])
600  {
601  splitPoints.append(e[0]);
602  }
603  break;
604  }
605  }
606  }
607 
608  // Check
609  if (oldStart == startVertI)
610  {
612  << " unsplitEdge:" << unsplitEdge
613  << " does not correspond to split edges "
614  << UIndirectList<edge>(cutEdges, stringedEdges)
615  << abort(FatalError);
616  }
617  }
618 
619  //Pout<< "For master edge:"
620  // << unsplitEdge
621  // << " Found stringed points "
622  // << UIndirectList<point>
623  // (
624  // cutFaces().localPoints(),
625  // splitPoints.shrink()
626  // )
627  // << endl;
628 
629  cutEdgeToPoints_.insert(unsplitEdge, splitPoints.shrink());
630  }
631  }
632 }
633 
634 
635 Foam::label Foam::faceCoupleInfo::matchFaces
636 (
637  const scalar absTol,
638  const pointField& points0,
639  const face& f0,
640  const pointField& points1,
641  const face& f1,
642  const bool sameOrientation
643 )
644 {
645  if (f0.size() != f1.size())
646  {
648  << "Different sizes for supposedly matching faces." << nl
649  << "f0:" << f0 << " coords:" << UIndirectList<point>(points0, f0)
650  << nl
651  << "f1:" << f1 << " coords:" << UIndirectList<point>(points1, f1)
652  << abort(FatalError);
653  }
654 
655  const scalar absTolSqr = sqr(absTol);
656 
657 
658  label matchFp = -1;
659 
660  forAll(f0, startFp)
661  {
662  // See -if starting from startFp on f0- the two faces match.
663  bool fullMatch = true;
664 
665  label fp0 = startFp;
666  label fp1 = 0;
667 
668  forAll(f1, i)
669  {
670  scalar distSqr = Foam::magSqr(points0[f0[fp0]] - points1[f1[fp1]]);
671 
672  if (distSqr > absTolSqr)
673  {
674  fullMatch = false;
675  break;
676  }
677 
678  fp0 = f0.fcIndex(fp0); // walk forward
679 
680  if (sameOrientation)
681  {
682  fp1 = f1.fcIndex(fp1);
683  }
684  else
685  {
686  fp1 = f1.rcIndex(fp1);
687  }
688  }
689 
690  if (fullMatch)
691  {
692  matchFp = startFp;
693  break;
694  }
695  }
696 
697  if (matchFp == -1)
698  {
700  << "No unique match between two faces" << nl
701  << "Face " << f0 << " coords "
702  << UIndirectList<point>(points0, f0) << nl
703  << "Face " << f1 << " coords "
704  << UIndirectList<point>(points1, f1)
705  << "when using tolerance " << absTol
706  << " and forwardMatching:" << sameOrientation
707  << abort(FatalError);
708  }
709 
710  return matchFp;
711 }
712 
713 
714 bool Foam::faceCoupleInfo::matchPointsThroughFaces
715 (
716  const scalar absTol,
717  const pointField& cutPoints,
718  const faceList& cutFaces,
719  const pointField& patchPoints,
720  const faceList& patchFaces,
721  const bool sameOrientation,
722 
723  labelList& patchToCutPoints, // patch to (uncompacted) cut points
724  labelList& cutToCompact, // compaction list for cut points
725  labelList& compactToCut // inverse ,,
726 )
727 {
728  // Find correspondence from patch points to cut points. This might detect
729  // shared points so the output is a patch-to-cut point list and a compaction
730  // list for the cut points (which will always be equal or more connected
731  // than the patch). Returns true if there are any duplicates.
732 
733  // From slave to cut point
734  patchToCutPoints.setSize(patchPoints.size());
735  patchToCutPoints = -1;
736 
737  // Compaction list for cut points: either -1 or index into master which
738  // gives the point to compact to.
739  labelList cutPointRegion(cutPoints.size(), -1);
740  DynamicList<label> cutPointRegionMaster;
741 
742  forAll(patchFaces, patchFacei)
743  {
744  const face& patchF = patchFaces[patchFacei];
745 
746  //const face& cutF = cutFaces[patchToCutFaces[patchFacei]];
747  const face& cutF = cutFaces[patchFacei];
748 
749  // Do geometric matching to get position of cutF[0] in patchF
750  label patchFp = matchFaces
751  (
752  absTol,
753  patchPoints,
754  patchF,
755  cutPoints,
756  cutF,
757  sameOrientation // orientation
758  );
759 
760  forAll(cutF, cutFp)
761  {
762  label cutPointi = cutF[cutFp];
763  label patchPointi = patchF[patchFp];
764 
765  //const point& cutPt = cutPoints[cutPointi];
766  //const point& patchPt = patchPoints[patchPointi];
767  //if (mag(cutPt - patchPt) > SMALL)
768  //{
769  // FatalErrorInFunction
770  // << "cutP:" << cutPt
771  // << " patchP:" << patchPt
772  // << abort(FatalError);
773  //}
774 
775  if (patchToCutPoints[patchPointi] == -1)
776  {
777  patchToCutPoints[patchPointi] = cutPointi;
778  }
779  else if (patchToCutPoints[patchPointi] != cutPointi)
780  {
781  // Multiple cut points connecting to same patch.
782  // Check if already have region & region master for this set
783  label otherCutPointi = patchToCutPoints[patchPointi];
784 
785  //Pout<< "PatchPoint:" << patchPt
786  // << " matches to:" << cutPointi
787  // << " coord:" << cutPoints[cutPointi]
788  // << " and to:" << otherCutPointi
789  // << " coord:" << cutPoints[otherCutPointi]
790  // << endl;
791 
792  if (cutPointRegion[otherCutPointi] != -1)
793  {
794  // Have region for this set. Copy.
795  label region = cutPointRegion[otherCutPointi];
796  cutPointRegion[cutPointi] = region;
797 
798  // Update region master with min point label
799  cutPointRegionMaster[region] = min
800  (
801  cutPointRegionMaster[region],
802  cutPointi
803  );
804  }
805  else
806  {
807  // Create new region.
808  label region = cutPointRegionMaster.size();
809  cutPointRegionMaster.append
810  (
811  min(cutPointi, otherCutPointi)
812  );
813  cutPointRegion[cutPointi] = region;
814  cutPointRegion[otherCutPointi] = region;
815  }
816  }
817 
818  if (sameOrientation)
819  {
820  patchFp = patchF.fcIndex(patchFp);
821  }
822  else
823  {
824  patchFp = patchF.rcIndex(patchFp);
825  }
826  }
827  }
828 
829  // Rework region&master into compaction array
830  compactToCut.setSize(cutPointRegion.size());
831  cutToCompact.setSize(cutPointRegion.size());
832  cutToCompact = -1;
833  label compactPointi = 0;
834 
835  forAll(cutPointRegion, i)
836  {
837  if (cutPointRegion[i] == -1)
838  {
839  // Unduplicated point. Allocate new compacted point.
840  cutToCompact[i] = compactPointi;
841  compactToCut[compactPointi] = i;
842  compactPointi++;
843  }
844  else
845  {
846  // Duplicate point. Get master.
847 
848  label masterPointi = cutPointRegionMaster[cutPointRegion[i]];
849 
850  if (cutToCompact[masterPointi] == -1)
851  {
852  cutToCompact[masterPointi] = compactPointi;
853  compactToCut[compactPointi] = masterPointi;
854  compactPointi++;
855  }
856  cutToCompact[i] = cutToCompact[masterPointi];
857  }
858  }
859  compactToCut.setSize(compactPointi);
860 
861  return compactToCut.size() != cutToCompact.size();
862 }
863 
864 
865 Foam::scalar Foam::faceCoupleInfo::maxDistance
866 (
867  const face& cutF,
868  const pointField& cutPoints,
869  const face& masterF,
870  const pointField& masterPoints
871 )
872 {
873  scalar maxDist = -GREAT;
874 
875  forAll(cutF, fp)
876  {
877  const point& cutPt = cutPoints[cutF[fp]];
878 
879  pointHit pHit = masterF.nearestPoint(cutPt, masterPoints);
880 
881  maxDist = max(maxDist, pHit.distance());
882  }
883  return maxDist;
884 }
885 
886 
887 void Foam::faceCoupleInfo::findPerfectMatchingFaces
888 (
889  const primitiveMesh& mesh0,
890  const primitiveMesh& mesh1,
891  const scalar absTol,
892 
893  labelList& mesh0Faces,
894  labelList& mesh1Faces
895 )
896 {
897  // Quick check: skip face matching if either mesh has no faces
898  if (!mesh0.nFaces() || !mesh1.nFaces())
899  {
900  mesh0Faces.clear();
901  mesh1Faces.clear();
902 
903  return;
904  }
905 
906  // Face centres of external faces (without invoking
907  // mesh.faceCentres since mesh might have been clearedOut)
908 
909  pointField fc0
910  (
911  calcFaceCentres<List>
912  (
913  mesh0.faces(),
914  mesh0.points(),
915  mesh0.nInternalFaces(),
916  mesh0.nBoundaryFaces()
917  )
918  );
919 
920  pointField fc1
921  (
922  calcFaceCentres<List>
923  (
924  mesh1.faces(),
925  mesh1.points(),
926  mesh1.nInternalFaces(),
927  mesh1.nBoundaryFaces()
928  )
929  );
930 
931 
932  if (debug)
933  {
934  Pout<< "Face matching tolerance : " << absTol << endl;
935  }
936 
937 
938  // Match geometrically
939  labelList from1To0;
940  bool matchedAllFaces = matchPoints
941  (
942  fc1,
943  fc0,
944  scalarField(fc1.size(), absTol),
945  false,
946  from1To0
947  );
948 
949  if (matchedAllFaces)
950  {
952  << "Matched ALL " << fc1.size()
953  << " boundary faces of mesh0 to boundary faces of mesh1." << endl
954  << "This is only valid if the mesh to add is fully"
955  << " enclosed by the mesh it is added to." << endl;
956  }
957 
958 
959  // Collect matches.
960  label nMatched = 0;
961 
962  mesh0Faces.setSize(fc0.size());
963  mesh1Faces.setSize(fc1.size());
964 
965  forAll(from1To0, i)
966  {
967  if (from1To0[i] != -1)
968  {
969  mesh1Faces[nMatched] = i + mesh1.nInternalFaces();
970  mesh0Faces[nMatched] = from1To0[i] + mesh0.nInternalFaces();
971 
972  nMatched++;
973  }
974  }
975 
976  mesh0Faces.setSize(nMatched);
977  mesh1Faces.setSize(nMatched);
978 }
979 
980 
981 void Foam::faceCoupleInfo::findSlavesCoveringMaster
982 (
983  const primitiveMesh& mesh0,
984  const primitiveMesh& mesh1,
985  const scalar absTol,
986 
987  labelList& mesh0Faces,
988  labelList& mesh1Faces
989 )
990 {
991  // Construct octree from all mesh0 boundary faces
992  labelList bndFaces
993  (
994  identity(mesh0.nBoundaryFaces(), mesh0.nInternalFaces())
995  );
996 
997  treeBoundBox overallBb(mesh0.points());
998 
999  Random rndGen(123456);
1000 
1001  indexedOctree<treeDataFace> tree
1002  (
1003  treeDataFace // all information needed to search faces
1004  (
1005  false, // do not cache bb
1006  mesh0,
1007  bndFaces // boundary faces only
1008  ),
1009  overallBb.extend(rndGen, 1e-4), // overall search domain
1010  8, // maxLevel
1011  10, // leafsize
1012  3.0 // duplicity
1013  );
1014 
1015  if (debug)
1016  {
1017  Pout<< "findSlavesCoveringMaster :"
1018  << " constructed octree for mesh0 boundary faces" << endl;
1019  }
1020 
1021  // Search nearest face for every mesh1 boundary face.
1022 
1023  labelHashSet mesh0Set(mesh0.nBoundaryFaces());
1024  labelHashSet mesh1Set(mesh1.nBoundaryFaces());
1025 
1026  for
1027  (
1028  label mesh1Facei = mesh1.nInternalFaces();
1029  mesh1Facei < mesh1.nFaces();
1030  mesh1Facei++
1031  )
1032  {
1033  const face& f1 = mesh1.faces()[mesh1Facei];
1034 
1035  // Generate face centre (prevent cellCentres() reconstruction)
1036  point fc(f1.centre(mesh1.points()));
1037 
1038  pointIndexHit nearInfo = tree.findNearest(fc, Foam::sqr(absTol));
1039 
1040  if (nearInfo.hit())
1041  {
1042  label mesh0Facei = tree.shapes().faceLabels()[nearInfo.index()];
1043 
1044  // Check if points of f1 actually lie on top of mesh0 face
1045  // This is the bit that might fail since if f0 is severely warped
1046  // and f1's points are not present on f0 (since subdivision)
1047  // then the distance of the points to f0 might be quite large
1048  // and the test will fail. This all should in fact be some kind
1049  // of walk from known corresponding points/edges/faces.
1050  scalar dist =
1051  maxDistance
1052  (
1053  f1,
1054  mesh1.points(),
1055  mesh0.faces()[mesh0Facei],
1056  mesh0.points()
1057  );
1058 
1059  if (dist < absTol)
1060  {
1061  mesh0Set.insert(mesh0Facei);
1062  mesh1Set.insert(mesh1Facei);
1063  }
1064  }
1065  }
1066 
1067  if (debug)
1068  {
1069  Pout<< "findSlavesCoveringMaster :"
1070  << " matched " << mesh1Set.size() << " mesh1 faces to "
1071  << mesh0Set.size() << " mesh0 faces" << endl;
1072  }
1073 
1074  mesh0Faces = mesh0Set.toc();
1075  mesh1Faces = mesh1Set.toc();
1076 }
1077 
1078 
1079 Foam::label Foam::faceCoupleInfo::growCutFaces
1080 (
1081  const labelList& cutToMasterEdges,
1082  Map<labelList>& candidates
1083 )
1084 {
1085  if (debug)
1086  {
1087  Pout<< "growCutFaces :"
1088  << " growing cut faces to masterPatch" << endl;
1089  }
1090 
1091  label nTotChanged = 0;
1092 
1093  while (true)
1094  {
1095  const labelListList& cutFaceEdges = cutFaces().faceEdges();
1096  const labelListList& cutEdgeFaces = cutFaces().edgeFaces();
1097 
1098  label nChanged = 0;
1099 
1100  forAll(cutToMasterFaces_, cutFacei)
1101  {
1102  const label masterFacei = cutToMasterFaces_[cutFacei];
1103 
1104  if (masterFacei != -1)
1105  {
1106  // We now have a cutFace for which we have already found a
1107  // master face. Grow this masterface across any internal edge
1108  // (internal: no corresponding master edge)
1109 
1110  const labelList& fEdges = cutFaceEdges[cutFacei];
1111 
1112  forAll(fEdges, i)
1113  {
1114  const label cutEdgeI = fEdges[i];
1115 
1116  if (cutToMasterEdges[cutEdgeI] == -1)
1117  {
1118  // So this edge:
1119  // - internal to the cutPatch (since all region edges
1120  // marked before)
1121  // - on cutFacei which corresponds to masterFace.
1122  // Mark all connected faces with this masterFace.
1123 
1124  const labelList& eFaces = cutEdgeFaces[cutEdgeI];
1125 
1126  forAll(eFaces, j)
1127  {
1128  const label facei = eFaces[j];
1129 
1130  if (cutToMasterFaces_[facei] == -1)
1131  {
1132  cutToMasterFaces_[facei] = masterFacei;
1133  candidates.erase(facei);
1134  nChanged++;
1135  }
1136  else if (cutToMasterFaces_[facei] != masterFacei)
1137  {
1138  const pointField& cutPoints =
1139  cutFaces().points();
1140  const pointField& masterPoints =
1141  masterPatch().points();
1142 
1143  const edge& e = cutFaces().edges()[cutEdgeI];
1144 
1145  label myMaster = cutToMasterFaces_[facei];
1146  const face& myF = masterPatch()[myMaster];
1147 
1148  const face& nbrF = masterPatch()[masterFacei];
1149 
1151  << "Cut face "
1152  << cutFaces()[facei].points(cutPoints)
1153  << " has master "
1154  << myMaster
1155  << " but also connects to nbr face "
1156  << cutFaces()[cutFacei].points(cutPoints)
1157  << " with master " << masterFacei
1158  << nl
1159  << "myMasterFace:"
1160  << myF.points(masterPoints)
1161  << " nbrMasterFace:"
1162  << nbrF.points(masterPoints) << nl
1163  << "Across cut edge " << cutEdgeI
1164  << " coord:"
1165  << cutFaces().localPoints()[e[0]]
1166  << cutFaces().localPoints()[e[1]]
1167  << abort(FatalError);
1168  }
1169  }
1170  }
1171  }
1172  }
1173  }
1174 
1175  if (debug)
1176  {
1177  Pout<< "growCutFaces : Grown an additional " << nChanged
1178  << " cut to master face" << " correspondence" << endl;
1179  }
1180 
1181  nTotChanged += nChanged;
1182 
1183  if (nChanged == 0)
1184  {
1185  break;
1186  }
1187  }
1188 
1189  return nTotChanged;
1190 }
1191 
1192 
1193 void Foam::faceCoupleInfo::checkMatch(const labelList& cutToMasterEdges) const
1194 {
1195  const pointField& cutLocalPoints = cutFaces().localPoints();
1196 
1197  const pointField& masterLocalPoints = masterPatch().localPoints();
1198  const faceList& masterLocalFaces = masterPatch().localFaces();
1199 
1200  forAll(cutToMasterEdges, cutEdgeI)
1201  {
1202  const edge& e = cutFaces().edges()[cutEdgeI];
1203 
1204  if (cutToMasterEdges[cutEdgeI] == -1)
1205  {
1206  // Internal edge. Check that master face is same on both sides.
1207  const labelList& cutEFaces = cutFaces().edgeFaces()[cutEdgeI];
1208 
1209  label masterFacei = -1;
1210 
1211  forAll(cutEFaces, i)
1212  {
1213  label cutFacei = cutEFaces[i];
1214 
1215  if (cutToMasterFaces_[cutFacei] != -1)
1216  {
1217  if (masterFacei == -1)
1218  {
1219  masterFacei = cutToMasterFaces_[cutFacei];
1220  }
1221  else if (masterFacei != cutToMasterFaces_[cutFacei])
1222  {
1223  label myMaster = cutToMasterFaces_[cutFacei];
1224  const face& myF = masterLocalFaces[myMaster];
1225 
1226  const face& nbrF = masterLocalFaces[masterFacei];
1227 
1229  << "Internal CutEdge " << e
1230  << " coord:"
1231  << cutLocalPoints[e[0]]
1232  << cutLocalPoints[e[1]]
1233  << " connects to master " << myMaster
1234  << " and to master " << masterFacei << nl
1235  << "myMasterFace:"
1236  << myF.points(masterLocalPoints)
1237  << " nbrMasterFace:"
1238  << nbrF.points(masterLocalPoints)
1239  << abort(FatalError);
1240  }
1241  }
1242  }
1243  }
1244  }
1245 }
1246 
1247 
1248 Foam::label Foam::faceCoupleInfo::matchEdgeFaces
1249 (
1250  const labelList& cutToMasterEdges,
1251  Map<labelList>& candidates
1252 )
1253 {
1254  // Extends matching information by elimination across cutFaces using more
1255  // than one region edge. Updates cutToMasterFaces_ and sets candidates which
1256  // is for every cutface on a region edge the possible master faces.
1257 
1258  // For every unassigned cutFacei the possible list of master faces.
1259  candidates.clear();
1260  candidates.resize(cutFaces().size());
1261 
1262  label nChanged = 0;
1263 
1264  forAll(cutToMasterEdges, cutEdgeI)
1265  {
1266  label masterEdgeI = cutToMasterEdges[cutEdgeI];
1267 
1268  if (masterEdgeI != -1)
1269  {
1270  // So cutEdgeI is matched to masterEdgeI. For all cut faces using
1271  // the cut edge store the master face as a candidate match.
1272 
1273  const labelList& cutEFaces = cutFaces().edgeFaces()[cutEdgeI];
1274  const labelList& masterEFaces =
1275  masterPatch().edgeFaces()[masterEdgeI];
1276 
1277  forAll(cutEFaces, i)
1278  {
1279  label cutFacei = cutEFaces[i];
1280 
1281  if (cutToMasterFaces_[cutFacei] == -1)
1282  {
1283  // So this face (cutFacei) is on an edge (cutEdgeI) that
1284  // is used by some master faces (masterEFaces). Check if
1285  // the cutFacei and some of these masterEFaces share more
1286  // than one edge (which uniquely defines face)
1287 
1288  // Combine master faces with current set of candidate
1289  // master faces.
1290  auto fnd = candidates.find(cutFacei);
1291 
1292  if (!fnd.found())
1293  {
1294  // No info yet for cutFacei. Add all master faces as
1295  // candidates
1296  candidates.insert(cutFacei, masterEFaces);
1297  }
1298  else
1299  {
1300  // From some other cutEdgeI there are already some
1301  // candidate master faces. Check the overlap with
1302  // the current set of master faces.
1303  const labelList& masterFaces = fnd.val();
1304 
1305  DynamicList<label> newCandidates(masterFaces.size());
1306 
1307  forAll(masterEFaces, j)
1308  {
1309  if (masterFaces.found(masterEFaces[j]))
1310  {
1311  newCandidates.append(masterEFaces[j]);
1312  }
1313  }
1314 
1315  if (newCandidates.size() == 1)
1316  {
1317  // Perfect match. Delete entry from candidates map.
1318  cutToMasterFaces_[cutFacei] = newCandidates[0];
1319  candidates.erase(cutFacei);
1320  nChanged++;
1321  }
1322  else
1323  {
1324  // Should not happen?
1325  //Pout<< "On edge:" << cutEdgeI
1326  // << " have connected masterFaces:"
1327  // << masterEFaces
1328  // << " and from previous edge we have"
1329  // << " connected masterFaces" << masterFaces
1330  // << " . Overlap:" << newCandidates << endl;
1331 
1332  fnd() = newCandidates.shrink();
1333  }
1334  }
1335  }
1336 
1337  }
1338  }
1339  }
1340 
1341  if (debug)
1342  {
1343  Pout<< "matchEdgeFaces : Found " << nChanged
1344  << " faces where there was"
1345  << " only one remaining choice for cut-master correspondence"
1346  << endl;
1347  }
1348 
1349  return nChanged;
1350 }
1351 
1352 
1353 Foam::label Foam::faceCoupleInfo::geometricMatchEdgeFaces
1354 (
1355  Map<labelList>& candidates
1356 )
1357 {
1358  const pointField& cutPoints = cutFaces().points();
1359 
1360  label nChanged = 0;
1361 
1362  // Mark all master faces that have been matched so far.
1363 
1364  labelListList masterToCutFaces
1365  (
1367  (
1368  masterPatch().size(),
1369  cutToMasterFaces_
1370  )
1371  );
1372 
1373  forAllConstIters(candidates, iter)
1374  {
1375  label cutFacei = iter.key();
1376  const labelList& masterFaces = iter.val();
1377 
1378  const face& cutF = cutFaces()[cutFacei];
1379 
1380  if (cutToMasterFaces_[cutFacei] == -1)
1381  {
1382  // Find the best matching master face.
1383  scalar minDist = GREAT;
1384  label minMasterFacei = -1;
1385 
1386  forAll(masterFaces, i)
1387  {
1388  label masterFacei = masterFaces[i];
1389 
1390  if (masterToCutFaces[masterFaces[i]].empty())
1391  {
1392  scalar dist = maxDistance
1393  (
1394  cutF,
1395  cutPoints,
1396  masterPatch()[masterFacei],
1397  masterPatch().points()
1398  );
1399 
1400  if (dist < minDist)
1401  {
1402  minDist = dist;
1403  minMasterFacei = masterFacei;
1404  }
1405  }
1406  }
1407 
1408  if (minMasterFacei != -1)
1409  {
1410  cutToMasterFaces_[cutFacei] = minMasterFacei;
1411  masterToCutFaces[minMasterFacei] = cutFacei;
1412  nChanged++;
1413  }
1414  }
1415  }
1416 
1417  // (inefficiently) force candidates to be uptodate.
1418  forAll(cutToMasterFaces_, cutFacei)
1419  {
1420  if (cutToMasterFaces_[cutFacei] != -1)
1421  {
1422  candidates.erase(cutFacei);
1423  }
1424  }
1425 
1426 
1427  if (debug)
1428  {
1429  Pout<< "geometricMatchEdgeFaces : Found " << nChanged
1430  << " faces where there was"
1431  << " only one remaining choice for cut-master correspondence"
1432  << endl;
1433  }
1434 
1435  return nChanged;
1436 }
1437 
1438 
1439 void Foam::faceCoupleInfo::perfectPointMatch
1440 (
1441  const scalar absTol,
1442  const bool slaveFacesOrdered
1443 )
1444 {
1445  // Calculate the set of cut faces inbetween master and slave patch assuming
1446  // perfect match (and optional face ordering on slave)
1447 
1448  if (debug)
1449  {
1450  Pout<< "perfectPointMatch :"
1451  << " Matching master and slave to cut."
1452  << " Master and slave faces are identical" << nl;
1453 
1454  if (slaveFacesOrdered)
1455  {
1456  Pout<< "and master and slave faces are ordered"
1457  << " (on coupled patches)" << endl;
1458  }
1459  else
1460  {
1461  Pout<< "and master and slave faces are not ordered"
1462  << " (on coupled patches)" << endl;
1463  }
1464  }
1465 
1466  cutToMasterFaces_ = identity(masterPatch().size());
1467  cutPoints_ = masterPatch().localPoints();
1468  cutFacesPtr_.reset
1469  (
1470  new primitiveFacePatch
1471  (
1472  masterPatch().localFaces(),
1473  cutPoints_
1474  )
1475  );
1476  masterToCutPoints_ = identity(cutPoints_.size());
1477 
1478 
1479  // Cut faces to slave patch.
1480  bool matchedAllFaces = false;
1481 
1482  if (slaveFacesOrdered)
1483  {
1484  cutToSlaveFaces_ = identity(cutFaces().size());
1485  matchedAllFaces = (cutFaces().size() == slavePatch().size());
1486  }
1487  else
1488  {
1489  // Faces do not have to be ordered (but all have
1490  // to match). Note: Faces will be already ordered if we enter here from
1491  // construct from meshes.
1492 
1493  matchedAllFaces = matchPoints
1494  (
1495  calcFaceCentres<List>
1496  (
1497  cutFaces(),
1498  cutFaces().points(),
1499  0,
1500  cutFaces().size()
1501  ),
1502  calcFaceCentres<IndirectList>
1503  (
1504  slavePatch(),
1505  slavePatch().points(),
1506  0,
1507  slavePatch().size()
1508  ),
1509  scalarField(slavePatch().size(), absTol),
1510  false,
1511  cutToSlaveFaces_
1512  );
1513 
1514  // If some of the face centres did not match, then try to match the
1515  // point averages instead. There is no division by the face area in
1516  // calculating the point average, so this is more stable when faces
1517  // collapse onto a line or point.
1518  if (!matchedAllFaces)
1519  {
1520  labelList cutToSlaveFacesTemp(cutToSlaveFaces_.size(), -1);
1521 
1522  matchPoints
1523  (
1524  calcFacePointAverages<List>
1525  (
1526  cutFaces(),
1527  cutFaces().points(),
1528  0,
1529  cutFaces().size()
1530  ),
1531  calcFacePointAverages<IndirectList>
1532  (
1533  slavePatch(),
1534  slavePatch().points(),
1535  0,
1536  slavePatch().size()
1537  ),
1538  scalarField(slavePatch().size(), absTol),
1539  true,
1540  cutToSlaveFacesTemp
1541  );
1542 
1543  cutToSlaveFaces_ = max(cutToSlaveFaces_, cutToSlaveFacesTemp);
1544 
1545  matchedAllFaces = min(cutToSlaveFaces_) != -1;
1546  }
1547  }
1548 
1549 
1550  if (!matchedAllFaces)
1551  {
1553  << "Did not match all of the master faces to the slave faces"
1554  << endl
1555  << "This usually means that the slave patch and master patch"
1556  << " do not align to within " << absTol << " metre."
1557  << abort(FatalError);
1558  }
1559 
1560 
1561  // Find correspondence from slave points to cut points. This might
1562  // detect shared points so the output is a slave-to-cut point list
1563  // and a compaction list.
1564 
1565  labelList cutToCompact, compactToCut;
1566  matchPointsThroughFaces
1567  (
1568  absTol,
1569  cutFaces().localPoints(),
1570  reorder(cutToSlaveFaces_, cutFaces().localFaces()),
1571  slavePatch().localPoints(),
1572  slavePatch().localFaces(),
1573  false, // slave and cut have opposite orientation
1574 
1575  slaveToCutPoints_, // slave to (uncompacted) cut points
1576  cutToCompact, // compaction map: from cut to compacted
1577  compactToCut // compaction map: from compacted to cut
1578  );
1579 
1580 
1581  // Use compaction lists to renumber cutPoints.
1582  cutPoints_ = UIndirectList<point>(cutPoints_, compactToCut)();
1583  {
1584  const faceList& cutLocalFaces = cutFaces().localFaces();
1585 
1586  faceList compactFaces(cutLocalFaces.size());
1587  forAll(cutLocalFaces, i)
1588  {
1589  compactFaces[i] = renumber(cutToCompact, cutLocalFaces[i]);
1590  }
1591  cutFacesPtr_.reset
1592  (
1593  new primitiveFacePatch
1594  (
1595  compactFaces,
1596  cutPoints_
1597  )
1598  );
1599  }
1600  inplaceRenumber(cutToCompact, slaveToCutPoints_);
1601  inplaceRenumber(cutToCompact, masterToCutPoints_);
1602 }
1603 
1604 
1605 void Foam::faceCoupleInfo::subDivisionMatch
1606 (
1607  const polyMesh& slaveMesh,
1608  const bool patchDivision,
1609  const scalar absTol
1610 )
1611 {
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  }
1619 
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());
1625 
1626  forAll(cutFaces, i)
1627  {
1628  cutFaces[i] = slavePatch().localFaces()[i].reverseFace();
1629  }
1630  cutFacesPtr_.reset(new primitiveFacePatch(cutFaces, cutPoints_));
1631  }
1632 
1633  // Cut is copy of slave so addressing to slave is trivial.
1634  cutToSlaveFaces_ = identity(cutFaces().size());
1635  slaveToCutPoints_ = identity(slavePatch().nPoints());
1636 
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  );
1647 
1648 
1649  if (debug)
1650  {
1651  OFstream str("regionEdges.obj");
1652 
1653  Pout<< "subDivisionMatch :"
1654  << " addressing for slave patch fully done."
1655  << " Dumping region edges to " << str.name() << endl;
1656 
1657  label vertI = 0;
1658 
1659  forAll(slavePatch().edges(), slaveEdgeI)
1660  {
1661  if (regionEdge(slaveMesh, slaveEdgeI))
1662  {
1663  const edge& e = slavePatch().edges()[slaveEdgeI];
1664 
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  }
1673 
1674 
1675  // Addressing from cut to master.
1676 
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  }
1685 
1686  bool matchedAllPoints = matchPoints
1687  (
1688  masterPatch().localPoints(),
1689  cutPoints_,
1690  scalarField(masterPatch().nPoints(), absTol),
1691  true,
1692  masterToCutPoints_
1693  );
1694 
1695  if (!matchedAllPoints)
1696  {
1698  << "Did not match all of the master points to the slave points"
1699  << endl
1700  << "This usually means that the slave patch is not a"
1701  << " subdivision of the master patch"
1702  << abort(FatalError);
1703  }
1704 
1705 
1706  // Do masterEdges to cutEdges :
1707  // - mark all edges between two masterEdge endpoints. (geometric test since
1708  // this is the only distinction)
1709  // - this gives the borders inbetween which all cutfaces come from
1710  // a single master face.
1711  if (debug)
1712  {
1713  Pout<< "subDivisionMatch :"
1714  << " matching cut edges to master edges" << endl;
1715  }
1716 
1717  const edgeList& masterEdges = masterPatch().edges();
1718  const pointField& masterPoints = masterPatch().localPoints();
1719 
1720  const edgeList& cutEdges = cutFaces().edges();
1721 
1722  labelList cutToMasterEdges(cutFaces().nEdges(), -1);
1723 
1724  forAll(masterEdges, masterEdgeI)
1725  {
1726  const edge& masterEdge = masterEdges[masterEdgeI];
1727 
1728  label cutPoint0 = masterToCutPoints_[masterEdge[0]];
1729  label cutPoint1 = masterToCutPoints_[masterEdge[1]];
1730 
1731  // Find edges between cutPoint0 and cutPoint1.
1732 
1733  label cutPointi = cutPoint0;
1734  do
1735  {
1736  // Find edge (starting at pointi on cut), aligned with master
1737  // edge.
1738  label cutEdgeI =
1739  mostAlignedCutEdge
1740  (
1741  false,
1742  slaveMesh,
1743  patchDivision,
1744  cutToMasterEdges,
1745  cutToSlaveEdges,
1746  cutPointi,
1747  cutPoint0,
1748  cutPoint1
1749  );
1750 
1751  if (cutEdgeI == -1)
1752  {
1753  // Problem. Report while matching to produce nice error message
1754  mostAlignedCutEdge
1755  (
1756  true,
1757  slaveMesh,
1758  patchDivision,
1759  cutToMasterEdges,
1760  cutToSlaveEdges,
1761  cutPointi,
1762  cutPoint0,
1763  cutPoint1
1764  );
1765 
1766  Pout<< "Dumping unmatched pointEdges to errorEdges.obj"
1767  << endl;
1768 
1769  writeOBJ
1770  (
1771  "errorEdges.obj",
1772  edgeList
1773  (
1774  UIndirectList<edge>
1775  (
1776  cutFaces().edges(),
1777  cutFaces().pointEdges()[cutPointi]
1778  )
1779  ),
1780  cutFaces().localPoints(),
1781  false
1782  );
1783 
1785  << "Problem in finding cut edges corresponding to"
1786  << " master edge " << masterEdge
1787  << " points:" << masterPoints[masterEdge[0]]
1788  << ' ' << masterPoints[masterEdge[1]]
1789  << " corresponding cut edge: (" << cutPoint0
1790  << ") " << cutPoint1
1791  << abort(FatalError);
1792  }
1793 
1794  cutToMasterEdges[cutEdgeI] = masterEdgeI;
1795 
1796  cutPointi = cutEdges[cutEdgeI].otherVertex(cutPointi);
1797 
1798  } while (cutPointi != cutPoint1);
1799  }
1800 
1801  if (debug)
1802  {
1803  // Write all matched edges.
1804  writeEdges(cutToMasterEdges, cutToSlaveEdges);
1805  }
1806 
1807  // Rework cutToMasterEdges into list of points inbetween two endpoints
1808  // (cutEdgeToPoints_)
1809  setCutEdgeToPoints(cutToMasterEdges);
1810 
1811 
1812  // Now that we have marked the cut edges that lie on top of master edges
1813  // we can find cut faces that have two (or more) of these edges.
1814  // Note that there can be multiple faces having two or more matched edges
1815  // since the cut faces can form a non-manifold surface(?)
1816  // So the matching is done as an elimination process where for every
1817  // cutFace on a matched edge we store the possible master faces and
1818  // eliminate more and more until we only have one possible master face
1819  // left.
1820 
1821  if (debug)
1822  {
1823  Pout<< "subDivisionMatch :"
1824  << " matching (topological) cut faces to masterPatch" << endl;
1825  }
1826 
1827  // For every unassigned cutFacei the possible list of master faces.
1828  Map<labelList> candidates(cutFaces().size());
1829 
1830  cutToMasterFaces_.setSize(cutFaces().size());
1831  cutToMasterFaces_ = -1;
1832 
1833  while (true)
1834  {
1835  // See if there are any edges left where there is only one remaining
1836  // candidate.
1837  label nChanged = matchEdgeFaces(cutToMasterEdges, candidates);
1838 
1839  checkMatch(cutToMasterEdges);
1840 
1841 
1842  // Now we should have found a face correspondence for every cutFace
1843  // that uses two or more cutEdges. Floodfill from these across
1844  // 'internal' cutedges (i.e. edges that do not have a master
1845  // equivalent) to determine some more cutToMasterFaces
1846  nChanged += growCutFaces(cutToMasterEdges, candidates);
1847 
1848  checkMatch(cutToMasterEdges);
1849 
1850  if (nChanged == 0)
1851  {
1852  break;
1853  }
1854  }
1855 
1856  if (debug)
1857  {
1858  Pout<< "subDivisionMatch :"
1859  << " matching (geometric) cut faces to masterPatch" << endl;
1860  }
1861 
1862  // Above should have matched all cases fully. Cannot prove this yet so
1863  // do any remaining unmatched edges by a geometric test.
1864  while (true)
1865  {
1866  // See if there are any edges left where there is only one remaining
1867  // candidate.
1868  label nChanged = geometricMatchEdgeFaces(candidates);
1869 
1870  checkMatch(cutToMasterEdges);
1871 
1872  nChanged += growCutFaces(cutToMasterEdges, candidates);
1873 
1874  checkMatch(cutToMasterEdges);
1875 
1876  if (nChanged == 0)
1877  {
1878  break;
1879  }
1880  }
1881 
1882 
1883  // All cut faces matched?
1884  forAll(cutToMasterFaces_, cutFacei)
1885  {
1886  if (cutToMasterFaces_[cutFacei] == -1)
1887  {
1888  const face& cutF = cutFaces()[cutFacei];
1889 
1891  << "Did not match all of cutFaces to a master face" << nl
1892  << "First unmatched cut face:" << cutFacei << " with points:"
1893  << UIndirectList<point>(cutFaces().points(), cutF)
1894  << nl
1895  << "This usually means that the slave patch is not a"
1896  << " subdivision of the master patch"
1897  << abort(FatalError);
1898  }
1899  }
1900 
1901  if (debug)
1902  {
1903  Pout<< "subDivisionMatch :"
1904  << " finished matching master and slave to cut" << endl;
1905  }
1906 
1907  if (debug)
1908  {
1909  writePointsFaces();
1910  }
1911 }
1912 
1913 
1914 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1915 
1918  const polyMesh& masterMesh,
1919  const polyMesh& slaveMesh,
1920  const scalar absTol,
1921  const bool perfectMatch
1922 )
1923 :
1924  masterPatchPtr_(nullptr),
1925  slavePatchPtr_(nullptr),
1926  cutPoints_(0),
1927  cutFacesPtr_(nullptr),
1928  cutToMasterFaces_(0),
1929  masterToCutPoints_(0),
1930  cutToSlaveFaces_(0),
1931  slaveToCutPoints_(0),
1932  cutEdgeToPoints_(0)
1933 {
1934  // Get faces on both meshes that are aligned.
1935  // (not ordered i.e. masterToMesh[0] does
1936  // not couple to slaveToMesh[0]. This ordering is done later on)
1937  labelList masterToMesh;
1938  labelList slaveToMesh;
1939 
1940  if (perfectMatch)
1941  {
1942  // Identical faces so use tight face-centre comparison.
1943  findPerfectMatchingFaces
1944  (
1945  masterMesh,
1946  slaveMesh,
1947  absTol,
1948  masterToMesh,
1949  slaveToMesh
1950  );
1951  }
1952  else
1953  {
1954  // Slave subdivision of master so use 'nearest'. Bit dodgy, especially
1955  // with using absTol (which is quite small)
1956  findSlavesCoveringMaster
1957  (
1958  masterMesh,
1959  slaveMesh,
1960  absTol,
1961  masterToMesh,
1962  slaveToMesh
1963  );
1964  }
1965 
1966  // Construct addressing engines for both sides
1967  masterPatchPtr_.reset
1968  (
1970  (
1971  IndirectList<face>(masterMesh.faces(), masterToMesh),
1972  masterMesh.points()
1973  )
1974  );
1975 
1976  slavePatchPtr_.reset
1977  (
1979  (
1980  IndirectList<face>(slaveMesh.faces(), slaveToMesh),
1981  slaveMesh.points()
1982  )
1983  );
1984 
1985 
1986  if (perfectMatch)
1987  {
1988  // Faces are perfectly aligned but probably not ordered.
1989  perfectPointMatch(absTol, false);
1990  }
1991  else
1992  {
1993  // Slave faces are subdivision of master face. Faces not ordered.
1994  subDivisionMatch(slaveMesh, false, absTol);
1995  }
1996 
1997  if (debug)
1998  {
1999  writePointsFaces();
2000  }
2001 }
2002 
2003 
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
2014 )
2015 :
2016  masterPatchPtr_
2017  (
2019  (
2020  IndirectList<face>(masterMesh.faces(), masterAddressing),
2021  masterMesh.points()
2022  )
2023  ),
2024  slavePatchPtr_
2025  (
2027  (
2028  IndirectList<face>(slaveMesh.faces(), slaveAddressing),
2029  slaveMesh.points()
2030  )
2031  ),
2032  cutPoints_(0),
2033  cutFacesPtr_(nullptr),
2034  cutToMasterFaces_(0),
2035  masterToCutPoints_(0),
2036  cutToSlaveFaces_(0),
2037  slaveToCutPoints_(0),
2038  cutEdgeToPoints_(0)
2039 {
2040  if (perfectMatch && (masterAddressing.size() != slaveAddressing.size()))
2041  {
2043  << "Perfect match specified but number of master and slave faces"
2044  << " differ." << endl
2045  << "master:" << masterAddressing.size()
2046  << " slave:" << slaveAddressing.size()
2047  << abort(FatalError);
2048  }
2049 
2050  if
2051  (
2052  masterAddressing.size()
2053  && min(masterAddressing) < masterMesh.nInternalFaces()
2054  )
2055  {
2057  << "Supplied internal face on master mesh to couple." << nl
2058  << "Faces to be coupled have to be boundary faces."
2059  << abort(FatalError);
2060  }
2061  if
2062  (
2063  slaveAddressing.size()
2064  && min(slaveAddressing) < slaveMesh.nInternalFaces()
2065  )
2066  {
2068  << "Supplied internal face on slave mesh to couple." << nl
2069  << "Faces to be coupled have to be boundary faces."
2070  << abort(FatalError);
2071  }
2072 
2073 
2074  if (perfectMatch)
2075  {
2076  perfectPointMatch(absTol, orderedFaces);
2077  }
2078  else
2079  {
2080  // Slave faces are subdivision of master face. Faces not ordered.
2081  subDivisionMatch(slaveMesh, patchDivision, absTol);
2082  }
2083 
2084  if (debug)
2085  {
2086  writePointsFaces();
2087  }
2088 }
2089 
2090 
2091 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2092 
2094 {
2095  labelList faces(pp.size());
2096 
2097  label facei = pp.start();
2098 
2099  forAll(pp, i)
2100  {
2101  faces[i] = facei++;
2102  }
2103  return faces;
2104 }
2105 
2106 
2108 {
2109  Map<label> map(lst.size());
2110 
2111  forAll(lst, i)
2112  {
2113  if (lst[i] != -1)
2114  {
2115  map.insert(i, lst[i]);
2116  }
2117  }
2118  return map;
2119 }
2120 
2121 
2124  const labelListList& lst
2125 )
2126 {
2127  Map<labelList> map(lst.size());
2128 
2129  forAll(lst, i)
2130  {
2131  if (lst[i].size())
2132  {
2133  map.insert(i, lst[i]);
2134  }
2135  }
2136  return map;
2137 }
2138 
2139 
2140 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::polyMesh::points
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1069
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
meshTools.H
Foam::edgeList
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
s
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Definition: gmvOutputSpray.H:25
Foam::List::resize
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
Foam::primitiveFacePatch
PrimitivePatch< List< face >, const pointField & > primitiveFacePatch
A PrimitivePatch with List storage for the faces, const reference for the point field.
Definition: primitiveFacePatch.H:51
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::meshTools::writeOBJ
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:203
indexedOctree.H
Foam::Map
A HashTable to objects of type <T> with a label key.
Definition: lumpedPointController.H:69
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
polyMesh.H
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::invert
labelList invert(const label len, const labelUList &map)
Create an inverse one-to-one mapping.
Definition: ListOps.C:36
Foam::inplaceRenumber
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:61
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
OFstream.H
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
treeDataFace.H
nPoints
label nPoints
Definition: gmvOutputHeader.H:2
matchPoints.H
Determine correspondence between points. See below.
Foam::faceCoupleInfo::faceLabels
static labelList faceLabels(const polyPatch &)
Utility functions.
Definition: faceCoupleInfo.C:2093
Foam::meshTools::findEdge
label findEdge(const edgeList &edges, const labelList &candidates, const label v0, const label v1)
Return edge among candidates that uses the two vertices.
Definition: meshTools.C:359
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:68
Foam::faceCoupleInfo::faceCoupleInfo
faceCoupleInfo(const polyMesh &mesh0, const polyMesh &mesh1, const scalar absTol, const bool perfectMatch)
Construct from two meshes and absolute tolerance.
Definition: faceCoupleInfo.C:1917
Foam::OSstream::name
virtual const fileName & name() const
Get the name of the stream.
Definition: OSstream.H:107
Foam::IndirectList
A List with indirect addressing.
Definition: IndirectList.H:56
Foam::reorder
ListType reorder(const labelUList &oldToNew, const ListType &input, const bool prune=false)
Reorder the elements of a list.
Definition: ListOpsTemplates.C:80
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
indirectPrimitivePatch.H
faceCoupleInfo.H
newPointi
label newPointi
Definition: readKivaGrid.H:496
Foam::FatalError
error FatalError
Foam::pointHit
PointHit< point > pointHit
A PointIndexHit for 3D points.
Definition: pointHit.H:44
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::polyPatch::start
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:361
Foam::normalised
VectorSpace< Form, Cmpt, Ncmpts > normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:487
Foam::indirectPrimitivePatch
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
Definition: indirectPrimitivePatch.H:49
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
points0
pointField points0(pointIOField(IOobject("points", mesh.time().constant(), polyMesh::meshSubDir, mesh, IOobject::MUST_READ, IOobject::NO_WRITE, false)))
Foam::renumber
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:37
Foam::polyMesh::faces
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1094
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::pointIndexHit
PointIndexHit< point > pointIndexHit
A PointIndexHit for 3D points.
Definition: pointIndexHit.H:46
Foam::nl
constexpr char nl
Definition: Ostream.H:404
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Foam::foamVersion::patch
const std::string patch
OpenFOAM patch number as a std::string.
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::primitiveMesh::nInternalFaces
label nInternalFaces() const noexcept
Number of internal faces.
Definition: primitiveMeshI.H:78
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::identity
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Definition: labelList.C:38
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
rndGen
Random rndGen
Definition: createFields.H:23
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
Foam::invertOneToMany
labelListList invertOneToMany(const label len, const labelUList &map)
Invert one-to-many map. Unmapped elements will be size 0.
Definition: ListOps.C:114
Foam::faceCoupleInfo::makeMap
static Map< label > makeMap(const labelList &)
Create Map from List.
Definition: faceCoupleInfo.C:2107
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::matchPoints
bool matchPoints(const UList< point > &pts0, const UList< point > &pts1, const UList< scalar > &matchDistance, const bool verbose, labelList &from0To1, const point &origin=point::zero)
Determine correspondence between pointFields. Gets passed.
Definition: matchPoints.C:36
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:79