removeCells.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2015-2018 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "removeCells.H"
30 #include "bitSet.H"
31 #include "polyMesh.H"
32 #include "polyTopoChange.H"
33 #include "polyRemoveCell.H"
34 #include "polyRemoveFace.H"
35 #include "polyModifyFace.H"
36 #include "polyRemovePoint.H"
37 #include "syncTools.H"
38 
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 
41 namespace Foam
42 {
43  defineTypeNameAndDebug(removeCells, 0);
44 }
45 
46 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
47 
48 namespace
49 {
50 
51 // Increase count (usage) of elements of list
52 inline void incrCount(const Foam::labelUList& list, Foam::labelList& counter)
53 {
54  for (auto idx : list)
55  {
56  ++counter[idx];
57  }
58 }
59 
60 // Decrease count (usage) of elements of list
61 inline void decrCount(const Foam::labelUList& list, Foam::labelList& counter)
62 {
63  for (auto idx : list)
64  {
65  --counter[idx];
66  }
67 }
68 
69 } // End anonymous namespace
70 
71 
72 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
73 
74 Foam::removeCells::removeCells(const polyMesh& mesh, const bool syncPar)
75 :
76  mesh_(mesh),
77  syncPar_(syncPar)
78 {}
79 
80 
81 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
82 
84 (
85  const bitSet& removedCell
86 ) const
87 {
88  const labelList& faceOwner = mesh_.faceOwner();
89  const labelList& faceNeighbour = mesh_.faceNeighbour();
90 
91  // Count cells using face.
92  labelList nCellsUsingFace(mesh_.nFaces(), Zero);
93 
94  for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
95  {
96  const label own = faceOwner[facei];
97  const label nei = faceNeighbour[facei];
98 
99  if (!removedCell[own])
100  {
101  ++nCellsUsingFace[facei];
102  }
103  if (!removedCell[nei])
104  {
105  ++nCellsUsingFace[facei];
106  }
107  }
108 
109  for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); ++facei)
110  {
111  const label own = faceOwner[facei];
112 
113  if (!removedCell[own])
114  {
115  ++nCellsUsingFace[facei];
116  }
117  }
118 
119  // Coupled faces: add number of cells using face across couple.
120  {
121  // Note cyclics done always, parallel bits only done if syncPar_
122 
123  SubList<label> bndValues
124  (
125  nCellsUsingFace,
126  mesh_.nBoundaryFaces(),
127  mesh_.nInternalFaces()
128  );
129 
131  (
132  mesh_,
133  bndValues,
134  plusEqOp<label>(),
136  syncPar_
137  );
138  }
139 
140  // Now nCellsUsingFace:
141  // 0 : internal face whose both cells get deleted
142  // boundary face whose all cells get deleted
143  // 1 : internal face that gets exposed
144  // unaffected (uncoupled) boundary face
145  // coupled boundary face that gets exposed ('uncoupled')
146  // 2 : unaffected internal face
147  // unaffected coupled boundary face
148 
149  DynamicList<label> exposedFaces(mesh_.nFaces()/10);
150 
151  for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
152  {
153  if (nCellsUsingFace[facei] == 1)
154  {
155  exposedFaces.append(facei);
156  }
157  }
158 
159  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
160 
161  for (const polyPatch& pp : patches)
162  {
163  if (pp.coupled())
164  {
165  label facei = pp.start();
166 
167  forAll(pp, i)
168  {
169  const label own = faceOwner[facei];
170 
171  if (nCellsUsingFace[facei] == 1 && !removedCell[own])
172  {
173  // My owner not removed but other side is so has to become
174  // normal, uncoupled, boundary face
175  exposedFaces.append(facei);
176  }
177 
178  ++facei;
179  }
180  }
181  }
182 
183  return exposedFaces.shrink();
184 }
185 
186 
188 (
189  const bitSet& removedCell,
190  const labelUList& exposedFaceLabels,
191  const labelUList& exposedPatchIDs,
192  polyTopoChange& meshMod
193 ) const
194 {
195  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
196 
197  if (exposedFaceLabels.size() != exposedPatchIDs.size())
198  {
200  << "Size of exposedFaceLabels " << exposedFaceLabels.size()
201  << " differs from size of exposedPatchIDs "
202  << exposedPatchIDs.size()
203  << abort(FatalError);
204  }
205 
206  // List of new patchIDs
207  labelList newPatchID(mesh_.nFaces(), -1);
208 
209  forAll(exposedFaceLabels, i)
210  {
211  const label facei = exposedFaceLabels[i];
212  const label patchi = exposedPatchIDs[i];
213 
214  if (patchi < 0 || patchi >= patches.size())
215  {
217  << "Invalid patch " << patchi
218  << " for exposed face " << facei << nl
219  << "Valid patches 0.." << patches.size()-1
220  << abort(FatalError);
221  }
222 
223  if (patches[patchi].coupled())
224  {
226  << "Trying to put exposed face " << facei
227  << " into a coupled patch : " << patches[patchi].name()
228  << nl
229  << "This is illegal."
230  << abort(FatalError);
231  }
232 
233  newPatchID[facei] = patchi;
234  }
235 
236 
237  // Walk all the cells mentioned for removal
238  for (const label celli : removedCell)
239  {
240  //Pout<< "Removing cell " << celli
241  // << " cc:" << mesh_.cellCentres()[celli] << endl;
242 
243  meshMod.setAction(polyRemoveCell(celli));
244  }
245 
246 
247  // Remove faces that are no longer used. Modify faces that
248  // are used by one cell only.
249 
250  const faceList& faces = mesh_.faces();
251  const labelList& faceOwner = mesh_.faceOwner();
252  const labelList& faceNeighbour = mesh_.faceNeighbour();
253  const faceZoneMesh& faceZones = mesh_.faceZones();
254 
255  // Count starting number of faces using each point.
256  // Update whenever removing a face.
257  labelList nFacesUsingPoint(mesh_.nPoints(), Zero);
258 
259  for (const face& f : faces)
260  {
261  incrCount(f, nFacesUsingPoint);
262  }
263 
264 
265  for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
266  {
267  const face& f = faces[facei];
268  const label own = faceOwner[facei];
269  const label nei = faceNeighbour[facei];
270 
271  if (removedCell[own])
272  {
273  if (removedCell[nei])
274  {
275  // Face no longer used
276  //Pout<< "Removing internal face " << facei
277  // << " fc:" << mesh_.faceCentres()[facei] << endl;
278 
279  meshMod.setAction(polyRemoveFace(facei));
280  decrCount(f, nFacesUsingPoint);
281  }
282  else
283  {
284  if (newPatchID[facei] == -1)
285  {
287  << "No patchID provided for exposed face " << facei
288  << " on cell " << nei << nl
289  << "Did you provide patch IDs for all exposed faces?"
290  << abort(FatalError);
291  }
292 
293  // nei is remaining cell. Facei becomes external cell
294 
295  const label zoneID = faceZones.whichZone(facei);
296  bool zoneFlip = false;
297 
298  if (zoneID >= 0)
299  {
300  const faceZone& fZone = faceZones[zoneID];
301  // Note: we reverse the owner/neighbour of the face
302  // so should also select the other side of the zone
303  zoneFlip = !fZone.flipMap()[fZone.whichFace(facei)];
304  }
305 
306  //Pout<< "Putting exposed internal face " << facei
307  // << " fc:" << mesh_.faceCentres()[facei]
308  // << " into patch " << newPatchID[facei] << endl;
309 
310  meshMod.setAction
311  (
312  polyModifyFace
313  (
314  f.reverseFace(), // modified face
315  facei, // label of face being modified
316  nei, // owner
317  -1, // neighbour
318  true, // face flip
319  newPatchID[facei], // patch for face
320  false, // remove from zone
321  zoneID, // zone for face
322  zoneFlip // face flip in zone
323  )
324  );
325  }
326  }
327  else if (removedCell[nei])
328  {
329  if (newPatchID[facei] == -1)
330  {
332  << "No patchID provided for exposed face " << facei
333  << " on cell " << own << nl
334  << "Did you provide patch IDs for all exposed faces?"
335  << abort(FatalError);
336  }
337 
338  //Pout<< "Putting exposed internal face " << facei
339  // << " fc:" << mesh_.faceCentres()[facei]
340  // << " into patch " << newPatchID[facei] << endl;
341 
342  // own is remaining cell. Facei becomes external cell.
343  const label zoneID = faceZones.whichZone(facei);
344  bool zoneFlip = false;
345 
346  if (zoneID >= 0)
347  {
348  const faceZone& fZone = faceZones[zoneID];
349  zoneFlip = fZone.flipMap()[fZone.whichFace(facei)];
350  }
351 
352  meshMod.setAction
353  (
354  polyModifyFace
355  (
356  f, // modified face
357  facei, // label of face being modified
358  own, // owner
359  -1, // neighbour
360  false, // face flip
361  newPatchID[facei], // patch for face
362  false, // remove from zone
363  zoneID, // zone for face
364  zoneFlip // face flip in zone
365  )
366  );
367  }
368  }
369 
370  for (const polyPatch& pp : patches)
371  {
372  if (pp.coupled())
373  {
374  label facei = pp.start();
375 
376  forAll(pp, i)
377  {
378  if (newPatchID[facei] != -1)
379  {
380  //Pout<< "Putting uncoupled coupled face " << facei
381  // << " fc:" << mesh_.faceCentres()[facei]
382  // << " into patch " << newPatchID[facei] << endl;
383 
384  const label zoneID = faceZones.whichZone(facei);
385  bool zoneFlip = false;
386 
387  if (zoneID >= 0)
388  {
389  const faceZone& fZone = faceZones[zoneID];
390  zoneFlip = fZone.flipMap()[fZone.whichFace(facei)];
391  }
392 
393  meshMod.setAction
394  (
395  polyModifyFace
396  (
397  faces[facei], // modified face
398  facei, // label of face
399  faceOwner[facei], // owner
400  -1, // neighbour
401  false, // face flip
402  newPatchID[facei], // patch for face
403  false, // remove from zone
404  zoneID, // zone for face
405  zoneFlip // face flip in zone
406  )
407  );
408  }
409  else if (removedCell[faceOwner[facei]])
410  {
411  // Face no longer used
412  //Pout<< "Removing boundary face " << facei
413  // << " fc:" << mesh_.faceCentres()[facei]
414  // << endl;
415 
416  meshMod.setAction(polyRemoveFace(facei));
417  decrCount(faces[facei], nFacesUsingPoint);
418  }
419 
420  ++facei;
421  }
422  }
423  else
424  {
425  label facei = pp.start();
426 
427  forAll(pp, i)
428  {
429  if (newPatchID[facei] != -1)
430  {
432  << "new patchID provided for boundary face " << facei
433  << " even though it is not on a coupled face."
434  << abort(FatalError);
435  }
436 
437  if (removedCell[faceOwner[facei]])
438  {
439  // Face no longer used
440  //Pout<< "Removing boundary face " << facei
441  // << " fc:" << mesh_.faceCentres()[facei]
442  // << endl;
443 
444  meshMod.setAction(polyRemoveFace(facei));
445  decrCount(faces[facei], nFacesUsingPoint);
446  }
447 
448  ++facei;
449  }
450  }
451  }
452 
453 
454  // Remove points that are no longer used.
455  // Loop rewritten to not use pointFaces.
456 
457  forAll(nFacesUsingPoint, pointi)
458  {
459  if (nFacesUsingPoint[pointi] == 0)
460  {
461  //Pout<< "Removing unused point " << pointi
462  // << " at:" << mesh_.points()[pointi] << endl;
463 
464  meshMod.setAction(polyRemovePoint(pointi));
465  }
466  else if (nFacesUsingPoint[pointi] == 1)
467  {
469  << "point " << pointi << " at coordinate "
470  << mesh_.points()[pointi]
471  << " is only used by 1 face after removing cells."
472  << " This probably results in an illegal mesh."
473  << endl;
474  }
475  }
476 }
477 
478 
480 (
481  const labelUList& cellsToRemove
482 ) const
483 {
484  bitSet removeCell(mesh_.nCells(), cellsToRemove);
485 
486  return getExposedFaces(removeCell);
487 }
488 
489 
491 (
492  const labelUList& cellsToRemove,
493  const labelUList& exposedFaceLabels,
494  const labelUList& exposedPatchIDs,
495  polyTopoChange& meshMod
496 ) const
497 {
498  bitSet removedCell(mesh_.nCells(), cellsToRemove);
499 
500  setRefinement
501  (
502  removedCell,
503  exposedFaceLabels,
504  exposedPatchIDs,
505  meshMod
506  );
507 }
508 
509 
510 // ************************************************************************* //
labelList getExposedFaces(const bitSet &removedCell) const
Get labels of faces exposed after cells removal.
Definition: removeCells.C:77
ZoneMesh< faceZone, polyMesh > faceZoneMesh
A ZoneMesh with the type faceZone.
static void syncBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop, const TransformOp &top, const bool parRun=UPstream::parRun())
Synchronize values on boundary faces only.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:517
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1122
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:195
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
label nFaces() const noexcept
Number of mesh faces.
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
dynamicFvMesh & mesh
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:608
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1116
label nInternalFaces() const noexcept
Number of internal faces.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
void setRefinement(const bitSet &removedCell, const labelUList &facesToExpose, const labelUList &patchIDs, polyTopoChange &) const
Play commands into polyTopoChange to remove cells.
Definition: removeCells.C:181
removeCells(const polyMesh &mesh, const bool syncPar=true)
Construct from mesh. Parallel synchronized by default.
Definition: removeCells.C:67
defineTypeNameAndDebug(combustionModel, 0)
labelList f(nPoints)
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
#define WarningInFunction
Report a warning using Foam::Warning.
Direct mesh changes based on v1.3 polyTopoChange syntax.
const polyBoundaryMesh & patches
List< label > labelList
A List of labels.
Definition: List.H:62
bool coupled
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:521
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127