boundaryMesh.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-2016 OpenFOAM Foundation
9  Copyright (C) 2020-2022 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 "boundaryMesh.H"
30 #include "Time.H"
31 #include "polyMesh.H"
32 #include "repatchPolyTopoChanger.H"
33 #include "faceList.H"
34 #include "indexedOctree.H"
35 #include "treeDataPrimitivePatch.H"
36 #include "triSurface.H"
37 #include "SortableList.H"
38 #include "OFstream.H"
39 #include "primitivePatch.H"
40 #include "indirectPrimitivePatch.H"
41 
42 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 
44 namespace Foam
45 {
46  defineTypeNameAndDebug(boundaryMesh, 0);
47 }
48 
49 // Normal along which to divide faces into categories (used in getNearest)
50 const Foam::vector Foam::boundaryMesh::splitNormal_(3, 2, 1);
51 
52 // Distance to face tolerance for getNearest
53 const Foam::scalar Foam::boundaryMesh::distanceTol_ = 1e-2;
54 
55 
56 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
57 
58 // Returns number of feature edges connected to pointi
59 Foam::label Foam::boundaryMesh::nFeatureEdges(label pointi) const
60 {
61  label nFeats = 0;
62 
63  const labelList& pEdges = mesh().pointEdges()[pointi];
64 
65  forAll(pEdges, pEdgeI)
66  {
67  label edgeI = pEdges[pEdgeI];
68 
69  if (edgeToFeature_[edgeI] != -1)
70  {
71  nFeats++;
72  }
73  }
74  return nFeats;
75 }
76 
77 
78 // Returns next feature edge connected to pointi
79 Foam::label Foam::boundaryMesh::nextFeatureEdge
80 (
81  const label edgeI,
82  const label vertI
83 ) const
84 {
85  const labelList& pEdges = mesh().pointEdges()[vertI];
86 
87  forAll(pEdges, pEdgeI)
88  {
89  label nbrEdgeI = pEdges[pEdgeI];
90 
91  if (nbrEdgeI != edgeI)
92  {
93  label featI = edgeToFeature_[nbrEdgeI];
94 
95  if (featI != -1)
96  {
97  return nbrEdgeI;
98  }
99  }
100  }
101 
102  return -1;
103 }
104 
105 
106 // Finds connected feature edges, starting from startPointi and returns
107 // feature labels (not edge labels). Marks feature edges handled in
108 // featVisited.
109 Foam::labelList Foam::boundaryMesh::collectSegment
110 (
111  const boolList& isFeaturePoint,
112  const label startEdgeI,
113  boolList& featVisited
114 ) const
115 {
116  // Find starting feature point on edge.
117 
118  label edgeI = startEdgeI;
119 
120  const edge& e = mesh().edges()[edgeI];
121 
122  label vertI = e.start();
123 
124  while (!isFeaturePoint[vertI])
125  {
126  // Step to next feature edge
127 
128  edgeI = nextFeatureEdge(edgeI, vertI);
129 
130  if ((edgeI == -1) || (edgeI == startEdgeI))
131  {
132  break;
133  }
134 
135  // Step to next vertex on edge
136 
137  const edge& e = mesh().edges()[edgeI];
138 
139  vertI = e.otherVertex(vertI);
140  }
141 
142  //
143  // Now we have:
144  // edgeI : first edge on this segment
145  // vertI : one of the endpoints of this segment
146  //
147  // Start walking other way and storing edges as we go along.
148  //
149 
150  // Untrimmed storage for current segment
151  labelList featLabels(featureEdges_.size());
152 
153  label featLabelI = 0;
154 
155  label initEdgeI = edgeI;
156 
157  do
158  {
159  // Mark edge as visited
160  label featI = edgeToFeature_[edgeI];
161 
162  if (featI == -1)
163  {
165  << "Problem" << abort(FatalError);
166  }
167  featLabels[featLabelI++] = featI;
168 
169  featVisited[featI] = true;
170 
171  // Step to next vertex on edge
172 
173  const edge& e = mesh().edges()[edgeI];
174 
175  vertI = e.otherVertex(vertI);
176 
177  // Step to next feature edge
178 
179  edgeI = nextFeatureEdge(edgeI, vertI);
180 
181  if ((edgeI == -1) || (edgeI == initEdgeI))
182  {
183  break;
184  }
185  }
186  while (!isFeaturePoint[vertI]);
187 
188 
189  // Trim to size
190  featLabels.setSize(featLabelI);
191 
192  return featLabels;
193 }
194 
195 
196 void Foam::boundaryMesh::markEdges
197 (
198  const label maxDistance,
199  const label edgeI,
200  const label distance,
201  labelList& minDistance,
202  DynamicList<label>& visited
203 ) const
204 {
205  if (distance < maxDistance)
206  {
207  // Don't do anything if reached beyond maxDistance.
208 
209  if (minDistance[edgeI] == -1)
210  {
211  // First visit of edge. Store edge label.
212  visited.append(edgeI);
213  }
214  else if (minDistance[edgeI] <= distance)
215  {
216  // Already done this edge
217  return;
218  }
219 
220  minDistance[edgeI] = distance;
221 
222  const edge& e = mesh().edges()[edgeI];
223 
224  // Do edges connected to e.start
225  const labelList& startEdges = mesh().pointEdges()[e.start()];
226 
227  forAll(startEdges, pEdgeI)
228  {
229  markEdges
230  (
231  maxDistance,
232  startEdges[pEdgeI],
233  distance+1,
234  minDistance,
235  visited
236  );
237  }
238 
239  // Do edges connected to e.end
240  const labelList& endEdges = mesh().pointEdges()[e.end()];
241 
242  forAll(endEdges, pEdgeI)
243  {
244  markEdges
245  (
246  maxDistance,
247  endEdges[pEdgeI],
248  distance+1,
249  minDistance,
250  visited
251  );
252  }
253  }
254 }
255 
256 
257 Foam::label Foam::boundaryMesh::findPatchID
258 (
259  const polyPatchList& patches,
260  const word& patchName
261 ) const
262 {
263  forAll(patches, patchi)
264  {
265  if (patches[patchi].name() == patchName)
266  {
267  return patchi;
268  }
269  }
270 
271  return -1;
272 }
273 
274 
276 {
277  wordList names(patches_.size());
278 
279  forAll(patches_, patchi)
280  {
281  names[patchi] = patches_[patchi].name();
282  }
283  return names;
284 }
285 
286 
287 Foam::label Foam::boundaryMesh::whichPatch
288 (
289  const polyPatchList& patches,
290  const label facei
291 ) const
292 {
293  forAll(patches, patchi)
294  {
295  const polyPatch& pp = patches[patchi];
296 
297  if ((facei >= pp.start()) && (facei < (pp.start() + pp.size())))
298  {
299  return patchi;
300  }
301  }
302  return -1;
303 }
304 
305 
306 // Gets labels of changed faces and propagates them to the edges. Returns
307 // labels of edges changed.
308 Foam::labelList Foam::boundaryMesh::faceToEdge
309 (
310  const boolList& regionEdge,
311  const label region,
312  const labelList& changedFaces,
313  labelList& edgeRegion
314 ) const
315 {
316  labelList changedEdges(mesh().nEdges(), -1);
317  label changedI = 0;
318 
319  forAll(changedFaces, i)
320  {
321  label facei = changedFaces[i];
322 
323  const labelList& fEdges = mesh().faceEdges()[facei];
324 
325  forAll(fEdges, fEdgeI)
326  {
327  label edgeI = fEdges[fEdgeI];
328 
329  if (!regionEdge[edgeI] && (edgeRegion[edgeI] == -1))
330  {
331  edgeRegion[edgeI] = region;
332 
333  changedEdges[changedI++] = edgeI;
334  }
335  }
336  }
337 
338  changedEdges.setSize(changedI);
339 
340  return changedEdges;
341 }
342 
343 
344 // Reverse of faceToEdge: gets edges and returns faces
345 Foam::labelList Foam::boundaryMesh::edgeToFace
346 (
347  const label region,
348  const labelList& changedEdges,
349  labelList& faceRegion
350 ) const
351 {
352  labelList changedFaces(mesh().size(), -1);
353  label changedI = 0;
354 
355  forAll(changedEdges, i)
356  {
357  label edgeI = changedEdges[i];
358 
359  const labelList& eFaces = mesh().edgeFaces()[edgeI];
360 
361  forAll(eFaces, eFacei)
362  {
363  label facei = eFaces[eFacei];
364 
365  if (faceRegion[facei] == -1)
366  {
367  faceRegion[facei] = region;
368 
369  changedFaces[changedI++] = facei;
370  }
371  }
372  }
373 
374  changedFaces.setSize(changedI);
375 
376  return changedFaces;
377 }
378 
379 
380 // Finds area, starting at facei, delimited by borderEdge
381 void Foam::boundaryMesh::markZone
382 (
383  const boolList& borderEdge,
384  label facei,
385  label currentZone,
386  labelList& faceZone
387 ) const
388 {
389  faceZone[facei] = currentZone;
390 
391  // List of faces whose faceZone has been set.
392  labelList changedFaces(1, facei);
393  // List of edges whose faceZone has been set.
394  labelList changedEdges;
395 
396  // Zones on all edges.
397  labelList edgeZone(mesh().nEdges(), -1);
398 
399  while (true)
400  {
401  changedEdges = faceToEdge
402  (
403  borderEdge,
404  currentZone,
405  changedFaces,
406  edgeZone
407  );
408 
409  if (debug)
410  {
411  Pout<< "From changedFaces:" << changedFaces.size()
412  << " to changedEdges:" << changedEdges.size()
413  << endl;
414  }
415 
416  if (changedEdges.empty())
417  {
418  break;
419  }
420 
421  changedFaces = edgeToFace(currentZone, changedEdges, faceZone);
422 
423  if (debug)
424  {
425  Pout<< "From changedEdges:" << changedEdges.size()
426  << " to changedFaces:" << changedFaces.size()
427  << endl;
428  }
429 
430  if (changedFaces.empty())
431  {
432  break;
433  }
434  }
435 }
436 
437 
438 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
439 
441 :
442  meshPtr_(nullptr),
443  patches_(),
444  meshFace_(),
445  featurePoints_(),
446  featureEdges_(),
447  featureToEdge_(),
448  edgeToFeature_(),
449  featureSegments_(),
450  extraEdges_()
451 {}
452 
453 
454 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
457 {
458  meshPtr_.reset(nullptr);
459 }
460 
461 
463 {
464  patches_.clear();
465  patches_.resize(mesh.boundaryMesh().size());
466 
467  // Number of boundary faces
468  const label nBFaces = mesh.nBoundaryFaces();
469 
470  faceList bFaces(nBFaces);
471 
472  meshFace_.setSize(nBFaces);
473 
474  label bFacei = 0;
475 
476  // Collect all boundary faces.
477  forAll(mesh.boundaryMesh(), patchi)
478  {
479  const polyPatch& pp = mesh.boundaryMesh()[patchi];
480 
481  patches_.set
482  (
483  patchi,
484  new boundaryPatch
485  (
486  pp.name(),
487  patchi,
488  pp.size(),
489  bFacei,
490  pp.type()
491  )
492  );
493 
494  // Collect all faces in global numbering.
495  forAll(pp, patchFacei)
496  {
497  meshFace_[bFacei] = pp.start() + patchFacei;
498 
499  bFaces[bFacei] = pp[patchFacei];
500 
501  bFacei++;
502  }
503  }
504 
505 
506  if (debug)
507  {
508  Pout<< "read : patches now:" << endl;
509 
510  forAll(patches_, patchi)
511  {
512  const boundaryPatch& bp = patches_[patchi];
513 
514  Pout<< " name : " << bp.name() << endl
515  << " size : " << bp.size() << endl
516  << " start : " << bp.start() << endl
517  << " type : " << bp.physicalType() << endl
518  << endl;
519  }
520  }
521 
522  //
523  // Construct single patch for all of boundary
524  //
525 
526  // Temporary primitivePatch to calculate compact points & faces.
527  primitiveFacePatch globalPatch(bFaces, mesh.points());
528 
529  // Store in local(compact) addressing
530  clearOut();
531 
532  meshPtr_.reset
533  (
534  new bMesh(globalPatch.localFaces(), globalPatch.localPoints())
535  );
536 
537  if (debug & 2)
538  {
539  const bMesh& msh = *meshPtr_;
540 
541  Pout<< "** Start of Faces **" << endl;
542 
543  forAll(msh, facei)
544  {
545  const face& f = msh[facei];
546 
547  point ctr(Zero);
548 
549  forAll(f, fp)
550  {
551  ctr += msh.points()[f[fp]];
552  }
553  ctr /= f.size();
554 
555  Pout<< " " << facei
556  << " ctr:" << ctr
557  << " verts:" << f
558  << endl;
559  }
560 
561  Pout<< "** End of Faces **" << endl;
562 
563  Pout<< "** Start of Points **" << endl;
564 
565  forAll(msh.points(), pointi)
566  {
567  Pout<< " " << pointi
568  << " coord:" << msh.points()[pointi]
569  << endl;
570  }
571 
572  Pout<< "** End of Points **" << endl;
573  }
574 
575  // Clear edge storage
576  featurePoints_.clear();
577  featureEdges_.clear();
578 
579  featureToEdge_.clear();
580  edgeToFeature_.resize(meshPtr_->nEdges());
581  edgeToFeature_ = -1;
582 
583  featureSegments_.clear();
584  extraEdges_.clear();
585 }
586 
587 
589 {
590  triSurface surf(fName);
591 
592  if (surf.empty())
593  {
594  return;
595  }
596 
597  // Sort according to region
598  SortableList<label> regions(surf.size());
599 
600  forAll(surf, triI)
601  {
602  regions[triI] = surf[triI].region();
603  }
604  regions.sort();
605 
606  // Determine region mapping.
607  Map<label> regionToBoundaryPatch;
608 
609  label oldRegion = -1111;
610  label boundPatch = 0;
611 
612  forAll(regions, i)
613  {
614  if (regions[i] != oldRegion)
615  {
616  regionToBoundaryPatch.insert(regions[i], boundPatch);
617 
618  oldRegion = regions[i];
619  boundPatch++;
620  }
621  }
622 
623  const geometricSurfacePatchList& surfPatches = surf.patches();
624 
625  patches_.clear();
626 
627  if (surfPatches.size() == regionToBoundaryPatch.size())
628  {
629  // There are as many surface patches as region numbers in triangles
630  // so use the surface patches
631 
632  patches_.resize(surfPatches.size());
633 
634  // Take over patches, setting size to 0 for now.
635  forAll(surfPatches, patchi)
636  {
637  const geometricSurfacePatch& surfPatch = surfPatches[patchi];
638 
639  patches_.set
640  (
641  patchi,
642  new boundaryPatch
643  (
644  surfPatch.name(),
645  patchi,
646  0,
647  0,
648  surfPatch.geometricType()
649  )
650  );
651  }
652  }
653  else
654  {
655  // There are not enough surface patches. Make up my own.
656 
657  patches_.resize(regionToBoundaryPatch.size());
658 
659  forAll(patches_, patchi)
660  {
661  patches_.set
662  (
663  patchi,
664  new boundaryPatch
665  (
667  patchi,
668  0,
669  0,
671  )
672  );
673  }
674  }
675 
676  //
677  // Copy according into bFaces according to regions
678  //
679 
680  const labelList& indices = regions.indices();
681 
682  faceList bFaces(surf.size());
683 
684  meshFace_.setSize(surf.size());
685 
686  label bFacei = 0;
687 
688  // Current region number
689  label surfRegion = regions[0];
690  label foamRegion = regionToBoundaryPatch[surfRegion];
691 
692  Pout<< "Surface region " << surfRegion << " becomes boundary patch "
693  << foamRegion << " with name " << patches_[foamRegion].name() << endl;
694 
695 
696  // Index in bFaces of start of current patch
697  label startFacei = 0;
698 
699  forAll(indices, indexI)
700  {
701  label triI = indices[indexI];
702 
703  const labelledTri& tri = surf.localFaces()[triI];
704 
705  if (tri.region() != surfRegion)
706  {
707  // Change of region. We now know the size of the previous one.
708  boundaryPatch& bp = patches_[foamRegion];
709 
710  bp.size() = bFacei - startFacei;
711  bp.start() = startFacei;
712 
713  surfRegion = tri.region();
714  foamRegion = regionToBoundaryPatch[surfRegion];
715 
716  Pout<< "Surface region " << surfRegion << " becomes boundary patch "
717  << foamRegion << " with name " << patches_[foamRegion].name()
718  << endl;
719 
720  startFacei = bFacei;
721  }
722 
723  meshFace_[bFacei] = triI;
724 
725  bFaces[bFacei++] = face(tri);
726  }
727 
728  // Final region
729  boundaryPatch& bp = patches_[foamRegion];
730 
731  bp.size() = bFacei - startFacei;
732  bp.start() = startFacei;
733 
734  //
735  // Construct single primitivePatch for all of boundary
736  //
737 
738  clearOut();
739 
740  // Store compact.
741  meshPtr_.reset(new bMesh(bFaces, surf.localPoints()));
742 
743  // Clear edge storage
744  featurePoints_.clear();
745  featureEdges_.clear();
746 
747  featureToEdge_.clear();
748  edgeToFeature_.resize(meshPtr_->nEdges());
749  edgeToFeature_ = -1;
750 
751  featureSegments_.clear();
752  extraEdges_.clear();
753 }
754 
755 
756 void Foam::boundaryMesh::writeTriSurface(const fileName& fName) const
757 {
758  geometricSurfacePatchList surfPatches(patches_.size());
759 
760  forAll(patches_, patchi)
761  {
762  const boundaryPatch& bp = patches_[patchi];
763 
764  surfPatches[patchi] =
766  (
767  bp.name(),
768  patchi,
769  bp.physicalType()
770  );
771  }
772 
773  //
774  // Simple triangulation.
775  //
776 
777  // Get number of triangles per face
778  labelList nTris(mesh().size());
779 
780  label totalNTris = getNTris(0, mesh().size(), nTris);
781 
782  // Determine per face the starting triangle.
783  labelList startTri(mesh().size());
784 
785  label triI = 0;
786 
787  forAll(mesh(), facei)
788  {
789  startTri[facei] = triI;
790 
791  triI += nTris[facei];
792  }
793 
794  // Triangulate
795  labelList triVerts(3*totalNTris);
796 
797  triangulate(0, mesh().size(), totalNTris, triVerts);
798 
799  // Convert to labelledTri
800 
801  List<labelledTri> tris(totalNTris);
802 
803  triI = 0;
804 
805  forAll(patches_, patchi)
806  {
807  const boundaryPatch& bp = patches_[patchi];
808 
809  forAll(bp, patchFacei)
810  {
811  label facei = bp.start() + patchFacei;
812 
813  label triVertI = 3*startTri[facei];
814 
815  for (label faceTriI = 0; faceTriI < nTris[facei]; faceTriI++)
816  {
817  label v0 = triVerts[triVertI++];
818  label v1 = triVerts[triVertI++];
819  label v2 = triVerts[triVertI++];
820 
821  tris[triI++] = labelledTri(v0, v1, v2, patchi);
822  }
823  }
824  }
825 
826  triSurface surf(tris, surfPatches, mesh().points());
827 
828  OFstream surfStream(fName);
829 
830  surf.write(surfStream);
831 }
832 
833 
834 // Get index in this (boundaryMesh) of face nearest to each boundary face in
835 // pMesh.
836 // Originally all triangles/faces of boundaryMesh would be bunged into
837 // one big octree. Problem was that faces on top of each other, differing
838 // only in sign of normal, could not be found separately. It would always
839 // find only one. We could detect that it was probably finding the wrong one
840 // (based on normal) but could not 'tell' the octree to retrieve the other
841 // one (since they occupy exactly the same space)
842 // So now faces get put into different octrees depending on normal.
843 // !It still will not be possible to differentiate between two faces on top
844 // of each other having the same normal
846 (
847  const primitiveMesh& pMesh,
848  const vector& searchSpan
849 ) const
850 {
851 
852  // Divide faces into two bins acc. to normal
853  // - left of splitNormal
854  // - right ,,
855  DynamicList<label> leftFaces(mesh().size()/2);
856  DynamicList<label> rightFaces(mesh().size()/2);
857 
858  forAll(mesh(), bFacei)
859  {
860  scalar sign = mesh().faceNormals()[bFacei] & splitNormal_;
861 
862  if (sign > -1e-5)
863  {
864  rightFaces.append(bFacei);
865  }
866  if (sign < 1e-5)
867  {
868  leftFaces.append(bFacei);
869  }
870  }
871 
872  leftFaces.shrink();
873  rightFaces.shrink();
874 
875  if (debug)
876  {
877  Pout<< "getNearest :"
878  << " rightBin:" << rightFaces.size()
879  << " leftBin:" << leftFaces.size()
880  << endl;
881  }
882 
883  uindirectPrimitivePatch leftPatch
884  (
885  UIndirectList<face>(mesh(), leftFaces),
886  mesh().points()
887  );
888  uindirectPrimitivePatch rightPatch
889  (
890  UIndirectList<face>(mesh(), rightFaces),
891  mesh().points()
892  );
893 
894 
895  // Overall bb
896  treeBoundBox overallBb(mesh().localPoints());
897 
898  // Extend domain slightly (also makes it 3D if was 2D)
899  // Note asymmetry to avoid having faces align with octree cubes.
900  scalar tol = 1e-6 * overallBb.avgDim();
901 
902  point& bbMin = overallBb.min();
903  bbMin.x() -= tol;
904  bbMin.y() -= tol;
905  bbMin.z() -= tol;
906 
907  point& bbMax = overallBb.max();
908  bbMax.x() += 2*tol;
909  bbMax.y() += 2*tol;
910  bbMax.z() += 2*tol;
911 
912  const scalar planarTol =
914  perturbTol();
915 
916 
917  // Create the octrees
919  <
921  > leftTree
922  (
924  (
925  false, // cacheBb
926  leftPatch,
927  planarTol
928  ),
929  overallBb,
930  10, // maxLevel
931  10, // leafSize
932  3.0 // duplicity
933  );
935  <
937  > rightTree
938  (
940  (
941  false, // cacheBb
942  rightPatch,
943  planarTol
944  ),
945  overallBb,
946  10, // maxLevel
947  10, // leafSize
948  3.0 // duplicity
949  );
950 
951  if (debug)
952  {
953  Pout<< "getNearest : built trees" << endl;
954  }
955 
956 
957  const vectorField& ns = mesh().faceNormals();
958 
959 
960  //
961  // Search nearest triangle centre for every polyMesh boundary face
962  //
963 
964  labelList nearestBFacei(pMesh.nBoundaryFaces());
965 
966  const scalar searchDimSqr = magSqr(searchSpan);
967 
968  forAll(nearestBFacei, patchFacei)
969  {
970  label meshFacei = pMesh.nInternalFaces() + patchFacei;
971 
972  const point& ctr = pMesh.faceCentres()[meshFacei];
973 
974  if (debug && (patchFacei % 1000) == 0)
975  {
976  Pout<< "getNearest : patchFace:" << patchFacei
977  << " meshFacei:" << meshFacei << " ctr:" << ctr << endl;
978  }
979 
980 
981  // Get normal from area vector
982  vector n = pMesh.faceAreas()[meshFacei];
983  scalar area = mag(n);
984  n /= area;
985 
986  scalar typDim = -GREAT;
987  const face& f = pMesh.faces()[meshFacei];
988 
989  forAll(f, fp)
990  {
991  typDim = max(typDim, mag(pMesh.points()[f[fp]] - ctr));
992  }
993 
994  // Search right tree
995  pointIndexHit rightInfo = rightTree.findNearest(ctr, searchDimSqr);
996 
997  // Search left tree. Note: could start from rightDist bounding box
998  // instead of starting from top.
999  pointIndexHit leftInfo = leftTree.findNearest(ctr, searchDimSqr);
1000 
1001  if (rightInfo.hit())
1002  {
1003  if (leftInfo.hit())
1004  {
1005  // Found in both trees. Compare normals.
1006  label rightFacei = rightFaces[rightInfo.index()];
1007  label leftFacei = leftFaces[leftInfo.index()];
1008 
1009  label rightDist = rightInfo.point().dist(ctr);
1010  label leftDist = leftInfo.point().dist(ctr);
1011 
1012  scalar rightSign = n & ns[rightFacei];
1013  scalar leftSign = n & ns[leftFacei];
1014 
1015  if
1016  (
1017  (rightSign > 0 && leftSign > 0)
1018  || (rightSign < 0 && leftSign < 0)
1019  )
1020  {
1021  // Both same sign. Choose nearest.
1022  if (rightDist < leftDist)
1023  {
1024  nearestBFacei[patchFacei] = rightFacei;
1025  }
1026  else
1027  {
1028  nearestBFacei[patchFacei] = leftFacei;
1029  }
1030  }
1031  else
1032  {
1033  // Differing sign.
1034  // - if both near enough choose one with correct sign
1035  // - otherwise choose nearest.
1036 
1037  // Get local dimension as max of distance between ctr and
1038  // any face vertex.
1039 
1040  typDim *= distanceTol_;
1041 
1042  if (rightDist < typDim && leftDist < typDim)
1043  {
1044  // Different sign and nearby. Choosing matching normal
1045  if (rightSign > 0)
1046  {
1047  nearestBFacei[patchFacei] = rightFacei;
1048  }
1049  else
1050  {
1051  nearestBFacei[patchFacei] = leftFacei;
1052  }
1053  }
1054  else
1055  {
1056  // Different sign but faraway. Choosing nearest.
1057  if (rightDist < leftDist)
1058  {
1059  nearestBFacei[patchFacei] = rightFacei;
1060  }
1061  else
1062  {
1063  nearestBFacei[patchFacei] = leftFacei;
1064  }
1065  }
1066  }
1067  }
1068  else
1069  {
1070  // Found in right but not in left. Choose right regardless if
1071  // correct sign. Note: do we want this?
1072  label rightFacei = rightFaces[rightInfo.index()];
1073  nearestBFacei[patchFacei] = rightFacei;
1074  }
1075  }
1076  else
1077  {
1078  // No face found in right tree.
1079 
1080  if (leftInfo.hit())
1081  {
1082  // Found in left but not in right. Choose left regardless if
1083  // correct sign. Note: do we want this?
1084  nearestBFacei[patchFacei] = leftFaces[leftInfo.index()];
1085  }
1086  else
1087  {
1088  // No face found in left tree.
1089  nearestBFacei[patchFacei] = -1;
1090  }
1091  }
1092  }
1093 
1094  return nearestBFacei;
1095 }
1096 
1097 
1099 (
1100  const labelList& nearest,
1101  const polyBoundaryMesh& oldPatches,
1102  polyMesh& newMesh
1103 ) const
1104 {
1105 
1106  // 2 cases to be handled:
1107  // A- patches in boundaryMesh patches_
1108  // B- patches not in boundaryMesh patches_ but in polyMesh
1109 
1110  // Create maps from patch name to new patch index.
1111  HashTable<label> nameToIndex(2*patches_.size());
1112 
1113  Map<word> indexToName(2*patches_.size());
1114 
1115 
1116  label nNewPatches = patches_.size();
1117 
1118  forAll(oldPatches, oldPatchi)
1119  {
1120  const polyPatch& patch = oldPatches[oldPatchi];
1121  const label newPatchi = findPatchID(patch.name());
1122 
1123  if (newPatchi != -1)
1124  {
1125  nameToIndex.insert(patch.name(), newPatchi);
1126  indexToName.insert(newPatchi, patch.name());
1127  }
1128  }
1129 
1130  // Include all boundaryPatches not yet in nameToIndex (i.e. not in old
1131  // patches)
1132  forAll(patches_, bPatchi)
1133  {
1134  const boundaryPatch& bp = patches_[bPatchi];
1135 
1136  if (!nameToIndex.found(bp.name()))
1137  {
1138  nameToIndex.insert(bp.name(), bPatchi);
1139  indexToName.insert(bPatchi, bp.name());
1140  }
1141  }
1142 
1143  // Pass1:
1144  // Copy names&type of patches (with zero size) from old mesh as far as
1145  // possible. First patch created gets all boundary faces; all others get
1146  // zero faces (repatched later on). Exception is coupled patches which
1147  // keep their size.
1148 
1149  polyPatchList newPatches(nNewPatches);
1150 
1151  label meshFacei = newMesh.nInternalFaces();
1152 
1153  // First patch gets all non-coupled faces
1154  label facesToBeDone = newMesh.nBoundaryFaces();
1155 
1156  forAll(patches_, bPatchi)
1157  {
1158  const boundaryPatch& bp = patches_[bPatchi];
1159 
1160  const label newPatchi = nameToIndex[bp.name()];
1161 
1162  // Find corresponding patch in polyMesh
1163  const label oldPatchi = findPatchID(oldPatches, bp.name());
1164 
1165  if (oldPatchi == -1)
1166  {
1167  // Newly created patch. Gets all or zero faces.
1168  if (debug)
1169  {
1170  Pout<< "patchify : Creating new polyPatch:" << bp.name()
1171  << " type:" << bp.physicalType() << endl;
1172  }
1173 
1174  newPatches.set
1175  (
1176  newPatchi,
1178  (
1179  bp.physicalType(),
1180  bp.name(),
1181  facesToBeDone,
1182  meshFacei,
1183  newPatchi,
1184  newMesh.boundaryMesh()
1185  )
1186  );
1187 
1188  meshFacei += facesToBeDone;
1189 
1190  // first patch gets all boundary faces; all others get 0.
1191  facesToBeDone = 0;
1192  }
1193  else
1194  {
1195  // Existing patch. Gets all or zero faces.
1196  const polyPatch& oldPatch = oldPatches[oldPatchi];
1197 
1198  if (debug)
1199  {
1200  Pout<< "patchify : Cloning existing polyPatch:"
1201  << oldPatch.name() << endl;
1202  }
1203 
1204  newPatches.set
1205  (
1206  newPatchi,
1207  oldPatch.clone
1208  (
1209  newMesh.boundaryMesh(),
1210  newPatchi,
1211  facesToBeDone,
1212  meshFacei
1213  )
1214  );
1215 
1216  meshFacei += facesToBeDone;
1217 
1218  // first patch gets all boundary faces; all others get 0.
1219  facesToBeDone = 0;
1220  }
1221  }
1222 
1223 
1224  if (debug)
1225  {
1226  Pout<< "Patchify : new polyPatch list:" << endl;
1227 
1228  forAll(newPatches, patchi)
1229  {
1230  const polyPatch& newPatch = newPatches[patchi];
1231 
1232  if (debug)
1233  {
1234  Pout<< "polyPatch:" << newPatch.name() << endl
1235  << " type :" << newPatch.typeName << endl
1236  << " size :" << newPatch.size() << endl
1237  << " start:" << newPatch.start() << endl
1238  << " index:" << patchi << endl;
1239  }
1240  }
1241  }
1242 
1243  // Actually add new list of patches
1244  repatchPolyTopoChanger polyMeshRepatcher(newMesh);
1245  polyMeshRepatcher.changePatches(newPatches);
1246 
1247 
1248  // Pass2:
1249  // Change patch type for face
1250 
1251  if (newPatches.size())
1252  {
1253  List<DynamicList<label>> patchFaces(nNewPatches);
1254 
1255  // Give reasonable estimate for size of patches
1256  label nAvgFaces = newMesh.nBoundaryFaces() / nNewPatches;
1257 
1258  forAll(patchFaces, newPatchi)
1259  {
1260  patchFaces[newPatchi].setCapacity(nAvgFaces);
1261  }
1262 
1263  //
1264  // Sort faces acc. to new patch index. Can loop over all old patches
1265  // since will contain all faces.
1266  //
1267 
1268  forAll(oldPatches, oldPatchi)
1269  {
1270  const polyPatch& patch = oldPatches[oldPatchi];
1271 
1272  forAll(patch, patchFacei)
1273  {
1274  // Put face into region given by nearest boundary face
1275 
1276  label meshFacei = patch.start() + patchFacei;
1277 
1278  label bFacei = meshFacei - newMesh.nInternalFaces();
1279 
1280  patchFaces[whichPatch(nearest[bFacei])].append(meshFacei);
1281  }
1282  }
1283 
1284  forAll(patchFaces, newPatchi)
1285  {
1286  patchFaces[newPatchi].shrink();
1287  }
1288 
1289 
1290  // Change patch > 0. (since above we put all faces into the zeroth
1291  // patch)
1292 
1293  for (label newPatchi = 1; newPatchi < patchFaces.size(); newPatchi++)
1294  {
1295  const labelList& pFaces = patchFaces[newPatchi];
1296 
1297  forAll(pFaces, pFacei)
1298  {
1299  polyMeshRepatcher.changePatchID(pFaces[pFacei], newPatchi);
1300  }
1301  }
1302 
1303  polyMeshRepatcher.repatch();
1304  }
1305 }
1306 
1307 
1308 void Foam::boundaryMesh::setFeatureEdges(const scalar minCos)
1309 {
1310  edgeToFeature_.setSize(mesh().nEdges());
1311 
1312  edgeToFeature_ = -1;
1313 
1314  // 1. Mark feature edges
1315 
1316  // Storage for edge labels that are features. Trim later.
1317  featureToEdge_.setSize(mesh().nEdges());
1318 
1319  label featureI = 0;
1320 
1321  if (minCos >= 0.9999)
1322  {
1323  // Select everything
1324  forAll(mesh().edges(), edgeI)
1325  {
1326  edgeToFeature_[edgeI] = featureI;
1327  featureToEdge_[featureI++] = edgeI;
1328  }
1329  }
1330  else
1331  {
1332  forAll(mesh().edges(), edgeI)
1333  {
1334  const labelList& eFaces = mesh().edgeFaces()[edgeI];
1335 
1336  if (eFaces.size() == 2)
1337  {
1338  label face0I = eFaces[0];
1339 
1340  label face1I = eFaces[1];
1341 
1344  //if (whichPatch(face0I) != whichPatch(face1I))
1345  //{
1346  // edgeToFeature_[edgeI] = featureI;
1347  // featureToEdge_[featureI++] = edgeI;
1348  //}
1349  //else
1350  {
1351  const vector& n0 = mesh().faceNormals()[face0I];
1352 
1353  const vector& n1 = mesh().faceNormals()[face1I];
1354 
1355  float cosAng = n0 & n1;
1356 
1357  if (cosAng < minCos)
1358  {
1359  edgeToFeature_[edgeI] = featureI;
1360  featureToEdge_[featureI++] = edgeI;
1361  }
1362  }
1363  }
1364  else
1365  {
1366  //Should not occur: 0 or more than two faces
1367  edgeToFeature_[edgeI] = featureI;
1368  featureToEdge_[featureI++] = edgeI;
1369  }
1370  }
1371  }
1372 
1373  // Trim featureToEdge_ to actual number of edges.
1374  featureToEdge_.setSize(featureI);
1375 
1376  //
1377  // Compact edges i.e. relabel vertices.
1378  //
1379 
1380  featureEdges_.setSize(featureI);
1381  featurePoints_.setSize(mesh().nPoints());
1382 
1383  labelList featToMeshPoint(mesh().nPoints(), -1);
1384 
1385  label featPtI = 0;
1386 
1387  forAll(featureToEdge_, fEdgeI)
1388  {
1389  label edgeI = featureToEdge_[fEdgeI];
1390 
1391  const edge& e = mesh().edges()[edgeI];
1392 
1393  label start = featToMeshPoint[e.start()];
1394 
1395  if (start == -1)
1396  {
1397  featToMeshPoint[e.start()] = featPtI;
1398 
1399  featurePoints_[featPtI] = mesh().points()[e.start()];
1400 
1401  start = featPtI;
1402 
1403  featPtI++;
1404  }
1405 
1406  label end = featToMeshPoint[e.end()];
1407 
1408  if (end == -1)
1409  {
1410  featToMeshPoint[e.end()] = featPtI;
1411 
1412  featurePoints_[featPtI] = mesh().points()[e.end()];
1413 
1414  end = featPtI;
1415 
1416  featPtI++;
1417  }
1418 
1419  // Store with renumbered vertices.
1420  featureEdges_[fEdgeI] = edge(start, end);
1421  }
1422 
1423  // Compact points
1424  featurePoints_.setSize(featPtI);
1425 
1426 
1427  //
1428  // 2. Mark endpoints of feature segments. These are points with
1429  // != 2 feature edges connected.
1430  // Note: can add geometric constraint here as well that if 2 feature
1431  // edges the angle between them should be less than xxx.
1432  //
1433 
1434  boolList isFeaturePoint(mesh().nPoints(), false);
1435 
1436  forAll(featureToEdge_, featI)
1437  {
1438  label edgeI = featureToEdge_[featI];
1439 
1440  const edge& e = mesh().edges()[edgeI];
1441 
1442  if (nFeatureEdges(e.start()) != 2)
1443  {
1444  isFeaturePoint[e.start()] = true;
1445  }
1446 
1447  if (nFeatureEdges(e.end()) != 2)
1448  {
1449  isFeaturePoint[e.end()] = true;
1450  }
1451  }
1452 
1453 
1454  //
1455  // 3: Split feature edges into segments:
1456  // find point with not 2 feature edges -> start of feature segment
1457  //
1458 
1459  DynamicList<labelList> segments;
1460 
1461 
1462  boolList featVisited(featureToEdge_.size(), false);
1463 
1464  do
1465  {
1466  label startFeatI = -1;
1467 
1468  forAll(featVisited, featI)
1469  {
1470  if (!featVisited[featI])
1471  {
1472  startFeatI = featI;
1473 
1474  break;
1475  }
1476  }
1477 
1478  if (startFeatI == -1)
1479  {
1480  // No feature lines left.
1481  break;
1482  }
1483 
1484  segments.append
1485  (
1486  collectSegment
1487  (
1488  isFeaturePoint,
1489  featureToEdge_[startFeatI],
1490  featVisited
1491  )
1492  );
1493  }
1494  while (true);
1495 
1496 
1497  //
1498  // Store in *this
1499  //
1500  featureSegments_.setSize(segments.size());
1501 
1502  forAll(featureSegments_, segmentI)
1503  {
1504  featureSegments_[segmentI] = segments[segmentI];
1505  }
1506 }
1507 
1508 
1509 void Foam::boundaryMesh::setExtraEdges(const label edgeI)
1510 {
1511  labelList minDistance(mesh().nEdges(), -1);
1512 
1513  // All edge labels encountered
1514  DynamicList<label> visitedEdges;
1515 
1516  // Floodfill from edgeI starting from distance 0. Stop at distance.
1517  markEdges(8, edgeI, 0, minDistance, visitedEdges);
1518 
1519  // Set edge labels to display
1520  extraEdges_.transfer(visitedEdges);
1521 }
1522 
1523 
1524 Foam::label Foam::boundaryMesh::whichPatch(const label facei) const
1525 {
1526  forAll(patches_, patchi)
1527  {
1528  const boundaryPatch& bp = patches_[patchi];
1529 
1530  if ((facei >= bp.start()) && (facei < (bp.start() + bp.size())))
1531  {
1532  return patchi;
1533  }
1534  }
1535 
1537  << "Cannot find face " << facei << " in list of boundaryPatches "
1538  << patches_
1539  << abort(FatalError);
1540 
1541  return -1;
1542 }
1543 
1544 
1545 Foam::label Foam::boundaryMesh::findPatchID(const word& patchName) const
1546 {
1547  forAll(patches_, patchi)
1548  {
1549  if (patches_[patchi].name() == patchName)
1550  {
1551  return patchi;
1552  }
1553  }
1554 
1555  return -1;
1556 }
1557 
1558 
1559 void Foam::boundaryMesh::addPatch(const word& patchName)
1560 {
1561  patches_.setSize(patches_.size() + 1);
1562 
1563  // Add empty patch at end of patch list.
1564 
1565  label patchi = patches_.size()-1;
1566 
1567  boundaryPatch* bpPtr = new boundaryPatch
1568  (
1569  patchName,
1570  patchi,
1571  0,
1572  mesh().size(),
1573  "empty"
1574  );
1575 
1576  patches_.set(patchi, bpPtr);
1577 
1578  if (debug)
1579  {
1580  Pout<< "addPatch : patches now:" << endl;
1581 
1582  forAll(patches_, patchi)
1583  {
1584  const boundaryPatch& bp = patches_[patchi];
1585 
1586  Pout<< " name : " << bp.name() << endl
1587  << " size : " << bp.size() << endl
1588  << " start : " << bp.start() << endl
1589  << " type : " << bp.physicalType() << endl
1590  << endl;
1591  }
1592  }
1593 }
1594 
1595 
1596 void Foam::boundaryMesh::deletePatch(const word& patchName)
1597 {
1598  const label delPatchi = findPatchID(patchName);
1599 
1600  if (delPatchi == -1)
1601  {
1603  << "Can't find patch named " << patchName
1604  << abort(FatalError);
1605  }
1606 
1607  if (patches_[delPatchi].size())
1608  {
1610  << "Trying to delete non-empty patch " << patchName
1611  << endl << "Current size:" << patches_[delPatchi].size()
1612  << abort(FatalError);
1613  }
1614 
1615  PtrList<boundaryPatch> newPatches(patches_.size() - 1);
1616 
1617  for (label patchi = 0; patchi < delPatchi; patchi++)
1618  {
1619  newPatches.set(patchi, patches_[patchi].clone());
1620  }
1621 
1622  // Move patches down, starting from delPatchi.
1623 
1624  for (label patchi = delPatchi + 1; patchi < patches_.size(); patchi++)
1625  {
1626  newPatches.set(patchi - 1, patches_[patchi].clone());
1627  }
1628 
1629  patches_ = std::move(newPatches);
1630 
1631  if (debug)
1632  {
1633  Pout<< "deletePatch : patches now:" << endl;
1634 
1635  forAll(patches_, patchi)
1636  {
1637  const boundaryPatch& bp = patches_[patchi];
1638 
1639  Pout<< " name : " << bp.name() << endl
1640  << " size : " << bp.size() << endl
1641  << " start : " << bp.start() << endl
1642  << " type : " << bp.physicalType() << endl
1643  << endl;
1644  }
1645  }
1646 }
1647 
1648 
1650 (
1651  const word& patchName,
1652  const word& patchType
1653 )
1654 {
1655  const label changeI = findPatchID(patchName);
1656 
1657  if (changeI == -1)
1658  {
1660  << "Can't find patch named " << patchName
1661  << abort(FatalError);
1662  }
1663 
1664 
1665  // Cause we can't reassign to individual PtrList elems ;-(
1666  // work on copy
1667 
1668 
1669  PtrList<boundaryPatch> newPatches(patches_.size());
1670 
1671  forAll(patches_, patchi)
1672  {
1673  if (patchi == changeI)
1674  {
1675  // Create copy but for type
1676  const boundaryPatch& oldBp = patches_[patchi];
1677 
1678  boundaryPatch* bpPtr = new boundaryPatch
1679  (
1680  oldBp.name(),
1681  oldBp.index(),
1682  oldBp.size(),
1683  oldBp.start(),
1684  patchType
1685  );
1686 
1687  newPatches.set(patchi, bpPtr);
1688  }
1689  else
1690  {
1691  // Create copy
1692  newPatches.set(patchi, patches_[patchi].clone());
1693  }
1694  }
1695 
1696  patches_ = newPatches;
1697 }
1698 
1699 
1701 (
1702  const labelList& patchIDs,
1703  labelList& oldToNew
1704 )
1705 {
1706  if (patchIDs.size() != mesh().size())
1707  {
1709  << "List of patchIDs not equal to number of faces." << endl
1710  << "PatchIDs size:" << patchIDs.size()
1711  << " nFaces::" << mesh().size()
1712  << abort(FatalError);
1713  }
1714 
1715  // Count number of faces for each patch
1716 
1717  labelList nFaces(patches_.size(), Zero);
1718 
1719  forAll(patchIDs, facei)
1720  {
1721  label patchID = patchIDs[facei];
1722 
1723  if (patchID < 0 || patchID >= patches_.size())
1724  {
1726  << "PatchID " << patchID << " out of range"
1727  << abort(FatalError);
1728  }
1729  nFaces[patchID]++;
1730  }
1731 
1732 
1733  // Determine position in faces_ for each patch
1734 
1735  labelList startFace(patches_.size());
1736 
1737  startFace[0] = 0;
1738 
1739  for (label patchi = 1; patchi < patches_.size(); patchi++)
1740  {
1741  startFace[patchi] = startFace[patchi-1] + nFaces[patchi-1];
1742  }
1743 
1744  // Update patch info
1745  PtrList<boundaryPatch> newPatches(patches_.size());
1746 
1747  forAll(patches_, patchi)
1748  {
1749  const boundaryPatch& bp = patches_[patchi];
1750 
1751  newPatches.set
1752  (
1753  patchi,
1754  new boundaryPatch
1755  (
1756  bp.name(),
1757  patchi,
1758  nFaces[patchi],
1759  startFace[patchi],
1760  bp.physicalType()
1761  )
1762  );
1763  }
1764  patches_ = newPatches;
1765 
1766  if (debug)
1767  {
1768  Pout<< "changeFaces : patches now:" << endl;
1769 
1770  forAll(patches_, patchi)
1771  {
1772  const boundaryPatch& bp = patches_[patchi];
1773 
1774  Pout<< " name : " << bp.name() << endl
1775  << " size : " << bp.size() << endl
1776  << " start : " << bp.start() << endl
1777  << " type : " << bp.physicalType() << endl
1778  << endl;
1779  }
1780  }
1781 
1782 
1783  // Construct face mapping array
1784  oldToNew.setSize(patchIDs.size());
1785 
1786  forAll(patchIDs, facei)
1787  {
1788  int patchID = patchIDs[facei];
1789 
1790  oldToNew[facei] = startFace[patchID]++;
1791  }
1792 
1793  // Copy faces into correct position and maintain label of original face
1794  faceList newFaces(mesh().size());
1795 
1796  labelList newMeshFace(mesh().size());
1797 
1798  forAll(oldToNew, facei)
1799  {
1800  newFaces[oldToNew[facei]] = mesh()[facei];
1801  newMeshFace[oldToNew[facei]] = meshFace_[facei];
1802  }
1803 
1804  // Reconstruct 'mesh' from new faces and (copy of) existing points.
1805 
1806  std::unique_ptr<bMesh> newMeshPtr(new bMesh(newFaces, mesh().points()));
1807 
1808  // Reset meshFace_ to new ordering.
1809  meshFace_.transfer(newMeshFace);
1810 
1811 
1812  // Remove old PrimitivePatch on meshPtr_.
1813  clearOut();
1814 
1815  // And insert new 'mesh'.
1816  meshPtr_ = std::move(newMeshPtr);
1817 }
1818 
1819 
1820 Foam::label Foam::boundaryMesh::getNTris(const label facei) const
1821 {
1822  const face& f = mesh()[facei];
1823 
1824  return f.nTriangles(mesh().points());
1825 }
1826 
1827 
1828 Foam::label Foam::boundaryMesh::getNTris
1829 (
1830  const label startFacei,
1831  const label nFaces,
1832  labelList& nTris
1833 ) const
1834 {
1835  label totalNTris = 0;
1836 
1837  nTris.setSize(nFaces);
1838 
1839  for (label i = 0; i < nFaces; i++)
1840  {
1841  label faceNTris = getNTris(startFacei + i);
1842 
1843  nTris[i] = faceNTris;
1844 
1845  totalNTris += faceNTris;
1846  }
1847  return totalNTris;
1848 }
1849 
1850 
1851 // Simple triangulation of face subset. Stores vertices in tris[] as three
1852 // consecutive vertices per triangle.
1854 (
1855  const label startFacei,
1856  const label nFaces,
1857  const label totalNTris,
1858  labelList& triVerts
1859 ) const
1860 {
1861  // Triangulate faces.
1862  triVerts.setSize(3*totalNTris);
1863 
1864  label vertI = 0;
1865 
1866  for (label i = 0; i < nFaces; i++)
1867  {
1868  label facei = startFacei + i;
1869 
1870  const face& f = mesh()[facei];
1871 
1872  // Have face triangulate itself (results in faceList)
1873  faceList triFaces(f.nTriangles(mesh().points()));
1874 
1875  label nTri = 0;
1876 
1877  f.triangles(mesh().points(), nTri, triFaces);
1878 
1879  // Copy into triVerts
1880 
1881  forAll(triFaces, triFacei)
1882  {
1883  const face& triF = triFaces[triFacei];
1884 
1885  triVerts[vertI++] = triF[0];
1886  triVerts[vertI++] = triF[1];
1887  triVerts[vertI++] = triF[2];
1888  }
1889  }
1890 }
1891 
1892 
1893 // Number of local points in subset.
1895 (
1896  const label startFacei,
1897  const label nFaces
1898 ) const
1899 {
1901  (
1902  SubList<face>(mesh(), nFaces, startFacei),
1903  mesh().points()
1904  );
1906  return patch.nPoints();
1907 }
1908 
1909 
1910 // Triangulation of face subset in local coords.
1912 (
1913  const label startFacei,
1914  const label nFaces,
1915  const label totalNTris,
1916  labelList& triVerts,
1917  labelList& localToGlobal
1918 ) const
1919 {
1921  (
1922  SubList<face>(mesh(), nFaces, startFacei),
1923  mesh().points()
1924  );
1925 
1926  // Map from local to mesh().points() addressing
1927  localToGlobal = patch.meshPoints();
1928 
1929  // Triangulate patch faces.
1930  triVerts.setSize(3*totalNTris);
1931 
1932  label vertI = 0;
1933 
1934  for (label i = 0; i < nFaces; i++)
1935  {
1936  // Local face
1937  const face& f = patch.localFaces()[i];
1938 
1939  // Have face triangulate itself (results in faceList)
1940  faceList triFaces(f.nTriangles(patch.localPoints()));
1941 
1942  label nTri = 0;
1943 
1944  f.triangles(patch.localPoints(), nTri, triFaces);
1945 
1946  // Copy into triVerts
1947 
1948  forAll(triFaces, triFacei)
1949  {
1950  const face& triF = triFaces[triFacei];
1951 
1952  triVerts[vertI++] = triF[0];
1953  triVerts[vertI++] = triF[1];
1954  triVerts[vertI++] = triF[2];
1955  }
1956  }
1957 }
1958 
1959 
1961 (
1962  const labelList& protectedEdges,
1963  const label seedFacei,
1964  boolList& visited
1965 ) const
1966 {
1967  boolList protectedEdge(mesh().nEdges(), false);
1968 
1969  forAll(protectedEdges, i)
1970  {
1971  protectedEdge[protectedEdges[i]] = true;
1972  }
1973 
1974 
1975  // Initialize zone for all faces to -1
1976  labelList currentZone(mesh().size(), -1);
1977 
1978  // Mark with 0 all faces reachable from seedFacei
1979  markZone(protectedEdge, seedFacei, 0, currentZone);
1980 
1981  // Set in visited all reached ones.
1982  visited.setSize(mesh().size());
1983 
1984  forAll(currentZone, facei)
1985  {
1986  if (currentZone[facei] == 0)
1987  {
1988  visited[facei] = true;
1989  }
1990  else
1991  {
1992  visited[facei] = false;
1993  }
1994  }
1995 }
1996 
1997 
1998 // ************************************************************************* //
dimensionedScalar sign(const dimensionedScalar &ds)
const labelListList & pointEdges() const
Return point-edge addressing.
const labelList patchIDs(pbm.indices(polyPatchNames, true))
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
void addPatch(const word &patchName)
Add to back of patch list.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
List< word > names(const UPtrList< T > &list, const UnaryMatchPredicate &matcher)
List of names generated by calling name() for each list item and filtered for matches.
A class for handling file names.
Definition: fileName.H:72
void read(const polyMesh &)
Read from boundaryMesh of polyMesh.
Definition: boundaryMesh.C:455
void setFeatureEdges(const scalar minCos)
Set featureEdges, edgeToFeature, featureSegments according.
Like polyPatch but without reference to mesh. Used in boundaryMesh to hold data on patches...
Definition: boundaryPatch.H:51
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
const Field< point_type > & localPoints() const
Return pointField of points in patch.
label getNPoints(const label startFacei, const label nFaces) const
Number of points used in face subset.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
const labelListList & faceEdges() const
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
const labelListList & pointEdges() const
Cell-face mesh analysis engine.
Definition: primitiveMesh.H:75
void triangulate(const label startFacei, const label nFaces, const label totalNTris, labelList &triVerts) const
Simple triangulation of face subset. TotalNTris is total number.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
label getNTris(const label facei) const
Simple triangulation of face subset. Returns number of triangles.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
void writeTriSurface(const fileName &) const
Write to file.
Definition: boundaryMesh.C:749
virtual const pointField & points() const =0
Return mesh points.
void patchify(const labelList &nearest, const polyBoundaryMesh &oldPatches, polyMesh &newMesh) const
Take over patches onto polyMesh from nearest face in *this.
scalar distance(const vector &p1, const vector &p2)
Definition: curveTools.C:12
This class describes the interaction of an object (often a face) and a point. It carries the info of ...
Definition: pointIndexHit.H:44
labelList getNearest(const primitiveMesh &pMesh, const vector &searchSpan) const
Get bMesh index of nearest face for every boundary face in.
Definition: boundaryMesh.C:839
void markFaces(const labelList &protectedEdges, const label facei, boolList &visited) const
const point & min() const noexcept
Minimum describing the bounding box.
Definition: boundBoxI.H:162
virtual const fileName & name() const override
Get the name of the output serial stream. (eg, the name of the Fstream file name) ...
Definition: OSstream.H:128
void write(Ostream &os) const
Write to Ostream in simple OpenFOAM format.
Definition: triSurfaceIO.C:331
void changePatchType(const word &patchName, const word &type)
Change patch.
scalar avgDim() const
Average length/height/width dimension.
Definition: boundBoxI.H:228
void deletePatch(const word &patchName)
Delete from patch list.
boundaryMesh()
Default construct.
Definition: boundaryMesh.C:433
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1078
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static word defaultName(const label n=-1)
Default patch name: "patch" or "patchN".
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
PtrList< polyPatch > polyPatchList
Store lists of polyPatch as a PtrList.
Definition: polyPatch.H:56
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:342
const point & max() const noexcept
Maximum describing the bounding box.
Definition: boundBoxI.H:168
A list of faces which address into the list of points.
const point_type & point() const noexcept
Return point, no checks.
A List obtained as a section of another List.
Definition: SubList.H:50
const geometricSurfacePatchList & patches() const noexcept
Definition: triSurface.H:509
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:316
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
const wordList area
Standard area field types (scalar, vector, tensor, etc)
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:137
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:608
A class for handling words, derived from Foam::string.
Definition: word.H:63
label nPoints
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
Encapsulation of data needed to search on PrimitivePatches.
label nInternalFaces() const noexcept
Number of internal faces.
Vector< scalar > vector
Definition: vector.H:57
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:584
label index() const noexcept
Return the hit index.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie...
Definition: PtrList.H:159
wordList patchNames() const
Get names of patches.
Definition: boundaryMesh.C:268
const word & name() const noexcept
The patch name.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
int debug
Static debugging option.
DynamicList< T, SizeMin > & shrink()
Calls shrink_to_fit() and returns a reference to the DynamicList.
Definition: DynamicListI.H:447
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
const word & physicalType() const noexcept
The (optional) physical type of the patch.
List< geometricSurfacePatch > geometricSurfacePatchList
List of geometricSurfacePatch.
defineTypeNameAndDebug(combustionModel, 0)
static constexpr const char *const emptyType
The name for an &#39;empty&#39; type.
labelList f(nPoints)
PrimitivePatch< List< face >, const pointField & > primitiveFacePatch
A PrimitivePatch with List storage for the faces, const reference for the point field.
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field...
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
const vectorField & faceCentres() const
void setExtraEdges(const label edgeI)
Set extraEdges to edges &#39;near&#39; to edgeI. Uses point-edge walk.
List< word > wordList
List of word.
Definition: fileName.H:59
bool hit() const noexcept
Is there a hit?
vector point
Point is a vector.
Definition: point.H:37
Non-pointer based hierarchical recursive searching.
void readTriSurface(const fileName &)
Read from triSurface.
Definition: boundaryMesh.C:581
const vectorField & faceAreas() const
A List with indirect addressing. Like IndirectList but does not store addressing. ...
Definition: faMatrix.H:56
virtual const faceList & faces() const =0
Return faces.
const polyBoundaryMesh & patches
const std::string patch
OpenFOAM patch number as a std::string.
void triangulateLocal(const label startFacei, const label nFaces, const label totalNTris, labelList &triVerts, labelList &localToGlobal) const
Same as triangulate but in local vertex numbering.
Identifies a surface patch/zone by name and index, with geometric type.
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:90
label n
static autoPtr< polyPatch > New(const word &patchType, const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm)
Return pointer to a new patch created on freestore from components.
Definition: polyPatchNew.C:28
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
const bMesh & mesh() const
Definition: boundaryMesh.H:259
List< label > labelList
A List of labels.
Definition: List.H:62
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
label start() const noexcept
The start of the patch.
Triangulated surface description with patch information.
Definition: triSurface.H:71
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
PrimitivePatch< List< face >, const pointField > bMesh
Holder of faceList and points. (v.s. e.g. primitivePatch which references points) ...
Definition: bMesh.H:39
List< bool > boolList
A List of bools.
Definition: List.H:60
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
const labelListList & edgeFaces() const
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
label size() const noexcept
The size of the patch.
void changeFaces(const labelList &patchIDs, labelList &oldToNew)
Recalculate face ordering and patches. Return old to new.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127