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 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "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 
45 namespace 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 
94 Foam::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 
114 void 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)
137 bool Foam::addPatchCellLayer::sameEdgeNeighbour
138 (
139  const indirectPrimitivePatch& pp,
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.
165 Foam::labelPair Foam::addPatchCellLayer::getEdgeString
166 (
167  const indirectPrimitivePatch& pp,
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 
290 Foam::label Foam::addPatchCellLayer::addSideFace
291 (
292  const indirectPrimitivePatch& pp,
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  (
352  polyAddFace
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  (
435  polyAddFace
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 
462 void 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 
483 void Foam::addPatchCellLayer::setFaceProps
484 (
485  const polyMesh& mesh,
486  const indirectPrimitivePatch& pp,
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
619 Foam::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]];
656  }
657  }
658  }
659  return layerCells;
660 }
661 
662 
664 {
665  return addedCells(mesh_, layerFaces_);
666 }
667 
668 
670 (
671  const polyMesh& mesh,
672  const globalIndex& globalFaces,
673  const indirectPrimitivePatch& pp,
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,
718  ListOps::uniqueEqOp<label>(),
719  labelList() // null value
720  );
722  // Extract pp part
723  return labelListList(UIndirectList<labelList>(globalEdgeFaces, meshEdges));
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 
738 void Foam::addPatchCellLayer::markPatchEdges
739 (
740  const polyMesh& mesh,
741  const indirectPrimitivePatch& pp,
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,
783  orEqOp<unsigned int>(),
784  false // initial value
785  );
786 }
787 
788 
789 void Foam::addPatchCellLayer::globalEdgeInfo
790 (
791  const bool zoneFromAnyFace,
792 
793  const polyMesh& mesh,
794  const globalIndex& globalFaces,
795  const labelListList& edgeGlobalFaces,
796  const indirectPrimitivePatch& pp,
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 
936  const polyBoundaryMesh& patches = mesh.boundaryMesh();
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,
1026  maxEqOp<label>(),
1027  label(-1)
1028  );
1030  (
1031  mesh,
1032  meshEdgeToPatch,
1033  maxEqOp<label>(),
1034  label(-1)
1035  );
1037  (
1038  mesh,
1039  meshEdgeToZone,
1040  maxEqOp<label>(),
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,
1128  orEqOp<unsigned int>(),
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,
1152  const indirectPrimitivePatch& pp,
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,
1441  maxEqOp<label>(),
1442  dummyTransform()
1443  );
1445  (
1446  cppEdgeFlip,
1447  gd.globalEdgeSlaves(),
1448  gd.globalEdgeTransformedSlaves(),
1449  edgeMap,
1450  git,
1451  andEqOp<bool>(),
1452  dummyTransform()
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,
1480  const indirectPrimitivePatch& pp,
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());
1651  isBlockedFace.set(pp.addressing());
1652 
1653  // Some storage for edge-face-addressing.
1654  DynamicList<label> ef;
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,
1705  maxEqOp<label>(),
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,
1737  minEqOp<vector>(),
1738  vector::max
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
1839  labelList patchID(pp.size());
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  (
1943  polyAddPoint
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  (
1974  polyAddPoint
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  (
2042  polyAddCell
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  (
2207  polyAddFace
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  (
2263  polyModifyFace
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  (
2328  polyModifyFace
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  (
2380  polyAddFace
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,
2446  maxEqOp<label>(),
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:"
2706  << UIndirectList<point>
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:"
2721  << UIndirectList<point>
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,
2918  maxMagSqrEqOp<vector>(),
2919  vector::zero
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,
3263  const indirectPrimitivePatch& pp,
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 // ************************************************************************* //
label nPatches
Definition: readKivaGrid.H:394
label nPoints() const
Number of points supporting patch faces.
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:119
ZoneMesh< faceZone, polyMesh > faceZoneMesh
A ZoneMesh with faceZone content on a polyMesh.
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:502
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.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
const Field< point_type > & localPoints() const
Return pointField of points in patch.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:652
bool found(const Key &key) const
Same as contains()
Definition: HashTable.H:1370
static const bitSet & null() noexcept
Return a null bitSet (reference to a nullObject).
Definition: bitSet.H:138
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1107
List< edge > edgeList
List of edge.
Definition: edgeList.H:32
const bitSet isBlockedFace(intersectedFaces())
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.
const labelListList & pointEdges() const
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
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.
UIndirectList< label > labelUIndList
UIndirectList of labels.
Definition: IndirectList.H:65
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:518
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:
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1774
label nInternalEdges() const
Number of internal edges.
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:171
const cellList & cells() const
label k
Boltzmann constant.
label nFaces() const noexcept
Number of mesh faces.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field...
labelList faceLabels(nFaceLabels)
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
static bitSet getInternalOrCoupledFaces(const polyMesh &mesh)
Get per face whether it is internal or coupled.
Definition: syncTools.C:165
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:158
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
UList< label > labelUList
A UList of labels.
Definition: UList.H:76
const labelList & meshPoints() const
Return labelList of mesh points in patch.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1063
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:400
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 labelList & reverseFaceMap() const noexcept
Reverse face map.
Definition: mapPolyMesh.H:620
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
Dummy transform to be used with syncTools.
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
void operator()(face &x, const face &y) const
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
scalar y
A list of faces which address into the list of points.
Calculates a non-overlapping list of offsets based on an input size (eg, number of cells) from differ...
Definition: globalIndex.H:76
const Map< label > & meshPointMap() const
Mesh point map.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
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.
dynamicFvMesh & mesh
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
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:133
Adds layers of cells to outside (or inside) of polyMesh. Can optionally create stand-alone extruded m...
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:611
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
iterator find(const Key &key)
Find and return an iterator set at the hashed entry.
Definition: HashTableI.H:86
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
const Field< point_type > & faceCentres() const
Return face centres for patch.
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1101
const labelListList & edgeFaces() const
Return edge-face addressing.
const globalMeshData & globalData() const
Return parallel info (demand-driven)
Definition: polyMesh.C:1296
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
label nInternalFaces() const noexcept
Number of internal faces.
const labelList & reversePointMap() const noexcept
Reverse point map.
Definition: mapPolyMesh.H:582
Vector< scalar > vector
Definition: vector.H:57
const Field< point_type > & points() const noexcept
Return reference to global points.
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:576
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1088
label whichPatch(const label meshFacei) const
Return patch index for a given mesh face index. Uses binary search.
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.
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
label nEdges() const
Number of mesh edges.
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
label nEdges() const
Number of edges in patch.
int debug
Static debugging option.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
Type gMax(const FieldField< Field, Type > &f)
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:673
defineTypeNameAndDebug(combustionModel, 0)
const wordList edge
Standard (finite-area) edge field types (scalar, vector, tensor, etc)
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:451
labelList f(nPoints)
T & last()
Access last element of the list, position [size()-1].
Definition: UList.H:972
label whichZone(const label objectIndex) const
Given a global object index, return the zone it is in.
Definition: ZoneMesh.C:410
void updateMesh(const mapPolyMesh &, const labelList &faceMap, const labelList &pointMap)
Update any locally stored mesh information. Gets additional.
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
bool empty() const noexcept
True if the list is empty (ie, size() is zero).
Definition: PackedList.H:387
vector point
Point is a vector.
Definition: point.H:37
label toGlobal(const label proci, const label i) const
From local to global on proci.
Definition: globalIndexI.H:372
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:58
bool set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:468
#define WarningInFunction
Report a warning using Foam::Warning.
label newPointi
Definition: readKivaGrid.H:497
label nCells() const noexcept
Number of mesh cells.
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.
A List with indirect addressing. Like IndirectList but does not store addressing. ...
Definition: faMatrix.H:52
const polyBoundaryMesh & patches
const std::string patch
OpenFOAM patch number as a std::string.
const labelListList & faceEdges() const
Return face-edge addressing.
label n
labelListList addedCells() const
Added cells given current mesh & layerfaces.
Field< vector > vectorField
Specialisation of Field<T> for vector.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:76
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: stdFoam.H:416
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.
List< label > labelList
A List of labels.
Definition: List.H:61
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
List< bool > boolList
A List of bools.
Definition: List.H:59
bool found
void setSize(label n)
Alias for resize()
Definition: List.H:535
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
label size() const noexcept
Number of entries.
Definition: PackedList.H:392
const labelListList & edgeFaces() const
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
static int compare(const edge &a, const edge &b)
Compare edges.
Definition: edgeI.H:26
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:217
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127