FreeFOAM The Cross-Platform CFD Toolkit
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) 1991-2010 OpenCFD Ltd.
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 <OpenFOAM/polyMesh.H>
29 #include <OpenFOAM/DynamicList.H>
30 #include <dynamicMesh/meshCutter.H>
31 #include <dynamicMesh/cellCuts.H>
32 #include <dynamicMesh/splitCell.H>
33 #include <OpenFOAM/mapPolyMesh.H>
35 #include <meshTools/meshTools.H>
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41 
42 defineTypeNameAndDebug(undoableMeshCutter, 0);
43 
44 }
45 
46 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
47 
48 // For debugging
49 void Foam::undoableMeshCutter::printCellRefTree
50 (
51  Ostream& os,
52  const word& indent,
53  const splitCell* splitCellPtr
54 ) const
55 {
56  if (splitCellPtr)
57  {
58  os << indent << splitCellPtr->cellLabel() << endl;
59 
60  word subIndent = indent + "--";
61 
62  printCellRefTree(os, subIndent, splitCellPtr->master());
63 
64  printCellRefTree(os, subIndent, splitCellPtr->slave());
65  }
66 }
67 
68 
69 // For debugging
70 void Foam::undoableMeshCutter::printRefTree(Ostream& os) const
71 {
72  for
73  (
74  Map<splitCell*>::const_iterator iter = liveSplitCells_.begin();
75  iter != liveSplitCells_.end();
76  ++iter
77  )
78  {
79  const splitCell* splitPtr = iter();
80 
81  // Walk to top (master path only)
82  while (splitPtr->parent())
83  {
84  if (!splitPtr->isMaster())
85  {
86  splitPtr = NULL;
87 
88  break;
89  }
90  else
91  {
92  splitPtr = splitPtr->parent();
93  }
94  }
95 
96  // If we have reached top along master path start printing.
97  if (splitPtr)
98  {
99  // Print from top down
100  printCellRefTree(os, word(""), splitPtr);
101  }
102  }
103 }
104 
105 
106 // Update all (cell) labels on splitCell structure.
107 // Do in two passes to prevent allocation if nothing changed.
108 void Foam::undoableMeshCutter::updateLabels
109 (
110  const labelList& map,
111  Map<splitCell*>& liveSplitCells
112 )
113 {
114  // Pass1 : check if changed
115 
116  bool changed = false;
117 
118  forAllConstIter(Map<splitCell*>,liveSplitCells, iter)
119  {
120  const splitCell* splitPtr = iter();
121 
122  if (!splitPtr)
123  {
125  (
126  "undoableMeshCutter::updateLabels"
127  "(const labelList&, Map<splitCell*>&)"
128  ) << "Problem: null pointer on liveSplitCells list"
129  << abort(FatalError);
130  }
131 
132  label cellI = splitPtr->cellLabel();
133 
134  if (cellI != map[cellI])
135  {
136  changed = true;
137 
138  break;
139  }
140  }
141 
142 
143  // Pass2: relabel
144 
145  if (changed)
146  {
147  // Build new liveSplitCells
148  // since new labels (= keys in Map) might clash with existing ones.
149  Map<splitCell*> newLiveSplitCells(2*liveSplitCells.size());
150 
151  forAllIter(Map<splitCell*>, liveSplitCells, iter)
152  {
153  splitCell* splitPtr = iter();
154 
155  label cellI = splitPtr->cellLabel();
156 
157  label newCellI = map[cellI];
158 
159  if (debug && (cellI != newCellI))
160  {
161  Pout<< "undoableMeshCutter::updateLabels :"
162  << " Updating live (split)cell from " << cellI
163  << " to " << newCellI << endl;
164  }
165 
166  if (newCellI >= 0)
167  {
168  // Update splitCell. Can do inplace since only one cellI will
169  // refer to this structure.
170  splitPtr->cellLabel() = newCellI;
171 
172  // Update liveSplitCells
173  newLiveSplitCells.insert(newCellI, splitPtr);
174  }
175  }
176  liveSplitCells = newLiveSplitCells;
177  }
178 }
179 
180 
181 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
182 
183 // Construct from components
184 Foam::undoableMeshCutter::undoableMeshCutter
185 (
186  const polyMesh& mesh,
187  const bool undoable
188 )
189 :
190  meshCutter(mesh),
191  undoable_(undoable),
192  liveSplitCells_(mesh.nCells()/100 + 100),
193  faceRemover_
194  (
195  mesh,
197  )
198 {}
199 
200 
201 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
202 
204 {
205  // Clean split cell tree.
206 
207  forAllIter(Map<splitCell*>, liveSplitCells_, iter)
208  {
209  splitCell* splitPtr = iter();
210 
211  while (splitPtr)
212  {
213  splitCell* parentPtr = splitPtr->parent();
214 
215  // Sever ties with parent. Also of other side of refinement since
216  // we are handling rest of tree so other side will not have to.
217  if (parentPtr)
218  {
219  splitCell* otherSidePtr = splitPtr->getOther();
220 
221  otherSidePtr->parent() = NULL;
222 
223  splitPtr->parent() = NULL;
224  }
225 
226  // Delete splitCell (updates pointer on parent to itself)
227  delete splitPtr;
228 
229  splitPtr = parentPtr;
230  }
231  }
232 }
233 
234 
235 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
236 
238 (
239  const cellCuts& cuts,
240  polyTopoChange& meshMod
241 )
242 {
243  // Insert commands to actually cut cells
244  meshCutter::setRefinement(cuts, meshMod);
245 
246  if (undoable_)
247  {
248  // Use cells cut in this iteration to update splitCell tree.
249  forAllConstIter(Map<label>, addedCells(), iter)
250  {
251  label cellI = iter.key();
252 
253  label addedCellI = iter();
254 
255 
256  // Newly created split cell. (cellI -> cellI + addedCellI)
257 
258  // Check if cellI already part of split.
259  Map<splitCell*>::iterator findCell =
260  liveSplitCells_.find(cellI);
261 
262  if (findCell == liveSplitCells_.end())
263  {
264  // CellI not yet split. It cannot be unlive split cell
265  // since that would be illegal to split in the first
266  // place.
267 
268  // Create 0th level. Null parent to denote this.
269  splitCell* parentPtr = new splitCell(cellI, NULL);
270 
271  splitCell* masterPtr = new splitCell(cellI, parentPtr);
272 
273  splitCell* slavePtr = new splitCell(addedCellI, parentPtr);
274 
275  // Store newly created cells on parent together with face
276  // that splits them
277  parentPtr->master() = masterPtr;
278  parentPtr->slave() = slavePtr;
279 
280  // Insert master and slave into live splitcell list
281 
282  if (liveSplitCells_.found(addedCellI))
283  {
284  FatalErrorIn("undoableMeshCutter::setRefinement")
285  << "problem addedCell:" << addedCellI
286  << abort(FatalError);
287  }
288 
289  liveSplitCells_.insert(cellI, masterPtr);
290  liveSplitCells_.insert(addedCellI, slavePtr);
291  }
292  else
293  {
294  // Cell that was split has been split again.
295  splitCell* parentPtr = findCell();
296 
297  // It is no longer live
298  liveSplitCells_.erase(findCell);
299 
300  splitCell* masterPtr = new splitCell(cellI, parentPtr);
301 
302  splitCell* slavePtr = new splitCell(addedCellI, parentPtr);
303 
304  // Store newly created cells on parent together with face
305  // that splits them
306  parentPtr->master() = masterPtr;
307  parentPtr->slave() = slavePtr;
308 
309  // Insert master and slave into live splitcell list
310 
311  if (liveSplitCells_.found(addedCellI))
312  {
313  FatalErrorIn("undoableMeshCutter::setRefinement")
314  << "problem addedCell:" << addedCellI
315  << abort(FatalError);
316  }
317 
318  liveSplitCells_.insert(cellI, masterPtr);
319  liveSplitCells_.insert(addedCellI, slavePtr);
320  }
321  }
322 
323  if (debug & 2)
324  {
325  Pout<< "** After refinement: liveSplitCells_:" << endl;
326 
327  printRefTree(Pout);
328  }
329  }
330 }
331 
332 
334 {
335  // Update mesh cutter for new labels.
336  meshCutter::updateMesh(morphMap);
337 
338  // No need to update cell walker for new labels since does not store any.
339 
340  // Update faceRemover for new labels
341  faceRemover_.updateMesh(morphMap);
342 
343  if (undoable_)
344  {
345  // Update all live split cells for mesh mapper.
346  updateLabels(morphMap.reverseCellMap(), liveSplitCells_);
347  }
348 }
349 
350 
352 {
353  if (!undoable_)
354  {
355  FatalErrorIn("undoableMeshCutter::getSplitFaces()")
356  << "Only call if constructed with unrefinement capability"
357  << abort(FatalError);
358  }
359 
360  DynamicList<label> liveSplitFaces(liveSplitCells_.size());
361 
362  forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
363  {
364  const splitCell* splitPtr = iter();
365 
366  if (!splitPtr->parent())
367  {
368  FatalErrorIn("undoableMeshCutter::getSplitFaces()")
369  << "Live split cell without parent" << endl
370  << "splitCell:" << splitPtr->cellLabel()
371  << abort(FatalError);
372  }
373 
374  // Check if not top of refinement and whether it is the master side
375  if (splitPtr->isMaster())
376  {
377  splitCell* slavePtr = splitPtr->getOther();
378 
379  if
380  (
381  liveSplitCells_.found(slavePtr->cellLabel())
382  && splitPtr->isUnrefined()
383  && slavePtr->isUnrefined()
384  )
385  {
386  // Both master and slave are live and are not refined.
387  // Find common face.
388 
389  label cellI = splitPtr->cellLabel();
390 
391  label slaveCellI = slavePtr->cellLabel();
392 
393  label commonFaceI =
395  (
396  mesh(),
397  cellI,
398  slaveCellI
399  );
400 
401  liveSplitFaces.append(commonFaceI);
402  }
403  }
404  }
405 
406  return liveSplitFaces.shrink();
407 }
408 
409 
411 {
412  // (code copied from getSplitFaces)
413 
414  if (!undoable_)
415  {
416  FatalErrorIn("undoableMeshCutter::getAddedCells()")
417  << "Only call if constructed with unrefinement capability"
418  << abort(FatalError);
419  }
420 
421  Map<label> addedCells(liveSplitCells_.size());
422 
423  forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
424  {
425  const splitCell* splitPtr = iter();
426 
427  if (!splitPtr->parent())
428  {
429  FatalErrorIn("undoableMeshCutter::getAddedCells()")
430  << "Live split cell without parent" << endl
431  << "splitCell:" << splitPtr->cellLabel()
432  << abort(FatalError);
433  }
434 
435  // Check if not top of refinement and whether it is the master side
436  if (splitPtr->isMaster())
437  {
438  splitCell* slavePtr = splitPtr->getOther();
439 
440  if
441  (
442  liveSplitCells_.found(slavePtr->cellLabel())
443  && splitPtr->isUnrefined()
444  && slavePtr->isUnrefined()
445  )
446  {
447  // Both master and slave are live and are not refined.
448  addedCells.insert(splitPtr->cellLabel(), slavePtr->cellLabel());
449  }
450  }
451  }
452  return addedCells;
453 }
454 
455 
457 (
458  const labelList& splitFaces,
459  polyTopoChange& meshMod
460 )
461 {
462  if (!undoable_)
463  {
464  FatalErrorIn("undoableMeshCutter::removeSplitFaces(const labelList&)")
465  << "Only call if constructed with unrefinement capability"
466  << abort(FatalError);
467  }
468 
469  // Check with faceRemover what faces will get removed. Note that this can
470  // be more (but never less) than splitFaces provided.
471  labelList cellRegion;
472  labelList cellRegionMaster;
473  labelList facesToRemove;
474 
475  faceRemover().compatibleRemoves
476  (
477  splitFaces, // pierced faces
478  cellRegion, // per cell -1 or region it is merged into
479  cellRegionMaster, // per region the master cell
480  facesToRemove // new faces to be removed.
481  );
482 
483  if (facesToRemove.size() != splitFaces.size())
484  {
485  Pout<< "cellRegion:" << cellRegion << endl;
486  Pout<< "cellRegionMaster:" << cellRegionMaster << endl;
487 
489  (
490  "undoableMeshCutter::removeSplitFaces(const labelList&)"
491  ) << "Faces to remove:" << splitFaces << endl
492  << "to be removed:" << facesToRemove
493  << abort(FatalError);
494  }
495 
496 
497  // Every face removed will result in neighbour and owner being merged
498  // into owner.
499  forAll(facesToRemove, facesToRemoveI)
500  {
501  label faceI = facesToRemove[facesToRemoveI];
502 
503  if (!mesh().isInternalFace(faceI))
504  {
506  (
507  "undoableMeshCutter::removeSplitFaces(const labelList&)"
508  ) << "Trying to remove face that is not internal"
509  << abort(FatalError);
510  }
511 
512  label own = mesh().faceOwner()[faceI];
513 
514  label nbr = mesh().faceNeighbour()[faceI];
515 
516  Map<splitCell*>::iterator ownFind = liveSplitCells_.find(own);
517 
518  Map<splitCell*>::iterator nbrFind = liveSplitCells_.find(nbr);
519 
520  if
521  (
522  (ownFind == liveSplitCells_.end())
523  || (nbrFind == liveSplitCells_.end())
524  )
525  {
526  // Can happen because of removeFaces adding extra faces to
527  // original splitFaces
528  }
529  else
530  {
531  // Face is original splitFace.
532 
533  splitCell* ownPtr = ownFind();
534 
535  splitCell* nbrPtr = nbrFind();
536 
537  splitCell* parentPtr = ownPtr->parent();
538 
539  // Various checks on sanity.
540 
541  if (debug)
542  {
543  Pout<< "Updating for removed splitFace " << faceI
544  << " own:" << own << " nbr:" << nbr
545  << " ownPtr:" << ownPtr->cellLabel()
546  << " nbrPtr:" << nbrPtr->cellLabel()
547  << endl;
548  }
549  if (!parentPtr)
550  {
552  (
553  "undoableMeshCutter::removeSplitFaces(const labelList&)"
554  ) << "No parent for owner " << ownPtr->cellLabel()
555  << abort(FatalError);
556  }
557 
558  if (!nbrPtr->parent())
559  {
561  (
562  "undoableMeshCutter::removeSplitFaces(const labelList&)"
563  ) << "No parent for neighbour " << nbrPtr->cellLabel()
564  << abort(FatalError);
565  }
566 
567  if (parentPtr != nbrPtr->parent())
568  {
570  (
571  "undoableMeshCutter::removeSplitFaces(const labelList&)"
572  ) << "Owner and neighbour liveSplitCell entries do not have"
573  << " same parent. faceI:" << faceI << " owner:" << own
574  << " ownparent:" << parentPtr->cellLabel()
575  << " neighbour:" << nbr
576  << " nbrparent:" << nbrPtr->parent()->cellLabel()
577  << abort(FatalError);
578  }
579 
580  if
581  (
582  !ownPtr->isUnrefined()
583  || !nbrPtr->isUnrefined()
584  || parentPtr->isUnrefined()
585  )
586  {
587  // Live owner and neighbour are refined themselves.
589  (
590  "undoableMeshCutter::removeSplitFaces(const labelList&)"
591  ) << "Owner and neighbour liveSplitCell entries are"
592  << " refined themselves or the parent is not refined"
593  << endl
594  << "owner unrefined:" << ownPtr->isUnrefined()
595  << " neighbour unrefined:" << nbrPtr->isUnrefined()
596  << " master unrefined:" << parentPtr->isUnrefined()
597  << abort(FatalError);
598  }
599 
600  // Delete from liveSplitCell
601  liveSplitCells_.erase(ownFind);
602 
604  liveSplitCells_.erase(liveSplitCells_.find(nbr));
605 
606  // Delete entries themselves
607  delete ownPtr;
608  delete nbrPtr;
609 
610  //
611  // Update parent:
612  // - has parent itself: is part of split cell. Update cellLabel
613  // with merged cell one.
614  // - has no parent: is start of tree. Completely remove.
615 
616  if (parentPtr->parent())
617  {
618  // Update parent cell label to be new merged cell label
619  // (will be owner)
620  parentPtr->cellLabel() = own;
621 
622  // And insert into live cells (is ok since old entry with
623  // own as key has been removed above)
624  liveSplitCells_.insert(own, parentPtr);
625  }
626  else
627  {
628  // No parent so is start of tree. No need to keep splitCell
629  // tree.
630  delete parentPtr;
631  }
632  }
633  }
634 
635  // Insert all commands to combine cells. Never fails so don't have to
636  // test for success.
637  faceRemover().setRefinement
638  (
639  facesToRemove,
640  cellRegion,
641  cellRegionMaster,
642  meshMod
643  );
644 
645  return facesToRemove;
646 }
647 
648 
649 // ************************ vim: set sw=4 sts=4 et: ************************ //