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 | Copyright (C) 2011-2012 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 "mapPolyMesh.H"
34 #include "unitConversion.H"
35 #include "meshTools.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41 defineTypeNameAndDebug(undoableMeshCutter, 0);
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 = NULL;
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  (
120  "undoableMeshCutter::updateLabels"
121  "(const labelList&, Map<splitCell*>&)"
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  forAllIter(Map<splitCell*>, liveSplitCells, iter)
146  {
147  splitCell* splitPtr = iter();
148 
149  label cellI = splitPtr->cellLabel();
150 
151  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  forAllIter(Map<splitCell*>, liveSplitCells_, iter)
202  {
203  splitCell* splitPtr = iter();
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() = NULL;
216 
217  splitPtr->parent() = NULL;
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  forAllConstIter(Map<label>, addedCells(), iter)
244  {
245  label cellI = iter.key();
246 
247  label addedCellI = iter();
248 
249 
250  // Newly created split cell. (cellI -> cellI + addedCellI)
251 
252  // Check if cellI already part of split.
253  Map<splitCell*>::iterator findCell =
254  liveSplitCells_.find(cellI);
255 
256  if (findCell == liveSplitCells_.end())
257  {
258  // CellI not yet split. It cannot be unlive split cell
259  // since that would be illegal to split in the first
260  // place.
261 
262  // Create 0th level. Null parent to denote this.
263  splitCell* parentPtr = new splitCell(cellI, NULL);
264 
265  splitCell* masterPtr = new splitCell(cellI, parentPtr);
266 
267  splitCell* slavePtr = new splitCell(addedCellI, parentPtr);
268 
269  // Store newly created cells on parent together with face
270  // that splits them
271  parentPtr->master() = masterPtr;
272  parentPtr->slave() = slavePtr;
273 
274  // Insert master and slave into live splitcell list
275 
276  if (liveSplitCells_.found(addedCellI))
277  {
278  FatalErrorIn("undoableMeshCutter::setRefinement")
279  << "problem addedCell:" << addedCellI
280  << abort(FatalError);
281  }
282 
283  liveSplitCells_.insert(cellI, masterPtr);
284  liveSplitCells_.insert(addedCellI, slavePtr);
285  }
286  else
287  {
288  // Cell that was split has been split again.
289  splitCell* parentPtr = findCell();
290 
291  // It is no longer live
292  liveSplitCells_.erase(findCell);
293 
294  splitCell* masterPtr = new splitCell(cellI, parentPtr);
295 
296  splitCell* slavePtr = new splitCell(addedCellI, parentPtr);
297 
298  // Store newly created cells on parent together with face
299  // that splits them
300  parentPtr->master() = masterPtr;
301  parentPtr->slave() = slavePtr;
302 
303  // Insert master and slave into live splitcell list
304 
305  if (liveSplitCells_.found(addedCellI))
306  {
307  FatalErrorIn("undoableMeshCutter::setRefinement")
308  << "problem addedCell:" << addedCellI
309  << abort(FatalError);
310  }
311 
312  liveSplitCells_.insert(cellI, masterPtr);
313  liveSplitCells_.insert(addedCellI, slavePtr);
314  }
315  }
316 
317  if (debug & 2)
318  {
319  Pout<< "** After refinement: liveSplitCells_:" << endl;
320 
321  printRefTree(Pout);
322  }
323  }
324 }
325 
326 
328 {
329  // Update mesh cutter for new labels.
330  meshCutter::updateMesh(morphMap);
331 
332  // No need to update cell walker for new labels since does not store any.
333 
334  // Update faceRemover for new labels
335  faceRemover_.updateMesh(morphMap);
336 
337  if (undoable_)
338  {
339  // Update all live split cells for mesh mapper.
340  updateLabels(morphMap.reverseCellMap(), liveSplitCells_);
341  }
342 }
343 
344 
346 {
347  if (!undoable_)
348  {
349  FatalErrorIn("undoableMeshCutter::getSplitFaces()")
350  << "Only call if constructed with unrefinement capability"
351  << abort(FatalError);
352  }
353 
354  DynamicList<label> liveSplitFaces(liveSplitCells_.size());
355 
356  forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
357  {
358  const splitCell* splitPtr = iter();
359 
360  if (!splitPtr->parent())
361  {
362  FatalErrorIn("undoableMeshCutter::getSplitFaces()")
363  << "Live split cell without parent" << endl
364  << "splitCell:" << splitPtr->cellLabel()
365  << abort(FatalError);
366  }
367 
368  // Check if not top of refinement and whether it is the master side
369  if (splitPtr->isMaster())
370  {
371  splitCell* slavePtr = splitPtr->getOther();
372 
373  if
374  (
375  liveSplitCells_.found(slavePtr->cellLabel())
376  && splitPtr->isUnrefined()
377  && slavePtr->isUnrefined()
378  )
379  {
380  // Both master and slave are live and are not refined.
381  // Find common face.
382 
383  label cellI = splitPtr->cellLabel();
384 
385  label slaveCellI = slavePtr->cellLabel();
386 
387  label commonFaceI =
389  (
390  mesh(),
391  cellI,
392  slaveCellI
393  );
394 
395  liveSplitFaces.append(commonFaceI);
396  }
397  }
398  }
399 
400  return liveSplitFaces.shrink();
401 }
402 
403 
405 {
406  // (code copied from getSplitFaces)
407 
408  if (!undoable_)
409  {
410  FatalErrorIn("undoableMeshCutter::getAddedCells()")
411  << "Only call if constructed with unrefinement capability"
412  << abort(FatalError);
413  }
414 
415  Map<label> addedCells(liveSplitCells_.size());
416 
417  forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
418  {
419  const splitCell* splitPtr = iter();
420 
421  if (!splitPtr->parent())
422  {
423  FatalErrorIn("undoableMeshCutter::getAddedCells()")
424  << "Live split cell without parent" << endl
425  << "splitCell:" << splitPtr->cellLabel()
426  << abort(FatalError);
427  }
428 
429  // Check if not top of refinement and whether it is the master side
430  if (splitPtr->isMaster())
431  {
432  splitCell* slavePtr = splitPtr->getOther();
433 
434  if
435  (
436  liveSplitCells_.found(slavePtr->cellLabel())
437  && splitPtr->isUnrefined()
438  && slavePtr->isUnrefined()
439  )
440  {
441  // Both master and slave are live and are not refined.
442  addedCells.insert(splitPtr->cellLabel(), slavePtr->cellLabel());
443  }
444  }
445  }
446  return addedCells;
447 }
448 
449 
451 (
452  const labelList& splitFaces,
453  polyTopoChange& meshMod
454 )
455 {
456  if (!undoable_)
457  {
458  FatalErrorIn("undoableMeshCutter::removeSplitFaces(const labelList&)")
459  << "Only call if constructed with unrefinement capability"
460  << abort(FatalError);
461  }
462 
463  // Check with faceRemover what faces will get removed. Note that this can
464  // be more (but never less) than splitFaces provided.
465  labelList cellRegion;
466  labelList cellRegionMaster;
467  labelList facesToRemove;
468 
469  faceRemover().compatibleRemoves
470  (
471  splitFaces, // pierced faces
472  cellRegion, // per cell -1 or region it is merged into
473  cellRegionMaster, // per region the master cell
474  facesToRemove // new faces to be removed.
475  );
476 
477  if (facesToRemove.size() != splitFaces.size())
478  {
479  Pout<< "cellRegion:" << cellRegion << endl;
480  Pout<< "cellRegionMaster:" << cellRegionMaster << endl;
481 
483  (
484  "undoableMeshCutter::removeSplitFaces(const labelList&)"
485  ) << "Faces to remove:" << splitFaces << endl
486  << "to be removed:" << facesToRemove
487  << abort(FatalError);
488  }
489 
490 
491  // Every face removed will result in neighbour and owner being merged
492  // into owner.
493  forAll(facesToRemove, facesToRemoveI)
494  {
495  label faceI = facesToRemove[facesToRemoveI];
496 
497  if (!mesh().isInternalFace(faceI))
498  {
500  (
501  "undoableMeshCutter::removeSplitFaces(const labelList&)"
502  ) << "Trying to remove face that is not internal"
503  << abort(FatalError);
504  }
505 
506  label own = mesh().faceOwner()[faceI];
507 
508  label nbr = mesh().faceNeighbour()[faceI];
509 
510  Map<splitCell*>::iterator ownFind = liveSplitCells_.find(own);
511 
512  Map<splitCell*>::iterator nbrFind = liveSplitCells_.find(nbr);
513 
514  if
515  (
516  (ownFind == liveSplitCells_.end())
517  || (nbrFind == liveSplitCells_.end())
518  )
519  {
520  // Can happen because of removeFaces adding extra faces to
521  // original splitFaces
522  }
523  else
524  {
525  // Face is original splitFace.
526 
527  splitCell* ownPtr = ownFind();
528 
529  splitCell* nbrPtr = nbrFind();
530 
531  splitCell* parentPtr = ownPtr->parent();
532 
533  // Various checks on sanity.
534 
535  if (debug)
536  {
537  Pout<< "Updating for removed splitFace " << faceI
538  << " own:" << own << " nbr:" << nbr
539  << " ownPtr:" << ownPtr->cellLabel()
540  << " nbrPtr:" << nbrPtr->cellLabel()
541  << endl;
542  }
543  if (!parentPtr)
544  {
546  (
547  "undoableMeshCutter::removeSplitFaces(const labelList&)"
548  ) << "No parent for owner " << ownPtr->cellLabel()
549  << abort(FatalError);
550  }
551 
552  if (!nbrPtr->parent())
553  {
555  (
556  "undoableMeshCutter::removeSplitFaces(const labelList&)"
557  ) << "No parent for neighbour " << nbrPtr->cellLabel()
558  << abort(FatalError);
559  }
560 
561  if (parentPtr != nbrPtr->parent())
562  {
564  (
565  "undoableMeshCutter::removeSplitFaces(const labelList&)"
566  ) << "Owner and neighbour liveSplitCell entries do not have"
567  << " same parent. faceI:" << faceI << " owner:" << own
568  << " ownparent:" << parentPtr->cellLabel()
569  << " neighbour:" << nbr
570  << " nbrparent:" << nbrPtr->parent()->cellLabel()
571  << abort(FatalError);
572  }
573 
574  if
575  (
576  !ownPtr->isUnrefined()
577  || !nbrPtr->isUnrefined()
578  || parentPtr->isUnrefined()
579  )
580  {
581  // Live owner and neighbour are refined themselves.
583  (
584  "undoableMeshCutter::removeSplitFaces(const labelList&)"
585  ) << "Owner and neighbour liveSplitCell entries are"
586  << " refined themselves or the parent is not refined"
587  << endl
588  << "owner unrefined:" << ownPtr->isUnrefined()
589  << " neighbour unrefined:" << nbrPtr->isUnrefined()
590  << " master unrefined:" << parentPtr->isUnrefined()
591  << abort(FatalError);
592  }
593 
594  // Delete from liveSplitCell
595  liveSplitCells_.erase(ownFind);
596 
598  liveSplitCells_.erase(liveSplitCells_.find(nbr));
599 
600  // Delete entries themselves
601  delete ownPtr;
602  delete nbrPtr;
603 
604  //
605  // Update parent:
606  // - has parent itself: is part of split cell. Update cellLabel
607  // with merged cell one.
608  // - has no parent: is start of tree. Completely remove.
609 
610  if (parentPtr->parent())
611  {
612  // Update parent cell label to be new merged cell label
613  // (will be owner)
614  parentPtr->cellLabel() = own;
615 
616  // And insert into live cells (is ok since old entry with
617  // own as key has been removed above)
618  liveSplitCells_.insert(own, parentPtr);
619  }
620  else
621  {
622  // No parent so is start of tree. No need to keep splitCell
623  // tree.
624  delete parentPtr;
625  }
626  }
627  }
628 
629  // Insert all commands to combine cells. Never fails so don't have to
630  // test for success.
631  faceRemover().setRefinement
632  (
633  facesToRemove,
634  cellRegion,
635  cellRegionMaster,
636  meshMod
637  );
638 
639  return facesToRemove;
640 }
641 
642 
643 // ************************************************************************* //
Description of cell after splitting. Contains cellLabel and pointers to cells it it split in...
Definition: splitCell.H:51
void updateMesh(const mapPolyMesh &morphMap)
Update stored refinement pattern for changes to mesh. Only.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:158
label getSharedFace(const primitiveMesh &, const label cell0, const label cell1)
Return face shared by two cells. Throws error if none found.
Definition: meshTools.C:428
An STL-conforming iterator.
Definition: HashTable.H:415
A HashTable to objects of type <T> with a label key.
Definition: Map.H:49
#define forAllIter(Container, container, iter)
Definition: UList.H:440
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
void setRefinement(const cellCuts &cuts, polyTopoChange &)
Refine cells acc. to cellCuts. Plays topology changes.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
label nCells() const
splitCell * master() const
Definition: splitCell.H:113
dynamicFvMesh & mesh
Namespace for OpenFOAM.
void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Definition: meshCutter.C:984
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:39
splitCell * slave() const
Definition: splitCell.H:123
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
bool isUnrefined() const
Check if this is unrefined (i.e. has no master or slave)
Definition: splitCell.C:100
#define forAll(list, i)
Definition: UList.H:421
splitCell * getOther() const
Returns other half of split cell. I.e. slave if this is master.
Definition: splitCell.C:106
labelList getSplitFaces() const
Calculate split faces from current liveCells. Only.
dimensionedScalar cos(const dimensionedScalar &ds)
splitCell * parent() const
Definition: splitCell.H:103
Unit conversion functions.
errorManip< error > abort(error &err)
Definition: errorManip.H:131
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1073
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
error FatalError
List< label > labelList
A List of labels.
Definition: labelList.H:56
scalar degToRad(const scalar deg)
Conversion from degrees to radians.
bool isMaster() const
Check if this is master cell of split.
Definition: splitCell.C:70
const labelList & reverseCellMap() const
Reverse cell map.
Definition: mapPolyMesh.H:528
Cuts (splits) cells.
Definition: meshCutter.H:134
Direct mesh changes based on v1.3 polyTopoChange syntax.
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1079
label cellLabel() const
Definition: splitCell.H:93
Map< label > getAddedCells() const
Like getSplitFaces but returns map from original to added cell.
void setRefinement(const cellCuts &cuts, polyTopoChange &meshMod)
Do actual cutting with cut description. Inserts mesh changes.
Definition: meshCutter.C:530
defineTypeNameAndDebug(combustionModel, 0)
labelList removeSplitFaces(const labelList &splitFaces, polyTopoChange &)
Remove some refinement. Needs to be supplied subset of.
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53
Description of cuts across cells.
Definition: cellCuts.H:108