Loading...
Searching...
No Matches
addPatchCellLayer.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) 2015-2025 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 "addPatchCellLayer.H"
30#include "polyMesh.H"
31#include "polyTopoChange.H"
32#include "meshTools.H"
33#include "mapPolyMesh.H"
34#include "syncTools.H"
35#include "polyAddPoint.H"
36#include "polyAddFace.H"
37#include "polyModifyFace.H"
38#include "polyAddCell.H"
39#include "globalIndex.H"
40#include "PatchTools.H"
41#include "dummyTransform.H"
42
43// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44
45namespace Foam
46{
48
49 // Reduction class to get maximum value over coupled face.
50 class combineEqOpFace
51 {
52 public:
53
54 void operator()(face& x, const face& y) const
55 {
56 if (x.size())
57 {
58 if (y.size())
59 {
60 if (x.size() != y.size())
61 {
63 << "face x:" << flatOutput(x)
64 << " face y:" << flatOutput(y)
65 << exit(FatalError);
66 }
67
68 label j = 0;
69 forAll(x, i)
70 {
71 x[i] = max(x[i], y[j]);
72
73 j = y.rcIndex(j);
74 }
75 }
76 }
77 else if (y.size())
78 {
79 x.setSize(y.size());
80 label j = 0;
81 forAll(x, i)
82 {
83 x[i] = y[j];
84 j = y.rcIndex(j);
85 }
86 }
87 }
88 };
89}
90
91
92// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
93
94Foam::label Foam::addPatchCellLayer::nbrFace
95(
96 const labelListList& edgeFaces,
97 const label edgei,
98 const label facei
99)
100{
101 const labelList& eFaces = edgeFaces[edgei];
102
103 if (eFaces.size() == 2)
104 {
105 return (eFaces[0] != facei ? eFaces[0] : eFaces[1]);
106 }
107 else
108 {
109 return -1;
110 }
111}
112
113
114void Foam::addPatchCellLayer::addVertex
115(
116 const label pointi,
117 face& f,
118 label& fp
119)
120{
121 if (fp == 0)
122 {
123 f[fp++] = pointi;
124 }
125 else
126 {
127 if (f[fp-1] != pointi && f[0] != pointi)
128 {
129 f[fp++] = pointi;
130 }
131 }
132}
133
134
135// Is edge to the same neighbour? (and needs extrusion and has not been
136// dealt with already)
137bool Foam::addPatchCellLayer::sameEdgeNeighbour
138(
140 const labelListList& globalEdgeFaces,
141 const boolList& doneEdge,
142 const label thisGlobalFacei,
143 const label nbrGlobalFacei,
144 const label edgei
145) const
146{
147 const edge& e = pp.edges()[edgei];
148
149 return
150 !doneEdge[edgei] // not yet handled
151 && (
152 addedPoints_[e[0]].size() // is extruded
153 || addedPoints_[e[1]].size()
154 )
155 && (
156 nbrFace(globalEdgeFaces, edgei, thisGlobalFacei)
157 == nbrGlobalFacei // is to same neighbour
158 );
159}
160
161
162// Collect consecutive string of edges that connects the same two
163// (possibly coupled) faces. Returns -1 if no unvisited edge can be found.
164// Otherwise returns start and end index in face.
165Foam::labelPair Foam::addPatchCellLayer::getEdgeString
166(
168 const labelListList& globalEdgeFaces,
169 const boolList& doneEdge,
170 const label patchFacei,
171 const label globalFacei
172) const
173{
174 const labelList& fEdges = pp.faceEdges()[patchFacei];
175
176 label startFp = -1;
177 label endFp = -1;
178
179 // Get edge that hasn't been done yet but needs extrusion
180 forAll(fEdges, fp)
181 {
182 const label edgei = fEdges[fp];
183 const edge& e = pp.edges()[edgei];
184
185 if
186 (
187 !doneEdge[edgei]
188 && ( addedPoints_[e[0]].size() || addedPoints_[e[1]].size() )
189 )
190 {
191 startFp = fp;
192 break;
193 }
194 }
195
196 if (startFp != -1)
197 {
198 // We found an edge that needs extruding but hasn't been done yet.
199 // Now find the face on the other side
200 const label nbrGlobalFacei = nbrFace
201 (
202 globalEdgeFaces,
203 fEdges[startFp],
204 globalFacei
205 );
206
207 if (nbrGlobalFacei == -1)
208 {
209 // Proper boundary edge. Only extrude single edge.
210 endFp = startFp;
211 }
212 else
213 {
214 // Search back for edge
215 // - which hasn't been handled yet
216 // - with same neighbour
217 // - that needs extrusion
218
219 const label initFp = startFp;
220 while (true)
221 {
222 label prevFp = fEdges.rcIndex(startFp);
223
224 if (prevFp == initFp)
225 {
226 const edge& e = pp.edges()[fEdges[initFp]];
227 const face& localF = pp.localFaces()[patchFacei];
228
230 << "On face:" << patchFacei
231 << " fc:" << pp.faceCentres()[patchFacei]
232 << " vertices:" << localF
233 << " points:"
234 << UIndirectList<point>(pp.points(), pp[patchFacei])
235 << " edges:" << fEdges
236 << " All edges of face seem to have same neighbour "
237 << nbrGlobalFacei
238 << " starting walking from edge " << e
239 << exit(FatalError);
240 }
241
242 if
243 (
244 !sameEdgeNeighbour
245 (
246 pp,
247 globalEdgeFaces,
248 doneEdge,
249 globalFacei,
250 nbrGlobalFacei,
251 fEdges[prevFp]
252 )
253 )
254 {
255 break;
256 }
257 startFp = prevFp;
258 }
259
260 // Search forward for end of string
261 endFp = startFp;
262 while (true)
263 {
264 label nextFp = fEdges.fcIndex(endFp);
265
266 if
267 (
268 !sameEdgeNeighbour
269 (
270 pp,
271 globalEdgeFaces,
272 doneEdge,
273 globalFacei,
274 nbrGlobalFacei,
275 fEdges[nextFp]
276 )
277 )
278 {
279 break;
280 }
281 endFp = nextFp;
282 }
283 }
284 }
285
286 return labelPair(startFp, endFp);
287}
288
289
290Foam::label Foam::addPatchCellLayer::addSideFace
291(
293 const labelListList& addedCells, // per pp face the new extruded cell
294 const face& newFace,
295 const label newPatchID,
296 const label zonei,
297 const bool edgeFlip,
298 const label inflateFacei,
299
300 const label ownFacei, // pp face that provides owner
301 const label nbrFacei,
302 const label meshEdgei, // corresponding mesh edge
303 const label layeri, // layer
304 const label numEdgeFaces, // number of layers for edge
305 const labelList& meshFaces, // precalculated edgeFaces
306 polyTopoChange& meshMod
307) const
308{
309 // Adds a side face i.e. extrudes a patch edge.
310
311 label addedFacei = -1;
312
313
314 // Is patch edge external edge of indirectPrimitivePatch?
315 if (nbrFacei == -1)
316 {
317 // External edge so external face.
318
319 // Determine if different number of layer on owner and neighbour side
320 // (relevant only for coupled faces). See section for internal edge
321 // below.
322
323 label layerOwn;
324
325 if (addedCells[ownFacei].size() < numEdgeFaces)
326 {
327 label offset = numEdgeFaces - addedCells[ownFacei].size();
328 if (layeri <= offset)
329 {
330 layerOwn = 0;
331 }
332 else
333 {
334 layerOwn = layeri - offset;
335 }
336 }
337 else
338 {
339 layerOwn = layeri;
340 }
341
342
343 //Pout<< "Added boundary face:" << newFace
344 // << " atfc:" << newFace.centre(meshMod.points())
345 // << " n:" << newFace.unitNormal(meshMod.points())
346 // << " own:" << addedCells[ownFacei][layerOwn]
347 // << " patch:" << newPatchID
348 // << endl;
349
350 addedFacei = meshMod.setAction
351 (
353 (
354 newFace, // face
355 addedCells[ownFacei][layerOwn], // owner
356 -1, // neighbour
357 -1, // master point
358 -1, // master edge
359 inflateFacei, // master face
360 false, // flux flip
361 newPatchID, // patch for face
362 zonei, // zone for face
363 edgeFlip // face zone flip
364 )
365 );
366 }
367 else
368 {
369 // When adding side faces we need to modify neighbour and owners
370 // in region where layer mesh is stopped. Determine which side
371 // has max number of faces and make sure layers match closest to
372 // original pp if there are different number of layers.
373
374 label layerNbr;
375 label layerOwn;
376
377 if (addedCells[ownFacei].size() > addedCells[nbrFacei].size())
378 {
379 label offset =
380 addedCells[ownFacei].size() - addedCells[nbrFacei].size();
381
382 layerOwn = layeri;
383
384 if (layeri <= offset)
385 {
386 layerNbr = 0;
387 }
388 else
389 {
390 layerNbr = layeri - offset;
391 }
392 }
393 else if (addedCells[nbrFacei].size() > addedCells[ownFacei].size())
394 {
395 label offset =
396 addedCells[nbrFacei].size() - addedCells[ownFacei].size();
397
398 layerNbr = layeri;
399
400 if (layeri <= offset)
401 {
402 layerOwn = 0;
403 }
404 else
405 {
406 layerOwn = layeri - offset;
407 }
408 }
409 else
410 {
411 // Same number of layers on both sides.
412 layerNbr = layeri;
413 layerOwn = layeri;
414 }
415
416
417 // Check mesh internal faces using edge to initialise
418 label inflateEdgei = -1;
419 if (addToMesh_)
420 {
421 forAll(meshFaces, i)
422 {
423 if (mesh_.isInternalFace(meshFaces[i]))
424 {
425 // meshEdge uses internal faces so ok to inflate from it
426 inflateEdgei = meshEdgei;
427 break;
428 }
429 }
430 }
431
432
433 addedFacei = meshMod.setAction
434 (
436 (
437 newFace, // face
438 addedCells[ownFacei][layerOwn], // owner
439 addedCells[nbrFacei][layerNbr], // neighbour
440 -1, // master point
441 inflateEdgei, // master edge
442 -1, // master face
443 false, // flux flip
444 -1, // patch for face
445 zonei, // zone for face
446 edgeFlip // face zone flip
447 )
448 );
449
450 //Pout<< "Added internal face:" << newFace
451 // << " atfc:" << newFace.centre(meshMod.points())
452 // << " n:" << newFace.unitNormal(meshMod.points())
453 // << " own:" << addedCells[ownFacei][layerOwn]
454 // << " nei:" << addedCells[nbrFacei][layerNbr]
455 // << endl;
456 }
457
458 return addedFacei;
459}
460
461
462void Foam::addPatchCellLayer::setFaceProps
463(
464 const polyMesh& mesh,
465 const label facei,
466
467 label& patchi,
468 label& zonei,
469 bool& zoneFlip
470)
471{
472 patchi = mesh.boundaryMesh().whichPatch(facei);
473 zonei = mesh.faceZones().whichZone(facei);
474 zoneFlip = false;
475 if (zonei != -1)
476 {
477 label index = mesh.faceZones()[zonei].whichFace(facei);
478 zoneFlip = mesh.faceZones()[zonei].flipMap()[index];
479 }
480}
481
482
483void Foam::addPatchCellLayer::setFaceProps
484(
485 const polyMesh& mesh,
487 const label ppEdgeI,
488 const label faceI,
489
490 label& patchI,
491 label& zoneI,
492 bool& zoneFlip,
493 label& inflateFaceI
494)
495{
496 setFaceProps
497 (
498 mesh,
499 faceI,
500
501 patchI,
502 zoneI,
503 zoneFlip
504 );
505
506 if (patchI != -1 || zoneI != -1)
507 {
508 inflateFaceI = faceI;
509 }
510
511 if (zoneI != -1)
512 {
513 // Correct flip for patch edge ordering
514 const edge& ppEdge = pp.edges()[ppEdgeI];
515 const edge patchEdge
516 (
517 pp.meshPoints()[ppEdge[0]],
518 pp.meshPoints()[ppEdge[1]]
519 );
520
521 const face& f = mesh.faces()[faceI];
522 bool found = false;
523 forAll(f, fp)
524 {
525 const edge e(f[fp], f.nextLabel(fp));
526 int stat = edge::compare(e, patchEdge);
527 if (stat == 1)
528 {
529 found = true;
530 break;
531 }
532 else if (stat == -1)
533 {
534 found = true;
535 zoneFlip = !zoneFlip;
536 break;
537 }
538 }
539
540 if (!found)
541 {
542 //FatalErrorInFunction
544 << "Problem: cannot find patch edge " << ppEdgeI
545 << " with mesh vertices " << patchEdge
546 << " at " << patchEdge.line(mesh.points())
547 << " in face " << faceI << " with mesh vertices "
548 << f
549 << " at " << pointField(mesh.points(), f)
550 << endl
551 << "Continuing with potentially incorrect faceZone orientation"
552 //<< exit(FatalError);
553 << endl;
554 }
555 }
556}
557
558
559//void Foam::addPatchCellLayer::findZoneFace
560//(
561// const bool useInternalFaces,
562// const bool useBoundaryFaces,
563//
564// const polyMesh& mesh,
565// const indirectPrimitivePatch& pp,
566// const label ppEdgeI,
567// const labelUIndList& excludeFaces,
568// const labelList& meshFaces,
569//
570// label& inflateFaceI,
571// label& patchI,
572// label& zoneI,
573// bool& zoneFlip
574//)
575//{
576// inflateFaceI = -1;
577// patchI = -1;
578// zoneI = -1;
579// zoneFlip = false;
580//
581// forAll(meshFaces, k)
582// {
583// label faceI = meshFaces[k];
584//
585// if
586// (
587// !excludeFaces.found(faceI)
588// && (
589// (mesh.isInternalFace(faceI) && useInternalFaces)
590// || (!mesh.isInternalFace(faceI) && useBoundaryFaces)
591// )
592// )
593// {
594// setFaceProps
595// (
596// mesh,
597// pp,
598// ppEdgeI,
599// faceI,
600//
601// patchI,
602// zoneI,
603// zoneFlip,
604// inflateFaceI
605// );
606//
607// if (zoneI != -1 || patchI != -1)
608// {
609// break;
610// }
611// }
612// }
613//}
614
615
616// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
617
618// Construct from mesh
619Foam::addPatchCellLayer::addPatchCellLayer
620(
621 const polyMesh& mesh,
622 const bool addToMesh,
623 const bool extrude
624)
625:
626 mesh_(mesh),
627 addToMesh_(addToMesh),
628 extrude_(extrude),
629 addedPoints_(0),
630 layerFaces_(0)
631{}
632
633
634// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
635
637(
638 const polyMesh& mesh,
639 const labelListList& layerFaces
640)
641{
642 labelListList layerCells(layerFaces.size());
643
644 forAll(layerFaces, patchFacei)
645 {
646 const labelList& faceLabels = layerFaces[patchFacei];
647
648 if (faceLabels.size())
649 {
650 labelList& added = layerCells[patchFacei];
651 added.setSize(faceLabels.size()-1);
652
653 for (label i = 0; i < faceLabels.size()-1; i++)
654 {
655 added[i] = mesh.faceOwner()[faceLabels[i+1]];
657 }
658 }
659 return layerCells;
660}
661
664{
665 return addedCells(mesh_, layerFaces_);
666}
667
668
670(
671 const polyMesh& mesh,
672 const globalIndex& globalFaces,
674 const bitSet& ppFlip
675)
676{
677
678 // Precalculate mesh edges for pp.edges.
679 const labelList meshEdges(pp.meshEdges(mesh.edges(), mesh.pointEdges()));
680
681 // From mesh edge to global face labels. Non-empty sublists only for
682 // pp edges.
683 labelListList globalEdgeFaces(mesh.nEdges());
684
685 const labelListList& edgeFaces = pp.edgeFaces();
686
687 DynamicList<label> faceIDs;
688
689 forAll(edgeFaces, edgeI)
690 {
691 // Store face and processor as unique tag.
692 faceIDs.clear();
693 for (const label patchFacei : edgeFaces[edgeI])
694 {
695 const label facei = pp.addressing()[patchFacei];
696
697 // Ignore if ppFlip is on the other side of the (coupled) boundary
698 if
699 (
700 ppFlip.empty()
701 || !ppFlip[patchFacei]
702 || mesh.isInternalFace(facei)
703 )
704 {
705 faceIDs.append(globalFaces.toGlobal(facei));
706 }
707 }
708
709 globalEdgeFaces[meshEdges[edgeI]] = std::move(faceIDs);
710 }
711
712
713 // Synchronise across coupled edges.
715 (
716 mesh,
717 globalEdgeFaces,
719 labelList() // null value
720 );
721
722 // Extract pp part
724}
725
726
728(
729 const polyMesh& mesh,
730 const globalIndex& globalFaces,
732)
733{
734 return globalEdgeFaces(mesh, globalFaces, pp, bitSet::null());
735}
736
737
738void Foam::addPatchCellLayer::markPatchEdges
739(
740 const polyMesh& mesh,
742 const labelListList& edgeGlobalFaces,
743 const labelList& meshEdges,
744
745 bitSet& isPatchEdge,
746 bitSet& isPatchBoundaryEdge
747)
748{
749 // Mark (mesh) edges:
750 // - anywhere on extrusion
751 // - where the extrusion ends
752
753 isPatchEdge.setSize(mesh.nEdges());
754 isPatchEdge = false;
755 isPatchEdge.set(meshEdges);
756 // Synchronise across coupled edges
758 (
759 mesh,
760 isPatchEdge,
761 orEqOp<unsigned int>(),
762 false // initial value
763 );
764
765 isPatchBoundaryEdge.setSize(mesh.nEdges());
766 isPatchBoundaryEdge = false;
767 forAll(edgeGlobalFaces, edgei)
768 {
769 // Test that edge has single global extruded face.
770 // Mark on processor that holds the face (since edgeGlobalFaces
771 // only gets filled from pp faces so if there is only one this
772 // is it)
773 if (edgeGlobalFaces[edgei].size() == 1)
774 {
775 isPatchBoundaryEdge.set(meshEdges[edgei]);
776 }
777 }
778 // Synchronise across coupled edges
780 (
781 mesh,
782 isPatchBoundaryEdge,
784 false // initial value
785 );
786}
787
788
789void Foam::addPatchCellLayer::globalEdgeInfo
790(
791 const bool zoneFromAnyFace,
792
793 const polyMesh& mesh,
794 const globalIndex& globalFaces,
795 const labelListList& edgeGlobalFaces,
797 const labelList& meshEdges,
798
799 labelList& patchEdgeToFace, // face (in globalFaces index)
800 labelList& patchEdgeToPatch, // patch on face (or -1 for internal faces)
801 labelList& patchEdgeToZone, // zone on face
802 bitSet& patchEdgeToFlip // flip orientation on face
803)
804{
805 // For every edge on the outside of the patch return a potential patch/
806 // faceZone to extrude into.
807
808 // Mark (mesh) edges on pp.
809 bitSet isExtrudeEdge;
810 bitSet isBoundaryEdge;
811 markPatchEdges
812 (
813 mesh,
814 pp,
815 edgeGlobalFaces,
816 meshEdges,
817
818 isExtrudeEdge,
819 isBoundaryEdge
820 );
821
822 // Build map of pp edges (in mesh point indexing). Note that this
823 // is now also on processors that do not have pp (but do have the edge)
824 EdgeMap<label> isBoundaryEdgeSet(pp.nEdges());
825 for (const label edgei : isBoundaryEdge)
826 {
827 isBoundaryEdgeSet.insert(mesh.edges()[edgei], edgei);
828 }
829 EdgeMap<label> isExtrudeEdgeSet(pp.nEdges());
830 for (const label edgei : isExtrudeEdge)
831 {
832 isExtrudeEdgeSet.insert(mesh.edges()[edgei], edgei);
833 }
834
835
836 bitSet isPpFace(mesh.nFaces());
837 isPpFace.set(pp.addressing());
838 // Note: no need to sync isPpFace since does not include processor patches
839
840
841 const faceZoneMesh& fzs = mesh.faceZones();
842
843 // Extract zone info into mesh face indexing for ease of addressing
844 labelList faceToZone(mesh.nFaces(), -1);
845 bitSet faceToFlip(mesh.nFaces());
846 for (const faceZone& fz: fzs)
847 {
848 const labelList& addressing = fz;
849 UIndirectList<label>(faceToZone, addressing) = fz.index();
850
851 const boolList& fm = fz.flipMap();
852 forAll(addressing, i)
853 {
854 faceToFlip[addressing[i]] = fm[i];
855 }
856 }
857
858
859 // Storage (over all mesh edges)
860 // - face that data originates from (in globalFaces indexing)
861 labelList meshEdgeToFace(mesh.nEdges(), -1);
862 // - patch (for boundary faces)
863 labelList meshEdgeToPatch(mesh.nEdges(), -1);
864 // - faceZone
865 labelList meshEdgeToZone(mesh.nEdges(), -1);
866 // - faceZone orientation
867 bitSet meshEdgeToFlip(mesh.nEdges());
868
869 //if (useInternalFaces)
870 {
871 const bitSet isInternalOrCoupled
872 (
874 );
875
876 // Loop over edges of the face to find any faceZone.
877 // Edges kept as point pair so we don't construct mesh.faceEdges etc.
878
879 for (const label facei : isInternalOrCoupled)
880 {
881 if (isPpFace[facei])
882 {
883 continue;
884 }
885
886 const face& f = mesh.faces()[facei];
887
888 label prevPointi = f.last();
889 for (const label pointi : f)
890 {
891 const edge e(prevPointi, pointi);
892
893 // Check if edge is internal to extrusion. Take over faceZone
894 // etc from internal face.
895 const auto eFnd = isExtrudeEdgeSet.cfind(e);
896 if (eFnd)
897 {
898 const label edgei = eFnd();
899
900 if (faceToZone[facei] != -1)
901 {
902 // Found a zoned internal face. Use.
903 meshEdgeToFace[edgei] = globalFaces.toGlobal(facei);
904 meshEdgeToZone[edgei] = faceToZone[facei];
905 const edge& meshE = mesh.edges()[edgei];
906 const int d = edge::compare(e, meshE);
907 if (d == 1)
908 {
909 meshEdgeToFlip[edgei] = faceToFlip[facei];
910 }
911 else if (d == -1)
912 {
913 meshEdgeToFlip[edgei] = !faceToFlip[facei];
914 }
915 else
916 {
917 FatalErrorInFunction << "big problem"
918 << exit(FatalError);
919 }
920 }
921 }
922
923 prevPointi = pointi;
924 }
925 }
926 }
927
928
929 //if (useBoundaryFaces)
930 {
931 // Loop over all patches and find 'best' one (non-coupled,
932 // non-extrusion, non-constraint(?)). Note that logic is slightly
933 // different from internal faces loop above - first patch face
934 // is being used instead of first zoned face for internal faces
935
937
938
939 for (const polyPatch& pp : patches)
940 {
941 if (!pp.coupled())
942 {
943 // TBD. Check for constraint? This is usually a geometric
944 // constraint and not a topological one so should
945 // be handled in the extrusion vector calculation instead?
946
947 forAll(pp, i)
948 {
949 const label facei = pp.start()+i;
950
951 if (!isPpFace[facei])
952 {
953 const face& f = pp[i];
954
955 label prevPointi = f.last();
956 for (const label pointi : f)
957 {
958 const edge e(prevPointi, pointi);
959 const auto eFnd =
960 (
961 zoneFromAnyFace
962 ? isExtrudeEdgeSet.cfind(e)
963 : isBoundaryEdgeSet.cfind(e)
964 );
965 if (eFnd)
966 {
967 const label edgei = eFnd();
968 if (meshEdgeToFace[edgei] == -1)
969 {
970 // Found unassigned face. Use its
971 // information.
972 // Note that we use the lowest numbered
973 // patch face.
974
975 meshEdgeToFace[edgei] =
976 globalFaces.toGlobal(facei);
977 }
978
979 // Override any patch info. Note that
980 // meshEdgeToFace might be an internal face.
981 if (meshEdgeToPatch[edgei] == -1)
982 {
983 meshEdgeToPatch[edgei] = pp.index();
984 }
985
986 // Override any zone info
987 if (meshEdgeToZone[edgei] == -1)
988 {
989 meshEdgeToZone[edgei] =
990 faceToZone[facei];
991 const edge& meshE = mesh.edges()[edgei];
992 const int d = edge::compare(e, meshE);
993 if (d == 1)
994 {
995 meshEdgeToFlip[edgei] =
996 faceToFlip[facei];
997 }
998 else if (d == -1)
999 {
1000 meshEdgeToFlip[edgei] =
1001 !faceToFlip[facei];
1002 }
1003 else
1004 {
1006 << "big problem"
1007 << exit(FatalError);
1008 }
1009 }
1010 }
1011
1012 prevPointi = pointi;
1013 }
1014 }
1015 }
1016 }
1017 }
1018 }
1019
1020
1021 // Synchronise across coupled edges. Max patch/face/faceZone wins
1023 (
1024 mesh,
1025 meshEdgeToFace,
1027 label(-1)
1028 );
1030 (
1031 mesh,
1032 meshEdgeToPatch,
1034 label(-1)
1035 );
1037 (
1038 mesh,
1039 meshEdgeToZone,
1041 label(-1)
1042 );
1043// // Note: flipMap not yet done. Needs edge orientation. This is handled
1044// // later on.
1045// if (Pstream::parRun())
1046// {
1047// const globalMeshData& gd = mesh.globalData();
1048// const indirectPrimitivePatch& cpp = gd.coupledPatch();
1049//
1050// labelList patchEdges;
1051// labelList coupledEdges;
1052// bitSet sameEdgeOrientation;
1053// PatchTools::matchEdges
1054// (
1055// pp,
1056// cpp,
1057// patchEdges,
1058// coupledEdges,
1059// sameEdgeOrientation
1060// );
1061//
1062// // Convert data on pp edges to data on coupled patch
1063// labelList cppEdgeZoneID(cpp.nEdges(), -1);
1064// boolList cppEdgeFlip(cpp.nEdges(), false);
1065// forAll(coupledEdges, i)
1066// {
1067// label cppEdgei = coupledEdges[i];
1068// label ppEdgei = patchEdges[i];
1069//
1070// cppEdgeZoneID[cppEdgei] = edgeZoneID[ppEdgei];
1071// if (sameEdgeOrientation[i])
1072// {
1073// cppEdgeFlip[cppEdgei] = edgeFlip[ppEdgei];
1074// }
1075// else
1076// {
1077// cppEdgeFlip[cppEdgei] = !edgeFlip[ppEdgei];
1078// }
1079// }
1080//
1081// // Sync
1082// const globalIndexAndTransform& git = gd.globalTransforms();
1083// const mapDistribute& edgeMap = gd.globalEdgeSlavesMap();
1084//
1085// globalMeshData::syncData
1086// (
1087// cppEdgeZoneID,
1088// gd.globalEdgeSlaves(),
1089// gd.globalEdgeTransformedSlaves(),
1090// edgeMap,
1091// git,
1092// maxEqOp<label>(),
1093// dummyTransform()
1094// );
1095// globalMeshData::syncData
1096// (
1097// cppEdgeFlip,
1098// gd.globalEdgeSlaves(),
1099// gd.globalEdgeTransformedSlaves(),
1100// edgeMap,
1101// git,
1102// andEqOp<bool>(),
1103// dummyTransform()
1104// );
1105//
1106// // Convert data on coupled edges to pp edges
1107// forAll(coupledEdges, i)
1108// {
1109// label cppEdgei = coupledEdges[i];
1110// label ppEdgei = patchEdges[i];
1111//
1112// edgeZoneID[ppEdgei] = cppEdgeZoneID[cppEdgei];
1113// if (sameEdgeOrientation[i])
1114// {
1115// edgeFlip[ppEdgei] = cppEdgeFlip[cppEdgei];
1116// }
1117// else
1118// {
1119// edgeFlip[ppEdgei] = !cppEdgeFlip[cppEdgei];
1120// }
1121// }
1122// }
1123
1125 (
1126 mesh,
1127 meshEdgeToFlip,
1129 0
1130 );
1131
1132 // Extract pp info
1133 patchEdgeToFace = UIndirectList<label>(meshEdgeToFace, meshEdges);
1134 patchEdgeToPatch = UIndirectList<label>(meshEdgeToPatch, meshEdges);
1135 patchEdgeToZone = UIndirectList<label>(meshEdgeToZone, meshEdges);
1136 patchEdgeToFlip.setSize(meshEdges.size());
1137 patchEdgeToFlip = false;
1138 forAll(meshEdges, i)
1139 {
1140 patchEdgeToFlip[i] = meshEdgeToFlip[meshEdges[i]];
1141 }
1142}
1143
1144
1146(
1147 const bool zoneFromAnyFace,
1148
1149 const polyMesh& mesh,
1150 const globalIndex& globalFaces,
1151 const labelListList& globalEdgeFaces,
1153
1154 labelList& edgePatchID,
1155 label& nPatches,
1156 Map<label>& nbrProcToPatch,
1157 Map<label>& patchToNbrProc,
1158 labelList& edgeZoneID,
1159 boolList& edgeFlip,
1160 labelList& inflateFaceID
1161)
1162{
1163 const polyBoundaryMesh& patches = mesh.boundaryMesh();
1164 const globalMeshData& gd = mesh.globalData();
1165
1166 // Precalculate mesh edges for pp.edges.
1167 const labelList meshEdges(pp.meshEdges(mesh.edges(), mesh.pointEdges()));
1168
1169 edgePatchID.setSize(pp.nEdges());
1170 edgePatchID = -1;
1171 nPatches = patches.size();
1172 nbrProcToPatch.clear();
1173 patchToNbrProc.clear();
1174 edgeZoneID.setSize(pp.nEdges());
1175 edgeZoneID = -1;
1176 edgeFlip.setSize(pp.nEdges());
1177 edgeFlip = false;
1178 inflateFaceID.setSize(pp.nEdges(), -1);
1179
1180
1181 // Determine properties for faces extruded from edges
1182 // - edge inbetween two different processors:
1183 // - extrude as patch face on correct processor
1184 // - edge at end of patch (so edgeFaces.size() == 1):
1185 // - use mesh face that is a boundary face
1186 // - edge internal to patch (so edgeFaces.size() == 2):
1187
1188
1189 // Pass1:
1190 // For all edges inbetween two processors: see if matches to existing
1191 // processor patch or create interprocessor-patch if necessary.
1192 // Sets edgePatchID[edgeI] but none of the other quantities
1193
1194 forAll(globalEdgeFaces, edgei)
1195 {
1196 const labelList& eGlobalFaces = globalEdgeFaces[edgei];
1197 if
1198 (
1199 eGlobalFaces.size() == 2
1200 && pp.edgeFaces()[edgei].size() == 1
1201 )
1202 {
1203 // Locally but not globally a boundary edge. Hence a coupled
1204 // edge. Find the patch to use if on different processors.
1205
1206 label f0 = eGlobalFaces[0];
1207 label f1 = eGlobalFaces[1];
1208
1209 label otherProci = -1;
1210 if (globalFaces.isLocal(f0) && !globalFaces.isLocal(f1))
1211 {
1212 otherProci = globalFaces.whichProcID(f1);
1213 }
1214 else if (!globalFaces.isLocal(f0) && globalFaces.isLocal(f1))
1215 {
1216 otherProci = globalFaces.whichProcID(f0);
1217 }
1218
1219
1220 if (otherProci != -1)
1221 {
1222 // Use existing processorPolyPatch to otherProci?
1223
1224 label procPatchi =
1225 gd.topology().procPatchLookup(otherProci);
1226
1227 if (procPatchi < 0)
1228 {
1229 // No existing processorPolyPatch to otherProci.
1230 // See if already marked for addition
1231 procPatchi = nbrProcToPatch.lookup(otherProci, -1);
1232
1233 if (procPatchi < 0)
1234 {
1235 // Add new proc-patch, mark for addition.
1236
1237 procPatchi = nPatches;
1238 ++nPatches;
1239
1240 nbrProcToPatch.insert(otherProci, procPatchi);
1241 patchToNbrProc.insert(procPatchi, otherProci);
1242 }
1243 }
1244
1245 edgePatchID[edgei] = procPatchi;
1246 }
1247 }
1248 }
1249
1250
1251 // Pass2: determine face properties for all other edges
1252 // ----------------------------------------------------
1253
1254 // Info for edges of pp
1255 labelList edgeToFace;
1256 labelList edgeToPatch;
1257 labelList edgeToZone;
1258 bitSet edgeToFlip;
1259 globalEdgeInfo
1260 (
1261 zoneFromAnyFace, // internal edge info also from boundary faces
1262
1263 mesh,
1264 globalFaces,
1265 globalEdgeFaces,
1266 pp,
1267 meshEdges,
1268
1269 edgeToFace, // face (in globalFaces index)
1270 edgeToPatch, // patch on face (or -1 for internal faces)
1271 edgeToZone, // zone on face
1272 edgeToFlip // flip orientation on face
1273 );
1274
1275 const labelListList& edgeFaces = pp.edgeFaces();
1276
1277 DynamicList<label> dynMeshEdgeFaces;
1278
1279 forAll(edgeFaces, edgei)
1280 {
1281 if (edgePatchID[edgei] == -1)
1282 {
1283 if (edgeFaces[edgei].size() == 2)
1284 {
1285 // Internal edge. Look at any face (internal or boundary) to
1286 // determine extrusion properties. First one that has zone
1287 // info wins
1288 if (globalFaces.isLocal(edgeToFace[edgei]))
1289 {
1290 inflateFaceID[edgei] =
1291 globalFaces.toLocal(edgeToFace[edgei]);
1292 }
1293 edgeZoneID[edgei] = edgeToZone[edgei];
1294 edgeFlip[edgei] = edgeToFlip[edgei];
1295 }
1296 else
1297 {
1298 // Proper, uncoupled patch edge. Boundary to get info from
1299 // might be on a different processor!
1300
1301 if (globalFaces.isLocal(edgeToFace[edgei]))
1302 {
1303 inflateFaceID[edgei] =
1304 globalFaces.toLocal(edgeToFace[edgei]);
1305 }
1306 edgePatchID[edgei] = edgeToPatch[edgei];
1307 edgeZoneID[edgei] = edgeToZone[edgei];
1308 edgeFlip[edgei] = edgeToFlip[edgei];
1309 }
1310 }
1311 }
1312
1313
1314
1315 // Now hopefully every boundary edge has a edge patch. Check
1316 if (debug)
1317 {
1318 forAll(edgeFaces, edgei)
1319 {
1320 if (edgeFaces[edgei].size() == 1 && edgePatchID[edgei] == -1)
1321 {
1322 const edge& e = pp.edges()[edgei];
1324 << "Have no sidePatchID for edge " << edgei << " points "
1325 << pp.points()[pp.meshPoints()[e[0]]]
1326 << pp.points()[pp.meshPoints()[e[1]]]
1327 << endl;
1328 }
1329 }
1330 }
1331
1332
1333
1334 // Pass3: for any faces set in pass1 see if we can find a processor face
1335 // to inherit from (we only have a patch, not a patch face)
1336 forAll(edgeFaces, edgei)
1337 {
1338 if
1339 (
1340 edgeFaces[edgei].size() == 1
1341 && globalEdgeFaces[edgei].size() == 2
1342 && edgePatchID[edgei] != -1
1343 && inflateFaceID[edgei] == -1
1344 )
1345 {
1346 // 1. Do we have a local boundary face to inflate from
1347
1348 label myFaceI = pp.addressing()[edgeFaces[edgei][0]];
1349
1350 // Pick up any boundary face on this edge and use its properties
1351 label meshEdgei = meshEdges[edgei];
1352 const labelList& meshFaces = mesh.edgeFaces
1353 (
1354 meshEdgei,
1355 dynMeshEdgeFaces
1356 );
1357
1358 forAll(meshFaces, k)
1359 {
1360 label facei = meshFaces[k];
1361
1362 if (facei != myFaceI && !mesh.isInternalFace(facei))
1363 {
1364 if (patches.whichPatch(facei) == edgePatchID[edgei])
1365 {
1366 setFaceProps
1367 (
1368 mesh,
1369 pp,
1370 edgei,
1371 facei,
1372
1373 edgePatchID[edgei],
1374 edgeZoneID[edgei],
1375 edgeFlip[edgei],
1376 inflateFaceID[edgei]
1377 );
1378 break;
1379 }
1380 }
1381 }
1382 }
1383 }
1384
1385
1386
1387 // Sync all data:
1388 // - edgePatchID : might be local in case of processor patch. Do not
1389 // sync for now
1390 // - inflateFaceID: local. Do not sync
1391 // - edgeZoneID : global. sync.
1392 // - edgeFlip : global. sync.
1393
1394 if (Pstream::parRun())
1395 {
1396 const globalMeshData& gd = mesh.globalData();
1397 const indirectPrimitivePatch& cpp = gd.coupledPatch();
1398
1399 labelList patchEdges;
1400 labelList coupledEdges;
1401 bitSet sameEdgeOrientation;
1403 (
1404 pp,
1405 cpp,
1406 patchEdges,
1407 coupledEdges,
1408 sameEdgeOrientation
1409 );
1410
1411 // Convert data on pp edges to data on coupled patch
1412 labelList cppEdgeZoneID(cpp.nEdges(), -1);
1413 boolList cppEdgeFlip(cpp.nEdges(), false);
1414 forAll(coupledEdges, i)
1415 {
1416 label cppEdgei = coupledEdges[i];
1417 label ppEdgei = patchEdges[i];
1418
1419 cppEdgeZoneID[cppEdgei] = edgeZoneID[ppEdgei];
1420 if (sameEdgeOrientation[i])
1421 {
1422 cppEdgeFlip[cppEdgei] = edgeFlip[ppEdgei];
1423 }
1424 else
1425 {
1426 cppEdgeFlip[cppEdgei] = !edgeFlip[ppEdgei];
1427 }
1428 }
1429
1430 // Sync
1431 const globalIndexAndTransform& git = gd.globalTransforms();
1432 const mapDistribute& edgeMap = gd.globalEdgeSlavesMap();
1433
1435 (
1436 cppEdgeZoneID,
1437 gd.globalEdgeSlaves(),
1438 gd.globalEdgeTransformedSlaves(),
1439 edgeMap,
1440 git,
1443 );
1445 (
1446 cppEdgeFlip,
1447 gd.globalEdgeSlaves(),
1448 gd.globalEdgeTransformedSlaves(),
1449 edgeMap,
1450 git,
1451 andEqOp<bool>(),
1453 );
1454
1455 // Convert data on coupled edges to pp edges
1456 forAll(coupledEdges, i)
1457 {
1458 label cppEdgei = coupledEdges[i];
1459 label ppEdgei = patchEdges[i];
1460
1461 edgeZoneID[ppEdgei] = cppEdgeZoneID[cppEdgei];
1462 if (sameEdgeOrientation[i])
1463 {
1464 edgeFlip[ppEdgei] = cppEdgeFlip[cppEdgei];
1465 }
1466 else
1467 {
1468 edgeFlip[ppEdgei] = !cppEdgeFlip[cppEdgei];
1469 }
1470 }
1471 }
1472}
1473
1474
1476(
1477 const globalIndex& globalFaces,
1478 const labelListList& globalEdgeFaces,
1479 const scalarField& expansionRatio,
1481 const bitSet& ppFlip,
1482
1483 const labelList& edgePatchID,
1484 const labelList& edgeZoneID,
1485 const boolList& edgeFlip,
1486 const labelList& inflateFaceID,
1487
1488 const labelList& exposedPatchID,
1489 const labelList& nFaceLayers,
1490 const labelList& nPointLayers,
1491 const vectorField& firstLayerDisp,
1492 polyTopoChange& meshMod
1493)
1494{
1495 if (debug)
1496 {
1497 Pout<< "addPatchCellLayer::setRefinement : Adding up to "
1498 << gMax(nPointLayers)
1499 << " layers of cells to indirectPrimitivePatch with "
1500 << pp.nPoints() << " points" << endl;
1501 }
1502
1503 if
1504 (
1505 pp.nPoints() != firstLayerDisp.size()
1506 || pp.nPoints() != nPointLayers.size()
1507 || pp.size() != nFaceLayers.size()
1508 || pp.size() != ppFlip.size()
1509 )
1510 {
1512 << "Size of new points is not same as number of points used by"
1513 << " the face subset" << endl
1514 << " patch.nPoints:" << pp.nPoints()
1515 << " displacement:" << firstLayerDisp.size()
1516 << " nPointLayers:" << nPointLayers.size() << nl
1517 << " patch.nFaces:" << pp.size()
1518 << " flip map:" << ppFlip.size()
1519 << " nFaceLayers:" << nFaceLayers.size()
1520 << abort(FatalError);
1521 }
1522 if (!addToMesh_)
1523 {
1524 // flip map should be false
1525 if (ppFlip.count())
1526 {
1528 << "In generating stand-alone mesh the flip map should be empty"
1529 << ". Instead it is " << ppFlip.count()
1530 << abort(FatalError);
1531 }
1532 }
1533 else if (debug)
1534 {
1535 // Maybe check for adding to neighbour of boundary faces? How about
1536 // coupled faces where the faceZone flipMap is negated
1537
1538 // For all boundary faces:
1539 // -1 : not extruded
1540 // 0 : extruded from owner outwards (flip = false)
1541 // 1 : extrude from neighbour outwards
1542 labelList stateAndFlip(mesh_.nBoundaryFaces(), 0);
1543 forAll(pp.addressing(), patchFacei)
1544 {
1545 if (nFaceLayers[patchFacei] > 0)
1546 {
1547 const label meshFacei = pp.addressing()[patchFacei];
1548 const label bFacei = meshFacei-mesh_.nInternalFaces();
1549 if (bFacei >= 0)
1550 {
1551 stateAndFlip[bFacei] = label(ppFlip[patchFacei]);
1552 }
1553 }
1554 }
1555 // Make sure uncoupled patches do not trigger the error below
1556 for (const auto& patch : mesh_.boundaryMesh())
1557 {
1558 if (!patch.coupled())
1559 {
1560 forAll(patch, i)
1561 {
1562 label& state = stateAndFlip[patch.offset()+i];
1563 state = (state == 0 ? 1 : 0);
1564 }
1565 }
1566 }
1567 syncTools::swapBoundaryFaceList(mesh_, stateAndFlip);
1568
1569 forAll(pp.addressing(), patchFacei)
1570 {
1571 if (nFaceLayers[patchFacei] > 0)
1572 {
1573 const label meshFacei = pp.addressing()[patchFacei];
1574 const label bFacei = meshFacei-mesh_.nInternalFaces();
1575 if (bFacei >= 0)
1576 {
1577 if (stateAndFlip[bFacei] == -1)
1578 {
1580 << "At extruded face:" << meshFacei
1581 << " at:" << mesh_.faceCentres()[meshFacei]
1582 << " locally have nLayers:"
1583 << nFaceLayers[patchFacei]
1584 << " but remotely have none" << exit(FatalError);
1585 }
1586 else if (stateAndFlip[bFacei] == label(ppFlip[patchFacei]))
1587 {
1589 << "At extruded face:" << meshFacei
1590 << " at:" << mesh_.faceCentres()[meshFacei]
1591 << " locally have flip:" << ppFlip[patchFacei]
1592 << " which is not the opposite of coupled version "
1593 << stateAndFlip[bFacei]
1594 << exit(FatalError);
1595 }
1596 }
1597 }
1598 }
1599 }
1600
1601
1602 forAll(nPointLayers, i)
1603 {
1604 if (nPointLayers[i] < 0)
1605 {
1607 << "Illegal number of layers " << nPointLayers[i]
1608 << " at patch point " << i << abort(FatalError);
1609 }
1610 }
1611 forAll(nFaceLayers, i)
1612 {
1613 if (nFaceLayers[i] < 0)
1614 {
1616 << "Illegal number of layers " << nFaceLayers[i]
1617 << " at patch face " << i << abort(FatalError);
1618 }
1619 }
1620
1621 forAll(globalEdgeFaces, edgei)
1622 {
1623 if (globalEdgeFaces[edgei].size() > 2)
1624 {
1625 const edge& e = pp.edges()[edgei];
1626
1627 if (nPointLayers[e[0]] > 0 || nPointLayers[e[1]] > 0)
1628 {
1630 << "Trying to extrude edge "
1631 << e.line(pp.localPoints())
1632 << " which is non-manifold (has "
1633 << globalEdgeFaces[edgei].size()
1634 << " local or coupled faces using it)"
1635 << " of which "
1636 << pp.edgeFaces()[edgei].size()
1637 << " local"
1638 << abort(FatalError);
1639 }
1640 }
1641 }
1642
1643
1644 const labelList& meshPoints = pp.meshPoints();
1645
1646
1647 // Determine which points are on which side of the extrusion
1648 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1649
1650 bitSet isBlockedFace(mesh_.nFaces());
1652
1653 // Some storage for edge-face-addressing.
1655
1656 // Precalculate mesh edges for pp.edges.
1657 const labelList meshEdges(pp.meshEdges(mesh_.edges(), mesh_.pointEdges()));
1658
1659 if (debug)
1660 {
1661 // Check synchronisation
1662 // ~~~~~~~~~~~~~~~~~~~~~
1663
1664 {
1665 labelList n(mesh_.nPoints(), Zero);
1666 labelUIndList(n, meshPoints) = nPointLayers;
1667 syncTools::syncPointList(mesh_, n, maxEqOp<label>(), label(0));
1668
1669 // Non-synced
1670 forAll(meshPoints, i)
1671 {
1672 label meshPointi = meshPoints[i];
1673
1674 if (n[meshPointi] != nPointLayers[i])
1675 {
1677 << "At mesh point:" << meshPointi
1678 << " coordinate:" << mesh_.points()[meshPointi]
1679 << " specified nLayers:" << nPointLayers[i] << endl
1680 << "On coupled point a different nLayers:"
1681 << n[meshPointi] << " was specified."
1682 << abort(FatalError);
1683 }
1684 }
1685
1686
1687 // Check that nPointLayers equals the max layers of connected faces
1688 // (or 0). Anything else makes no sense.
1689 labelList nFromFace(mesh_.nPoints(), Zero);
1690 forAll(nFaceLayers, i)
1691 {
1692 const face& f = pp[i];
1693
1694 forAll(f, fp)
1695 {
1696 label pointi = f[fp];
1697
1698 nFromFace[pointi] = max(nFromFace[pointi], nFaceLayers[i]);
1699 }
1700 }
1702 (
1703 mesh_,
1704 nFromFace,
1706 label(0)
1707 );
1708
1709 forAll(nPointLayers, i)
1710 {
1711 label meshPointi = meshPoints[i];
1712
1713 if
1714 (
1715 nPointLayers[i] > 0
1716 && nPointLayers[i] != nFromFace[meshPointi]
1717 )
1718 {
1720 << "At mesh point:" << meshPointi
1721 << " coordinate:" << mesh_.points()[meshPointi]
1722 << " specified nLayers:" << nPointLayers[i] << endl
1723 << "but the max nLayers of surrounding faces is:"
1724 << nFromFace[meshPointi]
1725 << abort(FatalError);
1726 }
1727 }
1728 }
1729
1730 {
1731 pointField d(mesh_.nPoints(), vector::max);
1732 UIndirectList<point>(d, meshPoints) = firstLayerDisp;
1734 (
1735 mesh_,
1736 d,
1739 );
1740
1741 forAll(meshPoints, i)
1742 {
1743 label meshPointi = meshPoints[i];
1744
1745 if (mag(d[meshPointi] - firstLayerDisp[i]) > SMALL)
1746 {
1748 << "At mesh point:" << meshPointi
1749 << " coordinate:" << mesh_.points()[meshPointi]
1750 << " specified displacement:" << firstLayerDisp[i]
1751 << endl
1752 << "On coupled point a different displacement:"
1753 << d[meshPointi] << " was specified."
1754 << abort(FatalError);
1755 }
1756 }
1757 }
1758
1759 // Check that edges of pp (so ones that become boundary faces)
1760 // connect to only one boundary face. Guarantees uniqueness of
1761 // patch that they go into so if this is a coupled patch both
1762 // sides decide the same.
1763 // ~~~~~~~~~~~~~~~~~~~~~~
1764
1765 for (label edgei = pp.nInternalEdges(); edgei < pp.nEdges(); edgei++)
1766 {
1767 const edge& e = pp.edges()[edgei];
1768
1769 if (nPointLayers[e[0]] > 0 || nPointLayers[e[1]] > 0)
1770 {
1771 // Edge is to become a face
1772
1773 const labelList& eFaces = pp.edgeFaces()[edgei];
1774
1775 // First check: pp should be single connected.
1776 if (eFaces.size() != 1)
1777 {
1779 << "boundary-edge-to-be-extruded:"
1780 << pp.points()[meshPoints[e[0]]]
1781 << pp.points()[meshPoints[e[1]]]
1782 << " has more than two faces using it:" << eFaces
1783 << abort(FatalError);
1784 }
1785
1786 //label myFacei = pp.addressing()[eFaces[0]];
1787 //
1788 //label meshEdgei = meshEdges[edgei];
1789 //
1791 //const labelList& meshFaces = mesh_.edgeFaces(meshEdgei, ef);
1792 //
1794 //const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1795 //
1796 //label bFacei = -1;
1797 //
1798 //forAll(meshFaces, i)
1799 //{
1800 // label facei = meshFaces[i];
1801 //
1802 // if (facei != myFacei)
1803 // {
1804 // if (!mesh_.isInternalFace(facei))
1805 // {
1806 // if (bFacei == -1)
1807 // {
1808 // bFacei = facei;
1809 // }
1810 // else
1811 // {
1812 // //FatalErrorInFunction
1813 // WarningInFunction
1814 // << "boundary-edge-to-be-extruded:"
1815 // << pp.points()[meshPoints[e[0]]]
1816 // << pp.points()[meshPoints[e[1]]]
1817 // << " has more than one boundary faces"
1818 // << " using it:"
1819 // << bFacei << " fc:"
1820 // << mesh_.faceCentres()[bFacei]
1821 // << " patch:" << patches.whichPatch(bFacei)
1822 // << " and " << facei << " fc:"
1823 // << mesh_.faceCentres()[facei]
1824 // << " patch:" << patches.whichPatch(facei)
1825 // << endl;
1826 // //abort(FatalError);
1827 // }
1828 // }
1829 // }
1830 //}
1831 }
1832 }
1833 }
1834
1835
1836 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1837
1838 // Precalculated patchID for each patch face
1840
1841 forAll(pp, patchFacei)
1842 {
1843 label meshFacei = pp.addressing()[patchFacei];
1844
1845 patchID[patchFacei] = patches.whichPatch(meshFacei);
1846 }
1847
1848
1849 // From master point (in patch point label) to added points (in mesh point
1850 // label)
1851 addedPoints_.setSize(pp.nPoints());
1852
1853 // Mark points that do not get extruded by setting size of addedPoints_ to 0
1854 label nTruncated = 0;
1855
1856 forAll(nPointLayers, patchPointi)
1857 {
1858 if (nPointLayers[patchPointi] > 0)
1859 {
1860 addedPoints_[patchPointi].setSize(nPointLayers[patchPointi]);
1861 }
1862 else
1863 {
1864 nTruncated++;
1865 }
1866 }
1867
1868 if (debug)
1869 {
1870 Pout<< "Not adding points at " << nTruncated << " out of "
1871 << pp.nPoints() << " points" << endl;
1872 }
1873
1874
1875 // Store per face whether it uses the duplicated point or the original one
1876 // Also mark any affected cells. We could transport the duplicated point
1877 // itself but since it is a processor-local index only we only transport
1878 // a boolean.
1879 // Per face, per index in face either -1 or a valid index. Note:
1880 // most faces are not affected in which case the face will be zero size
1881 // and only have a nullptr and a size. Note: we do not actually use the
1882 // value of the index - it might be a remote patch point so not make any
1883 // sense. All we want to know is whether it is -1 or not.
1884 faceList baseFaces(mesh_.nFaces());
1885 {
1886 bitSet isDupPatchPoint(pp.nPoints());
1887 forAll(nPointLayers, patchPointi)
1888 {
1889 if (nPointLayers[patchPointi] > 0)
1890 {
1891 isDupPatchPoint.set(patchPointi);
1892 }
1893 }
1894 // Knock out point if not all local faces using it are extruded
1895 // Guess not needed since done outside of routine already.
1896 forAll(nFaceLayers, patchFacei)
1897 {
1898 if (nFaceLayers[patchFacei] == 0)
1899 {
1900 const face& f = pp.localFaces()[patchFacei];
1901 for (const label patchPointi : f)
1902 {
1903 if (isDupPatchPoint[patchPointi])
1904 {
1905 isDupPatchPoint.unset(patchPointi);
1906 }
1907 }
1908 }
1909 }
1910
1911 findDuplicatedPoints
1912 (
1913 mesh_,
1914 pp,
1915 ppFlip, // optional orientation on top of pp
1916 isBlockedFace, // any mesh faces not to be traversed.
1917 // Usually pp.addressing()
1918 isDupPatchPoint,
1919 extrude_,
1920
1921 baseFaces
1922 );
1923 }
1924
1925
1926 //
1927 // Create new points
1928 //
1929
1930 // If creating new mesh: copy existing patch points
1931 labelList copiedPatchPoints;
1932 if (!addToMesh_)
1933 {
1934 copiedPatchPoints.setSize(firstLayerDisp.size());
1935 forAll(firstLayerDisp, patchPointi)
1936 {
1937 if (addedPoints_[patchPointi].size())
1938 {
1939 label meshPointi = meshPoints[patchPointi];
1940 label zoneI = mesh_.pointZones().whichZone(meshPointi);
1941 copiedPatchPoints[patchPointi] = meshMod.setAction
1942 (
1944 (
1945 mesh_.points()[meshPointi], // point
1946 -1, // master point
1947 zoneI, // zone for point
1948 true // supports a cell
1949 )
1950 );
1951 }
1952 }
1953 }
1954
1955
1956 // Create points for additional layers
1957 forAll(firstLayerDisp, patchPointi)
1958 {
1959 if (addedPoints_[patchPointi].size())
1960 {
1961 const label meshPointi = meshPoints[patchPointi];
1962 const label zoneI = mesh_.pointZones().whichZone(meshPointi);
1963
1964 point pt = mesh_.points()[meshPointi];
1965
1966 vector disp = firstLayerDisp[patchPointi];
1967
1968 forAll(addedPoints_[patchPointi], i)
1969 {
1970 pt += disp;
1971
1972 const label addedVertI = meshMod.setAction
1973 (
1975 (
1976 pt, // point
1977 (addToMesh_ ? meshPointi : -1), // master point
1978 zoneI, // zone for point
1979 true // supports a cell
1980 )
1981 );
1982
1983
1984 //Pout<< "Adding point:" << addedVertI << " at:" << pt
1985 // << " from point:" << meshPointi
1986 // << " at:" << mesh_.points()[meshPointi]
1987 // << endl;
1988
1989 addedPoints_[patchPointi][i] = addedVertI;
1990
1991 disp *= expansionRatio[patchPointi];
1992 }
1993 }
1994 }
1995
1996
1997 //
1998 // Add cells to all boundaryFaces
1999 //
2000
2001 labelListList addedCells(pp.size());
2002
2003 forAll(pp, patchFacei)
2004 {
2005 if (nFaceLayers[patchFacei] > 0)
2006 {
2007 const label meshFacei = pp.addressing()[patchFacei];
2008
2009 label extrudeCelli = -2;
2010 label extrudeZonei;
2011 if (!addToMesh_)
2012 {
2013 extrudeCelli = -1;
2014 const label ownCelli = mesh_.faceOwner()[meshFacei];
2015 extrudeZonei = mesh_.cellZones().whichZone(ownCelli);
2016 }
2017 else if (!ppFlip[patchFacei])
2018 {
2019 // Normal: extrude from owner side
2020 extrudeCelli = mesh_.faceOwner()[meshFacei];
2021 extrudeZonei = mesh_.cellZones().whichZone(extrudeCelli);
2022 }
2023 else if (mesh_.isInternalFace(meshFacei))
2024 {
2025 // Extrude from neighbour side (if internal). Might be
2026 // that it is a coupled face and the other side is
2027 // extruded
2028 extrudeCelli = mesh_.faceNeighbour()[meshFacei];
2029 extrudeZonei = mesh_.cellZones().whichZone(extrudeCelli);
2030 }
2031
2032 if (extrudeCelli != -2)
2033 {
2034 addedCells[patchFacei].setSize(nFaceLayers[patchFacei]);
2035
2036 for (label i = 0; i < nFaceLayers[patchFacei]; i++)
2037 {
2038 // Note: add from cell (owner of patch face) or from face?
2039 // for now add from cell so we can map easily.
2040 addedCells[patchFacei][i] = meshMod.setAction
2041 (
2043 (
2044 -1, // master point
2045 -1, // master edge
2046 -1, // master face
2047 extrudeCelli, // master cell
2048 extrudeZonei // zone for cell
2049 )
2050 );
2051
2052 //Pout<< "Added cell:" << addedCells[patchFacei][i]
2053 // << " from master:" << extrudeCelli
2054 // << " at:" << mesh_.cellCentres()[extrudeCelli]
2055 // << endl;
2056 }
2057 }
2058 }
2059 }
2060
2061
2062
2063 // Create faces from the original patch faces.
2064 // These faces are created from original patch faces outwards (or inwards)
2065 // so in order
2066 // of increasing cell number. So orientation should be same as original
2067 // patch face for them to have owner<neighbour.
2068
2069 layerFaces_.setSize(pp.size());
2070
2071 forAll(pp.localFaces(), patchFacei)
2072 {
2073 label meshFacei = pp.addressing()[patchFacei];
2074
2075 if (addedCells[patchFacei].size())
2076 {
2077 layerFaces_[patchFacei].setSize(addedCells[patchFacei].size() + 1);
2078
2079 // Get duplicated vertices on the patch face.
2080 const face& f = pp.localFaces()[patchFacei];
2081
2082 face newFace(f.size());
2083
2084 forAll(addedCells[patchFacei], i)
2085 {
2086 forAll(f, fp)
2087 {
2088 if (addedPoints_[f[fp]].empty())
2089 {
2090 // Keep original point
2091 newFace[fp] =
2092 (
2093 addToMesh_
2094 ? meshPoints[f[fp]]
2095 : copiedPatchPoints[f[fp]]
2096 );
2097 }
2098 else
2099 {
2100 // Get new outside point
2101 label offset =
2102 addedPoints_[f[fp]].size()
2103 - addedCells[patchFacei].size();
2104 newFace[fp] = addedPoints_[f[fp]][i+offset];
2105 }
2106 }
2107 //Pout<< " newFace:" << newFace << endl;
2108 //Pout<< " coords:"
2109 // << UIndirectList<point>(meshMod.points(), newFace)
2110 // << " normal:" << newFace.unitNormal(meshMod.points())
2111 // << endl;
2112
2113 // Get new neighbour
2114 label own;
2115 label nei = -1;
2116 label patchi = -1;
2117 label zonei = -1;
2118 bool zoneFlip = false;
2119 bool fluxFlip = false;
2120
2121 if (i == addedCells[patchFacei].size()-1)
2122 {
2123 // Last layer so
2124 // - extrude : original patch or other cell
2125 // - intrude : original cell
2126
2127 if (extrude_)
2128 {
2129 patchi = patchID[patchFacei];
2130 zonei = mesh_.faceZones().whichZone(meshFacei);
2131 if (zonei != -1)
2132 {
2133 const faceZone& fz = mesh_.faceZones()[zonei];
2134 zoneFlip = fz.flipMap()[fz.whichFace(meshFacei)];
2135 }
2136 if (patchi == -1)
2137 {
2138 // Internal face between added cell and original
2139 // neighbour / owner
2140 own =
2141 (
2142 !ppFlip[patchFacei]
2143 ? mesh_.faceNeighbour()[meshFacei]
2144 : mesh_.faceOwner()[meshFacei]
2145 );
2146 nei = addedCells[patchFacei][i];
2147 if (!ppFlip[patchFacei])
2148 {
2149 newFace = newFace.reverseFace();
2150 if (zonei != -1)
2151 {
2152 zoneFlip = !zoneFlip;
2153 }
2154 fluxFlip = true;
2155 }
2156 }
2157 else
2158 {
2159 // Boundary face
2160 own = addedCells[patchFacei][i];
2161 }
2162 }
2163 else
2164 {
2165 // Intrude : face connects to original cell
2166 //if (patchID[patchFacei] == -1)
2167 {
2168 // Internal face between added cell and original
2169 // owner / neighbour. TBD: what if ppFlip set on
2170 // boundary face (so with no neighbour)
2171 own =
2172 (
2173 !ppFlip[patchFacei]
2174 ? mesh_.faceOwner()[meshFacei]
2175 : mesh_.faceNeighbour()[meshFacei]
2176 );
2177 nei = addedCells[patchFacei][i];
2178 if (ppFlip[patchFacei])
2179 {
2180 // Since neighbour now owns the face flip it
2181 newFace = newFace.reverseFace();
2182 if (zonei != -1)
2183 {
2184 zoneFlip = !zoneFlip;
2185 }
2186 fluxFlip = true;
2187 }
2188 }
2189 }
2190 }
2191 else
2192 {
2193 // Internal face between layer i and i+1
2194 own = addedCells[patchFacei][i];
2195 nei = addedCells[patchFacei][i+1];
2196
2197 if (ppFlip[patchFacei])
2198 {
2199 // Since neighbour now owns the face flip it
2200 newFace = newFace.reverseFace();
2201 fluxFlip = true;
2202 }
2203 }
2204
2205 layerFaces_[patchFacei][i+1] = meshMod.setAction
2206 (
2208 (
2209 newFace, // face
2210 own, // owner
2211 nei, // neighbour
2212 -1, // master point
2213 -1, // master edge
2214 (addToMesh_ ? meshFacei : -1), // master face
2215 fluxFlip, // flux flip
2216 patchi, // patch for face
2217 zonei, // zone for face
2218 zoneFlip // face zone flip
2219 )
2220 );
2221
2222 //Pout<< "added layer face:" << layerFaces_[patchFacei][i+1]
2223 // << " verts:" << newFace
2224 // << " newFc:" << newFace.centre(meshMod.points())
2225 // << " originalFc:" << mesh_.faceCentres()[meshFacei]
2226 // << nl
2227 // << " n:" << newFace.unitNormal(meshMod.points())
2228 // << " own:" << own << " nei:" << nei
2229 // << " patchi:" << patchi
2230 // << " zonei:" << zonei
2231 // << endl;
2232 }
2233 }
2234 }
2235
2236 //
2237 // Modify original face to have addedCells as neighbour
2238 //
2239
2240 if (addToMesh_)
2241 {
2242 forAll(pp, patchFacei)
2243 {
2244 if (addedCells[patchFacei].size())
2245 {
2246 const label meshFacei = pp.addressing()[patchFacei];
2247
2248 layerFaces_[patchFacei][0] = meshFacei;
2249 const face& f = pp[patchFacei];
2250
2251 if (extrude_)
2252 {
2253 const label own =
2254 (
2255 !ppFlip[patchFacei]
2256 ? mesh_.faceOwner()[meshFacei]
2257 : mesh_.faceNeighbour()[meshFacei]
2258 );
2259 const label nei = addedCells[patchFacei][0];
2260
2261 meshMod.setAction
2262 (
2264 (
2265 (ppFlip[patchFacei] ? f.reverseFace() : f),// verts
2266 meshFacei, // label of face
2267 own, // owner
2268 nei, // neighbour
2269 ppFlip[patchFacei], // face flip
2270 -1, // patch for face
2271 true, //false, // remove from zone
2272 -1, //zoneI, // zone for face
2273 false // face flip in zone
2274 )
2275 );
2276 }
2277 else
2278 {
2279 label patchi;
2280 label zonei;
2281 bool zoneOrient;
2282 setFaceProps
2283 (
2284 mesh_,
2285 meshFacei,
2286
2287 patchi,
2288 zonei,
2289 zoneOrient
2290 );
2291
2292 label own;
2293 label nei = -1;
2294 bool flip = false;
2295 if (!ppFlip[patchFacei])
2296 {
2297 if (patchi == -1)
2298 {
2299 own = mesh_.faceNeighbour()[meshFacei];
2300 nei = addedCells[patchFacei].first();
2301 flip = true;
2302 }
2303 else
2304 {
2305 own = addedCells[patchFacei].first();
2306 }
2307 }
2308 else
2309 {
2310 if (patchi == -1)
2311 {
2312 own = mesh_.faceOwner()[meshFacei];
2313 nei = addedCells[patchFacei].first();
2314 }
2315 else
2316 {
2317 own = addedCells[patchFacei].first();
2318 }
2319 }
2320
2321 if (zonei != -1 && flip)
2322 {
2323 zoneOrient = !zoneOrient;
2324 }
2325
2326 meshMod.setAction
2327 (
2329 (
2330 (flip ? f.reverseFace() : f), // verts
2331 meshFacei, // label of face
2332 own, // owner
2333 nei, // neighbour
2334 flip, // face flip
2335 patchi, // patch for face
2336 false, // remove from zone
2337 zonei, // zone for face
2338 zoneOrient // face flip in zone
2339 )
2340 );
2341 }
2342
2343 //Pout<< "Modified original face " << meshFacei
2344 // << " at:" << mesh_.faceCentres()[meshFacei]
2345 // << " new own:" << meshMod.faceOwner()[meshFacei]
2346 // << " new nei:" << meshMod.faceNeighbour()[meshFacei]
2347 // << " verts:" << meshMod.faces()[meshFacei]
2348 // << " n:"
2349 // << meshMod.faces()[meshFacei].unitNormal(meshMod.points())
2350 // << endl;
2351 }
2352 }
2353 }
2354 else
2355 {
2356 // If creating new mesh: reverse original faces and put them
2357 // in the exposed patch ID.
2358 forAll(pp, patchFacei)
2359 {
2360 if (addedCells[patchFacei].size())
2361 {
2362 label meshFacei = pp.addressing()[patchFacei];
2363 label zoneI = mesh_.faceZones().whichZone(meshFacei);
2364 bool zoneFlip = false;
2365 if (zoneI != -1)
2366 {
2367 const faceZone& fz = mesh_.faceZones()[zoneI];
2368 zoneFlip = !fz.flipMap()[fz.whichFace(meshFacei)];
2369 }
2370
2371 // Reverse and renumber old patch face.
2372 face f(pp.localFaces()[patchFacei].reverseFace());
2373 forAll(f, fp)
2374 {
2375 f[fp] = copiedPatchPoints[f[fp]];
2376 }
2377
2378 layerFaces_[patchFacei][0] = meshMod.setAction
2379 (
2381 (
2382 f, // modified face
2383 addedCells[patchFacei][0], // owner
2384 -1, // neighbour
2385 -1, // masterPoint
2386 -1, // masterEdge
2387 -1, // masterFace
2388 true, // face flip
2389 exposedPatchID[patchFacei], // patch for face
2390 zoneI, // zone for face
2391 zoneFlip // face flip in zone
2392 )
2393 );
2394 }
2395 }
2396 }
2397
2398
2399
2400 //
2401 // Create 'side' faces, one per edge that is being extended.
2402 //
2403
2404 const labelListList& faceEdges = pp.faceEdges();
2405 const faceList& localFaces = pp.localFaces();
2406 const edgeList& edges = pp.edges();
2407
2408 // Get number of layers per edge. This is 0 if edge is not extruded;
2409 // max of connected faces otherwise.
2410 labelList edgeLayers(pp.nEdges());
2411
2412 {
2413 // Use list over mesh.nEdges() since syncTools does not yet support
2414 // partial list synchronisation.
2415 labelList meshEdgeLayers(mesh_.nEdges(), -1);
2416
2417 forAll(meshEdges, edgei)
2418 {
2419 const edge& e = edges[edgei];
2420
2421 label meshEdgei = meshEdges[edgei];
2422
2423 if ((nPointLayers[e[0]] == 0) && (nPointLayers[e[1]] == 0))
2424 {
2425 meshEdgeLayers[meshEdgei] = 0;
2426 }
2427 else
2428 {
2429 const labelList& eFaces = pp.edgeFaces()[edgei];
2430
2431 forAll(eFaces, i)
2432 {
2433 meshEdgeLayers[meshEdgei] = max
2434 (
2435 nFaceLayers[eFaces[i]],
2436 meshEdgeLayers[meshEdgei]
2437 );
2438 }
2439 }
2440 }
2441
2443 (
2444 mesh_,
2445 meshEdgeLayers,
2447 label(0) // initial value
2448 );
2449
2450 forAll(meshEdges, edgei)
2451 {
2452 edgeLayers[edgei] = meshEdgeLayers[meshEdges[edgei]];
2453 }
2454 }
2455
2456
2457 // Mark off which edges have been extruded
2458 boolList doneEdge(pp.nEdges(), false);
2459
2460
2461 // Create faces. Per face walk connected edges and find string of edges
2462 // between the same two faces and extrude string into a single face.
2463 forAll(pp, patchFacei)
2464 {
2465 // Get edges of face in vertex order
2466 const labelList& fEdges = faceEdges[patchFacei];
2467
2468 forAll(fEdges, i)
2469 {
2470 // Get string of edges that needs to be extruded as a single face.
2471 // Returned as indices in fEdges.
2472 labelPair indexPair
2473 (
2474 getEdgeString
2475 (
2476 pp,
2477 globalEdgeFaces,
2478 doneEdge,
2479 patchFacei,
2480 globalFaces.toGlobal(pp.addressing()[patchFacei])
2481 )
2482 );
2483
2484 //Pout<< "Found unextruded edges in edges:" << fEdges
2485 // << " start:" << indexPair[0]
2486 // << " end:" << indexPair[1]
2487 // << endl;
2488
2489 const label startFp = indexPair[0];
2490 const label endFp = indexPair[1];
2491
2492 if (startFp != -1)
2493 {
2494 // Extrude edges from indexPair[0] up to indexPair[1]
2495 // (note indexPair = indices of edges. There is one more vertex
2496 // than edges)
2497 const face& f = localFaces[patchFacei];
2498
2499 labelList stringedVerts;
2500 if (endFp >= startFp)
2501 {
2502 stringedVerts.setSize(endFp-startFp+2);
2503 }
2504 else
2505 {
2506 stringedVerts.setSize(endFp+f.size()-startFp+2);
2507 }
2508
2509 label fp = startFp;
2510
2511 for (label i = 0; i < stringedVerts.size()-1; i++)
2512 {
2513 stringedVerts[i] = f[fp];
2514 doneEdge[fEdges[fp]] = true;
2515 fp = f.fcIndex(fp);
2516 }
2517 stringedVerts.last() = f[fp];
2518
2519
2520 // Now stringedVerts contains the vertices in order of face f.
2521 // This is consistent with the order if f becomes the owner cell
2522 // and nbrFacei the neighbour cell. Note that the cells get
2523 // added in order of pp so we can just use face ordering and
2524 // because we loop in incrementing order as well we will
2525 // always have nbrFacei > patchFacei.
2526
2527 const label startEdgei = fEdges[startFp];
2528
2529 const label meshEdgei = meshEdges[startEdgei];
2530
2531 const label numEdgeSideFaces = edgeLayers[startEdgei];
2532
2533 for (label i = 0; i < numEdgeSideFaces; i++)
2534 {
2535 const label vEnd = stringedVerts.last();
2536 const label vStart = stringedVerts[0];
2537
2538 // calculate number of points making up a face
2539 label newFp = 2*stringedVerts.size();
2540
2541 if (i == 0)
2542 {
2543 // layer 0 gets all the truncation of neighbouring
2544 // faces with more layers.
2545 if (addedPoints_[vEnd].size())
2546 {
2547 newFp +=
2548 addedPoints_[vEnd].size() - numEdgeSideFaces;
2549 }
2550 if (addedPoints_[vStart].size())
2551 {
2552 newFp +=
2553 addedPoints_[vStart].size() - numEdgeSideFaces;
2554 }
2555 }
2556
2557 face newFace(newFp);
2558
2559 newFp = 0;
2560
2561 // For layer 0 get pp points, for all other layers get
2562 // points of layer-1.
2563 if (i == 0)
2564 {
2565 forAll(stringedVerts, stringedI)
2566 {
2567 const label v = stringedVerts[stringedI];
2568 addVertex
2569 (
2570 (
2571 addToMesh_
2572 ? meshPoints[v]
2573 : copiedPatchPoints[v]
2574 ),
2575 newFace,
2576 newFp
2577 );
2578 }
2579 }
2580 else
2581 {
2582 forAll(stringedVerts, stringedI)
2583 {
2584 const label v = stringedVerts[stringedI];
2585 if (addedPoints_[v].size())
2586 {
2587 const label offset =
2588 addedPoints_[v].size() - numEdgeSideFaces;
2589 addVertex
2590 (
2591 addedPoints_[v][i+offset-1],
2592 newFace,
2593 newFp
2594 );
2595 }
2596 else
2597 {
2598 addVertex
2599 (
2600 (
2601 addToMesh_
2602 ? meshPoints[v]
2603 : copiedPatchPoints[v]
2604 ),
2605 newFace,
2606 newFp
2607 );
2608 }
2609 }
2610 }
2611
2612 // add points between stringed vertices (end)
2613 if (numEdgeSideFaces < addedPoints_[vEnd].size())
2614 {
2615 if (i == 0 && addedPoints_[vEnd].size())
2616 {
2617 const label offset =
2618 addedPoints_[vEnd].size() - numEdgeSideFaces;
2619 for (label ioff = 0; ioff < offset; ioff++)
2620 {
2621 addVertex
2622 (
2623 addedPoints_[vEnd][ioff],
2624 newFace,
2625 newFp
2626 );
2627 }
2628 }
2629 }
2630
2631 forAllReverse(stringedVerts, stringedI)
2632 {
2633 const label v = stringedVerts[stringedI];
2634 if (addedPoints_[v].size())
2635 {
2636 const label offset =
2637 addedPoints_[v].size() - numEdgeSideFaces;
2638 addVertex
2639 (
2640 addedPoints_[v][i+offset],
2641 newFace,
2642 newFp
2643 );
2644 }
2645 else
2646 {
2647 addVertex
2648 (
2649 (
2650 addToMesh_
2651 ? meshPoints[v]
2652 : copiedPatchPoints[v]
2653 ),
2654 newFace,
2655 newFp
2656 );
2657 }
2658 }
2659
2660
2661 // add points between stringed vertices (start)
2662 if (numEdgeSideFaces < addedPoints_[vStart].size())
2663 {
2664 if (i == 0 && addedPoints_[vStart].size())
2665 {
2666 const label offset =
2667 addedPoints_[vStart].size() - numEdgeSideFaces;
2668 for (label ioff = offset-1; ioff >= 0; ioff--)
2669 {
2670 addVertex
2671 (
2672 addedPoints_[vStart][ioff],
2673 newFace,
2674 newFp
2675 );
2676 }
2677 }
2678 }
2679
2680 if (newFp >= 3)
2681 {
2682 // Add face inbetween faces patchFacei and nbrFacei
2683 // (possibly -1 for external edges)
2684
2685 newFace.setSize(newFp);
2686
2687 // Walked edges as if owner face was extruded. Reverse
2688 // for neighbour face extrusion.
2689 if (extrude_ == ppFlip[patchFacei])
2690 {
2691 newFace = newFace.reverseFace();
2692 }
2693
2694 if (debug)
2695 {
2696 labelHashSet verts(2*newFace.size());
2697 forAll(newFace, fp)
2698 {
2699 if (!verts.insert(newFace[fp]))
2700 {
2702 << "Duplicate vertex in face"
2703 << " to be added." << nl
2704 << "newFace:" << newFace << nl
2705 << "points:"
2707 (
2708 meshMod.points(),
2709 newFace
2710 ) << nl
2711 << "Layer:" << i
2712 << " out of:" << numEdgeSideFaces << nl
2713 << "ExtrudeEdge:" << meshEdgei
2714 << " at:"
2715 << mesh_.edges()[meshEdgei].line
2716 (
2717 mesh_.points()
2718 ) << nl
2719 << "string:" << stringedVerts
2720 << "stringpoints:"
2722 (
2723 pp.localPoints(),
2724 stringedVerts
2725 ) << nl
2726 << "stringNLayers:"
2727 << labelUIndList
2728 (
2729 nPointLayers,
2730 stringedVerts
2731 ) << nl
2732 << abort(FatalError);
2733 }
2734 }
2735 }
2736
2737 label nbrFacei = nbrFace
2738 (
2739 pp.edgeFaces(),
2740 startEdgei,
2741 patchFacei
2742 );
2743
2744 const labelList& meshFaces = mesh_.edgeFaces
2745 (
2746 meshEdgei,
2747 ef
2748 );
2749
2750 // Because we walk in order of patch face and in order
2751 // of face edges so face orientation will be opposite
2752 // that of the patch edge
2753 bool zoneFlip = false;
2754 if (edgeZoneID[startEdgei] != -1)
2755 {
2756 zoneFlip = !edgeFlip[startEdgei];
2757 }
2758
2759 addSideFace
2760 (
2761 pp,
2762 addedCells,
2763
2764 newFace, // vertices of new face
2765 edgePatchID[startEdgei],// -1 or patch for face
2766 edgeZoneID[startEdgei],
2767 zoneFlip,
2768 inflateFaceID[startEdgei],
2769
2770 patchFacei,
2771 nbrFacei,
2772 meshEdgei, // (mesh) edge to inflate
2773 i, // layer
2774 numEdgeSideFaces, // num layers
2775 meshFaces, // edgeFaces
2776 meshMod
2777 );
2778 }
2779 }
2780 }
2781 }
2782 }
2783
2784
2785 // Adjust side faces if they're on the side where points were duplicated
2786 // (i.e. adding to internal faces). Like duplicatePoints::setRefinement.
2787 if (addToMesh_)
2788 {
2789 face newFace;
2790
2791 // For intrusion correction later on: store displacement of modified
2792 // points so they can be adapted on connected faces.
2793 pointField displacement(mesh_.nPoints(), Zero);
2794
2795 forAll(mesh_.faces(), facei)
2796 {
2797 const face& f = mesh_.faces()[facei];
2798 const face& baseF = baseFaces[facei];
2799
2800 if (isBlockedFace(facei) || baseF.empty())
2801 {
2802 // Either part of patch or no duplicated points on face
2803 continue;
2804 }
2805
2806 // Start off from original face
2807 newFace = f;
2808 forAll(f, fp)
2809 {
2810 const label meshPointi = f[fp];
2811 if (baseF[fp] != -1)
2812 {
2813 // Duplicated point. Might not be present on processor?
2814 //const label patchPointi = pp.meshPointMap()[meshPointi];
2815 const auto pointFnd = pp.meshPointMap().find(meshPointi);
2816 if (pointFnd)
2817 {
2818 const label patchPointi = pointFnd();
2819 const label addedPointi =
2820 addedPoints_[patchPointi].last();
2821
2822 // Adapt vertices of face
2823 newFace[fp] = addedPointi;
2824
2825 // Store displacement for syncing later on
2826 displacement[meshPointi] =
2827 meshMod.points()[addedPointi]
2828 -mesh_.points()[meshPointi];
2829 }
2830 }
2831 }
2832
2833 //Pout<< "for face:" << facei << nl
2834 // << " old:" << f
2835 // << " n:" << newFace.unitNormal(meshMod.points())
2836 // << " coords:" << UIndirectList<point>(mesh_.points(), f)
2837 // << nl
2838 // << " new:" << newFace
2839 // << " n:" << newFace.unitNormal(meshMod.points())
2840 // << " coords:"
2841 // << UIndirectList<point>(meshMod.points(), newFace)
2842 // << endl;
2843
2844 // Get current zone info
2845 label zoneID = mesh_.faceZones().whichZone(facei);
2846 bool zoneFlip = false;
2847 if (zoneID >= 0)
2848 {
2849 const faceZone& fZone = mesh_.faceZones()[zoneID];
2850 zoneFlip = fZone.flipMap()[fZone.whichFace(facei)];
2851 }
2852
2853
2854 if (mesh_.isInternalFace(facei))
2855 {
2856 meshMod.modifyFace
2857 (
2858 newFace, // modified face
2859 facei, // label of modified face
2860 mesh_.faceOwner()[facei], // owner
2861 mesh_.faceNeighbour()[facei], // neighbour
2862 false, // face flip
2863 -1, // patch for face
2864 zoneID, // zone for face
2865 zoneFlip // face flip in zone
2866 );
2867 }
2868 else
2869 {
2870 meshMod.modifyFace
2871 (
2872 newFace, // modified face
2873 facei, // label of modified face
2874 mesh_.faceOwner()[facei], // owner
2875 -1, // neighbour
2876 false, // face flip
2877 patches.whichPatch(facei), // patch for face
2878 zoneID, // zone for face
2879 zoneFlip // face flip in zone
2880 );
2881 }
2882
2883
2884 //Pout<< "Adapted point on existing face:" << facei
2885 // << " at:" << mesh_.faceCentres()[facei]
2886 // << " zone:" << zoneID << nl
2887 // << " old:" << f
2888 // << " n:" << newFace.unitNormal(meshMod.points())
2889 // << " coords:" << UIndirectList<point>(mesh_.points(), f)
2890 // << nl
2891 // << " new:" << newFace
2892 // << " n:" << newFace.unitNormal(meshMod.points())
2893 // << " coords:"
2894 // << UIndirectList<point>(meshMod.points(), newFace)
2895 // << endl;
2896 }
2897
2898 if (!extrude_)
2899 {
2900 // Bit tricky:
2901 // - if intruding we're modifying the vertices on existing
2902 // coupled faces (in extrude mode we're adding additional points/
2903 // faces where we're already doing the right thing)
2904 // - if the other side face is itself not on an extrudePatch
2905 // it will not be adapted so you'll get a coupled point mismatch
2906 // - so send over the new point position (or use some map on
2907 // coupled faces to describe which vertex on the face is changed?)
2908 // - and adapt any point that was marked but not an extrusion point
2909 // - to test: take 2x2 blockMesh and remove one of the cells. Put
2910 // all 3 cells on different processors. Now one of the processors
2911 // will be coupled to extrude/intruded points but itself have
2912 // no patch.
2913
2915 (
2916 mesh_,
2917 displacement,
2920 );
2921
2922 forAll(baseFaces, facei)
2923 {
2924 const face& f = mesh_.faces()[facei];
2925 const face& baseF = baseFaces[facei];
2926
2927 if (isBlockedFace(facei) || baseF.empty())
2928 {
2929 // Either part of patch or no duplicated points on face
2930 continue;
2931 }
2932
2933 // Start off from original face
2934 forAll(f, fp)
2935 {
2936 if (baseF[fp] != -1)
2937 {
2938 // Duplicated point. Might not be present on processor?
2939 const label meshPointi = f[fp];
2940
2941 if
2942 (
2943 !pp.meshPointMap().found(meshPointi)
2944 && displacement[meshPointi] != vector::zero
2945 )
2946 {
2947 const point newPt
2948 (
2949 mesh_.points()[meshPointi]
2950 + displacement[meshPointi]
2951 );
2952 meshMod.modifyPoint
2953 (
2954 meshPointi,
2955 newPt,
2956 mesh_.pointZones().whichZone(meshPointi),
2957 true
2958 );
2959
2960 // Unmark as being done
2961 displacement[meshPointi] = Zero;
2962 }
2963 }
2964 }
2965 }
2966 }
2967 }
2968
2969
2970
2971 //if (debug & 4)
2972 //{
2973 // Pout<< "Checking whole mesh" << endl;
2974 // pointField fCtrs;
2975 // vectorField fAreas;
2976 // const UList<face>& faces = meshMod.faces();
2977 // const pointField p(meshMod.points());
2978 // primitiveMeshTools::makeFaceCentresAndAreas
2979 // (
2980 // faces,
2981 // p,
2982 // fCtrs,
2983 // fAreas
2984 // );
2985 //
2986 // const label nCells = max(meshMod.faceOwner())+1;
2987 //
2988 // pointField cellCtrs;
2989 // scalarField cellVols;
2990 // {
2991 // // See primitiveMeshTools::makeCellCentresAndVols
2992 // // Clear the fields for accumulation
2993 // cellCtrs.setSize(nCells, Zero);
2994 // cellVols.setSize(nCells, Zero);
2995 //
2996 // const labelList& own = meshMod.faceOwner();
2997 // const labelList& nei = meshMod.faceNeighbour();
2998 //
2999 // Field<solveVector> cEst(nCells, Zero);
3000 // labelField nCellFaces(nCells, Zero);
3001 //
3002 // forAll(own, facei)
3003 // {
3004 // cEst[own[facei]] += fCtrs[facei];
3005 // ++nCellFaces[own[facei]];
3006 // }
3007 //
3008 // forAll(nei, facei)
3009 // {
3010 // if (nei[facei] == -1)
3011 // {
3012 // continue;
3013 // }
3014 // cEst[nei[facei]] += fCtrs[facei];
3015 // ++nCellFaces[nei[facei]];
3016 // }
3017 //
3018 // forAll(cEst, celli)
3019 // {
3020 // cEst[celli] /= nCellFaces[celli];
3021 // }
3022 //
3023 // forAll(own, facei)
3024 // {
3025 // const solveVector fc(fCtrs[facei]);
3026 // const solveVector fA(fAreas[facei]);
3027 //
3028 // // Calculate 3*face-pyramid volume
3029 // solveScalar pyr3Vol = fA & (fc - cEst[own[facei]]);
3030 //
3031 // // Calculate face-pyramid centre
3032 // solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cEst[own[facei]];
3033 //
3034 // // Accumulate volume-weighted face-pyramid centre
3035 // cellCtrs[own[facei]] += pyr3Vol*pc;
3036 //
3037 // // Accumulate face-pyramid volume
3038 // cellVols[own[facei]] += pyr3Vol;
3039 // }
3040 //
3041 // forAll(nei, facei)
3042 // {
3043 // if (nei[facei] == -1)
3044 // {
3045 // continue;
3046 // }
3047 //
3048 // const solveVector fc(fCtrs[facei]);
3049 // const solveVector fA(fAreas[facei]);
3050 //
3051 // // Calculate 3*face-pyramid volume
3052 // solveScalar pyr3Vol = fA & (cEst[nei[facei]] - fc);
3053 //
3054 // // Calculate face-pyramid centre
3055 // solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cEst[nei[facei]];
3056 //
3057 // // Accumulate volume-weighted face-pyramid centre
3058 // cellCtrs[nei[facei]] += pyr3Vol*pc;
3059 //
3060 // // Accumulate face-pyramid volume
3061 // cellVols[nei[facei]] += pyr3Vol;
3062 // }
3063 //
3064 // forAll(cellCtrs, celli)
3065 // {
3066 // if (mag(cellVols[celli]) > VSMALL)
3067 // {
3068 // cellCtrs[celli] /= cellVols[celli];
3069 // }
3070 // else
3071 // {
3072 // cellCtrs[celli] = cEst[celli];
3073 // }
3074 // }
3075 // cellVols *= (1.0/3.0);
3076 // }
3077 // cellList cells(nCells);
3078 // {
3079 // const labelList& own = meshMod.faceOwner();
3080 // const labelList& nei = meshMod.faceNeighbour();
3081 //
3082 // labelList nFaces(nCells, 0);
3083 // forAll(own, facei)
3084 // {
3085 // nFaces[own[facei]]++;
3086 // }
3087 // forAll(nei, facei)
3088 // {
3089 // if (nei[facei] == -1)
3090 // {
3091 // continue;
3092 // }
3093 // nFaces[nei[facei]]++;
3094 // }
3095 //
3096 // forAll(cells, celli)
3097 // {
3098 // cells[celli].resize_nocopy(nFaces[celli]);
3099 // nFaces[celli] = 0;
3100 // }
3101 //
3102 // forAll(own, facei)
3103 // {
3104 // const label celli = own[facei];
3105 // cells[celli][nFaces[celli]++] = facei;
3106 // }
3107 // forAll(nei, facei)
3108 // {
3109 // if (nei[facei] == -1)
3110 // {
3111 // continue;
3112 // }
3113 // const label celli = nei[facei];
3114 // cells[celli][nFaces[celli]++] = facei;
3115 // }
3116 // }
3117 //
3118 //
3119 // scalarField openness;
3120 // {
3121 // const labelList& own = meshMod.faceOwner();
3122 // const labelList& nei = meshMod.faceNeighbour();
3123 //
3124 // // Loop through cell faces and sum up the face area vectors for
3125 // // each cell. This should be zero in all vector components
3126 //
3127 // vectorField sumClosed(nCells, Zero);
3128 // vectorField sumMagClosed(nCells, Zero);
3129 //
3130 // forAll(own, facei)
3131 // {
3132 // // Add to owner
3133 // sumClosed[own[facei]] += fAreas[facei];
3134 // sumMagClosed[own[facei]] += cmptMag(fAreas[facei]);
3135 // }
3136 //
3137 // forAll(nei, facei)
3138 // {
3139 // // Subtract from neighbour
3140 // if (nei[facei] == -1)
3141 // {
3142 // continue;
3143 // }
3144 //
3145 // sumClosed[nei[facei]] -= fAreas[facei];
3146 // sumMagClosed[nei[facei]] += cmptMag(fAreas[facei]);
3147 // }
3148 //
3149 //
3150 // // Check the sums
3151 // openness.setSize(nCells);
3152 //
3153 // forAll(sumClosed, celli)
3154 // {
3155 // scalar maxOpenness = 0;
3156 //
3157 // for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
3158 // {
3159 // maxOpenness = max
3160 // (
3161 // maxOpenness,
3162 // mag(sumClosed[celli][cmpt])
3163 // /(sumMagClosed[celli][cmpt] + ROOTVSMALL)
3164 // );
3165 // }
3166 // openness[celli] = maxOpenness;
3167 //
3168 // if (openness[celli] > 1e-9)
3169 // {
3170 // Pout<< "cell:" << celli
3171 // << " at:" << cellCtrs[celli]
3172 // << " openness:" << openness[celli]
3173 // << endl;
3174 // OBJstream os
3175 // (
3176 // mesh_.time().timePath()
3177 // /"cell_" + Foam::name(celli) + ".obj"
3178 // );
3179 // faceList cellFaces
3180 // (
3181 // UIndirectList<face>
3182 // (
3183 // meshMod.faces(),
3184 // cells[celli]
3185 // )
3186 // );
3187 // os.write(cellFaces, mesh_.points(), false);
3188 // Pout<< "Written " << os.nVertices() << " to "
3189 // << os.name() << endl;
3190 // }
3191 // }
3192 // }
3193 //}
3194}
3195
3196
3198(
3199 const mapPolyMesh& morphMap,
3200 const labelList& faceMap, // new to old patch faces
3201 const labelList& pointMap // new to old patch points
3202)
3203{
3204 {
3205 labelListList newAddedPoints(pointMap.size());
3206
3207 forAll(newAddedPoints, newPointi)
3208 {
3209 label oldPointi = pointMap[newPointi];
3210
3211 const labelList& added = addedPoints_[oldPointi];
3212
3213 labelList& newAdded = newAddedPoints[newPointi];
3214 newAdded.setSize(added.size());
3215 label newI = 0;
3216
3217 forAll(added, i)
3218 {
3219 label newPointi = morphMap.reversePointMap()[added[i]];
3220
3221 if (newPointi >= 0)
3222 {
3223 newAdded[newI++] = newPointi;
3224 }
3225 }
3226 newAdded.setSize(newI);
3227 }
3228 addedPoints_.transfer(newAddedPoints);
3229 }
3230
3231 {
3232 labelListList newLayerFaces(faceMap.size());
3233
3234 forAll(newLayerFaces, newFacei)
3235 {
3236 label oldFacei = faceMap[newFacei];
3237
3238 const labelList& added = layerFaces_[oldFacei];
3239
3240 labelList& newAdded = newLayerFaces[newFacei];
3241 newAdded.setSize(added.size());
3242 label newI = 0;
3243
3244 forAll(added, i)
3245 {
3246 label newFacei = morphMap.reverseFaceMap()[added[i]];
3247
3248 if (newFacei >= 0)
3249 {
3250 newAdded[newI++] = newFacei;
3251 }
3252 }
3253 newAdded.setSize(newI);
3254 }
3255 layerFaces_.transfer(newLayerFaces);
3256 }
3257}
3258
3259
3261(
3262 const polyMesh& mesh,
3264 const bitSet& ppFlip, // optional orientation on top of pp
3265 const bitSet& isBlockedFace, // any mesh faces not to be traversed.
3266 // Usually pp.addressing()
3267 const bitSet& isDupPatchPoint,
3268 const bool extrude,
3269 faceList& isDupMeshPoint // per face, per index either -1
3270 // or some index (value not relevant)
3271)
3272{
3273 if (isBlockedFace.size() != mesh.nFaces())
3274 {
3275 FatalErrorInFunction << "Incorrect size" << exit(FatalError);
3276 }
3277 if (ppFlip.size() != pp.size() || isDupPatchPoint.size() != pp.nPoints())
3278 {
3279 FatalErrorInFunction << "Incorrect patch sizes"
3280 << exit(FatalError);
3281 }
3282
3283 const auto& owner = mesh.faceOwner();
3284 const auto& neighbour = mesh.faceNeighbour();
3285
3286
3287 // Store per face whether it uses the duplicated point or the original one
3288 // Also mark any affected cells. We could transport the duplicated point
3289 // itself but since it is a processor-local index only we only transport
3290 // a boolean.
3291
3292 // Per face, per index in face either -1 or a valid index. Note:
3293 // most faces are not affected in which case the face will be zero size
3294 // and only have a nullptr and a size.
3295 isDupMeshPoint.resize_nocopy(mesh.nFaces());
3296 isDupMeshPoint = face();
3297 bitSet isAffectedCell(mesh.nCells());
3298 {
3299 const faceList& localFaces = pp.localFaces();
3300 forAll(localFaces, patchFacei)
3301 {
3302 const face& f = localFaces[patchFacei];
3303 forAll(f, fp)
3304 {
3305 const label patchPointi = f[fp];
3306 if (isDupPatchPoint[patchPointi])
3307 {
3308 const label meshFacei = pp.addressing()[patchFacei];
3309 face& baseF = isDupMeshPoint[meshFacei];
3310 // Initialise to -1 if not yet sized
3311 baseF.setSize(f.size(), -1);
3312 baseF[fp] = pp.meshPoints()[patchPointi];
3313
3314 if (extrude == ppFlip[patchFacei])
3315 {
3316 // either:
3317 // - extrude out of neighbour so new points connect
3318 // to owner
3319 // - or intrude into owner
3320 isAffectedCell.set(owner[meshFacei]);
3321 }
3322 else if (mesh.isInternalFace(meshFacei))
3323 {
3324 // Owner unaffected. Affected points on neighbour side
3325 isAffectedCell.set(neighbour[meshFacei]);
3326 }
3327 }
3328 }
3329 }
3330 }
3331
3332
3333 // Transport affected side across faces. Could do across edges: say we have
3334 // a loose cell edge-(but not face-)connected to face-to-be-extruded do
3335 // we want it to move with the extrusion or stay connected to the original?
3336 // For now just keep it connected to the original.
3337 {
3338 // Work space
3339 Map<label> minPointValue;
3340
3341 while (true)
3342 {
3343 bitSet newIsAffectedCell(mesh.nCells());
3344
3345 label nChanged = 0;
3346 for (const label celli : isAffectedCell)
3347 {
3348 const cell& cFaces = mesh.cells()[celli];
3349
3350 // 1. Determine marked base points. Inside a single cell all
3351 // faces (e.g. 3 for hex) use the same 'instance' of a point.
3352 minPointValue.clear();
3353 for (const label facei : cFaces)
3354 {
3355 const face& baseF = isDupMeshPoint[facei];
3356 const face& f = mesh.faces()[facei];
3357
3358 forAll(baseF, fp)
3359 {
3360 if (baseF[fp] != -1)
3361 {
3362 // Could check here for inconsistent patchPoint
3363 // e.g. cell using both sides of a
3364 // face-to-be-extruded.
3365
3366 const auto mpm = pp.meshPointMap().find(f[fp]);
3367 if (mpm && !isDupPatchPoint[mpm()])
3368 {
3369 // Local copy of point is explicitly not
3370 // marked for extrusion so ignore. This
3371 // occasionally happens with point-connected
3372 // faces where one face (& point) does
3373 // extrude but the other face does not
3374 // since pointing in the other direction.
3375 // Should ideally be covered by checking
3376 // across edges, not across points.
3377 }
3378 else
3379 {
3380 minPointValue.insert(f[fp], baseF[fp]);
3381 }
3382 }
3383 }
3384 }
3385
3386
3387 // 2. Transport marked points on all cell points
3388 for (const label facei : cFaces)
3389 {
3390 const face& f = mesh.faces()[facei];
3391 face& baseF = isDupMeshPoint[facei];
3392
3393 const label oldNChanged = nChanged;
3394 forAll(f, fp)
3395 {
3396 const auto fnd = minPointValue.find(f[fp]);
3397 if (fnd.good())
3398 {
3399 const auto mpm = pp.meshPointMap().find(f[fp]);
3400 if (mpm && !isDupPatchPoint[mpm()])
3401 {
3402 // See above
3403 continue;
3404 }
3405
3406 baseF.setSize(f.size(), -1);
3407 if (baseF[fp] == -1)
3408 {
3409 baseF[fp] = fnd();
3410 nChanged++;
3411 }
3412 }
3413 }
3414
3415 if (!isBlockedFace(facei) && nChanged > oldNChanged)
3416 {
3417 // Mark neighbouring cells. Note that we do NOT check
3418 // for whether cell is already in isAffectedCell but
3419 // always add it. This is because different information
3420 // can come in from the neighbour in different
3421 // iterations.
3422 newIsAffectedCell.set(owner[facei]);
3423 if (mesh.isInternalFace(facei))
3424 {
3425 newIsAffectedCell.set(neighbour[facei]);
3426 }
3427 }
3428 }
3429 }
3430
3431
3432 if (debug)
3433 {
3434 Pout<< "isAffectedCell:" << isAffectedCell.count() << endl;
3435 Pout<< "newIsAffectedCell:" << newIsAffectedCell.count()
3436 << endl;
3437 Pout<< "nChanged:" << nChanged << endl;
3438 }
3439
3440
3441 if (!returnReduceOr(nChanged))
3442 {
3443 break;
3444 }
3445
3446
3447 // Transport minimum across coupled faces
3448 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3449 // Faces can be either
3450 // - null
3451 // - face with some -1 or >= 0
3452 // - blocked face (isBlockedFace, should be synced already)
3454 forAll(l, bFacei)
3455 {
3456 const label facei = mesh.nInternalFaces()+bFacei;
3457
3458 if (isBlockedFace(facei))
3459 {
3460 // Make sure nothing is transferred. Since isBlockedFace is
3461 // synced both sides should have null
3462 if (l[bFacei].size())
3463 {
3464 l[bFacei].clear();
3465 }
3466 }
3467 else
3468 {
3469 l[bFacei] = isDupMeshPoint[facei];
3470 }
3471 }
3472
3473
3475 (
3476 mesh,
3477 l,
3478 combineEqOpFace(), // transport vertex >= 0
3479 Foam::dummyTransform() // dummy transformation
3480 );
3481
3482 // Copy back
3483 forAll(l, bFacei)
3484 {
3485 const label facei = mesh.nInternalFaces()+bFacei;
3486
3487 if (!isBlockedFace(facei))
3488 {
3489 // 1. Check if anything changed. Update isAffectedCell.
3490 // Note: avoid special handling of comparing zero-sized
3491 // faces (see face::operator==). Review.
3492 const labelUList& newVts = l[bFacei];
3493 const labelUList& oldVts = isDupMeshPoint[facei];
3494
3495 if (newVts != oldVts)
3496 {
3497 const label own = owner[facei];
3498 if (!isAffectedCell[own])
3499 {
3500 newIsAffectedCell.set(own);
3501 }
3502 }
3503
3504
3505 // 2. Update isDupMeshPoint
3506 isDupMeshPoint[facei] = l[bFacei];
3507 }
3508 }
3509
3510
3511 isAffectedCell = newIsAffectedCell;
3512 }
3513 }
3514}
3515
3516
3517// ************************************************************************* //
scalar y
label k
bool found
label n
labelList faceLabels(nFaceLabels)
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
void append(const T &val)
Copy append an element to the end of this list.
Map from edge (expressed as its endpoints) to value. Hashing (and ==) on an edge is symmetric.
Definition edgeHashes.H:59
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition HashSet.H:229
const T & lookup(const Key &key, const T &deflt) const
Return hashed entry if it exists, or return the given default.
Definition HashTableI.H:222
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
iterator find(const Key &key)
Find and return an iterator set at the hashed entry.
Definition HashTableI.H:86
void clear()
Remove all entries from table.
Definition HashTable.C:742
const Addr & addressing() const noexcept
The addressing used for the list.
label size() const noexcept
The number of elements in the list.
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition ListI.H:171
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
bool empty() const noexcept
True if the list is empty (ie, size() is zero).
Definition PackedList.H:387
void setSize(const label n, unsigned int val=0u)
Alias for resize().
Definition PackedList.H:819
label size() const noexcept
Number of entries.
Definition PackedList.H:392
static void matchEdges(const PrimitivePatch< FaceList1, PointField1 > &p1, const PrimitivePatch< FaceList2, PointField2 > &p2, labelList &p1EdgeLabels, labelList &p2EdgeLabels, bitSet &sameOrientation)
Find corresponding edges on patches sharing the same points.
label nEdges() const
Number of edges in patch.
label nPoints() const
Number of points supporting patch faces.
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
label nInternalEdges() const
Number of internal edges.
labelList meshEdges(const edgeList &allEdges, const labelListList &cellEdges, const labelList &faceCells) const
Return labels of patch edges in the global edge list using cell addressing.
const Map< label > & meshPointMap() const
Mesh point map.
const labelList & meshPoints() const
Return labelList of mesh points in patch.
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 Field< point_type > & faceCentres() const
Return face centres for patch.
const labelListList & edgeFaces() const
Return edge-face addressing.
const labelListList & faceEdges() const
Return face-edge addressing.
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
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
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
T & last()
Access last element of the list, position [size()-1].
Definition UList.H:971
label fcIndex(const label i) const noexcept
The forward circular index. The next index in the list which returns to the first at the end of the l...
Definition UListI.H:99
static bool parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
static const Form zero
static const Form max
label whichZone(const label objectIndex) const
Given a global object index, return the zone it is in.
Definition ZoneMesh.C:410
Adds layers of cells to outside (or inside) of polyMesh. Can optionally create stand-alone extruded m...
static labelListList addedCells(const polyMesh &, const labelListList &layerFaces)
Helper: get added cells per patch face.
void setRefinement(const globalIndex &globalFaces, const labelListList &globalEdgeFaces, const scalarField &expansionRatio, const indirectPrimitivePatch &pp, const bitSet &flip, const labelList &sidePatchID, const labelList &sideZoneID, const boolList &sideFlip, const labelList &inflateFaceID, const labelList &exposedPatchID, const labelList &nFaceLayers, const labelList &nPointLayers, const vectorField &firstLayerDisp, polyTopoChange &meshMod)
Play commands into polyTopoChange to create layers on top.
const labelListList & layerFaces() const
Layer faces per patch face. See above.
static labelListList globalEdgeFaces(const polyMesh &, const globalIndex &globalFaces, const indirectPrimitivePatch &pp, const bitSet &orientation)
Per patch edge the pp faces (in global indices) using it.
void updateMesh(const mapPolyMesh &, const labelList &faceMap, const labelList &pointMap)
Update any locally stored mesh information. Gets additional.
static void findDuplicatedPoints(const polyMesh &mesh, const indirectPrimitivePatch &pp, const bitSet &ppFlip, const bitSet &isBlockedFace, const bitSet &isDupPatchPoint, const bool extrude, faceList &isDupMeshPoint)
Helper: given patch and points on patch that are extruded.
static void calcExtrudeInfo(const bool zoneFromAnyFace, const polyMesh &, const globalIndex &globalFaces, const labelListList &globalEdgeFaces, const indirectPrimitivePatch &pp, labelList &edgePatchID, label &nPatches, Map< label > &nbrProcToPatch, Map< label > &patchToNbrProc, labelList &edgeZoneID, boolList &edgeFlip, labelList &inflateFaceID)
Determine extrude information per patch edge:
labelListList addedCells() const
Added cells given current mesh & layerfaces.
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
unsigned int count(const bool on=true) const
Count number of bits set.
Definition bitSetI.H:420
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition bitSetI.H:502
bitSet & unset(const bitSet &other)
Unset (subtract) the bits specified in the other bitset, which is a set difference corresponds to the...
Definition bitSetI.H:540
static const bitSet & null() noexcept
Return a null bitSet (reference to a nullObject).
Definition bitSet.H:138
A cell is defined as a list of faces with extra functionality.
Definition cell.H:56
void operator()(face &x, const face &y) const
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
static int compare(const edge &a, const edge &b)
Compare edges.
Definition edgeI.H:26
A subset of mesh faces organised as a primitive patch.
Definition faceZone.H:63
label whichFace(const label meshFaceID) const
The local index of the given mesh face, -1 if not in the zone.
Definition faceZone.H:394
const boolList & flipMap() const noexcept
Return face flip map.
Definition faceZone.H:389
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
label find(const Foam::edge &e) const
Find the edge within the face.
Definition face.C:791
face reverseFace() const
Return face with reverse direction.
Definition face.C:612
Determination and storage of the possible independent transforms introduced by coupledPolyPatches,...
Calculates a non-overlapping list of offsets based on an input size (eg, number of cells) from differ...
Definition globalIndex.H:77
label toLocal(const label proci, const label i) const
From global to local on proci.
label whichProcID(const label proci, const label i) const
Which processor does global id come from? Checks proci first (assumed to occur reasonably frequently)...
bool isLocal(const label proci, const label i) const
Is on processor proci.
label toGlobal(const label proci, const label i) const
From local to global on proci.
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
const labelListList & globalEdgeTransformedSlaves() const
const mapDistribute & globalEdgeSlavesMap() const
static void syncData(List< Type > &elems, const labelListList &slaves, const labelListList &transformedSlaves, const mapDistribute &slavesMap, const globalIndexAndTransform &, const CombineOp &cop, const TransformOp &top)
Helper: synchronise data with transforms.
const globalIndexAndTransform & globalTransforms() const
Global transforms numbering.
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
const labelListList & globalEdgeSlaves() const
const processorTopology & topology() const noexcept
The processor to processor topology.
Class containing processor-to-processor mapping information.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const labelList & reverseFaceMap() const noexcept
Reverse face map.
const labelList & reversePointMap() const noexcept
Reverse point map.
Class containing data for cell addition.
Definition polyAddCell.H:45
A face addition data class. A face can be inflated either from a point or from another face and can e...
Definition polyAddFace.H:50
Class containing data for point addition.
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
label whichPatch(const label meshFacei) const
Return patch index for a given mesh face index. Uses binary search.
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition polyMesh.H:671
virtual const faceList & faces() const
Return raw faces.
Definition polyMesh.C:1088
virtual const labelList & faceOwner() const
Return face owner.
Definition polyMesh.C:1101
const globalMeshData & globalData() const
Return parallel info (demand-driven).
Definition polyMesh.C:1296
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition polyMesh.C:1107
virtual const pointField & points() const
Return raw points.
Definition polyMesh.C:1063
Class describing modification of a face.
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
Direct mesh changes based on v1.3 polyTopoChange syntax.
label setAction(const topoAction &action)
For compatibility with polyTopoChange: set topological action.
void modifyFace(const face &f, const label facei, const label own, const label nei, const bool flipFaceFlux, const label patchID, const label zoneID, const bool zoneFlip, const bool multiZone=false)
Modify vertices or cell of face.
void modifyPoint(const label pointi, const point &pt, const label zoneID, const bool inCell, const bool multiZone=false)
Modify coordinate.
const DynamicList< point > & points() const
Points. Shrunk after constructing mesh (or calling of compact()).
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces).
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
label nInternalFaces() const noexcept
Number of internal faces.
label nCells() const noexcept
Number of mesh cells.
label nFaces() const noexcept
Number of mesh faces.
const labelListList & edgeFaces() const
const cellList & cells() const
label nEdges() const
Number of mesh edges.
label procPatchLookup(const label proci) const
Which local boundary is attached to specified neighbour processor.
static bitSet getInternalOrCoupledFaces(const polyMesh &mesh)
Get per face whether it is internal or coupled.
Definition syncTools.C:165
static void syncBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop, const TransformOp &top, const bool parRun=UPstream::parRun())
Synchronize values on boundary faces only.
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const bool parRun=UPstream::parRun())
Swap coupled boundary face values. Uses eqOp.
Definition syncTools.H:524
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top, const FlipOp &fop)
Synchronize values on all mesh edges.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
Dummy transform to be used with syncTools.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const bitSet isBlockedFace(intersectedFaces())
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for handling debugging switches.
Definition debug.C:45
const std::string patch
OpenFOAM patch number as a std::string.
Namespace for OpenFOAM.
List< edge > edgeList
List of edge.
Definition edgeList.H:32
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
List< label > labelList
A List of labels.
Definition List.H:62
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition HashSet.H:85
UIndirectList< label > labelUIndList
UIndirectList of labels.
ZoneMesh< faceZone, polyMesh > faceZoneMesh
A ZoneMesh with faceZone content on a polyMesh.
List< face > faceList
List of faces.
Definition faceListFwd.H:41
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition FlatOutput.H:217
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< 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...
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
vectorField pointField
pointField is a vectorField.
Vector< scalar > vector
Definition vector.H:57
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
UList< label > labelUList
A UList of labels.
Definition UList.H:75
Type gMax(const FieldField< Field, Type > &f)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
label newPointi
labelList f(nPoints)
label nPatches
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition stdFoam.H:315
List helper to append y unique elements onto the end of x.
Definition ListOps.H:721