polyTopoChange.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2024 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "polyTopoChange.H"
27 #include "SortableList.H"
28 #include "polyMesh.H"
29 #include "objectMap.H"
30 #include "processorPolyPatch.H"
31 #include "fvMesh.H"
32 #include "CompactListList.H"
33 #include "ListOps.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
40 }
41 
42 
43 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44 
45 void Foam::polyTopoChange::renumberReverseMap
46 (
47  const labelList& map,
48  DynamicList<label>& elems
49 )
50 {
51  forAll(elems, elemI)
52  {
53  label val = elems[elemI];
54 
55  if (val >= 0)
56  {
57  elems[elemI] = map[val];
58  }
59  else if (val < -1)
60  {
61  label mergedVal = -val-2;
62  elems[elemI] = -map[mergedVal]-2;
63  }
64  }
65 }
66 
67 
68 void Foam::polyTopoChange::renumber
69 (
70  const labelList& map,
71  labelHashSet& elems
72 )
73 {
74  labelHashSet newElems(elems.size());
75 
76  forAllConstIter(labelHashSet, elems, iter)
77  {
78  label newElem = map[iter.key()];
79 
80  if (newElem >= 0)
81  {
82  newElems.insert(newElem);
83  }
84  }
85 
86  elems.transfer(newElems);
87 }
88 
89 
90 void Foam::polyTopoChange::renumberCompact
91 (
92  const labelList& map,
93  labelList& elems
94 )
95 {
96  label newElemI = 0;
97 
98  forAll(elems, elemI)
99  {
100  label newVal = map[elems[elemI]];
101 
102  if (newVal != -1)
103  {
104  elems[newElemI++] = newVal;
105  }
106  }
107  elems.setSize(newElemI);
108 }
109 
110 
111 void Foam::polyTopoChange::countMap
112 (
113  const labelList& map,
114  const labelList& reverseMap,
115  label& nSplit,
116  label& nInserted,
117  label& nMerge,
118  label& nRemove
119 )
120 {
121  nSplit = 0;
122  nInserted = 0;
123  nMerge = 0;
124  nRemove = 0;
125 
126  forAll(map, newCelli)
127  {
128  label oldCelli = map[newCelli];
129 
130  if (oldCelli >= 0)
131  {
132  if (reverseMap[oldCelli] == newCelli)
133  {
134  // unchanged
135  }
136  else
137  {
138  // Added from another cell
139  nSplit++;
140  }
141  }
142  else if (oldCelli == -1)
143  {
144  // Created from nothing
145  nInserted++;
146  }
147  else
148  {
150  << " new:" << newCelli << abort(FatalError);
151  }
152  }
153 
154  forAll(reverseMap, oldCelli)
155  {
156  label newCelli = reverseMap[oldCelli];
157 
158  if (newCelli >= 0)
159  {
160  // unchanged
161  }
162  else if (newCelli == -1)
163  {
164  // removed
165  nRemove++;
166  }
167  else
168  {
169  // merged into -newCelli-2
170  nMerge++;
171  }
172  }
173 }
174 
175 
176 Foam::labelHashSet Foam::polyTopoChange::getSetIndices
177 (
178  const PackedBoolList& lst
179 )
180 {
181  labelHashSet values(lst.count());
182  forAll(lst, i)
183  {
184  if (lst[i])
185  {
186  values.insert(i);
187  }
188  }
189  return values;
190 }
191 
192 
193 void Foam::polyTopoChange::writeMeshStats(const polyMesh& mesh, Ostream& os)
194 {
195  const polyBoundaryMesh& patches = mesh.boundaryMesh();
196 
197  labelList patchSizes(patches.size());
198  labelList patchStarts(patches.size());
200  {
201  patchSizes[patchi] = patches[patchi].size();
202  patchStarts[patchi] = patches[patchi].start();
203  }
204 
205  os << " Points : " << mesh.nPoints() << nl
206  << " Faces : " << mesh.nFaces() << nl
207  << " Cells : " << mesh.nCells() << nl
208  << " PatchSizes : " << patchSizes << nl
209  << " PatchStarts : " << patchStarts << nl
210  << endl;
211 }
212 
213 
214 void Foam::polyTopoChange::getMergeSets
215 (
216  const labelList& reverseCellMap,
217  const labelList& cellMap,
218  List<objectMap>& cellsFromCells
219 )
220 {
221  // Per new cell the number of old cells that have been merged into it
222  labelList nMerged(cellMap.size(), 1);
223 
224  forAll(reverseCellMap, oldCelli)
225  {
226  label newCelli = reverseCellMap[oldCelli];
227 
228  if (newCelli < -1)
229  {
230  label mergeCelli = -newCelli-2;
231 
232  nMerged[mergeCelli]++;
233  }
234  }
235 
236  // From merged cell to set index
237  labelList cellToMergeSet(cellMap.size(), -1);
238 
239  label nSets = 0;
240 
241  forAll(nMerged, celli)
242  {
243  if (nMerged[celli] > 1)
244  {
245  cellToMergeSet[celli] = nSets++;
246  }
247  }
248 
249  // Collect cell labels.
250  // Each objectMap will have
251  // - index : new mesh cell label
252  // - masterObjects : list of old cells that have been merged. Element 0
253  // will be the original destination cell label.
254 
255  cellsFromCells.setSize(nSets);
256 
257  forAll(reverseCellMap, oldCelli)
258  {
259  label newCelli = reverseCellMap[oldCelli];
260 
261  if (newCelli < -1)
262  {
263  label mergeCelli = -newCelli-2;
264 
265  // oldCelli was merged into mergeCelli
266 
267  label setI = cellToMergeSet[mergeCelli];
268 
269  objectMap& mergeSet = cellsFromCells[setI];
270 
271  if (mergeSet.masterObjects().empty())
272  {
273  // First occurrence of master cell mergeCelli
274 
275  mergeSet.index() = mergeCelli;
276  mergeSet.masterObjects().setSize(nMerged[mergeCelli]);
277 
278  // old master label
279  mergeSet.masterObjects()[0] = cellMap[mergeCelli];
280 
281  // old slave label
282  mergeSet.masterObjects()[1] = oldCelli;
283 
284  nMerged[mergeCelli] = 2;
285  }
286  else
287  {
288  mergeSet.masterObjects()[nMerged[mergeCelli]++] = oldCelli;
289  }
290  }
291  }
292 }
293 
294 
295 bool Foam::polyTopoChange::hasValidPoints(const face& f) const
296 {
297  forAll(f, fp)
298  {
299  if (f[fp] < 0 || f[fp] >= points_.size())
300  {
301  return false;
302  }
303  }
304  return true;
305 }
306 
307 
308 Foam::pointField Foam::polyTopoChange::facePoints(const face& f) const
309 {
310  pointField points(f.size());
311  forAll(f, fp)
312  {
313  if (f[fp] < 0 && f[fp] >= points_.size())
314  {
316  << "Problem." << abort(FatalError);
317  }
318  points[fp] = points_[f[fp]];
319  }
320  return points;
321 }
322 
323 
324 void Foam::polyTopoChange::checkFace
325 (
326  const face& f,
327  const label facei,
328  const label own,
329  const label nei,
330  const label patchi
331 ) const
332 {
333  if (nei == -1)
334  {
335  if (own == -1)
336  {
337  // retired face
338  }
339  else if (patchi == -1 || patchi >= nPatches_)
340  {
342  << "Face has no neighbour (so external) but does not have"
343  << " a valid patch" << nl
344  << "f:" << f
345  << " facei(-1 if added face):" << facei
346  << " own:" << own << " nei:" << nei
347  << " patchi:" << patchi << nl;
348  if (hasValidPoints(f))
349  {
350  FatalError
351  << "points (removed points marked with "
352  << vector::max << ") " << facePoints(f);
353  }
355  }
356  }
357  else
358  {
359  if (patchi != -1)
360  {
362  << "Cannot both have valid patchi and neighbour" << nl
363  << "f:" << f
364  << " facei(-1 if added face):" << facei
365  << " own:" << own << " nei:" << nei
366  << " patchi:" << patchi << nl;
367  if (hasValidPoints(f))
368  {
369  FatalError
370  << "points (removed points marked with "
371  << vector::max << ") : " << facePoints(f);
372  }
374  }
375 
376  if (nei <= own)
377  {
379  << "Owner cell label should be less than neighbour cell label"
380  << nl
381  << "f:" << f
382  << " facei(-1 if added face):" << facei
383  << " own:" << own << " nei:" << nei
384  << " patchi:" << patchi << nl;
385  if (hasValidPoints(f))
386  {
387  FatalError
388  << "points (removed points marked with "
389  << vector::max << ") : " << facePoints(f);
390  }
392  }
393  }
394 
395  if (f.size() < 3 || findIndex(f, -1) != -1)
396  {
398  << "Illegal vertices in face"
399  << nl
400  << "f:" << f
401  << " facei(-1 if added face):" << facei
402  << " own:" << own << " nei:" << nei
403  << " patchi:" << patchi << nl;
404  if (hasValidPoints(f))
405  {
406  FatalError
407  << "points (removed points marked with "
408  << vector::max << ") : " << facePoints(f);
409  }
411  }
412  if (facei >= 0 && facei < faces_.size() && faceRemoved(facei))
413  {
415  << "Face already marked for removal"
416  << nl
417  << "f:" << f
418  << " facei(-1 if added face):" << facei
419  << " own:" << own << " nei:" << nei
420  << " patchi:" << patchi << nl;
421  if (hasValidPoints(f))
422  {
423  FatalError
424  << "points (removed points marked with "
425  << vector::max << ") : " << facePoints(f);
426  }
428  }
429  forAll(f, fp)
430  {
431  if (f[fp] < points_.size() && pointRemoved(f[fp]))
432  {
434  << "Face uses removed vertices"
435  << nl
436  << "f:" << f
437  << " facei(-1 if added face):" << facei
438  << " own:" << own << " nei:" << nei
439  << " patchi:" << patchi << nl;
440  if (hasValidPoints(f))
441  {
442  FatalError
443  << "points (removed points marked with "
444  << vector::max << ") : " << facePoints(f);
445  }
447  }
448  }
449 }
450 
451 
452 void Foam::polyTopoChange::makeCells
453 (
454  const label nActiveFaces,
455  labelList& cellFaces,
456  labelList& cellFaceOffsets
457 ) const
458 {
459  cellFaces.setSize(2*nActiveFaces);
460  cellFaceOffsets.setSize(cellMap_.size() + 1);
461 
462  // Faces per cell
463  labelList nNbrs(cellMap_.size(), 0);
464 
465  // 1. Count faces per cell
466 
467  for (label facei = 0; facei < nActiveFaces; facei++)
468  {
469  if (faceOwner_[facei] < 0)
470  {
472  << "Face " << facei << " is active but its owner has"
473  << " been deleted. This is usually due to deleting cells"
474  << " without modifying exposed faces to be boundary faces."
475  << exit(FatalError);
476  }
477  nNbrs[faceOwner_[facei]]++;
478  }
479  for (label facei = 0; facei < nActiveFaces; facei++)
480  {
481  if (faceNeighbour_[facei] >= 0)
482  {
483  nNbrs[faceNeighbour_[facei]]++;
484  }
485  }
486 
487  // 2. Calculate offsets
488 
489  cellFaceOffsets[0] = 0;
490  forAll(nNbrs, celli)
491  {
492  cellFaceOffsets[celli+1] = cellFaceOffsets[celli] + nNbrs[celli];
493  }
494 
495  // 3. Fill faces per cell
496 
497  // reset the whole list to use as counter
498  nNbrs = 0;
499 
500  for (label facei = 0; facei < nActiveFaces; facei++)
501  {
502  label celli = faceOwner_[facei];
503 
504  cellFaces[cellFaceOffsets[celli] + nNbrs[celli]++] = facei;
505  }
506 
507  for (label facei = 0; facei < nActiveFaces; facei++)
508  {
509  label celli = faceNeighbour_[facei];
510 
511  if (celli >= 0)
512  {
513  cellFaces[cellFaceOffsets[celli] + nNbrs[celli]++] = facei;
514  }
515  }
516 
517  // Last offset points to beyond end of cellFaces.
518  cellFaces.setSize(cellFaceOffsets[cellMap_.size()]);
519 }
520 
521 
522 void Foam::polyTopoChange::makeCellCells
523 (
524  const label nActiveFaces,
525  CompactListList<label>& cellCells
526 ) const
527 {
528  // Neighbours per cell
529  labelList nNbrs(cellMap_.size(), 0);
530 
531  // 1. Count neighbours (through internal faces) per cell
532 
533  for (label facei = 0; facei < nActiveFaces; facei++)
534  {
535  if (faceNeighbour_[facei] >= 0)
536  {
537  nNbrs[faceOwner_[facei]]++;
538  nNbrs[faceNeighbour_[facei]]++;
539  }
540  }
541 
542  // 2. Construct csr
543  cellCells.setSize(nNbrs);
544 
545 
546  // 3. Fill faces per cell
547 
548  // reset the whole list to use as counter
549  nNbrs = 0;
550 
551  for (label facei = 0; facei < nActiveFaces; facei++)
552  {
553  label nei = faceNeighbour_[facei];
554 
555  if (nei >= 0)
556  {
557  label own = faceOwner_[facei];
558  cellCells.m()[cellCells.index(own, nNbrs[own]++)] = nei;
559  cellCells.m()[cellCells.index(nei, nNbrs[nei]++)] = own;
560  }
561  }
562 }
563 
564 
565 Foam::label Foam::polyTopoChange::getCellOrder
566 (
567  const CompactListList<label>& cellCellAddressing,
568  labelList& oldToNew
569 ) const
570 {
571  labelList newOrder(cellCellAddressing.size());
572 
573  // Fifo buffer for string of cells
574  SLList<label> nextCell;
575 
576  // Whether cell has been done already
577  PackedBoolList visited(cellCellAddressing.size());
578 
579  label cellInOrder = 0;
580 
581 
582  // Work arrays. Kept outside of loop to minimise allocations.
583  // - neighbour cells
584  DynamicList<label> nbrs;
585  // - corresponding weights
586  DynamicList<label> weights;
587 
588  // - ordering
590 
591 
592  while (true)
593  {
594  // For a disconnected region find the lowest connected cell.
595 
596  label currentCell = -1;
597  label minWeight = labelMax;
598 
599  forAll(visited, celli)
600  {
601  // find the lowest connected cell that has not been visited yet
602  if (!cellRemoved(celli) && !visited[celli])
603  {
604  if (cellCellAddressing[celli].size() < minWeight)
605  {
606  minWeight = cellCellAddressing[celli].size();
607  currentCell = celli;
608  }
609  }
610  }
611 
612 
613  if (currentCell == -1)
614  {
615  break;
616  }
617 
618 
619  // Starting from currentCell walk breadth-first
620 
621 
622  // use this cell as a start
623  nextCell.append(currentCell);
624 
625  // loop through the nextCell list. Add the first cell into the
626  // cell order if it has not already been visited and ask for its
627  // neighbours. If the neighbour in question has not been visited,
628  // add it to the end of the nextCell list
629 
630  while (nextCell.size())
631  {
632  currentCell = nextCell.removeHead();
633 
634  if (!visited[currentCell])
635  {
636  visited[currentCell] = 1;
637 
638  // add into cellOrder
639  newOrder[cellInOrder] = currentCell;
640  cellInOrder++;
641 
642  // find if the neighbours have been visited
643  const labelUList neighbours = cellCellAddressing[currentCell];
644 
645  // Add in increasing order of connectivity
646 
647  // 1. Count neighbours of unvisited neighbours
648  nbrs.clear();
649  weights.clear();
650 
651  forAll(neighbours, nI)
652  {
653  label nbr = neighbours[nI];
654  if (!cellRemoved(nbr) && !visited[nbr])
655  {
656  // not visited, add to the list
657  nbrs.append(nbr);
658  weights.append(cellCellAddressing[nbr].size());
659  }
660  }
661  // 2. Sort
662  sortedOrder(weights, order);
663  // 3. Add in sorted order
664  forAll(order, i)
665  {
666  nextCell.append(nbrs[i]);
667  }
668  }
669  }
670  }
671 
672  // Now we have new-to-old in newOrder.
673  newOrder.setSize(cellInOrder);
674 
675  // Invert to get old-to-new. Make sure removed (i.e. unmapped) cells are -1.
676  oldToNew = invert(cellCellAddressing.size(), newOrder);
677 
678  return cellInOrder;
679 }
680 
681 
682 void Foam::polyTopoChange::getFaceOrder
683 (
684  const label nActiveFaces,
685  const labelList& cellFaces,
686  const labelList& cellFaceOffsets,
687 
688  labelList& oldToNew,
689  labelList& patchSizes,
690  labelList& patchStarts
691 ) const
692 {
693  oldToNew.setSize(faceOwner_.size());
694  oldToNew = -1;
695 
696  // First unassigned face
697  label newFacei = 0;
698 
699  labelList nbr;
701 
702  forAll(cellMap_, celli)
703  {
704  label startOfCell = cellFaceOffsets[celli];
705  label nFaces = cellFaceOffsets[celli+1] - startOfCell;
706 
707  // Neighbouring cells
708  // SortableList<label> nbr(nFaces);
709  nbr.setSize(nFaces);
710 
711  for (label i = 0; i < nFaces; i++)
712  {
713  label facei = cellFaces[startOfCell + i];
714 
715  label nbrCelli = faceNeighbour_[facei];
716 
717  if (facei >= nActiveFaces)
718  {
719  // Retired face.
720  nbr[i] = -1;
721  }
722  else if (nbrCelli != -1)
723  {
724  // Internal face. Get cell on other side.
725  if (nbrCelli == celli)
726  {
727  nbrCelli = faceOwner_[facei];
728  }
729 
730  if (celli < nbrCelli)
731  {
732  // Celli is master
733  nbr[i] = nbrCelli;
734  }
735  else
736  {
737  // nbrCell is master. Let it handle this face.
738  nbr[i] = -1;
739  }
740  }
741  else
742  {
743  // External face. Do later.
744  nbr[i] = -1;
745  }
746  }
747 
748  // nbr.sort();
749  order.setSize(nFaces);
750  sortedOrder(nbr, order);
751 
752  // forAll(nbr, i)
753  //{
754  // if (nbr[i] != -1)
755  // {
756  // oldToNew[cellFaces[startOfCell + nbr.indices()[i]]] =
757  // newFacei++;
758  // }
759  //}
760  forAll(order, i)
761  {
762  label index = order[i];
763  if (nbr[index] != -1)
764  {
765  oldToNew[cellFaces[startOfCell + index]] = newFacei++;
766  }
767  }
768  }
769 
770 
771  // Pick up all patch faces in patch face order.
772  patchStarts.setSize(nPatches_);
773  patchStarts = 0;
774  patchSizes.setSize(nPatches_);
775  patchSizes = 0;
776 
777  if (nPatches_ > 0)
778  {
779  patchStarts[0] = newFacei;
780 
781  for (label facei = 0; facei < nActiveFaces; facei++)
782  {
783  if (region_[facei] >= 0)
784  {
785  patchSizes[region_[facei]]++;
786  }
787  }
788 
789  label facei = patchStarts[0];
790 
791  forAll(patchStarts, patchi)
792  {
793  patchStarts[patchi] = facei;
794  facei += patchSizes[patchi];
795  }
796  }
797 
798  labelList workPatchStarts(patchStarts);
799 
800  for (label facei = 0; facei < nActiveFaces; facei++)
801  {
802  if (region_[facei] >= 0)
803  {
804  oldToNew[facei] = workPatchStarts[region_[facei]]++;
805  }
806  }
807 
808  // Retired faces.
809  for (label facei = nActiveFaces; facei < oldToNew.size(); facei++)
810  {
811  oldToNew[facei] = facei;
812  }
813 
814  // Check done all faces.
815  forAll(oldToNew, facei)
816  {
817  if (oldToNew[facei] == -1)
818  {
820  << "Did not determine new position"
821  << " for face " << facei
822  << " owner " << faceOwner_[facei]
823  << " neighbour " << faceNeighbour_[facei]
824  << " region " << region_[facei] << endl
825  << "This is usually caused by not specifying a patch for"
826  << " a boundary face." << nl
827  << "Switch on the polyTopoChange::debug flag to catch"
828  << " this error earlier." << nl;
829  if (hasValidPoints(faces_[facei]))
830  {
831  FatalError
832  << "points (removed points marked with "
833  << vector::max << ") " << facePoints(faces_[facei]);
834  }
836  }
837  }
838 }
839 
840 
841 void Foam::polyTopoChange::reorderCompactFaces
842 (
843  const label newSize,
844  const labelList& oldToNew
845 )
846 {
847  reorder(oldToNew, faces_);
848  faces_.setCapacity(newSize);
849 
850  reorder(oldToNew, region_);
851  region_.setCapacity(newSize);
852 
853  reorder(oldToNew, faceOwner_);
854  faceOwner_.setCapacity(newSize);
855 
856  reorder(oldToNew, faceNeighbour_);
857  faceNeighbour_.setCapacity(newSize);
858 
859  // Update faceMaps.
860  reorder(oldToNew, faceMap_);
861  faceMap_.setCapacity(newSize);
862 
863  renumberReverseMap(oldToNew, reverseFaceMap_);
864 
865  inplaceReorder(oldToNew, flipFaceFlux_);
866  flipFaceFlux_.setCapacity(newSize);
867 }
868 
869 
870 void Foam::polyTopoChange::compact
871 (
872  const bool orderCells,
873  const bool orderPoints,
874  label& nInternalPoints,
875  labelList& patchSizes,
876  labelList& patchStarts
877 )
878 {
879  points_.shrink();
880  pointMap_.shrink();
881  reversePointMap_.shrink();
882 
883  faces_.shrink();
884  region_.shrink();
885  faceOwner_.shrink();
886  faceNeighbour_.shrink();
887  faceMap_.shrink();
888  reverseFaceMap_.shrink();
889 
890  cellMap_.shrink();
891  reverseCellMap_.shrink();
892 
893 
894  // Compact points
895  label nActivePoints = 0;
896  {
897  labelList localPointMap(points_.size(), -1);
898  label newPointi = 0;
899 
900  if (!orderPoints)
901  {
902  nInternalPoints = -1;
903 
904  forAll(points_, pointi)
905  {
906  if (!pointRemoved(pointi) && !retiredPoints_.found(pointi))
907  {
908  localPointMap[pointi] = newPointi++;
909  }
910  }
911  nActivePoints = newPointi;
912  }
913  else
914  {
915  forAll(points_, pointi)
916  {
917  if (!pointRemoved(pointi) && !retiredPoints_.found(pointi))
918  {
919  nActivePoints++;
920  }
921  }
922 
923  // Mark boundary points
924  forAll(faceOwner_, facei)
925  {
926  if
927  (
928  !faceRemoved(facei)
929  && faceOwner_[facei] >= 0
930  && faceNeighbour_[facei] < 0
931  )
932  {
933  // Valid boundary face
934  const face& f = faces_[facei];
935 
936  forAll(f, fp)
937  {
938  label pointi = f[fp];
939 
940  if (localPointMap[pointi] == -1)
941  {
942  if
943  (
944  pointRemoved(pointi)
945  || retiredPoints_.found(pointi)
946  )
947  {
949  << "Removed or retired point " << pointi
950  << " in face " << f
951  << " at position " << facei << endl
952  << "Probably face has not been adapted for"
953  << " removed points." << abort(FatalError);
954  }
955  localPointMap[pointi] = newPointi++;
956  }
957  }
958  }
959  }
960 
961  label nBoundaryPoints = newPointi;
962  nInternalPoints = nActivePoints - nBoundaryPoints;
963 
964  // Move the boundary addressing up
965  forAll(localPointMap, pointi)
966  {
967  if (localPointMap[pointi] != -1)
968  {
969  localPointMap[pointi] += nInternalPoints;
970  }
971  }
972 
973  newPointi = 0;
974 
975  // Mark internal points
976  forAll(faceOwner_, facei)
977  {
978  if
979  (
980  !faceRemoved(facei)
981  && faceOwner_[facei] >= 0
982  && faceNeighbour_[facei] >= 0
983  )
984  {
985  // Valid internal face
986  const face& f = faces_[facei];
987 
988  forAll(f, fp)
989  {
990  label pointi = f[fp];
991 
992  if (localPointMap[pointi] == -1)
993  {
994  if
995  (
996  pointRemoved(pointi)
997  || retiredPoints_.found(pointi)
998  )
999  {
1001  << "Removed or retired point " << pointi
1002  << " in face " << f
1003  << " at position " << facei << endl
1004  << "Probably face has not been adapted for"
1005  << " removed points." << abort(FatalError);
1006  }
1007  localPointMap[pointi] = newPointi++;
1008  }
1009  }
1010  }
1011  }
1012 
1013  if (newPointi != nInternalPoints)
1014  {
1016  << "Problem." << abort(FatalError);
1017  }
1018  newPointi = nActivePoints;
1019  }
1020 
1021  forAllConstIter(labelHashSet, retiredPoints_, iter)
1022  {
1023  localPointMap[iter.key()] = newPointi++;
1024  }
1025 
1026 
1027  if (debug)
1028  {
1029  Pout<< "Points : active:" << nActivePoints
1030  << " removed:" << points_.size()-newPointi << endl;
1031  }
1032 
1033  reorder(localPointMap, points_);
1034  points_.setCapacity(newPointi);
1035 
1036  // Update pointMaps
1037  reorder(localPointMap, pointMap_);
1038  pointMap_.setCapacity(newPointi);
1039  renumberReverseMap(localPointMap, reversePointMap_);
1040 
1041  renumberKey(localPointMap, oldPoints_);
1042  renumber(localPointMap, retiredPoints_);
1043 
1044  // Use map to relabel face vertices
1045  forAll(faces_, facei)
1046  {
1047  face& f = faces_[facei];
1048 
1049  // labelList oldF(f);
1050  renumberCompact(localPointMap, f);
1051 
1052  if (!faceRemoved(facei) && f.size() < 3)
1053  {
1055  << "Created illegal face " << f
1056  //<< " from face " << oldF
1057  << " at position:" << facei
1058  << " when filtering removed points"
1059  << abort(FatalError);
1060  }
1061  }
1062  }
1063 
1064 
1065  // Compact faces.
1066  {
1067  labelList localFaceMap(faces_.size(), -1);
1068  label newFacei = 0;
1069 
1070  forAll(faces_, facei)
1071  {
1072  if (!faceRemoved(facei) && faceOwner_[facei] >= 0)
1073  {
1074  localFaceMap[facei] = newFacei++;
1075  }
1076  }
1077  nActiveFaces_ = newFacei;
1078 
1079  forAll(faces_, facei)
1080  {
1081  if (!faceRemoved(facei) && faceOwner_[facei] < 0)
1082  {
1083  // Retired face
1084  localFaceMap[facei] = newFacei++;
1085  }
1086  }
1087 
1088  if (debug)
1089  {
1090  Pout<< "Faces : active:" << nActiveFaces_
1091  << " removed:" << faces_.size()-newFacei << endl;
1092  }
1093 
1094  // Reorder faces.
1095  reorderCompactFaces(newFacei, localFaceMap);
1096  }
1097 
1098  // Compact cells.
1099  {
1100  labelList localCellMap;
1101  label newCelli;
1102 
1103  if (orderCells)
1104  {
1105  // Construct cellCell addressing
1106  CompactListList<label> cellCells;
1107  makeCellCells(nActiveFaces_, cellCells);
1108 
1109  // Cell ordering (based on bandCompression). Handles removed cells.
1110  newCelli = getCellOrder(cellCells, localCellMap);
1111  }
1112  else
1113  {
1114  // Compact out removed cells
1115  localCellMap.setSize(cellMap_.size());
1116  localCellMap = -1;
1117 
1118  newCelli = 0;
1119  forAll(cellMap_, celli)
1120  {
1121  if (!cellRemoved(celli))
1122  {
1123  localCellMap[celli] = newCelli++;
1124  }
1125  }
1126  }
1127 
1128  if (debug)
1129  {
1130  Pout<< "Cells : active:" << newCelli
1131  << " removed:" << cellMap_.size()-newCelli << endl;
1132  }
1133 
1134  // Renumber -if cells reordered or -if cells removed
1135  if (orderCells || (newCelli != cellMap_.size()))
1136  {
1137  reorder(localCellMap, cellMap_);
1138  cellMap_.setCapacity(newCelli);
1139  renumberReverseMap(localCellMap, reverseCellMap_);
1140 
1141  // Renumber owner/neighbour. Take into account if neighbour suddenly
1142  // gets lower cell than owner.
1143  forAll(faceOwner_, facei)
1144  {
1145  label own = faceOwner_[facei];
1146  label nei = faceNeighbour_[facei];
1147 
1148  if (own >= 0)
1149  {
1150  // Update owner
1151  faceOwner_[facei] = localCellMap[own];
1152 
1153  if (nei >= 0)
1154  {
1155  // Update neighbour.
1156  faceNeighbour_[facei] = localCellMap[nei];
1157 
1158  // Check if face needs reversing.
1159  if
1160  (
1161  faceNeighbour_[facei] >= 0
1162  && faceNeighbour_[facei] < faceOwner_[facei]
1163  )
1164  {
1165  faces_[facei].flip();
1166  Swap(faceOwner_[facei], faceNeighbour_[facei]);
1167  flipFaceFlux_[facei] =
1168  (
1169  flipFaceFlux_[facei]
1170  ? 0
1171  : 1
1172  );
1173  }
1174  }
1175  }
1176  else if (nei >= 0)
1177  {
1178  // Update neighbour.
1179  faceNeighbour_[facei] = localCellMap[nei];
1180  }
1181  }
1182  }
1183  }
1184 
1185  // Reorder faces into upper-triangular and patch ordering
1186  {
1187  // Create cells (packed storage)
1188  labelList cellFaces;
1189  labelList cellFaceOffsets;
1190  makeCells(nActiveFaces_, cellFaces, cellFaceOffsets);
1191 
1192  // Do upper triangular order and patch sorting
1193  labelList localFaceMap;
1194  getFaceOrder
1195  (
1196  nActiveFaces_,
1197  cellFaces,
1198  cellFaceOffsets,
1199 
1200  localFaceMap,
1201  patchSizes,
1202  patchStarts
1203  );
1204 
1205  // Reorder faces.
1206  reorderCompactFaces(localFaceMap.size(), localFaceMap);
1207  }
1208 }
1209 
1210 
1211 Foam::labelList Foam::polyTopoChange::selectFaces
1212 (
1213  const primitiveMesh& mesh,
1214  const labelList& faceLabels,
1215  const bool internalFacesOnly
1216 )
1217 {
1218  label nFaces = 0;
1219 
1220  forAll(faceLabels, i)
1221  {
1222  label facei = faceLabels[i];
1223 
1224  if (internalFacesOnly == mesh.isInternalFace(facei))
1225  {
1226  nFaces++;
1227  }
1228  }
1229 
1230  labelList collectedFaces;
1231 
1232  if (nFaces == 0)
1233  {
1234  // Did not find any faces of the correct type so just use any old
1235  // face.
1236  collectedFaces = faceLabels;
1237  }
1238  else
1239  {
1240  collectedFaces.setSize(nFaces);
1241 
1242  nFaces = 0;
1243 
1244  forAll(faceLabels, i)
1245  {
1246  label facei = faceLabels[i];
1247 
1248  if (internalFacesOnly == mesh.isInternalFace(facei))
1249  {
1250  collectedFaces[nFaces++] = facei;
1251  }
1252  }
1253  }
1254 
1255  return collectedFaces;
1256 }
1257 
1258 
1259 void Foam::polyTopoChange::calcPatchPointMap
1260 (
1261  const List<Map<label>>& oldPatchMeshPointMaps,
1262  const polyBoundaryMesh& boundary,
1263  labelListList& patchPointMap
1264 ) const
1265 {
1266  patchPointMap.setSize(boundary.size());
1267 
1269  {
1270  const labelList& meshPoints = boundary[patchi].meshPoints();
1271 
1272  const Map<label>& oldMeshPointMap = oldPatchMeshPointMaps[patchi];
1273 
1274  labelList& curPatchPointRnb = patchPointMap[patchi];
1275 
1276  curPatchPointRnb.setSize(meshPoints.size());
1277 
1278  forAll(meshPoints, i)
1279  {
1280  if (meshPoints[i] < pointMap_.size())
1281  {
1282  // Check if old point was part of same patch
1283  Map<label>::const_iterator ozmpmIter = oldMeshPointMap.find
1284  (
1285  pointMap_[meshPoints[i]]
1286  );
1287 
1288  if (ozmpmIter != oldMeshPointMap.end())
1289  {
1290  curPatchPointRnb[i] = ozmpmIter();
1291  }
1292  else
1293  {
1294  curPatchPointRnb[i] = -1;
1295  }
1296  }
1297  else
1298  {
1299  curPatchPointRnb[i] = -1;
1300  }
1301  }
1302  }
1303 }
1304 
1305 
1306 void Foam::polyTopoChange::reorderCoupledFaces
1307 (
1308  const bool syncParallel,
1309  const polyBoundaryMesh& boundary,
1310  const labelList& patchStarts,
1311  const labelList& patchSizes,
1312  const pointField& points
1313 )
1314 {
1315  // Mapping for faces (old to new). Extends over all mesh faces for
1316  // convenience (could be just the external faces)
1317  labelList oldToNew(identityMap(faces_.size()));
1318 
1319  // Rotation on new faces.
1320  labelList rotation(faces_.size(), 0);
1321 
1322  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
1323 
1324  // Send ordering
1326  {
1327  if (syncParallel || !isA<processorPolyPatch>(boundary[patchi]))
1328  {
1329  boundary[patchi].initOrder
1330  (
1331  pBufs,
1333  (
1334  SubList<face>
1335  (
1336  faces_,
1337  patchSizes[patchi],
1338  patchStarts[patchi]
1339  ),
1340  points
1341  )
1342  );
1343  }
1344  }
1345 
1346  if (syncParallel)
1347  {
1348  pBufs.finishedSends();
1349  }
1350 
1351  // Receive and calculate ordering
1352 
1353  bool anyChanged = false;
1354 
1356  {
1357  if (syncParallel || !isA<processorPolyPatch>(boundary[patchi]))
1358  {
1359  labelList patchFaceMap(patchSizes[patchi], -1);
1360  labelList patchFaceRotation(patchSizes[patchi], 0);
1361 
1362  bool changed = boundary[patchi].order
1363  (
1364  pBufs,
1366  (
1367  SubList<face>
1368  (
1369  faces_,
1370  patchSizes[patchi],
1371  patchStarts[patchi]
1372  ),
1373  points
1374  ),
1375  patchFaceMap,
1376  patchFaceRotation
1377  );
1378 
1379  if (changed)
1380  {
1381  // Merge patch face reordering into mesh face reordering table
1382  label start = patchStarts[patchi];
1383 
1384  forAll(patchFaceMap, patchFacei)
1385  {
1386  oldToNew[patchFacei + start] =
1387  start + patchFaceMap[patchFacei];
1388  }
1389 
1390  forAll(patchFaceRotation, patchFacei)
1391  {
1392  rotation[patchFacei + start] =
1393  patchFaceRotation[patchFacei];
1394  }
1395 
1396  anyChanged = true;
1397  }
1398  }
1399  }
1400 
1401  if (syncParallel)
1402  {
1403  reduce(anyChanged, orOp<bool>());
1404  }
1405 
1406  if (anyChanged)
1407  {
1408  // Reorder faces according to oldToNew.
1409  reorderCompactFaces(oldToNew.size(), oldToNew);
1410 
1411  // Rotate faces (rotation is already in new face indices).
1412  forAll(rotation, facei)
1413  {
1414  if (rotation[facei] != 0)
1415  {
1416  inplaceRotateList<List, label>(faces_[facei], rotation[facei]);
1417  }
1418  }
1419  }
1420 }
1421 
1422 
1423 void Foam::polyTopoChange::compactAndReorder
1424 (
1425  const polyMesh& mesh,
1426  const bool syncParallel,
1427  const bool orderCells,
1428  const bool orderPoints,
1429 
1430  label& nInternalPoints,
1431  pointField& newPoints,
1432  labelList& patchSizes,
1433  labelList& patchStarts,
1434  List<objectMap>& pointsFromPoints,
1435  List<objectMap>& facesFromFaces,
1436  List<objectMap>& cellsFromCells,
1437  List<Map<label>>& oldPatchMeshPointMaps,
1438  labelList& oldPatchNMeshPoints,
1439  labelList& oldPatchSizes,
1440  labelList& oldPatchStarts
1441 )
1442 {
1443  if (mesh.boundaryMesh().size() != nPatches_)
1444  {
1446  << "polyTopoChange was constructed with a mesh with "
1447  << nPatches_ << " patches." << endl
1448  << "The mesh now provided has a different number of patches "
1449  << mesh.boundaryMesh().size()
1450  << " which is illegal" << endl
1451  << abort(FatalError);
1452  }
1453 
1454  // Remove any holes from points/faces/cells and sort faces.
1455  // Sets nActiveFaces_.
1456  compact(orderCells, orderPoints, nInternalPoints, patchSizes, patchStarts);
1457 
1458  // Transfer points to pointField. points_ are now cleared!
1459  // Only done since e.g. reorderCoupledFaces requires pointField.
1460  newPoints.transfer(points_);
1461 
1462  // Reorder any coupled faces
1463  reorderCoupledFaces
1464  (
1465  syncParallel,
1466  mesh.boundaryMesh(),
1467  patchStarts,
1468  patchSizes,
1469  newPoints
1470  );
1471 
1472 
1473  // Calculate merging maps
1474  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1475  // These are for the new face(/point/cell) the old faces whose value
1476  // needs to be
1477  // averaged/summed to get the new value. These old faces come either from
1478  // merged old faces (face remove into other face).
1479  // As an additional complexity will use only internal faces
1480  // to create new value for internal face and vice versa only patch
1481  // faces to to create patch face value.
1482 
1483  // For point only point merging
1484  getMergeSets
1485  (
1486  reversePointMap_,
1487  pointMap_,
1488  pointsFromPoints
1489  );
1490 
1491  getMergeSets
1492  (
1493  reverseFaceMap_,
1494  faceMap_,
1495  facesFromFaces
1496  );
1497 
1498  getMergeSets
1499  (
1500  reverseCellMap_,
1501  cellMap_,
1502  cellsFromCells
1503  );
1504 
1505  const polyBoundaryMesh& boundary = mesh.boundaryMesh();
1506 
1507  // Grab patch mesh point maps
1508  oldPatchMeshPointMaps.setSize(boundary.size());
1509  oldPatchNMeshPoints.setSize(boundary.size());
1510  oldPatchSizes.setSize(boundary.size());
1511  oldPatchStarts.setSize(boundary.size());
1512 
1514  {
1515  oldPatchMeshPointMaps[patchi] = boundary[patchi].meshPointMap();
1516  oldPatchNMeshPoints[patchi] = boundary[patchi].meshPoints().size();
1517  oldPatchSizes[patchi] = boundary[patchi].size();
1518  oldPatchStarts[patchi] = boundary[patchi].start();
1519  }
1520 }
1521 
1522 
1523 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1524 
1526 :
1527  strict_(strict),
1528  nPatches_(nPatches),
1529  points_(0),
1530  pointMap_(0),
1531  reversePointMap_(0),
1532  retiredPoints_(0),
1533  oldPoints_(0),
1534  faces_(0),
1535  region_(0),
1536  faceOwner_(0),
1537  faceNeighbour_(0),
1538  faceMap_(0),
1539  reverseFaceMap_(0),
1540  flipFaceFlux_(0),
1541  nActiveFaces_(0),
1542  cellMap_(0),
1543  reverseCellMap_(0)
1544 {}
1545 
1546 
1548 (
1549  const polyMesh& mesh,
1550  const bool strict
1551 )
1552 :
1553  strict_(strict),
1554  nPatches_(mesh.boundaryMesh().size()),
1555  points_(0),
1556  pointMap_(0),
1557  reversePointMap_(0),
1558  retiredPoints_(0),
1559  oldPoints_(0),
1560  faces_(0),
1561  region_(0),
1562  faceOwner_(0),
1563  faceNeighbour_(0),
1564  faceMap_(0),
1565  reverseFaceMap_(0),
1566  flipFaceFlux_(0),
1567  nActiveFaces_(0),
1568  cellMap_(0),
1569  reverseCellMap_(0)
1570 {
1571  // Add points
1572  {
1573  const pointField& points = mesh.points();
1574 
1575  // Extend
1576  points_.setCapacity(points_.size() + points.size());
1577  pointMap_.setCapacity(pointMap_.size() + points.size());
1578  reversePointMap_.setCapacity(reversePointMap_.size() + points.size());
1579  // No need to extend oldPoints_
1580 
1581  // Add points in mesh order
1582  for (label pointi = 0; pointi < mesh.nPoints(); pointi++)
1583  {
1584  addPoint(points[pointi], pointi, true);
1585  }
1586  }
1587 
1588  // Add cells
1589  {
1590  // Resize
1591 
1592  // Note: polyMesh does not allow retired cells anymore. So allCells
1593  // always equals nCells
1594  label nAllCells = mesh.nCells();
1595 
1596  cellMap_.setCapacity(cellMap_.size() + nAllCells);
1597  reverseCellMap_.setCapacity(reverseCellMap_.size() + nAllCells);
1598 
1599  // Add cells in mesh order
1600  for (label celli = 0; celli < nAllCells; celli++)
1601  {
1602  addCell(celli);
1603  }
1604  }
1605 
1606  // Add faces
1607  {
1608  const polyBoundaryMesh& patches = mesh.boundaryMesh();
1609  const faceList& faces = mesh.faces();
1610  const labelList& faceOwner = mesh.faceOwner();
1611  const labelList& faceNeighbour = mesh.faceNeighbour();
1612 
1613  // Resize
1614  label nAllFaces = mesh.faces().size();
1615 
1616  faces_.setCapacity(faces_.size() + nAllFaces);
1617  region_.setCapacity(region_.size() + nAllFaces);
1618  faceOwner_.setCapacity(faceOwner_.size() + nAllFaces);
1619  faceNeighbour_.setCapacity(faceNeighbour_.size() + nAllFaces);
1620  faceMap_.setCapacity(faceMap_.size() + nAllFaces);
1621  reverseFaceMap_.setCapacity(reverseFaceMap_.size() + nAllFaces);
1622  flipFaceFlux_.setCapacity(faces_.size() + nAllFaces);
1623 
1624 
1625  // Add faces in mesh order
1626 
1627  // 1. Internal faces
1628  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
1629  {
1630  addFace
1631  (
1632  faces[facei],
1633  faceOwner[facei],
1634  faceNeighbour[facei],
1635  facei, // masterFaceID
1636  false, // flipFaceFlux
1637  -1 // patchID
1638  );
1639  }
1640 
1641  // 2. Patch faces
1643  {
1644  const polyPatch& pp = patches[patchi];
1645 
1646  if (pp.start() != faces_.size())
1647  {
1649  << "Problem : "
1650  << "Patch " << pp.name() << " starts at " << pp.start()
1651  << endl
1652  << "Current face counter at " << faces_.size() << endl
1653  << "Are patches in incremental order?"
1654  << abort(FatalError);
1655  }
1656  forAll(pp, patchFacei)
1657  {
1658  label facei = pp.start() + patchFacei;
1659 
1660  addFace
1661  (
1662  faces[facei],
1663  faceOwner[facei],
1664  -1, // neighbour
1665  facei, // masterFaceID
1666  false, // flipFaceFlux
1667  patchi // patchID
1668  );
1669  }
1670  }
1671  }
1672 }
1673 
1674 
1675 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1676 
1678 {
1679  points_.clearStorage();
1680  pointMap_.clearStorage();
1681  reversePointMap_.clearStorage();
1682  retiredPoints_.clearStorage();
1683  oldPoints_.clearStorage();
1684 
1685  faces_.clearStorage();
1686  region_.clearStorage();
1687  faceOwner_.clearStorage();
1688  faceNeighbour_.clearStorage();
1689  faceMap_.clearStorage();
1690  reverseFaceMap_.clearStorage();
1691  flipFaceFlux_.clearStorage();
1692  nActiveFaces_ = 0;
1693 
1694  cellMap_.clearStorage();
1695  reverseCellMap_.clearStorage();
1696 }
1697 
1698 
1700 (
1701  const label nPoints,
1702  const label nFaces,
1703  const label nCells
1704 )
1705 {
1706  points_.setCapacity(nPoints);
1707  pointMap_.setCapacity(nPoints);
1708  reversePointMap_.setCapacity(nPoints);
1709 
1710  faces_.setCapacity(nFaces);
1711  region_.setCapacity(nFaces);
1712  faceOwner_.setCapacity(nFaces);
1713  faceNeighbour_.setCapacity(nFaces);
1714  faceMap_.setCapacity(nFaces);
1715  reverseFaceMap_.setCapacity(nFaces);
1716  flipFaceFlux_.setCapacity(nFaces);
1717 
1718  cellMap_.setCapacity(nCells);
1719  reverseCellMap_.setCapacity(nCells);
1720 }
1721 
1722 
1724 (
1725  const point& pt,
1726  const label masterPointID,
1727  const bool inCell
1728 )
1729 {
1730  label pointi = points_.size();
1731 
1732  points_.append(pt);
1733  pointMap_.append(masterPointID);
1734  reversePointMap_.append(pointi);
1735 
1736  if (!inCell)
1737  {
1738  retiredPoints_.insert(pointi);
1739  }
1740 
1741  return pointi;
1742 }
1743 
1744 
1746 (
1747  const label pointi,
1748  const point& pt,
1749  const bool inCell
1750 )
1751 {
1752  if (pointi < 0 || pointi >= points_.size())
1753  {
1755  << "illegal point label " << pointi << endl
1756  << "Valid point labels are 0 .. " << points_.size()-1
1757  << abort(FatalError);
1758  }
1759  if (pointRemoved(pointi) || pointMap_[pointi] == -1)
1760  {
1762  << "point " << pointi << " already marked for removal"
1763  << abort(FatalError);
1764  }
1765  points_[pointi] = pt;
1766 
1767  if (inCell)
1768  {
1769  retiredPoints_.erase(pointi);
1770  }
1771  else
1772  {
1773  retiredPoints_.insert(pointi);
1774  }
1775 
1776  oldPoints_.erase(pointi);
1777 }
1778 
1779 
1781 (
1782  const label pointi,
1783  const label mergePointi
1784 )
1785 {
1786  if (pointi < 0 || pointi >= points_.size())
1787  {
1789  << "illegal point label " << pointi << endl
1790  << "Valid point labels are 0 .. " << points_.size()-1
1791  << abort(FatalError);
1792  }
1793 
1794  if
1795  (
1796  strict_
1797  && (pointRemoved(pointi) || pointMap_[pointi] == -1)
1798  )
1799  {
1801  << "point " << pointi << " already marked for removal" << nl
1802  << "Point:" << points_[pointi] << " pointMap:" << pointMap_[pointi]
1803  << abort(FatalError);
1804  }
1805 
1806  if (pointi == mergePointi)
1807  {
1809  << "Cannot remove/merge point " << pointi << " onto itself."
1810  << abort(FatalError);
1811  }
1812 
1813  points_[pointi] = point::max;
1814  pointMap_[pointi] = -1;
1815  if (mergePointi >= 0)
1816  {
1817  reversePointMap_[pointi] = -mergePointi-2;
1818  }
1819  else
1820  {
1821  reversePointMap_[pointi] = -1;
1822  }
1823  retiredPoints_.erase(pointi);
1824  oldPoints_.erase(pointi);
1825 }
1826 
1827 
1829 (
1830  const face& f,
1831  const label own,
1832  const label nei,
1833  const label masterFaceID,
1834  const bool flipFaceFlux,
1835  const label patchID
1836 )
1837 {
1838  // Check validity
1839  if (debug)
1840  {
1841  checkFace(f, -1, own, nei, patchID);
1842  }
1843 
1844  label facei = faces_.size();
1845 
1846  faces_.append(f);
1847  region_.append(patchID);
1848  faceOwner_.append(own);
1849  faceNeighbour_.append(nei);
1850 
1851  if (masterFaceID >= 0)
1852  {
1853  faceMap_.append(masterFaceID);
1854  }
1855  else
1856  {
1857  // Allow insert-from-nothing?
1858  // FatalErrorInFunction
1859  // << "Need to specify a master point, edge or face"
1860  // << "face:" << f << " own:" << own << " nei:" << nei
1861  // << abort(FatalError);
1862  faceMap_.append(-1);
1863  }
1864  reverseFaceMap_.append(facei);
1865 
1866  flipFaceFlux_[facei] = (flipFaceFlux ? 1 : 0);
1867 
1868  return facei;
1869 }
1870 
1871 
1873 (
1874  const face& f,
1875  const label facei,
1876  const label own,
1877  const label nei,
1878  const bool flipFaceFlux,
1879  const label patchID
1880 )
1881 {
1882  // Check validity
1883  if (debug)
1884  {
1885  checkFace(f, facei, own, nei, patchID);
1886  }
1887 
1888  faces_[facei] = f;
1889  faceOwner_[facei] = own;
1890  faceNeighbour_[facei] = nei;
1891  region_[facei] = patchID;
1892 
1893  flipFaceFlux_[facei] = (flipFaceFlux ? 1 : 0);
1894 }
1895 
1896 
1897 void Foam::polyTopoChange::removeFace(const label facei, const label mergeFacei)
1898 {
1899  if (facei < 0 || facei >= faces_.size())
1900  {
1902  << "illegal face label " << facei << endl
1903  << "Valid face labels are 0 .. " << faces_.size()-1
1904  << abort(FatalError);
1905  }
1906 
1907  if
1908  (
1909  strict_
1910  && (faceRemoved(facei) || faceMap_[facei] == -1)
1911  )
1912  {
1914  << "face " << facei
1915  << " already marked for removal"
1916  << abort(FatalError);
1917  }
1918 
1919  faces_[facei].setSize(0);
1920  region_[facei] = -1;
1921  faceOwner_[facei] = -1;
1922  faceNeighbour_[facei] = -1;
1923  faceMap_[facei] = -1;
1924  if (mergeFacei >= 0)
1925  {
1926  reverseFaceMap_[facei] = -mergeFacei-2;
1927  }
1928  else
1929  {
1930  reverseFaceMap_[facei] = -1;
1931  }
1932  flipFaceFlux_[facei] = 0;
1933 }
1934 
1935 
1937 {
1938  const label celli = cellMap_.size();
1939  cellMap_.append(masterCellID);
1940  reverseCellMap_.append(celli);
1941 
1942  return celli;
1943 }
1944 
1945 
1946 void Foam::polyTopoChange::removeCell(const label celli, const label mergeCelli)
1947 {
1948  if (celli < 0 || celli >= cellMap_.size())
1949  {
1951  << "illegal cell label " << celli << endl
1952  << "Valid cell labels are 0 .. " << cellMap_.size()-1
1953  << abort(FatalError);
1954  }
1955 
1956  if (strict_ && cellMap_[celli] == -2)
1957  {
1959  << "cell " << celli
1960  << " already marked for removal"
1961  << abort(FatalError);
1962  }
1963 
1964  cellMap_[celli] = -2;
1965  if (mergeCelli >= 0)
1966  {
1967  reverseCellMap_[celli] = -mergeCelli-2;
1968  }
1969  else
1970  {
1971  reverseCellMap_[celli] = -1;
1972  }
1973 }
1974 
1975 
1977 (
1978  polyMesh& mesh,
1979  const bool syncParallel,
1980  const bool orderCells,
1981  const bool orderPoints
1982 )
1983 {
1984  if (debug)
1985  {
1986  Pout<< "polyTopoChange::changeMesh"
1987  << "(polyMesh&, const bool, const bool, const bool, const bool)"
1988  << endl;
1989  }
1990 
1991  if (debug)
1992  {
1993  Pout<< "Old mesh:" << nl;
1994  writeMeshStats(mesh, Pout);
1995  }
1996 
1997  // new mesh points
1998  pointField newPoints;
1999 
2000  // number of internal points
2001  label nInternalPoints;
2002 
2003  // patch slicing
2004  labelList patchSizes;
2005  labelList patchStarts;
2006 
2007  // maps
2008  List<objectMap> pointsFromPoints;
2009  List<objectMap> facesFromFaces;
2010  List<objectMap> cellsFromCells;
2011 
2012  // old mesh info
2013  List<Map<label>> oldPatchMeshPointMaps;
2014  labelList oldPatchNMeshPoints;
2015  labelList oldPatchSizes;
2016  labelList oldPatchStarts;
2017 
2018  // Compact, reorder patch faces and calculate mesh/patch maps.
2019  compactAndReorder
2020  (
2021  mesh,
2022  syncParallel,
2023  orderCells,
2024  orderPoints,
2025 
2026  nInternalPoints,
2027  newPoints,
2028  patchSizes,
2029  patchStarts,
2030  pointsFromPoints,
2031  facesFromFaces,
2032  cellsFromCells,
2033  oldPatchMeshPointMaps,
2034  oldPatchNMeshPoints,
2035  oldPatchSizes,
2036  oldPatchStarts
2037  );
2038 
2039  const label nOldPoints(mesh.nPoints());
2040  const label nOldFaces(mesh.nFaces());
2041  const label nOldCells(mesh.nCells());
2042  autoPtr<scalarField> oldCellVolumes(new scalarField(mesh.cellVolumes()));
2043 
2044 
2045  // Change the mesh
2046  // ~~~~~~~~~~~~~~~
2047  // This will invalidate any addressing so better make sure you have
2048  // all the information you need!!!
2049 
2050  // Set new points.
2051  mesh.resetPrimitives
2052  (
2053  move(newPoints),
2054  move(faces_),
2055  move(faceOwner_),
2056  move(faceNeighbour_),
2057  patchSizes,
2058  patchStarts,
2059  syncParallel
2060  );
2061 
2062  // Clear out primitives
2063  {
2064  retiredPoints_.clearStorage();
2065  oldPoints_.clearStorage();
2066  region_.clearStorage();
2067  }
2068 
2069 
2070  if (debug)
2071  {
2072  // Some stats on changes
2073  label nSplit, nInserted, nMerge, nRemove;
2074  countMap
2075  (
2076  pointMap_,
2077  reversePointMap_,
2078  nSplit,
2079  nInserted,
2080  nMerge,
2081  nRemove
2082  );
2083  Pout<< "Points:"
2084  << " added(from point):" << nSplit
2085  << " added(from nothing):" << nInserted
2086  << " merged(into other point):" << nMerge
2087  << " removed:" << nRemove
2088  << nl;
2089 
2090  countMap(faceMap_, reverseFaceMap_, nSplit, nInserted, nMerge, nRemove);
2091  Pout<< "Faces:"
2092  << " added(from face):" << nSplit
2093  << " added(from nothing):" << nInserted
2094  << " merged(into other face):" << nMerge
2095  << " removed:" << nRemove
2096  << nl;
2097 
2098  countMap(cellMap_, reverseCellMap_, nSplit, nInserted, nMerge, nRemove);
2099  Pout<< "Cells:"
2100  << " added(from cell):" << nSplit
2101  << " added(from nothing):" << nInserted
2102  << " merged(into other cell):" << nMerge
2103  << " removed:" << nRemove
2104  << nl
2105  << endl;
2106  }
2107 
2108  if (debug)
2109  {
2110  Pout<< "New mesh:" << nl;
2111  writeMeshStats(mesh, Pout);
2112  }
2113 
2114 
2115  // Patch point renumbering
2116  // For every preserved point on a patch give the old position.
2117  // For added points, the index is set to -1
2118  labelListList patchPointMap(mesh.boundaryMesh().size());
2119  calcPatchPointMap
2120  (
2121  oldPatchMeshPointMaps,
2122  mesh.boundaryMesh(),
2123  patchPointMap
2124  );
2125 
2126  labelHashSet flipFaceFluxSet(getSetIndices(flipFaceFlux_));
2127 
2129  (
2130  new polyTopoChangeMap
2131  (
2132  mesh,
2133  nOldPoints,
2134  nOldFaces,
2135  nOldCells,
2136 
2137  move(pointMap_),
2138  move(pointsFromPoints),
2139 
2140  move(faceMap_),
2141  move(facesFromFaces),
2142 
2143  move(cellMap_),
2144  move(cellsFromCells),
2145 
2146  move(reversePointMap_),
2147  move(reverseFaceMap_),
2148  move(reverseCellMap_),
2149 
2150  move(flipFaceFluxSet),
2151 
2152  move(patchPointMap),
2153 
2154  move(oldPatchSizes),
2155  move(oldPatchStarts),
2156  move(oldPatchNMeshPoints),
2157 
2158  move(oldCellVolumes)
2159  )
2160  );
2161 
2162  // At this point all member DynamicList (pointMap_, cellMap_ etc.) will
2163  // be invalid.
2164 }
2165 
2166 
2168 (
2169  autoPtr<fvMesh>& newMeshPtr,
2170  const IOobject& io,
2171  const polyMesh& mesh,
2172  const bool syncParallel,
2173  const bool orderCells,
2174  const bool orderPoints
2175 )
2176 {
2177  if (debug)
2178  {
2179  Pout<< "polyTopoChange::makeMesh"
2180  << "(autoPtr<fvMesh>&, const IOobject&, const fvMesh&"
2181  << ", const bool, const bool, const bool)"
2182  << endl;
2183  }
2184 
2185  if (debug)
2186  {
2187  Pout<< "Old mesh:" << nl;
2188  writeMeshStats(mesh, Pout);
2189  }
2190 
2191  // new mesh points
2192  pointField newPoints;
2193  // number of internal points
2194  label nInternalPoints;
2195  // patch slicing
2196  labelList patchSizes;
2197  labelList patchStarts;
2198  // maps
2199  List<objectMap> pointsFromPoints;
2200  List<objectMap> facesFromFaces;
2201  List<objectMap> cellsFromCells;
2202 
2203  // old mesh info
2204  List<Map<label>> oldPatchMeshPointMaps;
2205  labelList oldPatchNMeshPoints;
2206  labelList oldPatchSizes;
2207  labelList oldPatchStarts;
2208 
2209  // Compact, reorder patch faces and calculate mesh/patch maps.
2210  compactAndReorder
2211  (
2212  mesh,
2213  syncParallel,
2214  orderCells,
2215  orderPoints,
2216 
2217  nInternalPoints,
2218  newPoints,
2219  patchSizes,
2220  patchStarts,
2221  pointsFromPoints,
2222  facesFromFaces,
2223  cellsFromCells,
2224  oldPatchMeshPointMaps,
2225  oldPatchNMeshPoints,
2226  oldPatchSizes,
2227  oldPatchStarts
2228  );
2229 
2230  const label nOldPoints(mesh.nPoints());
2231  const label nOldFaces(mesh.nFaces());
2232  const label nOldCells(mesh.nCells());
2233  autoPtr<scalarField> oldCellVolumes(new scalarField(mesh.cellVolumes()));
2234 
2235 
2236  // Create the mesh
2237  // ~~~~~~~~~~~~~~~
2238 
2239  IOobject noReadIO(io);
2240  noReadIO.readOpt() = IOobject::NO_READ;
2241  newMeshPtr.reset
2242  (
2243  new fvMesh
2244  (
2245  noReadIO,
2246  move(newPoints),
2247  move(faces_),
2248  move(faceOwner_),
2249  move(faceNeighbour_)
2250  )
2251  );
2252  fvMesh& newMesh = newMeshPtr();
2253 
2254  // Clear out primitives
2255  {
2256  retiredPoints_.clearStorage();
2257  oldPoints_.clearStorage();
2258  region_.clearStorage();
2259  }
2260 
2261 
2262  if (debug)
2263  {
2264  // Some stats on changes
2265  label nSplit, nInserted, nMerge, nRemove;
2266  countMap
2267  (
2268  pointMap_,
2269  reversePointMap_,
2270  nSplit,
2271  nInserted,
2272  nMerge,
2273  nRemove
2274  );
2275 
2276  Pout<< "Points:"
2277  << " added(from point):" << nSplit
2278  << " added(from nothing):" << nInserted
2279  << " merged(into other point):" << nMerge
2280  << " removed:" << nRemove
2281  << nl;
2282 
2283  countMap(faceMap_, reverseFaceMap_, nSplit, nInserted, nMerge, nRemove);
2284  Pout<< "Faces:"
2285  << " added(from face):" << nSplit
2286  << " added(from nothing):" << nInserted
2287  << " merged(into other face):" << nMerge
2288  << " removed:" << nRemove
2289  << nl;
2290 
2291  countMap(cellMap_, reverseCellMap_, nSplit, nInserted, nMerge, nRemove);
2292  Pout<< "Cells:"
2293  << " added(from cell):" << nSplit
2294  << " added(from nothing):" << nInserted
2295  << " merged(into other cell):" << nMerge
2296  << " removed:" << nRemove
2297  << nl
2298  << endl;
2299  }
2300 
2301 
2302  {
2303  const polyBoundaryMesh& oldPatches = mesh.boundaryMesh();
2304 
2305  List<polyPatch*> newBoundary(oldPatches.size());
2306 
2307  forAll(oldPatches, patchi)
2308  {
2309  newBoundary[patchi] = oldPatches[patchi].clone
2310  (
2311  newMesh.boundaryMesh(),
2312  patchi,
2313  patchSizes[patchi],
2314  patchStarts[patchi]
2315  ).ptr();
2316  }
2317  newMesh.addFvPatches(newBoundary);
2318  }
2319 
2320 
2321  // Zones
2322  // ~~~~~
2323 
2324  // Copy pointZone from old mesh
2325  const pointZoneList& oldPointZones = mesh.pointZones();
2326  List<pointZone*> pZonePtrs(oldPointZones.size());
2327  {
2328  forAll(oldPointZones, i)
2329  {
2330  pZonePtrs[i] = oldPointZones[i].clone(newMesh.pointZones()).ptr();
2331  }
2332  }
2333 
2334  // Copy faceZone from old mesh
2335  const faceZoneList& oldFaceZones = mesh.faceZones();
2336  List<faceZone*> fZonePtrs(oldFaceZones.size());
2337  {
2338  forAll(oldFaceZones, i)
2339  {
2340  fZonePtrs[i] = oldFaceZones[i].clone(newMesh.faceZones()).ptr();
2341  }
2342  }
2343 
2344  // Copy cellZone from old mesh
2345  const cellZoneList& oldCellZones = mesh.cellZones();
2346  List<cellZone*> cZonePtrs(oldCellZones.size());
2347  {
2348  forAll(oldCellZones, i)
2349  {
2350  cZonePtrs[i] = oldCellZones[i].clone(newMesh.cellZones()).ptr();
2351  }
2352  }
2353 
2354  newMesh.addZones(pZonePtrs, fZonePtrs, cZonePtrs);
2355 
2356  // Patch point renumbering
2357  // For every preserved point on a patch give the old position.
2358  // For added points, the index is set to -1
2359  labelListList patchPointMap(newMesh.boundaryMesh().size());
2360  calcPatchPointMap
2361  (
2362  oldPatchMeshPointMaps,
2363  newMesh.boundaryMesh(),
2364  patchPointMap
2365  );
2366 
2367  if (debug)
2368  {
2369  Pout<< "New mesh:" << nl;
2370  writeMeshStats(mesh, Pout);
2371  }
2372 
2373  labelHashSet flipFaceFluxSet(getSetIndices(flipFaceFlux_));
2374 
2376  (
2377  new polyTopoChangeMap
2378  (
2379  newMesh,
2380  nOldPoints,
2381  nOldFaces,
2382  nOldCells,
2383 
2384  move(pointMap_),
2385  move(pointsFromPoints),
2386 
2387  move(faceMap_),
2388  move(facesFromFaces),
2389 
2390  move(cellMap_),
2391  move(cellsFromCells),
2392 
2393  move(reversePointMap_),
2394  move(reverseFaceMap_),
2395  move(reverseCellMap_),
2396 
2397  move(flipFaceFluxSet),
2398 
2399  move(patchPointMap),
2400 
2401  move(oldPatchSizes),
2402  move(oldPatchStarts),
2403  move(oldPatchNMeshPoints),
2404 
2405  move(oldCellVolumes)
2406  )
2407  );
2408 
2409  // At this point all member DynamicList (pointMap_, cellMap_ etc.) will
2410  // be invalid.
2411 }
2412 
2413 
2414 // ************************************************************************* //
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
void setCapacity(const label)
Alter the size of the underlying storage.
Definition: DynamicListI.H:130
friend class const_iterator
Declare friendship with the const_iterator.
Definition: HashTable.H:197
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
readOption readOpt() const
Definition: IOobject.H:360
autoPtr< IOobject > clone() const
Clone.
Definition: IOobject.H:283
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
void setCapacity(const label)
Alter the size of the underlying storage.
Definition: PackedListI.H:838
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
static const Form max
Definition: VectorSpace.H:120
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
void reset(T *=nullptr)
If object pointer already set, delete object and set to given.
Definition: autoPtrI.H:114
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:76
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:99
void addFvPatches(const List< polyPatch * > &, const bool validBoundary=true)
Add boundary patches. Constructor helper.
Definition: fvMesh.C:680
const word & name() const
Return name.
Foam::polyBoundaryMesh.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
const pointZoneList & pointZones() const
Return point zones.
Definition: polyMesh.H:440
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:452
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1326
void resetPrimitives(pointField &&points, faceList &&faces, labelList &&owner, labelList &&neighbour, const labelList &patchSizes, const labelList &patchStarts, const bool validBoundary=true)
Reset mesh primitive data. Assumes all patch info correct.
Definition: polyMesh.C:703
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1339
const faceZoneList & faceZones() const
Return face zones.
Definition: polyMesh.H:446
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:404
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1345
void addZones(const List< pointZone * > &pz, const List< faceZone * > &fz, const List< cellZone * > &cz)
Add mesh zones.
Definition: polyMesh.C:1128
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1313
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:70
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:280
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Direct mesh changes based on v1.3 polyTopoChange syntax.
void modifyPoint(const label, const point &, const bool inCell)
Modify coordinate.
void removePoint(const label, const label)
Remove point / merge points.
autoPtr< polyTopoChangeMap > makeMesh(autoPtr< fvMesh > &newMesh, const IOobject &io, const polyMesh &mesh, const bool syncParallel=true, const bool orderCells=false, const bool orderPoints=false)
Create new mesh with old mesh patches.
polyTopoChange(const label nPatches, const bool strict=true)
Construct without mesh. Either specify nPatches or use.
const DynamicList< face > & faces() const
const DynamicList< point > & points() const
Points. Shrunk after constructing mesh (or calling of compact())
void removeFace(const label, const label)
Remove face / merge faces.
void setCapacity(const label nPoints, const label nFaces, const label nCells)
Explicitly pre-size the dynamic storage for expected mesh.
label addCell(const label masterCellID)
Add cell and return new cell index.
const DynamicList< label > & faceOwner() const
autoPtr< polyTopoChangeMap > changeMesh(polyMesh &mesh, const bool syncParallel=true, const bool orderCells=false, const bool orderPoints=false)
Inplace changes mesh without change of patches.
const DynamicList< label > & faceNeighbour() const
label addPoint(const point &, const label masterPointID, const bool inCell)
Add point and return new point index.
void clear()
Clear all storage.
void removeCell(const label, const label)
Remove cell / merge cells.
void modifyFace(const face &f, const label facei, const label own, const label nei, const bool flipFaceFlux, const label patchID)
Modify vertices or cell of face.
label addFace(const face &f, const label own, const label nei, const label masterFaceID, const bool flipFaceFlux, const label patchID)
Add face to cells and return new face index.
label nCells() const
label nPoints() const
const scalarField & cellVolumes() const
label nInternalFaces() const
label nFaces() const
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
const pointField & points
label nPoints
const fvPatchList & patches
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
labelList invert(const label len, const labelUList &)
Invert one-to-one map. Unmapped elements will be -1.
Definition: ListOps.C:37
int order(const scalar s)
errorManip< error > abort(error &err)
Definition: errorManip.H:131
ListType renumber(const labelUList &oldToNew, const ListType &)
Renumber the values (not the indices) of a list.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
Addressing for a faceList slice.
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
ListType reorder(const label size, const typename ListType::value_type &defaultValue, const labelUList &oldToNew, const ListType &lst)
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
defineTypeNameAndDebug(combustionModel, 0)
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
Definition: HashSet.H:213
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
void Swap(T &a, T &b)
Definition: Swap.H:43
static const label labelMax
Definition: label.H:62
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
void sortedOrder(const UList< T > &, labelList &order)
Generate the (stable) sort order for the list.
UList< label > labelUList
Definition: UList.H:65
static const char nl
Definition: Ostream.H:266
void inplaceReorder(const labelUList &oldToNew, ListType &)
Inplace reorder the elements of a list.
label newPointi
Definition: readKivaGrid.H:495
faceListList boundary(nPatches)
labelList f(nPoints)
label nPatches
Definition: readKivaGrid.H:396