undoableMeshCutter.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) 2019 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 "undoableMeshCutter.H"
30 #include "polyMesh.H"
31 #include "polyTopoChange.H"
32 #include "DynamicList.H"
33 #include "meshCutter.H"
34 #include "cellCuts.H"
35 #include "splitCell.H"
36 #include "mapPolyMesh.H"
37 #include "unitConversion.H"
38 #include "meshTools.H"
39 
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 
42 namespace Foam
43 {
44  defineTypeNameAndDebug(undoableMeshCutter, 0);
45 }
46 
47 
48 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 
50 // For debugging
51 void Foam::undoableMeshCutter::printCellRefTree
52 (
53  Ostream& os,
54  const word& indent,
55  const splitCell* splitCellPtr
56 ) const
57 {
58  if (splitCellPtr)
59  {
60  os << indent << splitCellPtr->cellLabel() << endl;
61 
62  word subIndent = indent + "--";
63 
64  printCellRefTree(os, subIndent, splitCellPtr->master());
65 
66  printCellRefTree(os, subIndent, splitCellPtr->slave());
67  }
68 }
69 
70 
71 // For debugging
72 void Foam::undoableMeshCutter::printRefTree(Ostream& os) const
73 {
74  forAllConstIters(liveSplitCells_, iter)
75  {
76  const splitCell* splitPtr = iter.val();
77 
78  // Walk to top (master path only)
79  while (splitPtr->parent())
80  {
81  if (!splitPtr->isMaster())
82  {
83  splitPtr = nullptr;
84 
85  break;
86  }
87  else
88  {
89  splitPtr = splitPtr->parent();
90  }
91  }
92 
93  // If we have reached top along master path start printing.
94  if (splitPtr)
95  {
96  // Print from top down
97  printCellRefTree(os, word(""), splitPtr);
98  }
99  }
100 }
101 
102 
103 // Update all (cell) labels on splitCell structure.
104 // Do in two passes to prevent allocation if nothing changed.
105 void Foam::undoableMeshCutter::updateLabels
106 (
107  const labelList& map,
108  Map<splitCell*>& liveSplitCells
109 )
110 {
111  // Pass1 : check if changed
112 
113  bool changed = false;
114 
115  forAllConstIters(liveSplitCells, iter)
116  {
117  const splitCell* splitPtr = iter.val();
118 
119  if (!splitPtr)
120  {
122  << "Problem: null pointer on liveSplitCells list"
123  << abort(FatalError);
124  }
125 
126  label celli = splitPtr->cellLabel();
127 
128  if (celli != map[celli])
129  {
130  changed = true;
131 
132  break;
133  }
134  }
135 
136 
137  // Pass2: relabel
138 
139  if (changed)
140  {
141  // Build new liveSplitCells
142  // since new labels (= keys in Map) might clash with existing ones.
143  Map<splitCell*> newLiveSplitCells(2*liveSplitCells.size());
144 
145  forAllIters(liveSplitCells, iter)
146  {
147  splitCell* splitPtr = iter.val();
148 
149  const label celli = splitPtr->cellLabel();
150 
151  const label newCelli = map[celli];
152 
153  if (debug && (celli != newCelli))
154  {
155  Pout<< "undoableMeshCutter::updateLabels :"
156  << " Updating live (split)cell from " << celli
157  << " to " << newCelli << endl;
158  }
159 
160  if (newCelli >= 0)
161  {
162  // Update splitCell. Can do inplace since only one celli will
163  // refer to this structure.
164  splitPtr->cellLabel() = newCelli;
165 
166  // Update liveSplitCells
167  newLiveSplitCells.insert(newCelli, splitPtr);
168  }
169  }
170  liveSplitCells = newLiveSplitCells;
171  }
172 }
173 
174 
175 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
176 
177 Foam::undoableMeshCutter::undoableMeshCutter
178 (
179  const polyMesh& mesh,
180  const bool undoable
181 )
182 :
183  meshCutter(mesh),
184  undoable_(undoable),
185  liveSplitCells_(mesh.nCells()/100 + 100),
186  faceRemover_
187  (
188  mesh,
189  Foam::cos(degToRad(30.0))
190  )
191 {}
192 
193 
194 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
195 
197 {
198  // Clean split cell tree.
199 
200  forAllIters(liveSplitCells_, iter)
201  {
202  splitCell* splitPtr = iter.val();
203 
204  while (splitPtr)
205  {
206  splitCell* parentPtr = splitPtr->parent();
207 
208  // Sever ties with parent. Also of other side of refinement since
209  // we are handling rest of tree so other side will not have to.
210  if (parentPtr)
211  {
212  splitCell* otherSidePtr = splitPtr->getOther();
213 
214  otherSidePtr->parent() = nullptr;
215 
216  splitPtr->parent() = nullptr;
217  }
218 
219  // Delete splitCell (updates pointer on parent to itself)
220  delete splitPtr;
221 
222  splitPtr = parentPtr;
223  }
224  }
225 }
226 
227 
228 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
229 
231 (
232  const cellCuts& cuts,
233  polyTopoChange& meshMod
234 )
235 {
236  // Insert commands to actually cut cells
237  meshCutter::setRefinement(cuts, meshMod);
238 
239  if (undoable_)
240  {
241  // Use cells cut in this iteration to update splitCell tree.
242  forAllConstIters(addedCells(), iter)
243  {
244  const label celli = iter.key();
245  const label addedCelli = iter.val();
246 
247  // Newly created split cell. (celli -> celli + addedCelli)
248 
249  // Check if celli already part of split.
250  auto findCell = liveSplitCells_.find(celli);
251 
252  if (!findCell.found())
253  {
254  // Celli not yet split. It cannot be unlive split cell
255  // since that would be illegal to split in the first
256  // place.
257 
258  // Create 0th level. Null parent to denote this.
259  splitCell* parentPtr = new splitCell(celli, nullptr);
260 
261  splitCell* masterPtr = new splitCell(celli, parentPtr);
262 
263  splitCell* slavePtr = new splitCell(addedCelli, parentPtr);
264 
265  // Store newly created cells on parent together with face
266  // that splits them
267  parentPtr->master() = masterPtr;
268  parentPtr->slave() = slavePtr;
269 
270  // Insert master and slave into live splitcell list
271 
272  if (liveSplitCells_.found(addedCelli))
273  {
275  << "problem addedCell:" << addedCelli
276  << abort(FatalError);
277  }
278 
279  liveSplitCells_.insert(celli, masterPtr);
280  liveSplitCells_.insert(addedCelli, slavePtr);
281  }
282  else
283  {
284  // Cell that was split has been split again.
285  splitCell* parentPtr = findCell();
286 
287  // It is no longer live
288  liveSplitCells_.erase(findCell);
289 
290  splitCell* masterPtr = new splitCell(celli, parentPtr);
291 
292  splitCell* slavePtr = new splitCell(addedCelli, parentPtr);
293 
294  // Store newly created cells on parent together with face
295  // that splits them
296  parentPtr->master() = masterPtr;
297  parentPtr->slave() = slavePtr;
298 
299  // Insert master and slave into live splitcell list
300 
301  if (liveSplitCells_.found(addedCelli))
302  {
304  << "problem addedCell:" << addedCelli
305  << abort(FatalError);
306  }
307 
308  liveSplitCells_.insert(celli, masterPtr);
309  liveSplitCells_.insert(addedCelli, slavePtr);
310  }
311  }
312 
313  if (debug & 2)
314  {
315  Pout<< "** After refinement: liveSplitCells_:" << endl;
316 
317  printRefTree(Pout);
318  }
319  }
320 }
321 
322 
324 {
325  // Update mesh cutter for new labels.
326  meshCutter::updateMesh(morphMap);
327 
328  // No need to update cell walker for new labels since does not store any.
329 
330  // Update faceRemover for new labels
331  faceRemover_.updateMesh(morphMap);
332 
333  if (undoable_)
334  {
335  // Update all live split cells for mesh mapper.
336  updateLabels(morphMap.reverseCellMap(), liveSplitCells_);
337  }
338 }
339 
340 
342 {
343  if (!undoable_)
344  {
346  << "Only call if constructed with unrefinement capability"
347  << abort(FatalError);
348  }
349 
350  DynamicList<label> liveSplitFaces(liveSplitCells_.size());
351 
352  forAllConstIters(liveSplitCells_, iter)
353  {
354  const splitCell* splitPtr = iter.val();
355 
356  if (!splitPtr->parent())
357  {
359  << "Live split cell without parent" << endl
360  << "splitCell:" << splitPtr->cellLabel()
361  << abort(FatalError);
362  }
363 
364  // Check if not top of refinement and whether it is the master side
365  if (splitPtr->isMaster())
366  {
367  splitCell* slavePtr = splitPtr->getOther();
368 
369  if
370  (
371  liveSplitCells_.found(slavePtr->cellLabel())
372  && splitPtr->isUnrefined()
373  && slavePtr->isUnrefined()
374  )
375  {
376  // Both master and slave are live and are not refined.
377  // Find common face.
378 
379  label celli = splitPtr->cellLabel();
380 
381  label slaveCelli = slavePtr->cellLabel();
382 
383  label commonFacei =
385  (
386  mesh(),
387  celli,
388  slaveCelli
389  );
390 
391  liveSplitFaces.append(commonFacei);
392  }
393  }
394  }
395 
396  return liveSplitFaces.shrink();
397 }
398 
399 
401 {
402  // (code copied from getSplitFaces)
403 
404  if (!undoable_)
405  {
407  << "Only call if constructed with unrefinement capability"
408  << abort(FatalError);
409  }
410 
411  Map<label> addedCells(liveSplitCells_.size());
412 
413  forAllConstIters(liveSplitCells_, iter)
414  {
415  const splitCell* splitPtr = iter.val();
416 
417  if (!splitPtr->parent())
418  {
420  << "Live split cell without parent" << endl
421  << "splitCell:" << splitPtr->cellLabel()
422  << abort(FatalError);
423  }
424 
425  // Check if not top of refinement and whether it is the master side
426  if (splitPtr->isMaster())
427  {
428  splitCell* slavePtr = splitPtr->getOther();
429 
430  if
431  (
432  liveSplitCells_.found(slavePtr->cellLabel())
433  && splitPtr->isUnrefined()
434  && slavePtr->isUnrefined()
435  )
436  {
437  // Both master and slave are live and are not refined.
438  addedCells.insert(splitPtr->cellLabel(), slavePtr->cellLabel());
439  }
440  }
441  }
442  return addedCells;
443 }
444 
445 
447 (
448  const labelList& splitFaces,
449  polyTopoChange& meshMod
450 )
451 {
452  if (!undoable_)
453  {
455  << "Only call if constructed with unrefinement capability"
456  << abort(FatalError);
457  }
458 
459  // Check with faceRemover what faces will get removed. Note that this can
460  // be more (but never less) than splitFaces provided.
461  labelList cellRegion;
462  labelList cellRegionMaster;
463  labelList facesToRemove;
464 
465  faceRemover().compatibleRemoves
466  (
467  splitFaces, // pierced faces
468  cellRegion, // per cell -1 or region it is merged into
469  cellRegionMaster, // per region the master cell
470  facesToRemove // new faces to be removed.
471  );
472 
473  if (facesToRemove.size() != splitFaces.size())
474  {
475  Pout<< "cellRegion:" << cellRegion << endl;
476  Pout<< "cellRegionMaster:" << cellRegionMaster << endl;
477 
479  << "Faces to remove:" << splitFaces << endl
480  << "to be removed:" << facesToRemove
481  << abort(FatalError);
482  }
483 
484 
485  // Every face removed will result in neighbour and owner being merged
486  // into owner.
487  forAll(facesToRemove, facesToRemoveI)
488  {
489  label facei = facesToRemove[facesToRemoveI];
490 
491  if (!mesh().isInternalFace(facei))
492  {
494  << "Trying to remove face that is not internal"
495  << abort(FatalError);
496  }
497 
498  label own = mesh().faceOwner()[facei];
499  label nbr = mesh().faceNeighbour()[facei];
500 
501  auto ownFind = liveSplitCells_.find(own);
502  auto nbrFind = liveSplitCells_.find(nbr);
503 
504  if (ownFind.found() && nbrFind.found())
505  {
506  // Face is original splitFace.
507 
508  splitCell* ownPtr = ownFind.val();
509 
510  splitCell* nbrPtr = nbrFind.val();
511 
512  splitCell* parentPtr = ownPtr->parent();
513 
514  // Various checks on sanity.
515 
516  if (debug)
517  {
518  Pout<< "Updating for removed splitFace " << facei
519  << " own:" << own << " nbr:" << nbr
520  << " ownPtr:" << ownPtr->cellLabel()
521  << " nbrPtr:" << nbrPtr->cellLabel()
522  << endl;
523  }
524  if (!parentPtr)
525  {
527  << "No parent for owner " << ownPtr->cellLabel()
528  << abort(FatalError);
529  }
530 
531  if (!nbrPtr->parent())
532  {
534  << "No parent for neighbour " << nbrPtr->cellLabel()
535  << abort(FatalError);
536  }
537 
538  if (parentPtr != nbrPtr->parent())
539  {
541  << "Owner and neighbour liveSplitCell entries do not have"
542  << " same parent. facei:" << facei << " owner:" << own
543  << " ownparent:" << parentPtr->cellLabel()
544  << " neighbour:" << nbr
545  << " nbrparent:" << nbrPtr->parent()->cellLabel()
546  << abort(FatalError);
547  }
548 
549  if
550  (
551  !ownPtr->isUnrefined()
552  || !nbrPtr->isUnrefined()
553  || parentPtr->isUnrefined()
554  )
555  {
556  // Live owner and neighbour are refined themselves.
558  << "Owner and neighbour liveSplitCell entries are"
559  << " refined themselves or the parent is not refined"
560  << endl
561  << "owner unrefined:" << ownPtr->isUnrefined()
562  << " neighbour unrefined:" << nbrPtr->isUnrefined()
563  << " master unrefined:" << parentPtr->isUnrefined()
564  << abort(FatalError);
565  }
566 
567  // Delete from liveSplitCell
568  liveSplitCells_.erase(ownFind);
569 
571  liveSplitCells_.erase(liveSplitCells_.find(nbr));
572 
573  // Delete entries themselves
574  delete ownPtr;
575  delete nbrPtr;
576 
577  // Update parent:
578  // - has parent itself: is part of split cell. Update cellLabel
579  // with merged cell one.
580  // - has no parent: is start of tree. Completely remove.
581 
582  if (parentPtr->parent())
583  {
584  // Update parent cell label to be new merged cell label
585  // (will be owner)
586  parentPtr->cellLabel() = own;
587 
588  // And insert into live cells (is ok since old entry with
589  // own as key has been removed above)
590  liveSplitCells_.insert(own, parentPtr);
591  }
592  else
593  {
594  // No parent so is start of tree. No need to keep splitCell
595  // tree.
596  delete parentPtr;
597  }
598  }
599  }
600 
601  // Insert all commands to combine cells. Never fails so don't have to
602  // test for success.
603  faceRemover().setRefinement
604  (
605  facesToRemove,
606  cellRegion,
607  cellRegionMaster,
608  meshMod
609  );
610 
611  return facesToRemove;
612 }
613 
614 
615 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::undoableMeshCutter::updateMesh
void updateMesh(const mapPolyMesh &morphMap)
Update stored refinement pattern for changes to mesh. Only.
Definition: undoableMeshCutter.C:323
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::undoableMeshCutter::getSplitFaces
labelList getSplitFaces() const
Calculate split faces from current liveCells. Only.
Definition: undoableMeshCutter.C:341
meshCutter.H
meshTools.H
Foam::meshCutter
Cuts (splits) cells.
Definition: meshCutter.H:138
splitCell.H
Foam::undoableMeshCutter::~undoableMeshCutter
~undoableMeshCutter()
Destructor.
Definition: undoableMeshCutter.C:196
Foam::DynamicList< label >
Foam::splitCell::slave
splitCell * slave() const
Definition: splitCell.H:123
Foam::undoableMeshCutter::removeSplitFaces
labelList removeSplitFaces(const labelList &splitFaces, polyTopoChange &)
Remove some refinement. Needs to be supplied subset of.
Definition: undoableMeshCutter.C:447
mapPolyMesh.H
Foam::splitCell::isUnrefined
bool isUnrefined() const
Check if this is unrefined (i.e. has no master or slave)
Definition: splitCell.C:101
polyTopoChange.H
Foam::polyTopoChange
Direct mesh changes based on v1.3 polyTopoChange syntax.
Definition: polyTopoChange.H:99
Foam::splitCell::parent
splitCell * parent() const
Definition: splitCell.H:103
Foam::Map
A HashTable to objects of type <T> with a label key.
Definition: lumpedPointController.H:69
unitConversion.H
Unit conversion functions.
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::undoableMeshCutter::getAddedCells
Map< label > getAddedCells() const
Like getSplitFaces but returns map from original to added cell.
Definition: undoableMeshCutter.C:400
undoableMeshCutter.H
Foam::meshCutter::updateMesh
void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Definition: meshCutter.C:995
polyMesh.H
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::primitiveMesh::nCells
label nCells() const noexcept
Number of mesh cells.
Definition: primitiveMeshI.H:96
Foam::splitCell::getOther
splitCell * getOther() const
Returns other half of split cell. I.e. slave if this is master.
Definition: splitCell.C:107
Foam::polyMesh::faceOwner
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1107
Foam::splitCell::cellLabel
label cellLabel() const
Definition: splitCell.H:93
forAllIters
#define forAllIters(container, iter)
Iterate across all elements in the container object.
Definition: stdFoam.H:223
cellCuts.H
Foam::FatalError
error FatalError
os
OBJstream os(runTime.globalPath()/outputName)
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::indent
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:339
Foam::degToRad
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Definition: unitConversion.H:48
Foam::mapPolyMesh::reverseCellMap
const labelList & reverseCellMap() const
Reverse cell map.
Definition: mapPolyMesh.H:532
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::splitCell
Description of cell after splitting. Contains cellLabel and pointers to cells it it split in....
Definition: splitCell.H:51
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Foam::meshCutter::setRefinement
void setRefinement(const cellCuts &cuts, polyTopoChange &meshMod)
Do actual cutting with cut description. Inserts mesh changes.
Definition: meshCutter.C:522
Foam::List< label >
Foam::mapPolyMesh
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:161
Foam::meshTools::getSharedFace
label getSharedFace(const primitiveMesh &mesh, const label cell0, const label cell1)
Return face shared by two cells. Throws error if none found.
Definition: meshTools.C:441
DynamicList.H
Foam::undoableMeshCutter::setRefinement
void setRefinement(const cellCuts &cuts, polyTopoChange &)
Refine cells acc. to cellCuts. Plays topology changes.
Definition: undoableMeshCutter.C:231
Foam::splitCell::master
splitCell * master() const
Definition: splitCell.H:113
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::splitCell::isMaster
bool isMaster() const
Check if this is master cell of split.
Definition: splitCell.C:71
Foam::polyMesh::faceNeighbour
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1113
Foam::cellCuts
Description of cuts across cells.
Definition: cellCuts.H:110
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:265