Loading...
Searching...
No Matches
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-------------------------------------------------------------------------------
11License
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"
33#include "faceList.H"
34#include "indexedOctree.H"
36#include "triSurface.H"
37#include "SortableList.H"
38#include "OFstream.H"
41
42// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43
44namespace Foam
45{
47}
48
49// Normal along which to divide faces into categories (used in getNearest)
50const Foam::vector Foam::boundaryMesh::splitNormal_(3, 2, 1);
51
52// Distance to face tolerance for getNearest
53const Foam::scalar Foam::boundaryMesh::distanceTol_ = 1e-2;
54
55
56// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
57
58// Returns number of feature edges connected to pointi
59Foam::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
79Foam::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.
109Foam::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
196void 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
257Foam::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;
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
287Foam::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.
308Foam::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
345Foam::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
381void Foam::boundaryMesh::markZone
382(
383 const boolList& borderEdge,
384 label facei,
385 label currentZone,
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;
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
756void 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
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 }
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 }
1302
1303 polyMeshRepatcher.repatch();
1304 }
1305}
1306
1307
1308void 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
1509void 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
1524Foam::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
1545Foam::label Foam::boundaryMesh::findPatchID(const word& patchName) const
1546{
1547 forAll(patches_, patchi)
1548 {
1549 if (patches_[patchi].name() == patchName)
1550 {
1551 return patchi;
1553 }
1554
1555 return -1;
1556}
1557
1558
1559void 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
1596void 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());
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_.
1814
1815 // And insert new 'mesh'.
1816 meshPtr_ = std::move(newMeshPtr);
1817}
1818
1819
1820Foam::label Foam::boundaryMesh::getNTris(const label facei) const
1822 const face& f = mesh()[facei];
1823
1824 return f.nTriangles(mesh().points());
1825}
1826
1827
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;
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()
1905
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{
1920 primitivePatch patch
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// ************************************************************************* //
label n
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
labelList patchIDs
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void append(const T &val)
Copy append an element to the end of this list.
DynamicList< T, SizeMin > & shrink()
Calls shrink_to_fit() and returns a reference to the DynamicList.
A HashTable similar to std::unordered_map.
Definition HashTable.H:124
bool found(const Key &key) const
Same as contains().
Definition HashTable.H:1370
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition HashTableI.H:152
label size() const noexcept
The number of elements in table.
Definition HashTable.H:358
label size() const noexcept
The number of elements in the list.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
bool set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition List.H:469
void append(const T &val)
Append an element at the end of the list.
Definition List.H:497
void setSize(label n)
Alias for resize().
Definition List.H:536
void clear()
Clear the list, i.e. set size to zero.
Definition ListI.H:133
A HashTable to objects of type <T> with a label key.
Definition Map.H:54
Output to file stream as an OSstream, normally using std::ofstream for the actual output.
Definition OFstream.H:75
label index() const noexcept
Return the hit index.
bool hit() const noexcept
Is there a hit?
const point_type & point() const noexcept
Return point, no checks.
const labelListList & pointEdges() const
Return point-edge addressing.
const Field< point_type > & localPoints() const
Return pointField of points in patch.
const Field< point_type > & points() const noexcept
Return reference to global points.
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition PtrList.H:67
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:171
A list that is sorted upon construction or when explicitly requested with the sort() method.
const labelList & indices() const noexcept
Return the list of sorted indices. Updated every sort.
void sort()
Forward (stable) sort the list (if changed after construction).
A non-owning sub-view of a List (allocated or unallocated storage).
Definition SubList.H:61
A List with indirect addressing. Like IndirectList but does not store addressing.
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
iterator end() noexcept
Return an iterator to end traversing the UList.
Definition UListI.H:454
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
label size() const noexcept
The number of entries in the list.
Definition UPtrListI.H:106
const Cmpt & x() const noexcept
Access to the vector x component.
Definition Vector.H:135
scalar dist(const Vector< Cmpt > &v2) const
The L2-norm distance from another vector. The mag() of the difference.
Definition VectorI.H:107
const Cmpt & z() const noexcept
Access to the vector z component.
Definition Vector.H:145
const Cmpt & y() const noexcept
Access to the vector y component.
Definition Vector.H:140
const point & max() const noexcept
Maximum describing the bounding box.
Definition boundBoxI.H:168
const point & min() const noexcept
Minimum describing the bounding box.
Definition boundBoxI.H:162
scalar avgDim() const
Average length/height/width dimension.
Definition boundBoxI.H:228
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
void addPatch(const word &patchName)
Add to back of patch list.
void writeTriSurface(const fileName &) const
Write to file.
void setFeatureEdges(const scalar minCos)
Set featureEdges, edgeToFeature, featureSegments according.
label getNTris(const label facei) const
Simple triangulation of face subset. Returns number of triangles.
void setExtraEdges(const label edgeI)
Set extraEdges to edges 'near' to edgeI. Uses point-edge walk.
void readTriSurface(const fileName &)
Read from triSurface.
void triangulate(const label startFacei, const label nFaces, const label totalNTris, labelList &triVerts) const
Simple triangulation of face subset. TotalNTris is total number.
void deletePatch(const word &patchName)
Delete from patch list.
wordList patchNames() const
Get names of patches.
boundaryMesh()
Default construct.
void triangulateLocal(const label startFacei, const label nFaces, const label totalNTris, labelList &triVerts, labelList &localToGlobal) const
Same as triangulate but in local vertex numbering.
labelList getNearest(const primitiveMesh &pMesh, const vector &searchSpan) const
Get bMesh index of nearest face for every boundary face in.
const bMesh & mesh() const
void changeFaces(const labelList &patchIDs, labelList &oldToNew)
Recalculate face ordering and patches. Return old to new.
label getNPoints(const label startFacei, const label nFaces) const
Number of points used in face subset.
void markFaces(const labelList &protectedEdges, const label facei, boolList &visited) const
void read(const polyMesh &)
Read from boundaryMesh of polyMesh.
void patchify(const labelList &nearest, const polyBoundaryMesh &oldPatches, polyMesh &newMesh) const
Take over patches onto polyMesh from nearest face in *this.
void changePatchType(const word &patchName, const word &type)
Change patch.
Like polyPatch but without reference to mesh. Used in boundaryMesh to hold data on patches....
label size() const noexcept
The size of the patch.
label start() const noexcept
The start of the patch.
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition edge.H:62
A subset of mesh faces organised as a primitive patch.
Definition faceZone.H:63
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
A class for handling file names.
Definition fileName.H:75
Identifies a surface patch/zone by name and index, with geometric type.
const word & geometricType() const noexcept
The geometric type of the patch/zone.
static constexpr const char *const emptyType
The name for an 'empty' type.
const word & name() const noexcept
The patch/zone name.
static word defaultName(const label n=-1)
Default patch name: "patch" or "patchN".
Non-pointer based hierarchical recursive searching.
A triFace with additional (region) index.
Definition labelledTri.H:56
label region() const noexcept
Return the region index.
const word & physicalType() const noexcept
The (optional) physical type of the patch.
label index() const noexcept
The index of this patch in the boundaryMesh.
const word & name() const noexcept
The patch name.
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
virtual const pointField & points() const
Return raw points.
Definition polyMesh.C:1063
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
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.
virtual autoPtr< polyPatch > clone(const labelList &faceCells) const
Construct and return a clone, setting faceCells.
Definition polyPatch.H:289
label start() const noexcept
Return start label of this patch in the polyMesh face list.
Definition polyPatch.H:446
Cell-face mesh analysis engine.
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces).
const labelListList & pointEdges() const
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
const vectorField & faceCentres() const
virtual const faceList & faces() const =0
Return faces.
label nInternalFaces() const noexcept
Number of internal faces.
const labelListList & edgeFaces() const
const labelListList & faceEdges() const
const vectorField & faceAreas() const
virtual const pointField & points() const =0
Return mesh points.
A mesh which allows changes in the patch distribution of the boundary faces. The change in patching i...
void changePatchID(const label faceID, const label patchID)
Change patch ID for a boundary face. Note: patchID should be in new numbering.
void changePatches(polyPatchList &patches)
Change patches.
Standard boundBox with extra functionality for use in octree.
Encapsulation of data needed to search on PrimitivePatches.
Triangulated surface description with patch information.
Definition triSurface.H:74
void write(Ostream &os) const
Write to Ostream in simple OpenFOAM format.
const geometricSurfacePatchList & patches() const noexcept
Definition triSurface.H:509
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
auto & name
auto & names
const pointField & points
label nPoints
const char * end
Definition SVGTools.H:223
Namespace for handling debugging switches.
Definition debug.C:45
const std::string patch
OpenFOAM patch number as a std::string.
Namespace for OpenFOAM.
scalar distance(const vector &p1, const vector &p2)
Definition curveTools.C:12
PtrList< polyPatch > polyPatchList
Store lists of polyPatch as a PtrList.
Definition polyPatch.H:61
List< word > wordList
List of word.
Definition fileName.H:60
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
dimensionedScalar sign(const dimensionedScalar &ds)
List< label > labelList
A List of labels.
Definition List.H:62
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field.
List< face > faceList
List of faces.
Definition faceListFwd.H:41
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
PrimitivePatch< List< face >, const pointField & > primitiveFacePatch
A PrimitivePatch with List storage for the faces, const reference for the point field.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
errorManip< error > abort(error &err)
Definition errorManip.H:139
Field< vector > vectorField
Specialisation of Field<T> for vector.
vector point
Point is a vector.
Definition point.H:37
List< geometricSurfacePatch > geometricSurfacePatchList
List of geometricSurfacePatch.
List< bool > boolList
A List of bools.
Definition List.H:60
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
PrimitivePatch< List< face >, const pointField > bMesh
Holder of faceList and points. (v.s. e.g. primitivePatch which references points).
Definition bMesh.H:39
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
Vector< scalar > vector
Definition vector.H:57
PointIndexHit< point > pointIndexHit
A PointIndexHit with a 3D point.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
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];} pointMap[start]=pointMap[end]=Foam::min(start, end);} } 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};constexpr 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< DynamicList< face > > pFaces[nBCs]
labelList f(nPoints)
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299