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 // Construct from components
178 Foam::undoableMeshCutter::undoableMeshCutter
179 (
180  const polyMesh& mesh,
181  const bool undoable
182 )
183 :
184  meshCutter(mesh),
185  undoable_(undoable),
186  liveSplitCells_(mesh.nCells()/100 + 100),
187  faceRemover_
188  (
189  mesh,
190  Foam::cos(degToRad(30.0))
191  )
192 {}
193 
194 
195 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
196 
198 {
199  // Clean split cell tree.
200 
201  forAllIters(liveSplitCells_, iter)
202  {
203  splitCell* splitPtr = iter.val();
204 
205  while (splitPtr)
206  {
207  splitCell* parentPtr = splitPtr->parent();
208 
209  // Sever ties with parent. Also of other side of refinement since
210  // we are handling rest of tree so other side will not have to.
211  if (parentPtr)
212  {
213  splitCell* otherSidePtr = splitPtr->getOther();
214 
215  otherSidePtr->parent() = nullptr;
216 
217  splitPtr->parent() = nullptr;
218  }
219 
220  // Delete splitCell (updates pointer on parent to itself)
221  delete splitPtr;
222 
223  splitPtr = parentPtr;
224  }
225  }
226 }
227 
228 
229 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
230 
232 (
233  const cellCuts& cuts,
234  polyTopoChange& meshMod
235 )
236 {
237  // Insert commands to actually cut cells
238  meshCutter::setRefinement(cuts, meshMod);
239 
240  if (undoable_)
241  {
242  // Use cells cut in this iteration to update splitCell tree.
243  forAllConstIters(addedCells(), iter)
244  {
245  const label celli = iter.key();
246  const label addedCelli = iter.val();
247 
248  // Newly created split cell. (celli -> celli + addedCelli)
249 
250  // Check if celli already part of split.
251  auto findCell = liveSplitCells_.find(celli);
252 
253  if (!findCell.found())
254  {
255  // Celli not yet split. It cannot be unlive split cell
256  // since that would be illegal to split in the first
257  // place.
258 
259  // Create 0th level. Null parent to denote this.
260  splitCell* parentPtr = new splitCell(celli, nullptr);
261 
262  splitCell* masterPtr = new splitCell(celli, parentPtr);
263 
264  splitCell* slavePtr = new splitCell(addedCelli, parentPtr);
265 
266  // Store newly created cells on parent together with face
267  // that splits them
268  parentPtr->master() = masterPtr;
269  parentPtr->slave() = slavePtr;
270 
271  // Insert master and slave into live splitcell list
272 
273  if (liveSplitCells_.found(addedCelli))
274  {
276  << "problem addedCell:" << addedCelli
277  << abort(FatalError);
278  }
279 
280  liveSplitCells_.insert(celli, masterPtr);
281  liveSplitCells_.insert(addedCelli, slavePtr);
282  }
283  else
284  {
285  // Cell that was split has been split again.
286  splitCell* parentPtr = findCell();
287 
288  // It is no longer live
289  liveSplitCells_.erase(findCell);
290 
291  splitCell* masterPtr = new splitCell(celli, parentPtr);
292 
293  splitCell* slavePtr = new splitCell(addedCelli, parentPtr);
294 
295  // Store newly created cells on parent together with face
296  // that splits them
297  parentPtr->master() = masterPtr;
298  parentPtr->slave() = slavePtr;
299 
300  // Insert master and slave into live splitcell list
301 
302  if (liveSplitCells_.found(addedCelli))
303  {
305  << "problem addedCell:" << addedCelli
306  << abort(FatalError);
307  }
308 
309  liveSplitCells_.insert(celli, masterPtr);
310  liveSplitCells_.insert(addedCelli, slavePtr);
311  }
312  }
313 
314  if (debug & 2)
315  {
316  Pout<< "** After refinement: liveSplitCells_:" << endl;
317 
318  printRefTree(Pout);
319  }
320  }
321 }
322 
323 
325 {
326  // Update mesh cutter for new labels.
327  meshCutter::updateMesh(morphMap);
328 
329  // No need to update cell walker for new labels since does not store any.
330 
331  // Update faceRemover for new labels
332  faceRemover_.updateMesh(morphMap);
333 
334  if (undoable_)
335  {
336  // Update all live split cells for mesh mapper.
337  updateLabels(morphMap.reverseCellMap(), liveSplitCells_);
338  }
339 }
340 
341 
343 {
344  if (!undoable_)
345  {
347  << "Only call if constructed with unrefinement capability"
348  << abort(FatalError);
349  }
350 
351  DynamicList<label> liveSplitFaces(liveSplitCells_.size());
352 
353  forAllConstIters(liveSplitCells_, iter)
354  {
355  const splitCell* splitPtr = iter.val();
356 
357  if (!splitPtr->parent())
358  {
360  << "Live split cell without parent" << endl
361  << "splitCell:" << splitPtr->cellLabel()
362  << abort(FatalError);
363  }
364 
365  // Check if not top of refinement and whether it is the master side
366  if (splitPtr->isMaster())
367  {
368  splitCell* slavePtr = splitPtr->getOther();
369 
370  if
371  (
372  liveSplitCells_.found(slavePtr->cellLabel())
373  && splitPtr->isUnrefined()
374  && slavePtr->isUnrefined()
375  )
376  {
377  // Both master and slave are live and are not refined.
378  // Find common face.
379 
380  label celli = splitPtr->cellLabel();
381 
382  label slaveCelli = slavePtr->cellLabel();
383 
384  label commonFacei =
386  (
387  mesh(),
388  celli,
389  slaveCelli
390  );
391 
392  liveSplitFaces.append(commonFacei);
393  }
394  }
395  }
396 
397  return liveSplitFaces.shrink();
398 }
399 
400 
402 {
403  // (code copied from getSplitFaces)
404 
405  if (!undoable_)
406  {
408  << "Only call if constructed with unrefinement capability"
409  << abort(FatalError);
410  }
411 
412  Map<label> addedCells(liveSplitCells_.size());
413 
414  forAllConstIters(liveSplitCells_, iter)
415  {
416  const splitCell* splitPtr = iter.val();
417 
418  if (!splitPtr->parent())
419  {
421  << "Live split cell without parent" << endl
422  << "splitCell:" << splitPtr->cellLabel()
423  << abort(FatalError);
424  }
425 
426  // Check if not top of refinement and whether it is the master side
427  if (splitPtr->isMaster())
428  {
429  splitCell* slavePtr = splitPtr->getOther();
430 
431  if
432  (
433  liveSplitCells_.found(slavePtr->cellLabel())
434  && splitPtr->isUnrefined()
435  && slavePtr->isUnrefined()
436  )
437  {
438  // Both master and slave are live and are not refined.
439  addedCells.insert(splitPtr->cellLabel(), slavePtr->cellLabel());
440  }
441  }
442  }
443  return addedCells;
444 }
445 
446 
448 (
449  const labelList& splitFaces,
450  polyTopoChange& meshMod
451 )
452 {
453  if (!undoable_)
454  {
456  << "Only call if constructed with unrefinement capability"
457  << abort(FatalError);
458  }
459 
460  // Check with faceRemover what faces will get removed. Note that this can
461  // be more (but never less) than splitFaces provided.
462  labelList cellRegion;
463  labelList cellRegionMaster;
464  labelList facesToRemove;
465 
466  faceRemover().compatibleRemoves
467  (
468  splitFaces, // pierced faces
469  cellRegion, // per cell -1 or region it is merged into
470  cellRegionMaster, // per region the master cell
471  facesToRemove // new faces to be removed.
472  );
473 
474  if (facesToRemove.size() != splitFaces.size())
475  {
476  Pout<< "cellRegion:" << cellRegion << endl;
477  Pout<< "cellRegionMaster:" << cellRegionMaster << endl;
478 
480  << "Faces to remove:" << splitFaces << endl
481  << "to be removed:" << facesToRemove
482  << abort(FatalError);
483  }
484 
485 
486  // Every face removed will result in neighbour and owner being merged
487  // into owner.
488  forAll(facesToRemove, facesToRemoveI)
489  {
490  label facei = facesToRemove[facesToRemoveI];
491 
492  if (!mesh().isInternalFace(facei))
493  {
495  << "Trying to remove face that is not internal"
496  << abort(FatalError);
497  }
498 
499  label own = mesh().faceOwner()[facei];
500  label nbr = mesh().faceNeighbour()[facei];
501 
502  auto ownFind = liveSplitCells_.find(own);
503  auto nbrFind = liveSplitCells_.find(nbr);
504 
505  if (ownFind.found() && nbrFind.found())
506  {
507  // Face is original splitFace.
508 
509  splitCell* ownPtr = ownFind.val();
510 
511  splitCell* nbrPtr = nbrFind.val();
512 
513  splitCell* parentPtr = ownPtr->parent();
514 
515  // Various checks on sanity.
516 
517  if (debug)
518  {
519  Pout<< "Updating for removed splitFace " << facei
520  << " own:" << own << " nbr:" << nbr
521  << " ownPtr:" << ownPtr->cellLabel()
522  << " nbrPtr:" << nbrPtr->cellLabel()
523  << endl;
524  }
525  if (!parentPtr)
526  {
528  << "No parent for owner " << ownPtr->cellLabel()
529  << abort(FatalError);
530  }
531 
532  if (!nbrPtr->parent())
533  {
535  << "No parent for neighbour " << nbrPtr->cellLabel()
536  << abort(FatalError);
537  }
538 
539  if (parentPtr != nbrPtr->parent())
540  {
542  << "Owner and neighbour liveSplitCell entries do not have"
543  << " same parent. facei:" << facei << " owner:" << own
544  << " ownparent:" << parentPtr->cellLabel()
545  << " neighbour:" << nbr
546  << " nbrparent:" << nbrPtr->parent()->cellLabel()
547  << abort(FatalError);
548  }
549 
550  if
551  (
552  !ownPtr->isUnrefined()
553  || !nbrPtr->isUnrefined()
554  || parentPtr->isUnrefined()
555  )
556  {
557  // Live owner and neighbour are refined themselves.
559  << "Owner and neighbour liveSplitCell entries are"
560  << " refined themselves or the parent is not refined"
561  << endl
562  << "owner unrefined:" << ownPtr->isUnrefined()
563  << " neighbour unrefined:" << nbrPtr->isUnrefined()
564  << " master unrefined:" << parentPtr->isUnrefined()
565  << abort(FatalError);
566  }
567 
568  // Delete from liveSplitCell
569  liveSplitCells_.erase(ownFind);
570 
572  liveSplitCells_.erase(liveSplitCells_.find(nbr));
573 
574  // Delete entries themselves
575  delete ownPtr;
576  delete nbrPtr;
577 
578  // Update parent:
579  // - has parent itself: is part of split cell. Update cellLabel
580  // with merged cell one.
581  // - has no parent: is start of tree. Completely remove.
582 
583  if (parentPtr->parent())
584  {
585  // Update parent cell label to be new merged cell label
586  // (will be owner)
587  parentPtr->cellLabel() = own;
588 
589  // And insert into live cells (is ok since old entry with
590  // own as key has been removed above)
591  liveSplitCells_.insert(own, parentPtr);
592  }
593  else
594  {
595  // No parent so is start of tree. No need to keep splitCell
596  // tree.
597  delete parentPtr;
598  }
599  }
600  }
601 
602  // Insert all commands to combine cells. Never fails so don't have to
603  // test for success.
604  faceRemover().setRefinement
605  (
606  facesToRemove,
607  cellRegion,
608  cellRegionMaster,
609  meshMod
610  );
611 
612  return facesToRemove;
613 }
614 
615 
616 // ************************************************************************* //
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:324
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:74
Foam::undoableMeshCutter::getSplitFaces
labelList getSplitFaces() const
Calculate split faces from current liveCells. Only.
Definition: undoableMeshCutter.C:342
meshCutter.H
meshTools.H
Foam::meshCutter
Cuts (splits) cells.
Definition: meshCutter.H:137
splitCell.H
Foam::undoableMeshCutter::~undoableMeshCutter
~undoableMeshCutter()
Destructor.
Definition: undoableMeshCutter.C:197
Foam::DynamicList< label >
Foam::splitCell::slave
splitCell * slave() const
Definition: splitCell.H:125
Foam::undoableMeshCutter::removeSplitFaces
labelList removeSplitFaces(const labelList &splitFaces, polyTopoChange &)
Remove some refinement. Needs to be supplied subset of.
Definition: undoableMeshCutter.C:448
mapPolyMesh.H
Foam::splitCell::isUnrefined
bool isUnrefined() const
Check if this is unrefined (i.e. has no master or slave)
Definition: splitCell.C:102
polyTopoChange.H
Foam::polyTopoChange
Direct mesh changes based on v1.3 polyTopoChange syntax.
Definition: polyTopoChange.H:100
Foam::splitCell::parent
splitCell * parent() const
Definition: splitCell.H:105
Foam::Map
A HashTable to objects of type <T> with a label key.
Definition: HashTableFwd.H:46
unitConversion.H
Unit conversion functions.
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
Foam::Pout
prefixOSstream Pout
An Ostream wrapper for parallel output to std::cout.
Foam::undoableMeshCutter::getAddedCells
Map< label > getAddedCells() const
Like getSplitFaces but returns map from original to added cell.
Definition: undoableMeshCutter.C:401
undoableMeshCutter.H
Foam::meshCutter::updateMesh
void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Definition: meshCutter.C:1001
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:290
Foam::splitCell::getOther
splitCell * getOther() const
Returns other half of split cell. I.e. slave if this is master.
Definition: splitCell.C:108
Foam::primitiveMesh::nCells
label nCells() const
Number of mesh cells.
Definition: primitiveMeshI.H:96
Foam::label
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:62
Foam::polyMesh::faceOwner
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1076
Foam::splitCell::cellLabel
label cellLabel() const
Definition: splitCell.H:95
forAllIters
#define forAllIters(container, iter)
Iterate across all elements in the container object.
Definition: stdFoam.H:217
cellCuts.H
Foam::FatalError
error FatalError
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:137
Foam::indent
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:307
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:531
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::splitCell
Description of cell after splitting. Contains cellLabel and pointers to cells it it split in....
Definition: splitCell.H:53
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:528
Foam::List< label >
Foam::mapPolyMesh
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:160
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:232
Foam::splitCell::master
splitCell * master() const
Definition: splitCell.H:115
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::splitCell::isMaster
bool isMaster() const
Check if this is master cell of split.
Definition: splitCell.C:72
Foam::polyMesh::faceNeighbour
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1082
Foam::cellCuts
Description of cuts across cells.
Definition: cellCuts.H:110
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:265