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