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