fvMeshSubset.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-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2022,2024 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 "fvMeshSubset.H"
30 #include "BitOps.H"
31 #include "Pstream.H"
32 #include "cyclicPolyPatch.H"
33 #include "emptyPolyPatch.H"
34 #include "processorPolyPatch.H"
35 #include "meshPointPatch.H"
36 #include "processorPointPatch.H"
37 
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
42  word fvMeshSubset::exposedPatchName("oldInternalFaces");
43  defineTypeNameAndDebug(fvMeshSubset, 0);
44 }
45 
46 
47 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
48 
49 namespace
50 {
51 
52 // Mark faces/points (with 0) in labelList
53 inline void markUsed
54 (
55  const Foam::labelUList& locations,
56  Foam::labelList& map
57 )
58 {
59  for (auto idx : locations)
60  {
61  map[idx] = 0;
62  }
63 }
64 
65 } // End anonymous namespace
66 
67 
68 namespace Foam
69 {
70 
71 // Perform a subset of a subset
73 (
74  const label nElems,
75  const labelUList& selectedElements, // First subset
76  const labelUList& subsetMap // Subset within first subset
77 )
78 {
79  if (selectedElements.empty() || subsetMap.empty())
80  {
81  // Trivial case
82  return labelList();
83  }
84 
85  // Mark selected elements.
86  const bitSet selected(nElems, selectedElements);
87 
88  // Count subset of selected elements
89  label n = 0;
90  forAll(subsetMap, i)
91  {
92  if (selected[subsetMap[i]])
93  {
94  ++n;
95  }
96  }
97 
98  // Collect selected elements
99  labelList subsettedElements(n);
100  n = 0;
101 
102  forAll(subsetMap, i)
103  {
104  if (selected[subsetMap[i]])
105  {
106  subsettedElements[n] = i;
107  ++n;
108  }
109  }
110 
111  return subsettedElements;
112 }
113 
114 } // End namespace Foam
115 
116 
117 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
118 
120 {
121  if (!subMeshPtr_)
122  {
124  << "Mesh is not subsetted!" << nl
125  << abort(FatalError);
126 
127  return false;
128  }
129 
130  return true;
131 }
132 
133 
134 void Foam::fvMeshSubset::calcFaceFlipMap() const
135 {
136  const labelList& subToBaseFace = faceMap();
137  const labelList& subToBaseCell = cellMap();
138 
139  faceFlipMapPtr_.reset(new labelList(subToBaseFace.size()));
140  auto& faceFlipMap = *faceFlipMapPtr_;
141 
142  // Only exposed internal faces might be flipped (since we don't do
143  // any cell renumbering, just compacting)
144  const label subInt = subMesh().nInternalFaces();
145 
146  const labelList& subOwn = subMesh().faceOwner();
147  const labelList& own = baseMesh_.faceOwner();
148 
149  for (label subFaceI = 0; subFaceI < subInt; ++subFaceI)
150  {
151  faceFlipMap[subFaceI] = subToBaseFace[subFaceI]+1;
152  }
153  for (label subFaceI = subInt; subFaceI < subOwn.size(); ++subFaceI)
154  {
155  const label faceI = subToBaseFace[subFaceI];
156  if (subToBaseCell[subOwn[subFaceI]] == own[faceI])
157  {
158  faceFlipMap[subFaceI] = faceI+1;
159  }
160  else
161  {
162  faceFlipMap[subFaceI] = -faceI-1;
163  }
164  }
165 }
166 
167 
168 void Foam::fvMeshSubset::doCoupledPatches
169 (
170  const bool syncPar,
171  labelUList& nCellsUsingFace
172 ) const
173 {
174  // Synchronize facesToSubset on both sides of coupled patches.
175  // Marks faces that become 'uncoupled' with 3.
176 
177  const polyBoundaryMesh& oldPatches = baseMesh().boundaryMesh();
178 
179  label nUncoupled = 0;
180 
181  if (syncPar && UPstream::parRun())
182  {
183  PstreamBuffers pBufs;
184 
185  // Send face usage across processor patches
186  if (!nCellsUsingFace.empty())
187  {
188  for (const polyPatch& pp : oldPatches)
189  {
190  const auto* procPatch = isA<processorPolyPatch>(pp);
191 
192  if (procPatch)
193  {
194  const label nbrProci = procPatch->neighbProcNo();
195 
196  UOPstream toNbr(nbrProci, pBufs);
197  toNbr <<
198  SubList<label>(nCellsUsingFace, pp.size(), pp.start());
199  }
200  }
201  }
202 
203  pBufs.finishedSends();
204 
205  // Receive face usage count and check for faces that become uncoupled.
206  for (const polyPatch& pp : oldPatches)
207  {
208  const auto* procPatch = isA<processorPolyPatch>(pp);
209 
210  if (procPatch)
211  {
212  const label nbrProci = procPatch->neighbProcNo();
213 
214  if (!pBufs.recvDataCount(nbrProci))
215  {
216  // Nothing to receive
217  continue;
218  }
219 
220  labelList nbrCellsUsingFace;
221  {
222  UIPstream fromNbr(nbrProci, pBufs);
223  fromNbr >> nbrCellsUsingFace;
224  }
225 
226  if (!nCellsUsingFace.empty() && !nbrCellsUsingFace.empty())
227  {
228  // Combine with this side.
229 
230  forAll(pp, i)
231  {
232  if
233  (
234  nCellsUsingFace[pp.start()+i] == 1
235  && nbrCellsUsingFace[i] == 0
236  )
237  {
238  // Face's neighbour is no longer there.
239  // Mark face off as coupled
240  nCellsUsingFace[pp.start()+i] = 3;
241  ++nUncoupled;
242  }
243  }
244  }
245  }
246  }
247  }
248 
249  // Do same for cyclics.
250  for (const polyPatch& pp : oldPatches)
251  {
252  const cyclicPolyPatch* cpp = isA<cyclicPolyPatch>(pp);
253 
254  if (cpp && !nCellsUsingFace.empty())
255  {
256  const auto& cycPatch = *cpp;
257 
258  forAll(cycPatch, i)
259  {
260  label thisFacei = cycPatch.start() + i;
261  label otherFacei = cycPatch.transformGlobalFace(thisFacei);
262 
263  if
264  (
265  nCellsUsingFace[thisFacei] == 1
266  && nCellsUsingFace[otherFacei] == 0
267  )
268  {
269  nCellsUsingFace[thisFacei] = 3;
270  ++nUncoupled;
271  }
272  }
273  }
274  }
275 
276  if (syncPar)
277  {
278  reduce(nUncoupled, sumOp<label>());
279  }
280 
281  if (nUncoupled)
282  {
283  Info<< "Uncoupled " << nUncoupled << " faces on coupled patches. "
284  << "(processorPolyPatch, cyclicPolyPatch)" << endl;
285  }
286 }
287 
288 
289 void Foam::fvMeshSubset::subsetZones()
290 {
291  // Keep all zones, even if zero size.
292 
293  #ifdef FULLDEBUG
294  checkHasSubMesh();
295  #endif
296 
297  auto& newSubMesh = subMeshPtr_();
298 
299  // PointZones
300 
301  const pointZoneMesh& pointZones = baseMesh().pointZones();
302 
303  List<pointZone*> pZones(pointZones.size());
304 
305  forAll(pointZones, zonei)
306  {
307  const pointZone& pz = pointZones[zonei];
308 
309  pZones[zonei] = new pointZone
310  (
311  pz.name(),
312  subsetSubset(baseMesh().nPoints(), pz, pointMap()),
313  zonei,
314  newSubMesh.pointZones()
315  );
316  }
317 
318 
319  // FaceZones
320  // Do we need to remove zones where the side we're interested in
321  // no longer exists? Guess not.
322 
323  const faceZoneMesh& faceZones = baseMesh().faceZones();
324 
325  List<faceZone*> fZones(faceZones.size());
326 
327  forAll(faceZones, zonei)
328  {
329  const faceZone& fz = faceZones[zonei];
330 
331  // Expand faceZone to full mesh
332  // +1 : part of faceZone, flipped
333  // -1 : ,, , unflipped
334  // 0 : not part of faceZone
335  labelList zone(baseMesh().nFaces(), Zero);
336  forAll(fz, j)
337  {
338  zone[fz[j]] = (fz.flipMap()[j] ? 1 : -1);
339  }
340 
341  // Select faces
342  label nSub = 0;
343  forAll(faceMap(), j)
344  {
345  if (zone[faceMap()[j]] != 0)
346  {
347  ++nSub;
348  }
349  }
350  labelList subAddressing(nSub);
351  boolList subFlipStatus(nSub);
352  nSub = 0;
353  forAll(faceMap(), subFacei)
354  {
355  const label meshFacei = faceMap()[subFacei];
356  if (zone[meshFacei] != 0)
357  {
358  subAddressing[nSub] = subFacei;
359  const label subOwner = subMesh().faceOwner()[subFacei];
360  const label baseOwner = baseMesh().faceOwner()[meshFacei];
361  // If subowner is the same cell as the base keep the flip status
362  const bool sameOwner = (cellMap()[subOwner] == baseOwner);
363  const bool flip = (zone[meshFacei] == 1);
364  subFlipStatus[nSub] = (sameOwner == flip);
365 
366  ++nSub;
367  }
368  }
369 
370  fZones[zonei] = new faceZone
371  (
372  fz.name(),
373  subAddressing,
374  subFlipStatus,
375  zonei,
376  newSubMesh.faceZones()
377  );
378  }
379 
380 
381  // Cell Zones
382 
383  const cellZoneMesh& cellZones = baseMesh().cellZones();
384 
385  List<cellZone*> cZones(cellZones.size());
386 
387  forAll(cellZones, zonei)
388  {
389  const cellZone& cz = cellZones[zonei];
390 
391  cZones[zonei] = new cellZone
392  (
393  cz.name(),
394  subsetSubset(baseMesh().nCells(), cz, cellMap()),
395  zonei,
396  newSubMesh.cellZones()
397  );
398  }
399 
400  // Add the zones
401  newSubMesh.addZones(pZones, fZones, cZones);
402 }
403 
404 
405 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
406 
408 :
409  baseMesh_(baseMesh),
410  subMeshPtr_(nullptr),
411  faceFlipMapPtr_(nullptr),
412  pointMap_(),
413  faceMap_(),
414  cellMap_(),
415  patchMap_()
416 {}
417 
418 
419 Foam::fvMeshSubset::fvMeshSubset(const fvMesh& baseMesh, const Foam::zero)
420 :
421  fvMeshSubset(baseMesh)
422 {
423  reset(Foam::zero{});
424 }
425 
426 
428 (
429  const fvMesh& baseMesh,
430  const bitSet& selectedCells,
431  const label patchID,
432  const bool syncPar
433 )
434 :
435  fvMeshSubset(baseMesh)
436 {
437  reset(selectedCells, patchID, syncPar);
438 }
439 
440 
442 (
443  const fvMesh& baseMesh,
444  const labelUList& selectedCells,
445  const label patchID,
446  const bool syncPar
447 )
448 :
449  fvMeshSubset(baseMesh)
450 {
451  reset(selectedCells, patchID, syncPar);
452 }
453 
454 
456 (
457  const fvMesh& baseMesh,
458  const labelHashSet& selectedCells,
459  const label patchID,
460  const bool syncPar
461 )
462 :
463  fvMeshSubset(baseMesh)
464 {
465  reset(selectedCells, patchID, syncPar);
466 }
467 
468 
470 (
471  const fvMesh& baseMesh,
472  const label regioni,
473  const labelUList& regions,
474  const label patchID,
475  const bool syncPar
476 )
477 :
478  fvMeshSubset(baseMesh)
479 {
480  reset(regioni, regions, patchID, syncPar);
481 }
482 
483 
484 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
485 
487 {
488  subMeshPtr_.reset(nullptr);
489  faceFlipMapPtr_.reset(nullptr);
490 
491  pointMap_.clear();
492  faceMap_.clear();
493  cellMap_.clear();
494  patchMap_.clear();
495 }
496 
497 
499 {
500  clear();
501 }
502 
503 
505 (
506  autoPtr<fvMesh>&& subMeshPtr,
507  labelList&& pointMap,
508  labelList&& faceMap,
509  labelList&& cellMap,
510  labelList&& patchMap
511 )
512 {
513  subMeshPtr_.reset(std::move(subMeshPtr));
514  faceFlipMapPtr_.reset(nullptr);
515 
516  pointMap_ = std::move(pointMap);
517  faceMap_ = std::move(faceMap);
518  cellMap_ = std::move(cellMap);
519  patchMap_ = std::move(patchMap);
520 
521  // Sanity
522  if (!subMeshPtr_)
523  {
524  clear();
525  }
526 }
527 
528 
530 {
531  // Was old pointMesh present?
532  const auto* basePointMeshPtr =
533  baseMesh_.thisDb().cfindObject<pointMesh>(pointMesh::typeName);
534  if (basePointMeshPtr)
535  {
536  DebugPout<< "fvMeshSubset::reset(const Foam::zero) :"
537  << " Detected pointMesh" << endl;
538  }
539 
540 
541  clear();
542 
543  // Create zero-sized subMesh
544  subMeshPtr_.reset
545  (
546  new fvMesh
547  (
548  IOobject
549  (
550  baseMesh_.name(),
551  baseMesh_.time().timeName(),
552  baseMesh_.time(),
553  IOobject::NO_READ, // Do not read any dictionaries
555  ),
556  baseMesh_, // Get dictionaries from base mesh
557  Foam::zero{} // zero-sized
558  // Uses syncPar (bounds) - should generally be OK
559  )
560  );
561  auto& newSubMesh = subMeshPtr_();
562 
563 
564  // Clone non-processor patches
565  {
566  const polyBoundaryMesh& oldBoundary = baseMesh_.boundaryMesh();
567  const polyBoundaryMesh& newBoundary = newSubMesh.boundaryMesh();
568 
569  polyPatchList newPatches(oldBoundary.nNonProcessor());
570 
571  patchMap_ = identity(newPatches.size());
572 
573  forAll(newPatches, patchi)
574  {
575  newPatches.set
576  (
577  patchi,
578  oldBoundary[patchi].clone
579  (
580  newBoundary,
581  patchi,
582  0, // patch size
583  0 // patch start
584  )
585  );
586  }
587 
588  // Add patches - make sure we don't trigger any parallel side effects
589  newSubMesh.addFvPatches(newPatches, false);
590  }
591 
592 
593  // Clone old additional point patches
594  if (basePointMeshPtr)
595  {
596  DebugPout<< "Subsetting pointMesh" << endl;
597  const auto& basePointMesh = *basePointMeshPtr;
598  const auto& oldPointBoundary = basePointMesh.boundary();
599 
600  // 1. Generate pointBoundaryMesh from polyBoundaryMesh (so ignoring
601  // any additional patches
602  const auto& newSubPointMesh = pointMesh::New(newSubMesh);
603 
604  auto& newBoundary =
605  const_cast<pointBoundaryMesh&>(newSubPointMesh.boundary());
606 
607  // Start off from (poly)patch map
608  pointPatchMap_ = patchMap_;
609 
610  // 2. Explicitly add subsetted meshPointPatches
611  for (const auto& oldPointPatch : oldPointBoundary)
612  {
613  const auto* mppPtr = isA<meshPointPatch>(oldPointPatch);
614  if (mppPtr && (newBoundary.findPatchID(mppPtr->name()) == -1))
615  {
616  newBoundary.push_back
617  (
618  mppPtr->clone
619  (
620  newBoundary,
621  newBoundary.size(),
622  labelList::null(), // map
623  labelList::null() // map
624  )
625  );
626  }
627  }
628 
629  // Extend patchMap with -1
630  pointPatchMap_.setSize(newBoundary.size(), -1);
631  }
633  // Add the zones
634  subsetZones();
635 }
636 
637 
639 (
640  const bitSet& selectedCells,
641  const label patchID,
642  const bool syncPar
643 )
644 {
645  // Was old pointMesh present?
646  const auto* basePointMeshPtr =
647  baseMesh_.thisDb().cfindObject<pointMesh>(pointMesh::typeName);
648  if (basePointMeshPtr)
649  {
650  DebugPout<< "fvMeshSubset::reset(const bitSet&) :"
651  << " Detected pointMesh" << endl;
652  }
653 
654 
655  // Clear all old maps and pointers
656  clear();
657 
658  const cellList& oldCells = baseMesh().cells();
659  const faceList& oldFaces = baseMesh().faces();
660  const pointField& oldPoints = baseMesh().points();
661  const labelList& oldOwner = baseMesh().faceOwner();
662  const labelList& oldNeighbour = baseMesh().faceNeighbour();
663  const polyBoundaryMesh& oldPatches = baseMesh().boundaryMesh();
664  const label oldNInternalFaces = baseMesh().nInternalFaces();
665 
666  // Initial check on patches before doing anything time consuming.
667 
668  label wantedPatchID = patchID;
669 
670  if (wantedPatchID == -1)
671  {
672  // No explicit patch specified. Put in oldInternalFaces patch.
673  // Check if patch with this name already exists.
674  wantedPatchID = oldPatches.findPatchID(exposedPatchName);
675  }
676  else if (wantedPatchID < 0 || wantedPatchID >= oldPatches.size())
677  {
679  << "Non-existing patch index " << wantedPatchID << endl
680  << "Should be between 0 and " << oldPatches.size()-1
681  << abort(FatalError);
682  }
683 
684  // The selected cells - sorted in ascending order
685  cellMap_ = selectedCells.sortedToc();
686 
687  // The selectedCells should normally be in the [0,nCells) range,
688  // but it is better not to trust that.
689  {
690  label len = cellMap_.size();
691  for
692  (
693  label i = len-1;
694  i >= 0 && (cellMap_[i] >= oldCells.size());
695  --i
696  )
697  {
698  len = i;
699  }
700  cellMap_.resize(len);
701  }
702 
703 
704  // Mark all used faces. Count number of cells using them
705  // 0: face not used anymore
706  // 1: face used by one cell, face becomes/stays boundary face
707  // 2: face still used and remains internal face
708  // 3: face coupled and used by one cell only (so should become normal,
709  // non-coupled patch face)
710  //
711  // Note that this is not really necessary - but means we can size things
712  // correctly. Also makes handling coupled faces much easier.
713 
714  labelList nCellsUsingFace(oldFaces.size(), Zero);
715 
716  label nFacesInSet = 0;
717 
718  forAll(oldFaces, oldFacei)
719  {
720  bool faceUsed = false;
721 
722  if (selectedCells.test(oldOwner[oldFacei]))
723  {
724  ++nCellsUsingFace[oldFacei];
725  faceUsed = true;
726  }
727 
728  if
729  (
730  baseMesh().isInternalFace(oldFacei)
731  && selectedCells.test(oldNeighbour[oldFacei])
732  )
733  {
734  ++nCellsUsingFace[oldFacei];
735  faceUsed = true;
736  }
737 
738  if (faceUsed)
739  {
740  ++nFacesInSet;
741  }
742  }
743  faceMap_.resize(nFacesInSet);
744 
745  // Handle coupled faces. Modifies patch faces to be uncoupled to 3.
746  doCoupledPatches(syncPar, nCellsUsingFace);
747 
748 
749  // See which patch to use for exposed internal faces.
750  label oldInternalPatchID = 0;
751 
752  // Insert faces before which patch
753  label nextPatchID = oldPatches.size();
754 
755  // old to new patches
756  labelList globalPatchMap(oldPatches.size());
757 
758  // New patch size
759  label nbSize = oldPatches.size();
760 
761  if (wantedPatchID == -1)
762  {
763  // Create 'oldInternalFaces' patch at the end (or before
764  // processorPatches)
765  // and put all exposed internal faces in there.
766 
767  forAll(oldPatches, patchi)
768  {
769  if (isA<processorPolyPatch>(oldPatches[patchi]))
770  {
771  nextPatchID = patchi;
772  break;
773  }
774  ++oldInternalPatchID;
775  }
776 
777  ++nbSize;
778 
779  // adapt old to new patches for inserted patch
780  for (label oldPatchi = 0; oldPatchi < nextPatchID; oldPatchi++)
781  {
782  globalPatchMap[oldPatchi] = oldPatchi;
783  }
784  for
785  (
786  label oldPatchi = nextPatchID;
787  oldPatchi < oldPatches.size();
788  oldPatchi++
789  )
790  {
791  globalPatchMap[oldPatchi] = oldPatchi+1;
792  }
793  }
794  else
795  {
796  oldInternalPatchID = wantedPatchID;
797  nextPatchID = wantedPatchID+1;
798 
799  // old to new patches
800  globalPatchMap = identity(oldPatches.size());
801  }
802 
803  labelList boundaryPatchSizes(nbSize, Zero);
804 
805 
806  // Make a global-to-local point map
807  labelList globalPointMap(oldPoints.size(), -1);
808  labelList globalFaceMap(oldFaces.size(), -1);
809 
810  label facei = 0;
811 
812  // 1. Pick up all preserved internal faces.
813  for (label oldFacei = 0; oldFacei < oldNInternalFaces; ++oldFacei)
814  {
815  if (nCellsUsingFace[oldFacei] == 2)
816  {
817  globalFaceMap[oldFacei] = facei;
818  faceMap_[facei++] = oldFacei;
819 
820  // Mark all points from the face
821  markUsed(oldFaces[oldFacei], globalPointMap);
822  }
823  }
824 
825  // These are all the internal faces in the mesh.
826  const label nInternalFaces = facei;
827 
828  // 2. Boundary faces up to where we want to insert old internal faces
829  for
830  (
831  label oldPatchi = 0;
832  oldPatchi < oldPatches.size()
833  && oldPatchi < nextPatchID;
834  oldPatchi++
835  )
836  {
837  const polyPatch& oldPatch = oldPatches[oldPatchi];
838 
839  label oldFacei = oldPatch.start();
840 
841  forAll(oldPatch, i)
842  {
843  if (nCellsUsingFace[oldFacei] == 1)
844  {
845  // Boundary face is kept.
846 
847  // Mark face and increment number of points in set
848  globalFaceMap[oldFacei] = facei;
849  faceMap_[facei++] = oldFacei;
850 
851  // Mark all points from the face
852  markUsed(oldFaces[oldFacei], globalPointMap);
853 
854  // Increment number of patch faces
855  ++boundaryPatchSizes[globalPatchMap[oldPatchi]];
856  }
857  ++oldFacei;
858  }
859  }
860 
861  // 3a. old internal faces that have become exposed.
862  for (label oldFacei = 0; oldFacei < oldNInternalFaces; ++oldFacei)
863  {
864  if (nCellsUsingFace[oldFacei] == 1)
865  {
866  globalFaceMap[oldFacei] = facei;
867  faceMap_[facei++] = oldFacei;
868 
869  // Mark all points from the face
870  markUsed(oldFaces[oldFacei], globalPointMap);
871 
872  // Increment number of patch faces
873  ++boundaryPatchSizes[oldInternalPatchID];
874  }
875  }
876 
877  // 3b. coupled patch faces that have become uncoupled.
878  for
879  (
880  label oldFacei = oldNInternalFaces;
881  oldFacei < oldFaces.size();
882  oldFacei++
883  )
884  {
885  if (nCellsUsingFace[oldFacei] == 3)
886  {
887  globalFaceMap[oldFacei] = facei;
888  faceMap_[facei++] = oldFacei;
889 
890  // Mark all points from the face
891  markUsed(oldFaces[oldFacei], globalPointMap);
892 
893  // Increment number of patch faces
894  ++boundaryPatchSizes[oldInternalPatchID];
895  }
896  }
897 
898  // 4. Remaining boundary faces
899  for
900  (
901  label oldPatchi = nextPatchID;
902  oldPatchi < oldPatches.size();
903  oldPatchi++
904  )
905  {
906  const polyPatch& oldPatch = oldPatches[oldPatchi];
907 
908  label oldFacei = oldPatch.start();
909 
910  forAll(oldPatch, i)
911  {
912  if (nCellsUsingFace[oldFacei] == 1)
913  {
914  // Boundary face is kept.
915 
916  // Mark face and increment number of points in set
917  globalFaceMap[oldFacei] = facei;
918  faceMap_[facei++] = oldFacei;
919 
920  // Mark all points from the face
921  markUsed(oldFaces[oldFacei], globalPointMap);
922 
923  // Increment number of patch faces
924  ++boundaryPatchSizes[globalPatchMap[oldPatchi]];
925  }
926  ++oldFacei;
927  }
928  }
929 
930  if (facei != nFacesInSet)
931  {
933  << "Problem" << abort(FatalError);
934  }
935 
936 
937  // Grab the points map
938  label nPointsInSet = 0;
939 
940  forAll(globalPointMap, pointi)
941  {
942  if (globalPointMap[pointi] != -1)
943  {
944  ++nPointsInSet;
945  }
946  }
947  pointMap_.setSize(nPointsInSet);
948 
949  nPointsInSet = 0;
950 
951  forAll(globalPointMap, pointi)
952  {
953  if (globalPointMap[pointi] != -1)
954  {
955  pointMap_[nPointsInSet] = pointi;
956  globalPointMap[pointi] = nPointsInSet;
957  ++nPointsInSet;
958  }
959  }
960 
961 
962  //Pout<< "Number of points,faces,cells in new mesh : "
963  // << pointMap_.size() << ' '
964  // << faceMap_.size() << ' '
965  // << cellMap_.size() << nl;
966 
967 
968  // Make a new mesh
969 
970  //
971  // Create new points
972  //
973  pointField newPoints(oldPoints, pointMap_);
974 
975 
976  //
977  // Create new faces
978  //
979 
980  faceList newFaces(faceMap_.size());
981  {
982  auto iter = newFaces.begin();
983  const auto& renumbering = globalPointMap;
984 
985  // Internal faces
986  for (label facei = 0; facei < nInternalFaces; ++facei)
987  {
988  face& newItem = *iter;
989  ++iter;
990 
991  const face& oldItem = oldFaces[faceMap_[facei]];
992 
993  // Copy relabelled
994  newItem.resize(oldItem.size());
995 
996  forAll(oldItem, i)
997  {
998  newItem[i] = renumbering[oldItem[i]];
999  }
1000  }
1001 
1002  // Boundary faces - may need to be flipped
1003  for (label facei = nInternalFaces; facei < faceMap_.size(); ++facei)
1004  {
1005  const label oldFacei = faceMap_[facei];
1006 
1007  face& newItem = *iter;
1008  ++iter;
1009 
1010  const face oldItem =
1011  (
1012  (
1013  baseMesh().isInternalFace(oldFacei)
1014  && selectedCells.test(oldNeighbour[oldFacei])
1015  && !selectedCells.test(oldOwner[oldFacei])
1016  )
1017  // Face flipped to point outwards
1018  ? oldFaces[oldFacei].reverseFace()
1019  : oldFaces[oldFacei]
1020  );
1021 
1022  // Copy relabelled
1023  newItem.resize(oldItem.size());
1024 
1025  forAll(oldItem, i)
1026  {
1027  newItem[i] = renumbering[oldItem[i]];
1028  }
1029  }
1030  }
1031 
1032 
1033  //
1034  // Create new cells
1035  //
1036 
1037  cellList newCells(cellMap_.size());
1038  {
1039  auto iter = newCells.begin();
1040  const auto& renumbering = globalFaceMap;
1041 
1042  for (const label oldCelli : cellMap_)
1043  {
1044  cell& newItem = *iter;
1045  ++iter;
1046 
1047  const labelList& oldItem = oldCells[oldCelli];
1048 
1049  // Copy relabelled
1050  newItem.resize(oldItem.size());
1051 
1052  forAll(oldItem, i)
1053  {
1054  newItem[i] = renumbering[oldItem[i]];
1055  }
1056  }
1057  }
1058 
1059 
1060  // Make a new mesh
1061  //
1062  // Note that mesh gets registered with same name as original mesh.
1063  // This is not proper but cannot be avoided since otherwise
1064  // surfaceInterpolation cannot find its fvSchemes.
1065  // It will try to read, for example. "system/region0SubSet/fvSchemes"
1066  //
1067  subMeshPtr_ = autoPtr<fvMesh>::New
1068  (
1069  IOobject
1070  (
1071  baseMesh_.name(),
1072  baseMesh_.time().timeName(),
1073  baseMesh_.time(),
1074  IOobject::NO_READ, // Do not read any dictionaries
1076  ),
1077  baseMesh_, // Get dictionaries from base mesh
1078  std::move(newPoints),
1079  std::move(newFaces),
1080  std::move(newCells),
1081  syncPar // parallel synchronisation
1082  );
1083 
1084 
1085  // Add old patches
1086  polyPatchList newBoundary(nbSize);
1087  patchMap_.resize(nbSize);
1088  label nNewPatches = 0;
1089  label patchStart = nInternalFaces;
1090 
1091 
1092  // For parallel: only remove patch if none of the processors has it.
1093  // This only gets done for patches before the one being inserted
1094  // (so patches < nextPatchID)
1095 
1096  // Get sum of patch sizes. Zero if patch can be deleted.
1097  labelList globalPatchSizes(boundaryPatchSizes);
1098  globalPatchSizes.setSize(nextPatchID);
1099 
1100  if (syncPar && Pstream::parRun())
1101  {
1102  // Get patch names (up to nextPatchID)
1103  List<wordList> patchNames(Pstream::nProcs());
1104  patchNames[Pstream::myProcNo()] = oldPatches.names();
1105  patchNames[Pstream::myProcNo()].setSize(nextPatchID);
1107 
1108  // Get patch sizes (up to nextPatchID).
1109  // Note that up to nextPatchID the globalPatchMap is an identity so
1110  // no need to index through that.
1111  Pstream::listReduce(globalPatchSizes, sumOp<label>());
1112 
1113  // Now all processors have all the patchnames.
1114  // Decide: if all processors have the same patch names and size is zero
1115  // everywhere remove the patch.
1116  bool samePatches = true;
1117 
1118  for (label proci = 1; proci < patchNames.size(); ++proci)
1119  {
1120  if (patchNames[proci] != patchNames[0])
1121  {
1122  samePatches = false;
1123  break;
1124  }
1125  }
1126 
1127  if (!samePatches)
1128  {
1129  // Patchnames not sync on all processors so disable removal of
1130  // zero sized patches.
1131  globalPatchSizes = labelMax;
1132  }
1133  }
1134 
1135 
1136  // Old patches
1137 
1138  for
1139  (
1140  label oldPatchi = 0;
1141  oldPatchi < oldPatches.size()
1142  && oldPatchi < nextPatchID;
1143  oldPatchi++
1144  )
1145  {
1146  const label newSize = boundaryPatchSizes[globalPatchMap[oldPatchi]];
1147 
1148  if (oldInternalPatchID != oldPatchi)
1149  {
1150  // Pure subset of patch faces (no internal faces added to this
1151  // patch). Can use mapping.
1152  labelList map(newSize);
1153  for (label patchFacei = 0; patchFacei < newSize; patchFacei++)
1154  {
1155  const label facei = patchStart+patchFacei;
1156  const label oldFacei = faceMap_[facei];
1157  map[patchFacei] = oldPatches[oldPatchi].whichFace(oldFacei);
1158  }
1159 
1160  newBoundary.set
1161  (
1162  nNewPatches,
1163  oldPatches[oldPatchi].clone
1164  (
1165  subMeshPtr_().boundaryMesh(),
1166  nNewPatches,
1167  map,
1168  patchStart
1169  )
1170  );
1171  }
1172  else
1173  {
1174  // Clone (even if 0 size)
1175  newBoundary.set
1176  (
1177  nNewPatches,
1178  oldPatches[oldPatchi].clone
1179  (
1180  subMeshPtr_().boundaryMesh(),
1181  nNewPatches,
1182  newSize,
1183  patchStart
1184  )
1185  );
1186  }
1187 
1188  patchStart += newSize;
1189  patchMap_[nNewPatches] = oldPatchi; // compact patchMap
1190  ++nNewPatches;
1191  }
1192 
1193  // Inserted patch
1194 
1195  label newInternalPatchID = -1;
1196 
1197  if (wantedPatchID == -1)
1198  {
1199  label oldInternalSize = boundaryPatchSizes[oldInternalPatchID];
1200 
1201  if (syncPar)
1202  {
1203  reduce(oldInternalSize, sumOp<label>());
1204  }
1205 
1206  // Newly created patch so is at end. Check if any faces in it.
1207  if (oldInternalSize > 0)
1208  {
1209  newBoundary.set
1210  (
1211  nNewPatches,
1212  new emptyPolyPatch
1213  (
1214  exposedPatchName,
1215  boundaryPatchSizes[oldInternalPatchID],
1216  patchStart,
1217  nNewPatches,
1218  subMeshPtr_().boundaryMesh(),
1219  emptyPolyPatch::typeName
1220  )
1221  );
1222 
1223  //Pout<< " " << exposedPatchName << " : "
1224  // << boundaryPatchSizes[oldInternalPatchID] << endl;
1225 
1226  // The index for the first patch is -1 as it originates from
1227  // the internal faces
1228  patchStart += boundaryPatchSizes[oldInternalPatchID];
1229  patchMap_[nNewPatches] = -1;
1230  newInternalPatchID = nNewPatches;
1231  ++nNewPatches;
1232  }
1233  }
1234 
1235  // Old patches
1236 
1237  for
1238  (
1239  label oldPatchi = nextPatchID;
1240  oldPatchi < oldPatches.size();
1241  oldPatchi++
1242  )
1243  {
1244  const label newSize = boundaryPatchSizes[globalPatchMap[oldPatchi]];
1245 
1246  if (oldInternalPatchID != oldPatchi)
1247  {
1248  // Pure subset of patch faces (no internal faces added to this
1249  // patch). Can use mapping.
1250  labelList map(newSize);
1251  for (label patchFacei = 0; patchFacei < newSize; patchFacei++)
1252  {
1253  const label facei = patchStart+patchFacei;
1254  const label oldFacei = faceMap_[facei];
1255  map[patchFacei] = oldPatches[oldPatchi].whichFace(oldFacei);
1256  }
1257 
1258  newBoundary.set
1259  (
1260  nNewPatches,
1261  oldPatches[oldPatchi].clone
1262  (
1263  subMeshPtr_().boundaryMesh(),
1264  nNewPatches,
1265  map,
1266  patchStart
1267  )
1268  );
1269  }
1270  else
1271  {
1272  // Patch still exists. Add it
1273  newBoundary.set
1274  (
1275  nNewPatches,
1276  oldPatches[oldPatchi].clone
1277  (
1278  subMeshPtr_().boundaryMesh(),
1279  nNewPatches,
1280  newSize,
1281  patchStart
1282  )
1283  );
1284  }
1285 
1286  //Pout<< " " << oldPatches[oldPatchi].name() << " : "
1287  // << newSize << endl;
1288 
1289  patchStart += newSize;
1290  patchMap_[nNewPatches] = oldPatchi; // compact patchMap
1291  ++nNewPatches;
1292  }
1293 
1294 
1295  // Reset the patch lists
1296  newBoundary.resize(nNewPatches);
1297  patchMap_.resize(nNewPatches);
1298 
1299 
1300  // Add the fvPatches
1301  subMeshPtr_().addFvPatches(newBoundary, syncPar);
1302 
1303  // Subset and add any zones
1304  subsetZones();
1305 
1306 
1307  if (basePointMeshPtr)
1308  {
1309  DebugPout<< "Subsetting pointMesh" << endl;
1310  const auto& basePointMesh = *basePointMeshPtr;
1311  const auto& oldPointBoundary = basePointMesh.boundary();
1312 
1313  // 1. Generate pointBoundaryMesh from polyBoundaryMesh (so ignoring
1314  // any additional patches
1315  const auto& newSubPointMesh = pointMesh::New(subMeshPtr_());
1316 
1317  pointPatchMap_ = patchMap_;
1318 
1319  auto& newBoundary =
1320  const_cast<pointBoundaryMesh&>(newSubPointMesh.boundary());
1321 
1322 
1323  // 2. Explicitly add subsetted meshPointPatches
1324  labelList oldToNewPoints(baseMesh_.nPoints(), -1);
1325  forAll(pointMap_, i)
1326  {
1327  oldToNewPoints[pointMap_[i]] = i;
1328  }
1329 
1330 
1331  // Add meshPointPatches
1332  pointPatchMap_.setSize(newBoundary.size(), -1);
1333 
1334  for (const auto& oldPointPatch : oldPointBoundary)
1335  {
1336  const auto* mppPtr = isA<meshPointPatch>(oldPointPatch);
1337  if (mppPtr && (newBoundary.findPatchID(mppPtr->name()) == -1))
1338  {
1339  const auto& mp = mppPtr->meshPoints();
1340  DynamicList<label> subPointMap(mp.size());
1341  forAll(mp, i)
1342  {
1343  const label newPointi = oldToNewPoints[mp[i]];
1344  if (newPointi != -1)
1345  {
1346  subPointMap.append(i);
1347  }
1348  }
1349 
1350  pointPatchMap_.push_back(mppPtr->index());
1351 
1352  newBoundary.push_back
1353  (
1354  mppPtr->clone
1355  (
1356  newBoundary,
1357  newBoundary.size(),
1358  subPointMap, // map
1359  oldToNewPoints
1360  )
1361  );
1362  }
1363  }
1364 
1365 
1366  // 3. rotate into place:
1367  // - global patches (including meshPointPatches)
1368  // - optional 'internalFaces' patch
1369  // - processor patches
1370  labelList oldToNew(newBoundary.size());
1371  label newPatchi = 0;
1372  forAll(newBoundary, patchi)
1373  {
1374  if
1375  (
1376  patchi != newInternalPatchID
1377  && !isA<processorPointPatch>(newBoundary[patchi])
1378  )
1379  {
1380  oldToNew[patchi] = newPatchi++;
1381  }
1382  }
1383  if (newInternalPatchID != -1)
1384  {
1385  oldToNew[newInternalPatchID] = newPatchi++;
1386  }
1387  forAll(newBoundary, patchi)
1388  {
1389  if (isA<processorPointPatch>(newBoundary[patchi]))
1390  {
1391  oldToNew[patchi] = newPatchi++;
1392  }
1393  }
1394  newBoundary.reorder(oldToNew, true);
1395  inplaceReorder(oldToNew, pointPatchMap_);
1396  }
1397 }
1398 
1399 
1401 (
1402  const labelUList& selectedCells,
1403  const label patchID,
1404  const bool syncPar
1405 )
1406 {
1407  reset
1408  (
1409  BitSetOps::create(baseMesh().nCells(), selectedCells),
1411  syncPar
1412  );
1413 }
1414 
1415 
1417 (
1418  const labelHashSet& selectedCells,
1419  const label patchID,
1420  const bool syncPar
1421 )
1422 {
1423  reset
1424  (
1425  BitSetOps::create(baseMesh().nCells(), selectedCells),
1427  syncPar
1428  );
1429 }
1430 
1431 
1433 (
1434  const label regioni,
1435  const labelUList& regions,
1436  const label patchID,
1437  const bool syncPar
1438 )
1439 {
1440  reset
1441  (
1442  BitSetOps::create(baseMesh().nCells(), regioni, regions),
1443  patchID,
1444  syncPar
1445  );
1446 }
1447 
1448 
1449 // ************************************************************************* //
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
ZoneMesh< faceZone, polyMesh > faceZoneMesh
A ZoneMesh with the type faceZone.
static word exposedPatchName
Name for exposed internal faces (default: oldInternalFaces)
Definition: fvMeshSubset.H:173
List< cell > cellList
List of cell.
Definition: cellListFwd.H:39
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:150
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:600
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1107
static FOAM_NO_DANGLING_REFERENCE const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create MeshObject registered with typeName.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
void inplaceReorder(const labelUList &oldToNew, ListType &input, const bool prune=false)
Inplace reorder the elements of a list.
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:697
labelList sortedToc() const
The indices of the on bits as a sorted labelList.
Definition: bitSetI.H:441
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1586
const cellList & cells() const
Ignore writing from objectRegistry::writeObject()
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition: UPstream.H:1611
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
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
void reduce(T &value, [[maybe_unused]] BinaryOp bop, [[maybe_unused]] const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce)
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1063
Mesh representing a set of points created from polyMesh.
Definition: pointMesh.H:45
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
PtrList< polyPatch > polyPatchList
Store lists of polyPatch as a PtrList.
Definition: polyPatch.H:56
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1602
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
void setSize(const label n)
Alias for resize()
Definition: List.H:325
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
bool checkHasSubMesh() const
FatalError if subset has not been performed.
Definition: fvMeshSubset.C:112
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:609
label nPoints
wordList patchNames(nPatches)
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1101
void reset()
Reset subMesh and all maps. Same as clear()
Definition: fvMeshSubset.C:491
label nInternalFaces() const noexcept
Number of internal faces.
ZoneMesh< pointZone, polyMesh > pointZoneMesh
A ZoneMesh with the type pointZone.
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1088
errorManip< error > abort(error &err)
Definition: errorManip.H:139
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition: UListI.H:385
bool test(const label pos) const
Test for True value at specified position, never auto-vivify entries.
Definition: bitSet.H:329
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:671
defineTypeNameAndDebug(combustionModel, 0)
Holds a reference to the original mesh (the baseMesh) and optionally to a subset of that mesh (the su...
Definition: fvMeshSubset.H:75
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual communication.
const pointZoneMesh & pointZones() const noexcept
Return point zone mesh.
Definition: polyMesh.H:663
fvMeshSubset(const fvMeshSubset &)=delete
No copy construct.
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
limits reset(1/(limits.max()+VSMALL), 1/(limits.min()+VSMALL))
label newPointi
Definition: readKivaGrid.H:497
surface1 clear()
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
Nothing to be read.
static labelList subsetSubset(const label nElems, const labelUList &selectedElements, const labelUList &subsetMap)
Definition: fvMeshSubset.C:66
const cellZoneMesh & cellZones() const noexcept
Return cell zone mesh.
Definition: polyMesh.H:679
#define DebugPout
Report an information message using Foam::Pout.
messageStream Info
Information stream (stdout output on master, null elsewhere)
constexpr label labelMax
Definition: label.H:55
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:57
label n
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
List< label > labelList
A List of labels.
Definition: List.H:61
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
bitSet create(const label n, const labelHashSet &locations, const bool on=true)
Create a bitSet with length n with the specified on locations.
Definition: BitOps.C:228
static void listReduce(UList< T > &values, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce list elements (list must be equal size on all ranks), applying bop to each list element...
List< bool > boolList
A List of bools.
Definition: List.H:59
static const List< label > & null() noexcept
Return a null List (reference to a nullObject). Behaves like an empty List.
Definition: List.H:158
ZoneMesh< cellZone, polyMesh > cellZoneMesh
A ZoneMesh with the type cellZone.
const dimensionedScalar mp
Proton mass.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
IOporosityModelList pZones(mesh)
void clear()
Reset subMesh and all maps.
Definition: fvMeshSubset.C:479
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127