1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "undoableMeshCutter.H"
29 #include "polyTopoChange.H"
30 #include "DynamicList.H"
31 #include "meshCutter.H"
33 #include "splitCell.H"
34 #include "mapPolyMesh.H"
35 #include "mathematicalConstants.H"
36 #include "meshTools.H"
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 defineTypeNameAndDebug(undoableMeshCutter, 0);
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
50 void Foam::undoableMeshCutter::printCellRefTree
54 const splitCell* splitCellPtr
59 os << indent << splitCellPtr->cellLabel() << endl;
61 word subIndent = indent + "--";
63 printCellRefTree(os, subIndent, splitCellPtr->master());
65 printCellRefTree(os, subIndent, splitCellPtr->slave());
71 void Foam::undoableMeshCutter::printRefTree(Ostream& os) const
75 Map<splitCell*>::const_iterator iter = liveSplitCells_.begin();
76 iter != liveSplitCells_.end();
80 const splitCell* splitPtr = iter();
82 // Walk to top (master path only)
83 while (splitPtr->parent())
85 if (!splitPtr->isMaster())
93 splitPtr = splitPtr->parent();
97 // If we have reached top along master path start printing.
100 // Print from top down
101 printCellRefTree(os, word(""), splitPtr);
107 // Update all (cell) labels on splitCell structure.
108 // Do in two passes to prevent allocation if nothing changed.
109 void Foam::undoableMeshCutter::updateLabels
111 const labelList& map,
112 Map<splitCell*>& liveSplitCells
115 // Pass1 : check if changed
117 bool changed = false;
119 forAllConstIter(Map<splitCell*>,liveSplitCells, iter)
121 const splitCell* splitPtr = iter();
127 "undoableMeshCutter::updateLabels"
128 "(const labelList&, Map<splitCell*>&)"
129 ) << "Problem: null pointer on liveSplitCells list"
130 << abort(FatalError);
133 label cellI = splitPtr->cellLabel();
135 if (cellI != map[cellI])
148 // Build new liveSplitCells
149 // since new labels (= keys in Map) might clash with existing ones.
150 Map<splitCell*> newLiveSplitCells(2*liveSplitCells.size());
152 forAllIter(Map<splitCell*>, liveSplitCells, iter)
154 splitCell* splitPtr = iter();
156 label cellI = splitPtr->cellLabel();
158 label newCellI = map[cellI];
160 if (debug && (cellI != newCellI))
162 Pout<< "undoableMeshCutter::updateLabels :"
163 << " Updating live (split)cell from " << cellI
164 << " to " << newCellI << endl;
169 // Update splitCell. Can do inplace since only one cellI will
170 // refer to this structure.
171 splitPtr->cellLabel() = newCellI;
173 // Update liveSplitCells
174 newLiveSplitCells.insert(newCellI, splitPtr);
177 liveSplitCells = newLiveSplitCells;
182 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
184 // Construct from components
185 Foam::undoableMeshCutter::undoableMeshCutter
187 const polyMesh& mesh,
193 liveSplitCells_(mesh.nCells()/100 + 100),
197 Foam::cos(30./180. * mathematicalConstant::pi)
202 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
204 Foam::undoableMeshCutter::~undoableMeshCutter()
206 // Clean split cell tree.
208 forAllIter(Map<splitCell*>, liveSplitCells_, iter)
210 splitCell* splitPtr = iter();
214 splitCell* parentPtr = splitPtr->parent();
216 // Sever ties with parent. Also of other side of refinement since
217 // we are handling rest of tree so other side will not have to.
220 splitCell* otherSidePtr = splitPtr->getOther();
222 otherSidePtr->parent() = NULL;
224 splitPtr->parent() = NULL;
227 // Delete splitCell (updates pointer on parent to itself)
230 splitPtr = parentPtr;
236 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
238 void Foam::undoableMeshCutter::setRefinement
240 const cellCuts& cuts,
241 polyTopoChange& meshMod
244 // Insert commands to actually cut cells
245 meshCutter::setRefinement(cuts, meshMod);
249 // Use cells cut in this iteration to update splitCell tree.
250 forAllConstIter(Map<label>, addedCells(), iter)
252 label cellI = iter.key();
254 label addedCellI = iter();
257 // Newly created split cell. (cellI -> cellI + addedCellI)
259 // Check if cellI already part of split.
260 Map<splitCell*>::iterator findCell =
261 liveSplitCells_.find(cellI);
263 if (findCell == liveSplitCells_.end())
265 // CellI not yet split. It cannot be unlive split cell
266 // since that would be illegal to split in the first
269 // Create 0th level. Null parent to denote this.
270 splitCell* parentPtr = new splitCell(cellI, NULL);
272 splitCell* masterPtr = new splitCell(cellI, parentPtr);
274 splitCell* slavePtr = new splitCell(addedCellI, parentPtr);
276 // Store newly created cells on parent together with face
278 parentPtr->master() = masterPtr;
279 parentPtr->slave() = slavePtr;
281 // Insert master and slave into live splitcell list
283 if (liveSplitCells_.found(addedCellI))
285 FatalErrorIn("undoableMeshCutter::setRefinement")
286 << "problem addedCell:" << addedCellI
287 << abort(FatalError);
290 liveSplitCells_.insert(cellI, masterPtr);
291 liveSplitCells_.insert(addedCellI, slavePtr);
295 // Cell that was split has been split again.
296 splitCell* parentPtr = findCell();
298 // It is no longer live
299 liveSplitCells_.erase(findCell);
301 splitCell* masterPtr = new splitCell(cellI, parentPtr);
303 splitCell* slavePtr = new splitCell(addedCellI, parentPtr);
305 // Store newly created cells on parent together with face
307 parentPtr->master() = masterPtr;
308 parentPtr->slave() = slavePtr;
310 // Insert master and slave into live splitcell list
312 if (liveSplitCells_.found(addedCellI))
314 FatalErrorIn("undoableMeshCutter::setRefinement")
315 << "problem addedCell:" << addedCellI
316 << abort(FatalError);
319 liveSplitCells_.insert(cellI, masterPtr);
320 liveSplitCells_.insert(addedCellI, slavePtr);
326 Pout<< "** After refinement: liveSplitCells_:" << endl;
334 void Foam::undoableMeshCutter::updateMesh(const mapPolyMesh& morphMap)
336 // Update mesh cutter for new labels.
337 meshCutter::updateMesh(morphMap);
339 // No need to update cell walker for new labels since does not store any.
341 // Update faceRemover for new labels
342 faceRemover_.updateMesh(morphMap);
346 // Update all live split cells for mesh mapper.
347 updateLabels(morphMap.reverseCellMap(), liveSplitCells_);
352 Foam::labelList Foam::undoableMeshCutter::getSplitFaces() const
356 FatalErrorIn("undoableMeshCutter::getSplitFaces()")
357 << "Only call if constructed with unrefinement capability"
358 << abort(FatalError);
361 DynamicList<label> liveSplitFaces(liveSplitCells_.size());
363 forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
365 const splitCell* splitPtr = iter();
367 if (!splitPtr->parent())
369 FatalErrorIn("undoableMeshCutter::getSplitFaces()")
370 << "Live split cell without parent" << endl
371 << "splitCell:" << splitPtr->cellLabel()
372 << abort(FatalError);
375 // Check if not top of refinement and whether it is the master side
376 if (splitPtr->isMaster())
378 splitCell* slavePtr = splitPtr->getOther();
382 liveSplitCells_.found(slavePtr->cellLabel())
383 && splitPtr->isUnrefined()
384 && slavePtr->isUnrefined()
387 // Both master and slave are live and are not refined.
390 label cellI = splitPtr->cellLabel();
392 label slaveCellI = slavePtr->cellLabel();
395 meshTools::getSharedFace
402 liveSplitFaces.append(commonFaceI);
407 return liveSplitFaces.shrink();
411 Foam::Map<Foam::label> Foam::undoableMeshCutter::getAddedCells() const
413 // (code copied from getSplitFaces)
417 FatalErrorIn("undoableMeshCutter::getAddedCells()")
418 << "Only call if constructed with unrefinement capability"
419 << abort(FatalError);
422 Map<label> addedCells(liveSplitCells_.size());
424 forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
426 const splitCell* splitPtr = iter();
428 if (!splitPtr->parent())
430 FatalErrorIn("undoableMeshCutter::getAddedCells()")
431 << "Live split cell without parent" << endl
432 << "splitCell:" << splitPtr->cellLabel()
433 << abort(FatalError);
436 // Check if not top of refinement and whether it is the master side
437 if (splitPtr->isMaster())
439 splitCell* slavePtr = splitPtr->getOther();
443 liveSplitCells_.found(slavePtr->cellLabel())
444 && splitPtr->isUnrefined()
445 && slavePtr->isUnrefined()
448 // Both master and slave are live and are not refined.
449 addedCells.insert(splitPtr->cellLabel(), slavePtr->cellLabel());
457 Foam::labelList Foam::undoableMeshCutter::removeSplitFaces
459 const labelList& splitFaces,
460 polyTopoChange& meshMod
465 FatalErrorIn("undoableMeshCutter::removeSplitFaces(const labelList&)")
466 << "Only call if constructed with unrefinement capability"
467 << abort(FatalError);
470 // Check with faceRemover what faces will get removed. Note that this can
471 // be more (but never less) than splitFaces provided.
472 labelList cellRegion;
473 labelList cellRegionMaster;
474 labelList facesToRemove;
476 faceRemover().compatibleRemoves
478 splitFaces, // pierced faces
479 cellRegion, // per cell -1 or region it is merged into
480 cellRegionMaster, // per region the master cell
481 facesToRemove // new faces to be removed.
484 if (facesToRemove.size() != splitFaces.size())
486 Pout<< "cellRegion:" << cellRegion << endl;
487 Pout<< "cellRegionMaster:" << cellRegionMaster << endl;
491 "undoableMeshCutter::removeSplitFaces(const labelList&)"
492 ) << "Faces to remove:" << splitFaces << endl
493 << "to be removed:" << facesToRemove
494 << abort(FatalError);
498 // Every face removed will result in neighbour and owner being merged
500 forAll(facesToRemove, facesToRemoveI)
502 label faceI = facesToRemove[facesToRemoveI];
504 if (!mesh().isInternalFace(faceI))
508 "undoableMeshCutter::removeSplitFaces(const labelList&)"
509 ) << "Trying to remove face that is not internal"
510 << abort(FatalError);
513 label own = mesh().faceOwner()[faceI];
515 label nbr = mesh().faceNeighbour()[faceI];
517 Map<splitCell*>::iterator ownFind = liveSplitCells_.find(own);
519 Map<splitCell*>::iterator nbrFind = liveSplitCells_.find(nbr);
523 (ownFind == liveSplitCells_.end())
524 || (nbrFind == liveSplitCells_.end())
527 // Can happen because of removeFaces adding extra faces to
528 // original splitFaces
532 // Face is original splitFace.
534 splitCell* ownPtr = ownFind();
536 splitCell* nbrPtr = nbrFind();
538 splitCell* parentPtr = ownPtr->parent();
540 // Various checks on sanity.
544 Pout<< "Updating for removed splitFace " << faceI
545 << " own:" << own << " nbr:" << nbr
546 << " ownPtr:" << ownPtr->cellLabel()
547 << " nbrPtr:" << nbrPtr->cellLabel()
554 "undoableMeshCutter::removeSplitFaces(const labelList&)"
555 ) << "No parent for owner " << ownPtr->cellLabel()
556 << abort(FatalError);
559 if (!nbrPtr->parent())
563 "undoableMeshCutter::removeSplitFaces(const labelList&)"
564 ) << "No parent for neighbour " << nbrPtr->cellLabel()
565 << abort(FatalError);
568 if (parentPtr != nbrPtr->parent())
572 "undoableMeshCutter::removeSplitFaces(const labelList&)"
573 ) << "Owner and neighbour liveSplitCell entries do not have"
574 << " same parent. faceI:" << faceI << " owner:" << own
575 << " ownparent:" << parentPtr->cellLabel()
576 << " neighbour:" << nbr
577 << " nbrparent:" << nbrPtr->parent()->cellLabel()
578 << abort(FatalError);
583 !ownPtr->isUnrefined()
584 || !nbrPtr->isUnrefined()
585 || parentPtr->isUnrefined()
588 // Live owner and neighbour are refined themselves.
591 "undoableMeshCutter::removeSplitFaces(const labelList&)"
592 ) << "Owner and neighbour liveSplitCell entries are"
593 << " refined themselves or the parent is not refined"
595 << "owner unrefined:" << ownPtr->isUnrefined()
596 << " neighbour unrefined:" << nbrPtr->isUnrefined()
597 << " master unrefined:" << parentPtr->isUnrefined()
598 << abort(FatalError);
601 // Delete from liveSplitCell
602 liveSplitCells_.erase(ownFind);
604 //!important: Redo search since ownFind entry deleted.
605 liveSplitCells_.erase(liveSplitCells_.find(nbr));
607 // Delete entries themselves
613 // - has parent itself: is part of split cell. Update cellLabel
614 // with merged cell one.
615 // - has no parent: is start of tree. Completely remove.
617 if (parentPtr->parent())
619 // Update parent cell label to be new merged cell label
621 parentPtr->cellLabel() = own;
623 // And insert into live cells (is ok since old entry with
624 // own as key has been removed above)
625 liveSplitCells_.insert(own, parentPtr);
629 // No parent so is start of tree. No need to keep splitCell
636 // Insert all commands to combine cells. Never fails so don't have to
638 faceRemover().setRefinement
646 return facesToRemove;
650 // ************************************************************************* //