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 
586  // - corresponding weights
587  DynamicList<label> weights;
588 
589  // - ordering
591 
592 
593  while (true)
594  {
595  // For a disconnected region find the lowest connected cell.
596 
597  label currentCell = -1;
598  label minWeight = labelMax;
599 
600  forAll(visited, celli)
601  {
602  // find the lowest connected cell that has not been visited yet
603  if (!cellRemoved(celli) && !visited[celli])
604  {
605  if (cellCellAddressing[celli].size() < minWeight)
606  {
607  minWeight = cellCellAddressing[celli].size();
608  currentCell = celli;
609  }
610  }
611  }
612 
613 
614  if (currentCell == -1)
615  {
616  break;
617  }
618 
619 
620  // Starting from currentCell walk breadth-first
621 
622 
623  // use this cell as a start
624  nextCell.append(currentCell);
625 
626  // loop through the nextCell list. Add the first cell into the
627  // cell order if it has not already been visited and ask for its
628  // neighbours. If the neighbour in question has not been visited,
629  // add it to the end of the nextCell list
630 
631  while (nextCell.size())
632  {
633  currentCell = nextCell.removeHead();
634 
635  if (!visited[currentCell])
636  {
637  visited[currentCell] = 1;
638 
639  // add into cellOrder
640  newOrder[cellInOrder] = currentCell;
641  cellInOrder++;
642 
643  // find if the neighbours have been visited
644  const labelUList neighbours = cellCellAddressing[currentCell];
645 
646  // Add in increasing order of connectivity
647 
648  // 1. Count neighbours of unvisited neighbours
649  nbrs.clear();
650  weights.clear();
651 
652  forAll(neighbours, nI)
653  {
654  label nbr = neighbours[nI];
655  if (!cellRemoved(nbr) && !visited[nbr])
656  {
657  // not visited, add to the list
658  nbrs.append(nbr);
659  weights.append(cellCellAddressing[nbr].size());
660  }
661  }
662  // 2. Sort
663  sortedOrder(weights, order);
664  // 3. Add in sorted order
665  forAll(order, i)
666  {
667  nextCell.append(nbrs[i]);
668  }
669  }
670  }
671  }
672 
673  // Now we have new-to-old in newOrder.
674  newOrder.setSize(cellInOrder);
675 
676  // Invert to get old-to-new. Make sure removed (i.e. unmapped) cells are -1.
677  oldToNew = invert(cellCellAddressing.size(), newOrder);
678 
679  return cellInOrder;
680 }
681 
682 
683 void Foam::polyTopoChange::getFaceOrder
684 (
685  const label nActiveFaces,
686  const labelList& cellFaces,
687  const labelList& cellFaceOffsets,
688 
689  labelList& oldToNew,
690  labelList& patchSizes,
691  labelList& patchStarts
692 ) const
693 {
694  oldToNew.setSize(faceOwner_.size());
695  oldToNew = -1;
696 
697  // First unassigned face
698  label newFacei = 0;
699 
700  labelList nbr;
702 
703  forAll(cellMap_, celli)
704  {
705  label startOfCell = cellFaceOffsets[celli];
706  label nFaces = cellFaceOffsets[celli+1] - startOfCell;
707 
708  // Neighbouring cells
709  // SortableList<label> nbr(nFaces);
710  nbr.setSize(nFaces);
711 
712  for (label i = 0; i < nFaces; i++)
713  {
714  label facei = cellFaces[startOfCell + i];
715 
716  label nbrCelli = faceNeighbour_[facei];
717 
718  if (facei >= nActiveFaces)
719  {
720  // Retired face.
721  nbr[i] = -1;
722  }
723  else if (nbrCelli != -1)
724  {
725  // Internal face. Get cell on other side.
726  if (nbrCelli == celli)
727  {
728  nbrCelli = faceOwner_[facei];
729  }
730 
731  if (celli < nbrCelli)
732  {
733  // Celli is master
734  nbr[i] = nbrCelli;
735  }
736  else
737  {
738  // nbrCell is master. Let it handle this face.
739  nbr[i] = -1;
740  }
741  }
742  else
743  {
744  // External face. Do later.
745  nbr[i] = -1;
746  }
747  }
748 
749  // nbr.sort();
750  order.setSize(nFaces);
751  sortedOrder(nbr, order);
752 
753  forAll(order, i)
754  {
755  label index = order[i];
756  if (nbr[index] != -1)
757  {
758  oldToNew[cellFaces[startOfCell + index]] = newFacei++;
759  }
760  }
761  }
762 
763 
764  // Pick up all patch faces in patch face order.
765  patchStarts.setSize(nPatches_);
766  patchStarts = 0;
767  patchSizes.setSize(nPatches_);
768  patchSizes = 0;
769 
770  if (nPatches_ > 0)
771  {
772  patchStarts[0] = newFacei;
773 
774  for (label facei = 0; facei < nActiveFaces; facei++)
775  {
776  if (region_[facei] >= 0)
777  {
778  patchSizes[region_[facei]]++;
779  }
780  }
781 
782  label facei = patchStarts[0];
783 
784  forAll(patchStarts, patchi)
785  {
786  patchStarts[patchi] = facei;
787  facei += patchSizes[patchi];
788  }
789  }
790 
791  labelList workPatchStarts(patchStarts);
792 
793  for (label facei = 0; facei < nActiveFaces; facei++)
794  {
795  if (region_[facei] >= 0)
796  {
797  oldToNew[facei] = workPatchStarts[region_[facei]]++;
798  }
799  }
800 
801  // Retired faces.
802  for (label facei = nActiveFaces; facei < oldToNew.size(); facei++)
803  {
804  oldToNew[facei] = facei;
805  }
806 
807  // Check done all faces.
808  forAll(oldToNew, facei)
809  {
810  if (oldToNew[facei] == -1)
811  {
813  << "Did not determine new position"
814  << " for face " << facei
815  << " owner " << faceOwner_[facei]
816  << " neighbour " << faceNeighbour_[facei]
817  << " region " << region_[facei] << endl
818  << "This is usually caused by not specifying a patch for"
819  << " a boundary face." << nl
820  << "Switch on the polyTopoChange::debug flag to catch"
821  << " this error earlier." << nl;
822  if (hasValidPoints(faces_[facei]))
823  {
824  FatalError
825  << "points (removed points marked with "
826  << vector::max << ") " << facePoints(faces_[facei]);
827  }
829  }
830  }
831 }
832 
833 
834 void Foam::polyTopoChange::reorderCompactFaces
835 (
836  const label newSize,
837  const labelList& oldToNew
838 )
839 {
840  reorder(oldToNew, faces_);
841  faces_.setCapacity(newSize);
842 
843  reorder(oldToNew, region_);
844  region_.setCapacity(newSize);
845 
846  reorder(oldToNew, faceOwner_);
847  faceOwner_.setCapacity(newSize);
848 
849  reorder(oldToNew, faceNeighbour_);
850  faceNeighbour_.setCapacity(newSize);
851 
852  // Update faceMaps.
853  reorder(oldToNew, faceMap_);
854  faceMap_.setCapacity(newSize);
855 
856  renumberReverseMap(oldToNew, reverseFaceMap_);
857 
858  inplaceReorder(oldToNew, flipFaceFlux_);
859  flipFaceFlux_.setCapacity(newSize);
860 }
861 
862 
863 void Foam::polyTopoChange::compact
864 (
865  const bool orderCells,
866  const bool orderPoints,
867  label& nInternalPoints,
868  labelList& patchSizes,
869  labelList& patchStarts
870 )
871 {
872  points_.shrink();
873  pointMap_.shrink();
874  reversePointMap_.shrink();
875 
876  faces_.shrink();
877  region_.shrink();
878  faceOwner_.shrink();
879  faceNeighbour_.shrink();
880  faceMap_.shrink();
881  reverseFaceMap_.shrink();
882 
883  cellMap_.shrink();
884  reverseCellMap_.shrink();
885 
886 
887  // Compact points
888  label nActivePoints = 0;
889  {
890  labelList localPointMap(points_.size(), -1);
891  label newPointi = 0;
892 
893  if (!orderPoints)
894  {
895  nInternalPoints = -1;
896 
897  forAll(points_, pointi)
898  {
899  if (!pointRemoved(pointi) && !retiredPoints_.found(pointi))
900  {
901  localPointMap[pointi] = newPointi++;
902  }
903  }
904  nActivePoints = newPointi;
905  }
906  else
907  {
908  forAll(points_, pointi)
909  {
910  if (!pointRemoved(pointi) && !retiredPoints_.found(pointi))
911  {
912  nActivePoints++;
913  }
914  }
915 
916  // Mark boundary points
917  forAll(faceOwner_, facei)
918  {
919  if
920  (
921  !faceRemoved(facei)
922  && faceOwner_[facei] >= 0
923  && faceNeighbour_[facei] < 0
924  )
925  {
926  // Valid boundary face
927  const face& f = faces_[facei];
928 
929  forAll(f, fp)
930  {
931  label pointi = f[fp];
932 
933  if (localPointMap[pointi] == -1)
934  {
935  if
936  (
937  pointRemoved(pointi)
938  || retiredPoints_.found(pointi)
939  )
940  {
942  << "Removed or retired point " << pointi
943  << " in face " << f
944  << " at position " << facei << endl
945  << "Probably face has not been adapted for"
946  << " removed points." << abort(FatalError);
947  }
948  localPointMap[pointi] = newPointi++;
949  }
950  }
951  }
952  }
953 
954  label nBoundaryPoints = newPointi;
955  nInternalPoints = nActivePoints - nBoundaryPoints;
956 
957  // Move the boundary addressing up
958  forAll(localPointMap, pointi)
959  {
960  if (localPointMap[pointi] != -1)
961  {
962  localPointMap[pointi] += nInternalPoints;
963  }
964  }
965 
966  newPointi = 0;
967 
968  // Mark internal points
969  forAll(faceOwner_, facei)
970  {
971  if
972  (
973  !faceRemoved(facei)
974  && faceOwner_[facei] >= 0
975  && faceNeighbour_[facei] >= 0
976  )
977  {
978  // Valid internal face
979  const face& f = faces_[facei];
980 
981  forAll(f, fp)
982  {
983  label pointi = f[fp];
984 
985  if (localPointMap[pointi] == -1)
986  {
987  if
988  (
989  pointRemoved(pointi)
990  || retiredPoints_.found(pointi)
991  )
992  {
994  << "Removed or retired point " << pointi
995  << " in face " << f
996  << " at position " << facei << endl
997  << "Probably face has not been adapted for"
998  << " removed points." << abort(FatalError);
999  }
1000  localPointMap[pointi] = newPointi++;
1001  }
1002  }
1003  }
1004  }
1005 
1006  if (newPointi != nInternalPoints)
1007  {
1009  << "Problem." << abort(FatalError);
1010  }
1011  newPointi = nActivePoints;
1012  }
1013 
1014  forAllConstIter(labelHashSet, retiredPoints_, iter)
1015  {
1016  localPointMap[iter.key()] = newPointi++;
1017  }
1018 
1019 
1020  if (debug)
1021  {
1022  Pout<< "Points : active:" << nActivePoints
1023  << " removed:" << points_.size()-newPointi << endl;
1024  }
1025 
1026  reorder(localPointMap, points_);
1027  points_.setCapacity(newPointi);
1028 
1029  // Update pointMaps
1030  reorder(localPointMap, pointMap_);
1031  pointMap_.setCapacity(newPointi);
1032  renumberReverseMap(localPointMap, reversePointMap_);
1033 
1034  renumberKey(localPointMap, oldPoints_);
1035  renumber(localPointMap, retiredPoints_);
1036 
1037  // Use map to relabel face vertices
1038  forAll(faces_, facei)
1039  {
1040  face& f = faces_[facei];
1041 
1042  // labelList oldF(f);
1043  renumberCompact(localPointMap, f);
1044 
1045  if (!faceRemoved(facei) && f.size() < 3)
1046  {
1048  << "Created illegal face " << f
1049  //<< " from face " << oldF
1050  << " at position:" << facei
1051  << " when filtering removed points"
1052  << abort(FatalError);
1053  }
1054  }
1055  }
1056 
1057 
1058  // Compact faces.
1059  {
1060  labelList localFaceMap(faces_.size(), -1);
1061  label newFacei = 0;
1062 
1063  forAll(faces_, facei)
1064  {
1065  if (!faceRemoved(facei) && faceOwner_[facei] >= 0)
1066  {
1067  localFaceMap[facei] = newFacei++;
1068  }
1069  }
1070  nActiveFaces_ = newFacei;
1071 
1072  forAll(faces_, facei)
1073  {
1074  if (!faceRemoved(facei) && faceOwner_[facei] < 0)
1075  {
1076  // Retired face
1077  localFaceMap[facei] = newFacei++;
1078  }
1079  }
1080 
1081  if (debug)
1082  {
1083  Pout<< "Faces : active:" << nActiveFaces_
1084  << " removed:" << faces_.size()-newFacei << endl;
1085  }
1086 
1087  // Reorder faces.
1088  reorderCompactFaces(newFacei, localFaceMap);
1089  }
1090 
1091  // Compact cells.
1092  {
1093  labelList localCellMap;
1094  label newCelli;
1095 
1096  if (orderCells)
1097  {
1098  // Construct cellCell addressing
1099  CompactListList<label> cellCells;
1100  makeCellCells(nActiveFaces_, cellCells);
1101 
1102  // Cell ordering (based on bandCompression). Handles removed cells.
1103  newCelli = getCellOrder(cellCells, localCellMap);
1104  }
1105  else
1106  {
1107  // Compact out removed cells
1108  localCellMap.setSize(cellMap_.size());
1109  localCellMap = -1;
1110 
1111  newCelli = 0;
1112  forAll(cellMap_, celli)
1113  {
1114  if (!cellRemoved(celli))
1115  {
1116  localCellMap[celli] = newCelli++;
1117  }
1118  }
1119  }
1120 
1121  if (debug)
1122  {
1123  Pout<< "Cells : active:" << newCelli
1124  << " removed:" << cellMap_.size()-newCelli << endl;
1125  }
1126 
1127  // Renumber -if cells reordered or -if cells removed
1128  if (orderCells || (newCelli != cellMap_.size()))
1129  {
1130  reorder(localCellMap, cellMap_);
1131  cellMap_.setCapacity(newCelli);
1132  renumberReverseMap(localCellMap, reverseCellMap_);
1133 
1134  // Renumber owner/neighbour. Take into account if neighbour suddenly
1135  // gets lower cell than owner.
1136  forAll(faceOwner_, facei)
1137  {
1138  label own = faceOwner_[facei];
1139  label nei = faceNeighbour_[facei];
1140 
1141  if (own >= 0)
1142  {
1143  // Update owner
1144  faceOwner_[facei] = localCellMap[own];
1145 
1146  if (nei >= 0)
1147  {
1148  // Update neighbour.
1149  faceNeighbour_[facei] = localCellMap[nei];
1150 
1151  // Check if face needs reversing.
1152  if
1153  (
1154  faceNeighbour_[facei] >= 0
1155  && faceNeighbour_[facei] < faceOwner_[facei]
1156  )
1157  {
1158  faces_[facei].flip();
1159  Swap(faceOwner_[facei], faceNeighbour_[facei]);
1160  flipFaceFlux_[facei] =
1161  (
1162  flipFaceFlux_[facei]
1163  ? 0
1164  : 1
1165  );
1166  }
1167  }
1168  }
1169  else if (nei >= 0)
1170  {
1171  // Update neighbour.
1172  faceNeighbour_[facei] = localCellMap[nei];
1173  }
1174  }
1175  }
1176  }
1177 
1178  // Reorder faces into upper-triangular and patch ordering
1179  {
1180  // Create cells (packed storage)
1181  labelList cellFaces;
1182  labelList cellFaceOffsets;
1183  makeCells(nActiveFaces_, cellFaces, cellFaceOffsets);
1184 
1185  // Do upper triangular order and patch sorting
1186  labelList localFaceMap;
1187  getFaceOrder
1188  (
1189  nActiveFaces_,
1190  cellFaces,
1191  cellFaceOffsets,
1192 
1193  localFaceMap,
1194  patchSizes,
1195  patchStarts
1196  );
1197 
1198  // Reorder faces.
1199  reorderCompactFaces(localFaceMap.size(), localFaceMap);
1200  }
1201 }
1202 
1203 
1204 Foam::labelList Foam::polyTopoChange::selectFaces
1205 (
1206  const primitiveMesh& mesh,
1207  const labelList& faceLabels,
1208  const bool internalFacesOnly
1209 )
1210 {
1211  label nFaces = 0;
1212 
1213  forAll(faceLabels, i)
1214  {
1215  label facei = faceLabels[i];
1216 
1217  if (internalFacesOnly == mesh.isInternalFace(facei))
1218  {
1219  nFaces++;
1220  }
1221  }
1222 
1223  labelList collectedFaces;
1224 
1225  if (nFaces == 0)
1226  {
1227  // Did not find any faces of the correct type so just use any old
1228  // face.
1229  collectedFaces = faceLabels;
1230  }
1231  else
1232  {
1233  collectedFaces.setSize(nFaces);
1234 
1235  nFaces = 0;
1236 
1237  forAll(faceLabels, i)
1238  {
1239  label facei = faceLabels[i];
1240 
1241  if (internalFacesOnly == mesh.isInternalFace(facei))
1242  {
1243  collectedFaces[nFaces++] = facei;
1244  }
1245  }
1246  }
1247 
1248  return collectedFaces;
1249 }
1250 
1251 
1252 void Foam::polyTopoChange::calcPatchPointMap
1253 (
1254  const List<Map<label>>& oldPatchMeshPointMaps,
1255  const polyBoundaryMesh& boundary,
1256  labelListList& patchPointMap
1257 ) const
1258 {
1259  patchPointMap.setSize(boundary.size());
1260 
1262  {
1263  const labelList& meshPoints = boundary[patchi].meshPoints();
1264 
1265  const Map<label>& oldMeshPointMap = oldPatchMeshPointMaps[patchi];
1266 
1267  labelList& curPatchPointRnb = patchPointMap[patchi];
1268 
1269  curPatchPointRnb.setSize(meshPoints.size());
1270 
1271  forAll(meshPoints, i)
1272  {
1273  if (meshPoints[i] < pointMap_.size())
1274  {
1275  // Check if old point was part of same patch
1276  Map<label>::const_iterator ozmpmIter = oldMeshPointMap.find
1277  (
1278  pointMap_[meshPoints[i]]
1279  );
1280 
1281  if (ozmpmIter != oldMeshPointMap.end())
1282  {
1283  curPatchPointRnb[i] = ozmpmIter();
1284  }
1285  else
1286  {
1287  curPatchPointRnb[i] = -1;
1288  }
1289  }
1290  else
1291  {
1292  curPatchPointRnb[i] = -1;
1293  }
1294  }
1295  }
1296 }
1297 
1298 
1299 void Foam::polyTopoChange::reorderCoupledFaces
1300 (
1301  const bool syncParallel,
1302  const polyBoundaryMesh& boundary,
1303  const labelList& patchStarts,
1304  const labelList& patchSizes,
1305  const pointField& points
1306 )
1307 {
1308  // Mapping for faces (old to new). Extends over all mesh faces for
1309  // convenience (could be just the external faces)
1310  labelList oldToNew(identityMap(faces_.size()));
1311 
1312  // Rotation on new faces.
1313  labelList rotation(faces_.size(), 0);
1314 
1315  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
1316 
1317  // Send ordering
1319  {
1320  if (syncParallel || !isA<processorPolyPatch>(boundary[patchi]))
1321  {
1322  boundary[patchi].initOrder
1323  (
1324  pBufs,
1326  (
1327  SubList<face>
1328  (
1329  faces_,
1330  patchSizes[patchi],
1331  patchStarts[patchi]
1332  ),
1333  points
1334  )
1335  );
1336  }
1337  }
1338 
1339  if (syncParallel)
1340  {
1341  pBufs.finishedSends();
1342  }
1343 
1344  // Receive and calculate ordering
1345 
1346  bool anyChanged = false;
1347 
1349  {
1350  if (syncParallel || !isA<processorPolyPatch>(boundary[patchi]))
1351  {
1352  labelList patchFaceMap(patchSizes[patchi], -1);
1353  labelList patchFaceRotation(patchSizes[patchi], 0);
1354 
1355  bool changed = boundary[patchi].order
1356  (
1357  pBufs,
1359  (
1360  SubList<face>
1361  (
1362  faces_,
1363  patchSizes[patchi],
1364  patchStarts[patchi]
1365  ),
1366  points
1367  ),
1368  patchFaceMap,
1369  patchFaceRotation
1370  );
1371 
1372  if (changed)
1373  {
1374  // Merge patch face reordering into mesh face reordering table
1375  label start = patchStarts[patchi];
1376 
1377  forAll(patchFaceMap, patchFacei)
1378  {
1379  oldToNew[patchFacei + start] =
1380  start + patchFaceMap[patchFacei];
1381  }
1382 
1383  forAll(patchFaceRotation, patchFacei)
1384  {
1385  rotation[patchFacei + start] =
1386  patchFaceRotation[patchFacei];
1387  }
1388 
1389  anyChanged = true;
1390  }
1391  }
1392  }
1393 
1394  if (syncParallel)
1395  {
1396  reduce(anyChanged, orOp<bool>());
1397  }
1398 
1399  if (anyChanged)
1400  {
1401  // Reorder faces according to oldToNew.
1402  reorderCompactFaces(oldToNew.size(), oldToNew);
1403 
1404  // Rotate faces (rotation is already in new face indices).
1405  forAll(rotation, facei)
1406  {
1407  if (rotation[facei] != 0)
1408  {
1409  inplaceRotateList<List, label>(faces_[facei], rotation[facei]);
1410  }
1411  }
1412  }
1413 }
1414 
1415 
1416 void Foam::polyTopoChange::compactAndReorder
1417 (
1418  const polyMesh& mesh,
1419  const bool syncParallel,
1420  const bool orderCells,
1421  const bool orderPoints,
1422 
1423  label& nInternalPoints,
1424  pointField& newPoints,
1425  labelList& patchSizes,
1426  labelList& patchStarts,
1427  List<objectMap>& pointsFromPoints,
1428  List<objectMap>& facesFromFaces,
1429  List<objectMap>& cellsFromCells,
1430  List<Map<label>>& oldPatchMeshPointMaps,
1431  labelList& oldPatchNMeshPoints,
1432  labelList& oldPatchSizes,
1433  labelList& oldPatchStarts
1434 )
1435 {
1436  if (mesh.boundaryMesh().size() != nPatches_)
1437  {
1439  << "polyTopoChange was constructed with a mesh with "
1440  << nPatches_ << " patches." << endl
1441  << "The mesh now provided has a different number of patches "
1442  << mesh.boundaryMesh().size()
1443  << " which is illegal" << endl
1444  << abort(FatalError);
1445  }
1446 
1447  // Remove any holes from points/faces/cells and sort faces.
1448  // Sets nActiveFaces_.
1449  compact(orderCells, orderPoints, nInternalPoints, patchSizes, patchStarts);
1450 
1451  // Transfer points to pointField. points_ are now cleared!
1452  // Only done since e.g. reorderCoupledFaces requires pointField.
1453  newPoints.transfer(points_);
1454 
1455  // Reorder any coupled faces
1456  reorderCoupledFaces
1457  (
1458  syncParallel,
1459  mesh.boundaryMesh(),
1460  patchStarts,
1461  patchSizes,
1462  newPoints
1463  );
1464 
1465 
1466  // Calculate merging maps
1467  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1468  // These are for the new face(/point/cell) the old faces whose value
1469  // needs to be
1470  // averaged/summed to get the new value. These old faces come either from
1471  // merged old faces (face remove into other face).
1472  // As an additional complexity will use only internal faces
1473  // to create new value for internal face and vice versa only patch
1474  // faces to to create patch face value.
1475 
1476  // For point only point merging
1477  getMergeSets
1478  (
1479  reversePointMap_,
1480  pointMap_,
1481  pointsFromPoints
1482  );
1483 
1484  getMergeSets
1485  (
1486  reverseFaceMap_,
1487  faceMap_,
1488  facesFromFaces
1489  );
1490 
1491  getMergeSets
1492  (
1493  reverseCellMap_,
1494  cellMap_,
1495  cellsFromCells
1496  );
1497 
1498  const polyBoundaryMesh& boundary = mesh.boundaryMesh();
1499 
1500  // Grab patch mesh point maps
1501  oldPatchMeshPointMaps.setSize(boundary.size());
1502  oldPatchNMeshPoints.setSize(boundary.size());
1503  oldPatchSizes.setSize(boundary.size());
1504  oldPatchStarts.setSize(boundary.size());
1505 
1507  {
1508  oldPatchMeshPointMaps[patchi] = boundary[patchi].meshPointMap();
1509  oldPatchNMeshPoints[patchi] = boundary[patchi].meshPoints().size();
1510  oldPatchSizes[patchi] = boundary[patchi].size();
1511  oldPatchStarts[patchi] = boundary[patchi].start();
1512  }
1513 }
1514 
1515 
1516 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1517 
1519 :
1520  strict_(strict),
1521  nPatches_(nPatches),
1522  points_(0),
1523  pointMap_(0),
1524  reversePointMap_(0),
1525  retiredPoints_(0),
1526  oldPoints_(0),
1527  faces_(0),
1528  region_(0),
1529  faceOwner_(0),
1530  faceNeighbour_(0),
1531  faceMap_(0),
1532  reverseFaceMap_(0),
1533  flipFaceFlux_(0),
1534  nActiveFaces_(0),
1535  cellMap_(0),
1536  reverseCellMap_(0)
1537 {}
1538 
1539 
1541 (
1542  const polyMesh& mesh,
1543  const bool strict
1544 )
1545 :
1546  strict_(strict),
1547  nPatches_(mesh.boundaryMesh().size()),
1548  points_(0),
1549  pointMap_(0),
1550  reversePointMap_(0),
1551  retiredPoints_(0),
1552  oldPoints_(0),
1553  faces_(0),
1554  region_(0),
1555  faceOwner_(0),
1556  faceNeighbour_(0),
1557  faceMap_(0),
1558  reverseFaceMap_(0),
1559  flipFaceFlux_(0),
1560  nActiveFaces_(0),
1561  cellMap_(0),
1562  reverseCellMap_(0)
1563 {
1564  // Add points
1565  {
1566  const pointField& points = mesh.points();
1567 
1568  // Extend
1569  points_.setCapacity(points_.size() + points.size());
1570  pointMap_.setCapacity(pointMap_.size() + points.size());
1571  reversePointMap_.setCapacity(reversePointMap_.size() + points.size());
1572  // No need to extend oldPoints_
1573 
1574  // Add points in mesh order
1575  for (label pointi = 0; pointi < mesh.nPoints(); pointi++)
1576  {
1577  addPoint(points[pointi], pointi, true);
1578  }
1579  }
1580 
1581  // Add cells
1582  {
1583  // Resize
1584 
1585  // Note: polyMesh does not allow retired cells anymore. So allCells
1586  // always equals nCells
1587  label nAllCells = mesh.nCells();
1588 
1589  cellMap_.setCapacity(cellMap_.size() + nAllCells);
1590  reverseCellMap_.setCapacity(reverseCellMap_.size() + nAllCells);
1591 
1592  // Add cells in mesh order
1593  for (label celli = 0; celli < nAllCells; celli++)
1594  {
1595  addCell(celli);
1596  }
1597  }
1598 
1599  // Add faces
1600  {
1602  const faceList& faces = mesh.faces();
1603  const labelList& faceOwner = mesh.faceOwner();
1605 
1606  // Resize
1607  label nAllFaces = mesh.faces().size();
1608 
1609  faces_.setCapacity(faces_.size() + nAllFaces);
1610  region_.setCapacity(region_.size() + nAllFaces);
1611  faceOwner_.setCapacity(faceOwner_.size() + nAllFaces);
1612  faceNeighbour_.setCapacity(faceNeighbour_.size() + nAllFaces);
1613  faceMap_.setCapacity(faceMap_.size() + nAllFaces);
1614  reverseFaceMap_.setCapacity(reverseFaceMap_.size() + nAllFaces);
1615  flipFaceFlux_.setCapacity(faces_.size() + nAllFaces);
1616 
1617 
1618  // Add faces in order
1619 
1620  // 1. Add internal faces in increasing face order
1621  for (label facei=0; facei<mesh.nInternalFaces(); facei++)
1622  {
1623  addFace
1624  (
1625  faces[facei],
1626  faceOwner[facei],
1627  faceNeighbour[facei],
1628  facei, // masterFaceID
1629  false, // flipFaceFlux
1630  -1 // patchID
1631  );
1632  }
1633 
1634  // Find patch order with increasing face order
1635  SortableList<label> patchStartOrder(patches.size());
1637  {
1638  patchStartOrder[patchi] = patches[patchi].start();
1639  }
1640  patchStartOrder.sort();
1641 
1642  // 2. Add patch faces in increasing face order
1643  forAll(patchStartOrder, i)
1644  {
1645  const label patchi = patchStartOrder.indices()[i];
1646  const polyPatch& pp = patches[patchi];
1647 
1648  forAll(pp, patchFacei)
1649  {
1650  const label facei = pp.start() + patchFacei;
1651 
1652  addFace
1653  (
1654  faces[facei],
1655  faceOwner[facei],
1656  -1, // neighbour
1657  facei, // masterFaceID
1658  false, // flipFaceFlux
1659  patchi // patchID
1660  );
1661  }
1662  }
1663  }
1664 }
1665 
1666 
1667 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1668 
1670 {
1671  points_.clearStorage();
1672  pointMap_.clearStorage();
1673  reversePointMap_.clearStorage();
1674  retiredPoints_.clearStorage();
1675  oldPoints_.clearStorage();
1676 
1677  faces_.clearStorage();
1678  region_.clearStorage();
1679  faceOwner_.clearStorage();
1680  faceNeighbour_.clearStorage();
1681  faceMap_.clearStorage();
1682  reverseFaceMap_.clearStorage();
1683  flipFaceFlux_.clearStorage();
1684  nActiveFaces_ = 0;
1685 
1686  cellMap_.clearStorage();
1687  reverseCellMap_.clearStorage();
1688 }
1689 
1690 
1692 (
1693  const label nPoints,
1694  const label nFaces,
1695  const label nCells
1696 )
1697 {
1698  points_.setCapacity(nPoints);
1699  pointMap_.setCapacity(nPoints);
1700  reversePointMap_.setCapacity(nPoints);
1701 
1702  faces_.setCapacity(nFaces);
1703  region_.setCapacity(nFaces);
1704  faceOwner_.setCapacity(nFaces);
1705  faceNeighbour_.setCapacity(nFaces);
1706  faceMap_.setCapacity(nFaces);
1707  reverseFaceMap_.setCapacity(nFaces);
1708  flipFaceFlux_.setCapacity(nFaces);
1709 
1710  cellMap_.setCapacity(nCells);
1711  reverseCellMap_.setCapacity(nCells);
1712 }
1713 
1714 
1716 (
1717  const point& pt,
1718  const label masterPointID,
1719  const bool inCell
1720 )
1721 {
1722  label pointi = points_.size();
1723 
1724  points_.append(pt);
1725  pointMap_.append(masterPointID);
1726  reversePointMap_.append(pointi);
1727 
1728  if (!inCell)
1729  {
1730  retiredPoints_.insert(pointi);
1731  }
1732 
1733  return pointi;
1734 }
1735 
1736 
1738 (
1739  const label pointi,
1740  const point& pt,
1741  const bool inCell
1742 )
1743 {
1744  if (pointi < 0 || pointi >= points_.size())
1745  {
1747  << "illegal point label " << pointi << endl
1748  << "Valid point labels are 0 .. " << points_.size()-1
1749  << abort(FatalError);
1750  }
1751  if (pointRemoved(pointi) || pointMap_[pointi] == -1)
1752  {
1754  << "point " << pointi << " already marked for removal"
1755  << abort(FatalError);
1756  }
1757  points_[pointi] = pt;
1758 
1759  if (inCell)
1760  {
1761  retiredPoints_.erase(pointi);
1762  }
1763  else
1764  {
1765  retiredPoints_.insert(pointi);
1766  }
1767 
1768  oldPoints_.erase(pointi);
1769 }
1770 
1771 
1773 (
1774  const label pointi,
1775  const label mergePointi
1776 )
1777 {
1778  if (pointi < 0 || pointi >= points_.size())
1779  {
1781  << "illegal point label " << pointi << endl
1782  << "Valid point labels are 0 .. " << points_.size()-1
1783  << abort(FatalError);
1784  }
1785 
1786  if
1787  (
1788  strict_
1789  && (pointRemoved(pointi) || pointMap_[pointi] == -1)
1790  )
1791  {
1793  << "point " << pointi << " already marked for removal" << nl
1794  << "Point:" << points_[pointi] << " pointMap:" << pointMap_[pointi]
1795  << abort(FatalError);
1796  }
1797 
1798  if (pointi == mergePointi)
1799  {
1801  << "Cannot remove/merge point " << pointi << " onto itself."
1802  << abort(FatalError);
1803  }
1804 
1805  points_[pointi] = point::max;
1806  pointMap_[pointi] = -1;
1807  if (mergePointi >= 0)
1808  {
1809  reversePointMap_[pointi] = -mergePointi-2;
1810  }
1811  else
1812  {
1813  reversePointMap_[pointi] = -1;
1814  }
1815  retiredPoints_.erase(pointi);
1816  oldPoints_.erase(pointi);
1817 }
1818 
1819 
1821 (
1822  const face& f,
1823  const label own,
1824  const label nei,
1825  const label masterFaceID,
1826  const bool flipFaceFlux,
1827  const label patchID
1828 )
1829 {
1830  // Check validity
1831  if (debug)
1832  {
1833  checkFace(f, -1, own, nei, patchID);
1834  }
1835 
1836  label facei = faces_.size();
1837 
1838  faces_.append(f);
1839  region_.append(patchID);
1840  faceOwner_.append(own);
1841  faceNeighbour_.append(nei);
1842 
1843  if (masterFaceID >= 0)
1844  {
1845  faceMap_.append(masterFaceID);
1846  }
1847  else
1848  {
1849  // Allow insert-from-nothing?
1850  // FatalErrorInFunction
1851  // << "Need to specify a master point, edge or face"
1852  // << "face:" << f << " own:" << own << " nei:" << nei
1853  // << abort(FatalError);
1854  faceMap_.append(-1);
1855  }
1856  reverseFaceMap_.append(facei);
1857 
1858  flipFaceFlux_[facei] = (flipFaceFlux ? 1 : 0);
1859 
1860  return facei;
1861 }
1862 
1863 
1865 (
1866  const face& f,
1867  const label facei,
1868  const label own,
1869  const label nei,
1870  const bool flipFaceFlux,
1871  const label patchID
1872 )
1873 {
1874  // Check validity
1875  if (debug)
1876  {
1877  checkFace(f, facei, own, nei, patchID);
1878  }
1879 
1880  faces_[facei] = f;
1881  faceOwner_[facei] = own;
1882  faceNeighbour_[facei] = nei;
1883  region_[facei] = patchID;
1884 
1885  flipFaceFlux_[facei] = (flipFaceFlux ? 1 : 0);
1886 }
1887 
1888 
1889 void Foam::polyTopoChange::removeFace(const label facei, const label mergeFacei)
1890 {
1891  if (facei < 0 || facei >= faces_.size())
1892  {
1894  << "illegal face label " << facei << endl
1895  << "Valid face labels are 0 .. " << faces_.size()-1
1896  << abort(FatalError);
1897  }
1898 
1899  if
1900  (
1901  strict_
1902  && (faceRemoved(facei) || faceMap_[facei] == -1)
1903  )
1904  {
1906  << "face " << facei
1907  << " already marked for removal"
1908  << abort(FatalError);
1909  }
1910 
1911  faces_[facei].setSize(0);
1912  region_[facei] = -1;
1913  faceOwner_[facei] = -1;
1914  faceNeighbour_[facei] = -1;
1915  faceMap_[facei] = -1;
1916  if (mergeFacei >= 0)
1917  {
1918  reverseFaceMap_[facei] = -mergeFacei-2;
1919  }
1920  else
1921  {
1922  reverseFaceMap_[facei] = -1;
1923  }
1924  flipFaceFlux_[facei] = 0;
1925 }
1926 
1927 
1929 {
1930  const label celli = cellMap_.size();
1931  cellMap_.append(masterCellID);
1932  reverseCellMap_.append(celli);
1933 
1934  return celli;
1935 }
1936 
1937 
1938 void Foam::polyTopoChange::removeCell(const label celli, const label mergeCelli)
1939 {
1940  if (celli < 0 || celli >= cellMap_.size())
1941  {
1943  << "illegal cell label " << celli << endl
1944  << "Valid cell labels are 0 .. " << cellMap_.size()-1
1945  << abort(FatalError);
1946  }
1947 
1948  if (strict_ && cellMap_[celli] == -2)
1949  {
1951  << "cell " << celli
1952  << " already marked for removal"
1953  << abort(FatalError);
1954  }
1955 
1956  cellMap_[celli] = -2;
1957  if (mergeCelli >= 0)
1958  {
1959  reverseCellMap_[celli] = -mergeCelli-2;
1960  }
1961  else
1962  {
1963  reverseCellMap_[celli] = -1;
1964  }
1965 }
1966 
1967 
1969 (
1970  polyMesh& mesh,
1971  const bool syncParallel,
1972  const bool orderCells,
1973  const bool orderPoints
1974 )
1975 {
1976  if (debug)
1977  {
1978  Pout<< "polyTopoChange::changeMesh"
1979  << "(polyMesh&, const bool, const bool, const bool, const bool)"
1980  << endl;
1981  }
1982 
1983  if (debug)
1984  {
1985  Pout<< "Old mesh:" << nl;
1986  writeMeshStats(mesh, Pout);
1987  }
1988 
1989  // new mesh points
1990  pointField newPoints;
1991 
1992  // number of internal points
1993  label nInternalPoints;
1994 
1995  // patch slicing
1996  labelList patchSizes;
1997  labelList patchStarts;
1998 
1999  // maps
2000  List<objectMap> pointsFromPoints;
2001  List<objectMap> facesFromFaces;
2002  List<objectMap> cellsFromCells;
2003 
2004  // old mesh info
2005  List<Map<label>> oldPatchMeshPointMaps;
2006  labelList oldPatchNMeshPoints;
2007  labelList oldPatchSizes;
2008  labelList oldPatchStarts;
2009 
2010  // Compact, reorder patch faces and calculate mesh/patch maps.
2011  compactAndReorder
2012  (
2013  mesh,
2014  syncParallel,
2015  orderCells,
2016  orderPoints,
2017 
2018  nInternalPoints,
2019  newPoints,
2020  patchSizes,
2021  patchStarts,
2022  pointsFromPoints,
2023  facesFromFaces,
2024  cellsFromCells,
2025  oldPatchMeshPointMaps,
2026  oldPatchNMeshPoints,
2027  oldPatchSizes,
2028  oldPatchStarts
2029  );
2030 
2031  const label nOldPoints(mesh.nPoints());
2032  const label nOldFaces(mesh.nFaces());
2033  const label nOldCells(mesh.nCells());
2034  autoPtr<scalarField> oldCellVolumes(new scalarField(mesh.cellVolumes()));
2035 
2036 
2037  // Change the mesh
2038  // ~~~~~~~~~~~~~~~
2039  // This will invalidate any addressing so better make sure you have
2040  // all the information you need!!!
2041 
2042  // Set new points.
2044  (
2045  move(newPoints),
2046  move(faces_),
2047  move(faceOwner_),
2048  move(faceNeighbour_),
2049  patchSizes,
2050  patchStarts,
2051  syncParallel
2052  );
2053 
2054  // Clear out primitives
2055  {
2056  retiredPoints_.clearStorage();
2057  oldPoints_.clearStorage();
2058  region_.clearStorage();
2059  }
2060 
2061 
2062  if (debug)
2063  {
2064  // Some stats on changes
2065  label nSplit, nInserted, nMerge, nRemove;
2066  countMap
2067  (
2068  pointMap_,
2069  reversePointMap_,
2070  nSplit,
2071  nInserted,
2072  nMerge,
2073  nRemove
2074  );
2075  Pout<< "Points:"
2076  << " added(from point):" << nSplit
2077  << " added(from nothing):" << nInserted
2078  << " merged(into other point):" << nMerge
2079  << " removed:" << nRemove
2080  << nl;
2081 
2082  countMap(faceMap_, reverseFaceMap_, nSplit, nInserted, nMerge, nRemove);
2083  Pout<< "Faces:"
2084  << " added(from face):" << nSplit
2085  << " added(from nothing):" << nInserted
2086  << " merged(into other face):" << nMerge
2087  << " removed:" << nRemove
2088  << nl;
2089 
2090  countMap(cellMap_, reverseCellMap_, nSplit, nInserted, nMerge, nRemove);
2091  Pout<< "Cells:"
2092  << " added(from cell):" << nSplit
2093  << " added(from nothing):" << nInserted
2094  << " merged(into other cell):" << nMerge
2095  << " removed:" << nRemove
2096  << nl
2097  << endl;
2098  }
2099 
2100  if (debug)
2101  {
2102  Pout<< "New mesh:" << nl;
2103  writeMeshStats(mesh, Pout);
2104  }
2105 
2106 
2107  // Patch point renumbering
2108  // For every preserved point on a patch give the old position.
2109  // For added points, the index is set to -1
2110  labelListList patchPointMap(mesh.boundaryMesh().size());
2111  calcPatchPointMap
2112  (
2113  oldPatchMeshPointMaps,
2114  mesh.boundaryMesh(),
2115  patchPointMap
2116  );
2117 
2118  labelHashSet flipFaceFluxSet(getSetIndices(flipFaceFlux_));
2119 
2121  (
2122  new polyTopoChangeMap
2123  (
2124  mesh,
2125  nOldPoints,
2126  nOldFaces,
2127  nOldCells,
2128 
2129  move(pointMap_),
2130  move(pointsFromPoints),
2131 
2132  move(faceMap_),
2133  move(facesFromFaces),
2134 
2135  move(cellMap_),
2136  move(cellsFromCells),
2137 
2138  move(reversePointMap_),
2139  move(reverseFaceMap_),
2140  move(reverseCellMap_),
2141 
2142  move(flipFaceFluxSet),
2143 
2144  move(patchPointMap),
2145 
2146  move(oldPatchSizes),
2147  move(oldPatchStarts),
2148  move(oldPatchNMeshPoints),
2149 
2150  move(oldCellVolumes)
2151  )
2152  );
2153 
2154  // At this point all member DynamicList (pointMap_, cellMap_ etc.) will
2155  // be invalid.
2156 }
2157 
2158 
2160 (
2161  autoPtr<fvMesh>& newMeshPtr,
2162  const IOobject& io,
2163  const polyMesh& mesh,
2164  const bool syncParallel,
2165  const bool orderCells,
2166  const bool orderPoints
2167 )
2168 {
2169  if (debug)
2170  {
2171  Pout<< "polyTopoChange::makeMesh"
2172  << "(autoPtr<fvMesh>&, const IOobject&, const fvMesh&"
2173  << ", const bool, const bool, const bool)"
2174  << endl;
2175  }
2176 
2177  if (debug)
2178  {
2179  Pout<< "Old mesh:" << nl;
2180  writeMeshStats(mesh, Pout);
2181  }
2182 
2183  // new mesh points
2184  pointField newPoints;
2185  // number of internal points
2186  label nInternalPoints;
2187  // patch slicing
2188  labelList patchSizes;
2189  labelList patchStarts;
2190  // maps
2191  List<objectMap> pointsFromPoints;
2192  List<objectMap> facesFromFaces;
2193  List<objectMap> cellsFromCells;
2194 
2195  // old mesh info
2196  List<Map<label>> oldPatchMeshPointMaps;
2197  labelList oldPatchNMeshPoints;
2198  labelList oldPatchSizes;
2199  labelList oldPatchStarts;
2200 
2201  // Compact, reorder patch faces and calculate mesh/patch maps.
2202  compactAndReorder
2203  (
2204  mesh,
2205  syncParallel,
2206  orderCells,
2207  orderPoints,
2208 
2209  nInternalPoints,
2210  newPoints,
2211  patchSizes,
2212  patchStarts,
2213  pointsFromPoints,
2214  facesFromFaces,
2215  cellsFromCells,
2216  oldPatchMeshPointMaps,
2217  oldPatchNMeshPoints,
2218  oldPatchSizes,
2219  oldPatchStarts
2220  );
2221 
2222  const label nOldPoints(mesh.nPoints());
2223  const label nOldFaces(mesh.nFaces());
2224  const label nOldCells(mesh.nCells());
2225  autoPtr<scalarField> oldCellVolumes(new scalarField(mesh.cellVolumes()));
2226 
2227 
2228  // Create the mesh
2229  // ~~~~~~~~~~~~~~~
2230 
2231  IOobject noReadIO(io);
2232  noReadIO.readOpt() = IOobject::NO_READ;
2233  newMeshPtr.reset
2234  (
2235  new fvMesh
2236  (
2237  noReadIO,
2238  move(newPoints),
2239  move(faces_),
2240  move(faceOwner_),
2241  move(faceNeighbour_)
2242  )
2243  );
2244  fvMesh& newMesh = newMeshPtr();
2245 
2246  // Clear out primitives
2247  {
2248  retiredPoints_.clearStorage();
2249  oldPoints_.clearStorage();
2250  region_.clearStorage();
2251  }
2252 
2253 
2254  if (debug)
2255  {
2256  // Some stats on changes
2257  label nSplit, nInserted, nMerge, nRemove;
2258  countMap
2259  (
2260  pointMap_,
2261  reversePointMap_,
2262  nSplit,
2263  nInserted,
2264  nMerge,
2265  nRemove
2266  );
2267 
2268  Pout<< "Points:"
2269  << " added(from point):" << nSplit
2270  << " added(from nothing):" << nInserted
2271  << " merged(into other point):" << nMerge
2272  << " removed:" << nRemove
2273  << nl;
2274 
2275  countMap(faceMap_, reverseFaceMap_, nSplit, nInserted, nMerge, nRemove);
2276  Pout<< "Faces:"
2277  << " added(from face):" << nSplit
2278  << " added(from nothing):" << nInserted
2279  << " merged(into other face):" << nMerge
2280  << " removed:" << nRemove
2281  << nl;
2282 
2283  countMap(cellMap_, reverseCellMap_, nSplit, nInserted, nMerge, nRemove);
2284  Pout<< "Cells:"
2285  << " added(from cell):" << nSplit
2286  << " added(from nothing):" << nInserted
2287  << " merged(into other cell):" << nMerge
2288  << " removed:" << nRemove
2289  << nl
2290  << endl;
2291  }
2292 
2293 
2294  {
2295  const polyBoundaryMesh& oldPatches = mesh.boundaryMesh();
2296 
2297  List<polyPatch*> newBoundary(oldPatches.size());
2298 
2299  forAll(oldPatches, patchi)
2300  {
2301  newBoundary[patchi] = oldPatches[patchi].clone
2302  (
2303  newMesh.boundaryMesh(),
2304  patchi,
2305  patchSizes[patchi],
2306  patchStarts[patchi]
2307  ).ptr();
2308  }
2309  newMesh.addFvPatches(newBoundary);
2310  }
2311 
2312 
2313  // Zones
2314  // ~~~~~
2315 
2316  // Copy pointZone from old mesh
2317  const pointZoneList& oldPointZones = mesh.pointZones();
2318  List<pointZone*> pZonePtrs(oldPointZones.size());
2319  {
2320  forAll(oldPointZones, i)
2321  {
2322  pZonePtrs[i] = oldPointZones[i].clone(newMesh.pointZones()).ptr();
2323  }
2324  }
2325 
2326  // Copy faceZone from old mesh
2327  const faceZoneList& oldFaceZones = mesh.faceZones();
2328  List<faceZone*> fZonePtrs(oldFaceZones.size());
2329  {
2330  forAll(oldFaceZones, i)
2331  {
2332  fZonePtrs[i] = oldFaceZones[i].clone(newMesh.faceZones()).ptr();
2333  }
2334  }
2335 
2336  // Copy cellZone from old mesh
2337  const cellZoneList& oldCellZones = mesh.cellZones();
2338  List<cellZone*> cZonePtrs(oldCellZones.size());
2339  {
2340  forAll(oldCellZones, i)
2341  {
2342  cZonePtrs[i] = oldCellZones[i].clone(newMesh.cellZones()).ptr();
2343  }
2344  }
2345 
2346  newMesh.addZones(pZonePtrs, fZonePtrs, cZonePtrs);
2347 
2348  // Patch point renumbering
2349  // For every preserved point on a patch give the old position.
2350  // For added points, the index is set to -1
2351  labelListList patchPointMap(newMesh.boundaryMesh().size());
2352  calcPatchPointMap
2353  (
2354  oldPatchMeshPointMaps,
2355  newMesh.boundaryMesh(),
2356  patchPointMap
2357  );
2358 
2359  if (debug)
2360  {
2361  Pout<< "New mesh:" << nl;
2362  writeMeshStats(mesh, Pout);
2363  }
2364 
2365  labelHashSet flipFaceFluxSet(getSetIndices(flipFaceFlux_));
2366 
2368  (
2369  new polyTopoChangeMap
2370  (
2371  newMesh,
2372  nOldPoints,
2373  nOldFaces,
2374  nOldCells,
2375 
2376  move(pointMap_),
2377  move(pointsFromPoints),
2378 
2379  move(faceMap_),
2380  move(facesFromFaces),
2381 
2382  move(cellMap_),
2383  move(cellsFromCells),
2384 
2385  move(reversePointMap_),
2386  move(reverseFaceMap_),
2387  move(reverseCellMap_),
2388 
2389  move(flipFaceFluxSet),
2390 
2391  move(patchPointMap),
2392 
2393  move(oldPatchSizes),
2394  move(oldPatchStarts),
2395  move(oldPatchNMeshPoints),
2396 
2397  move(oldCellVolumes)
2398  )
2399  );
2400 
2401  // At this point all member DynamicList (pointMap_, cellMap_ etc.) will
2402  // be invalid.
2403 }
2404 
2405 
2406 // ************************************************************************* //
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:476
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:357
autoPtr< IOobject > clone() const
Clone.
Definition: IOobject.H:280
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
void setSize(const label)
Reset size of PtrList. If extending the PtrList, new entries are.
Definition: PtrList.C:131
A list that is sorted upon construction or when explicitly requested with the sort() method.
Definition: SortableList.H:55
const labelList & indices() const
Return the list of sorted indices. Updated every sort.
Definition: SortableList.H:96
void sort()
(stable) sort the list (if changed after construction time)
Definition: SortableList.C:112
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:96
void addFvPatches(const List< polyPatch * > &, const bool validBoundary=true)
Add boundary patches. Constructor helper.
Definition: fvMesh.C:785
Foam::polyBoundaryMesh.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
const pointZoneList & pointZones() const
Return point zones.
Definition: polyMesh.H:437
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:449
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1344
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:716
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1357
const faceZoneList & faceZones() const
Return face zones.
Definition: polyMesh.H:443
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:401
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1363
void addZones(const List< pointZone * > &pz, const List< faceZone * > &fz, const List< cellZone * > &cz)
Add mesh zones.
Definition: polyMesh.C:1145
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1331
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.
const scalarField & cellVolumes() const
label nInternalFaces() const
label nCells() const
label nPoints() const
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
label nFaces() const
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#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:258
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:267
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