1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "undoableMeshCutter.H"
28 #include "polyTopoChange.H"
29 #include "DynamicList.H"
30 #include "meshCutter.H"
32 #include "splitCell.H"
33 #include "mapPolyMesh.H"
34 #include "unitConversion.H"
35 #include "meshTools.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 defineTypeNameAndDebug(Foam::undoableMeshCutter, 0);
42 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 void Foam::undoableMeshCutter::printCellRefTree
49 const splitCell* splitCellPtr
54 os << indent << splitCellPtr->cellLabel() << endl;
56 word subIndent = indent + "--";
58 printCellRefTree(os, subIndent, splitCellPtr->master());
60 printCellRefTree(os, subIndent, splitCellPtr->slave());
66 void Foam::undoableMeshCutter::printRefTree(Ostream& os) const
68 forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
70 const splitCell* splitPtr = iter();
72 // Walk to top (master path only)
73 while (splitPtr->parent())
75 if (!splitPtr->isMaster())
83 splitPtr = splitPtr->parent();
87 // If we have reached top along master path start printing.
90 // Print from top down
91 printCellRefTree(os, word(""), splitPtr);
97 // Update all (cell) labels on splitCell structure.
98 // Do in two passes to prevent allocation if nothing changed.
99 void Foam::undoableMeshCutter::updateLabels
101 const labelList& map,
102 Map<splitCell*>& liveSplitCells
105 // Pass1 : check if changed
107 bool changed = false;
109 forAllConstIter(Map<splitCell*>, liveSplitCells, iter)
111 const splitCell* splitPtr = iter();
117 "undoableMeshCutter::updateLabels"
118 "(const labelList&, Map<splitCell*>&)"
119 ) << "Problem: null pointer on liveSplitCells list"
120 << abort(FatalError);
123 label cellI = splitPtr->cellLabel();
125 if (cellI != map[cellI])
138 // Build new liveSplitCells
139 // since new labels (= keys in Map) might clash with existing ones.
140 Map<splitCell*> newLiveSplitCells(2*liveSplitCells.size());
142 forAllIter(Map<splitCell*>, liveSplitCells, iter)
144 splitCell* splitPtr = iter();
146 label cellI = splitPtr->cellLabel();
148 label newCellI = map[cellI];
150 if (debug && (cellI != newCellI))
152 Pout<< "undoableMeshCutter::updateLabels :"
153 << " Updating live (split)cell from " << cellI
154 << " to " << newCellI << endl;
159 // Update splitCell. Can do inplace since only one cellI will
160 // refer to this structure.
161 splitPtr->cellLabel() = newCellI;
163 // Update liveSplitCells
164 newLiveSplitCells.insert(newCellI, splitPtr);
167 liveSplitCells = newLiveSplitCells;
172 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
174 // Construct from components
175 Foam::undoableMeshCutter::undoableMeshCutter
177 const polyMesh& mesh,
183 liveSplitCells_(mesh.nCells()/100 + 100),
187 Foam::cos(degToRad(30.0))
192 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
194 Foam::undoableMeshCutter::~undoableMeshCutter()
196 // Clean split cell tree.
198 forAllIter(Map<splitCell*>, liveSplitCells_, iter)
200 splitCell* splitPtr = iter();
204 splitCell* parentPtr = splitPtr->parent();
206 // Sever ties with parent. Also of other side of refinement since
207 // we are handling rest of tree so other side will not have to.
210 splitCell* otherSidePtr = splitPtr->getOther();
212 otherSidePtr->parent() = NULL;
214 splitPtr->parent() = NULL;
217 // Delete splitCell (updates pointer on parent to itself)
220 splitPtr = parentPtr;
226 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
228 void Foam::undoableMeshCutter::setRefinement
230 const cellCuts& cuts,
231 polyTopoChange& meshMod
234 // Insert commands to actually cut cells
235 meshCutter::setRefinement(cuts, meshMod);
239 // Use cells cut in this iteration to update splitCell tree.
240 forAllConstIter(Map<label>, addedCells(), iter)
242 label cellI = iter.key();
244 label addedCellI = iter();
247 // Newly created split cell. (cellI -> cellI + addedCellI)
249 // Check if cellI already part of split.
250 Map<splitCell*>::iterator findCell =
251 liveSplitCells_.find(cellI);
253 if (findCell == liveSplitCells_.end())
255 // CellI not yet split. It cannot be unlive split cell
256 // since that would be illegal to split in the first
259 // Create 0th level. Null parent to denote this.
260 splitCell* parentPtr = new splitCell(cellI, NULL);
262 splitCell* masterPtr = new splitCell(cellI, parentPtr);
264 splitCell* slavePtr = new splitCell(addedCellI, parentPtr);
266 // Store newly created cells on parent together with face
268 parentPtr->master() = masterPtr;
269 parentPtr->slave() = slavePtr;
271 // Insert master and slave into live splitcell list
273 if (liveSplitCells_.found(addedCellI))
275 FatalErrorIn("undoableMeshCutter::setRefinement")
276 << "problem addedCell:" << addedCellI
277 << abort(FatalError);
280 liveSplitCells_.insert(cellI, masterPtr);
281 liveSplitCells_.insert(addedCellI, slavePtr);
285 // Cell that was split has been split again.
286 splitCell* parentPtr = findCell();
288 // It is no longer live
289 liveSplitCells_.erase(findCell);
291 splitCell* masterPtr = new splitCell(cellI, parentPtr);
293 splitCell* slavePtr = new splitCell(addedCellI, parentPtr);
295 // Store newly created cells on parent together with face
297 parentPtr->master() = masterPtr;
298 parentPtr->slave() = slavePtr;
300 // Insert master and slave into live splitcell list
302 if (liveSplitCells_.found(addedCellI))
304 FatalErrorIn("undoableMeshCutter::setRefinement")
305 << "problem addedCell:" << addedCellI
306 << abort(FatalError);
309 liveSplitCells_.insert(cellI, masterPtr);
310 liveSplitCells_.insert(addedCellI, slavePtr);
316 Pout<< "** After refinement: liveSplitCells_:" << endl;
324 void Foam::undoableMeshCutter::updateMesh(const mapPolyMesh& morphMap)
326 // Update mesh cutter for new labels.
327 meshCutter::updateMesh(morphMap);
329 // No need to update cell walker for new labels since does not store any.
331 // Update faceRemover for new labels
332 faceRemover_.updateMesh(morphMap);
336 // Update all live split cells for mesh mapper.
337 updateLabels(morphMap.reverseCellMap(), liveSplitCells_);
342 Foam::labelList Foam::undoableMeshCutter::getSplitFaces() const
346 FatalErrorIn("undoableMeshCutter::getSplitFaces()")
347 << "Only call if constructed with unrefinement capability"
348 << abort(FatalError);
351 DynamicList<label> liveSplitFaces(liveSplitCells_.size());
353 forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
355 const splitCell* splitPtr = iter();
357 if (!splitPtr->parent())
359 FatalErrorIn("undoableMeshCutter::getSplitFaces()")
360 << "Live split cell without parent" << endl
361 << "splitCell:" << splitPtr->cellLabel()
362 << abort(FatalError);
365 // Check if not top of refinement and whether it is the master side
366 if (splitPtr->isMaster())
368 splitCell* slavePtr = splitPtr->getOther();
372 liveSplitCells_.found(slavePtr->cellLabel())
373 && splitPtr->isUnrefined()
374 && slavePtr->isUnrefined()
377 // Both master and slave are live and are not refined.
380 label cellI = splitPtr->cellLabel();
382 label slaveCellI = slavePtr->cellLabel();
385 meshTools::getSharedFace
392 liveSplitFaces.append(commonFaceI);
397 return liveSplitFaces.shrink();
401 Foam::Map<Foam::label> Foam::undoableMeshCutter::getAddedCells() const
403 // (code copied from getSplitFaces)
407 FatalErrorIn("undoableMeshCutter::getAddedCells()")
408 << "Only call if constructed with unrefinement capability"
409 << abort(FatalError);
412 Map<label> addedCells(liveSplitCells_.size());
414 forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
416 const splitCell* splitPtr = iter();
418 if (!splitPtr->parent())
420 FatalErrorIn("undoableMeshCutter::getAddedCells()")
421 << "Live split cell without parent" << endl
422 << "splitCell:" << splitPtr->cellLabel()
423 << abort(FatalError);
426 // Check if not top of refinement and whether it is the master side
427 if (splitPtr->isMaster())
429 splitCell* slavePtr = splitPtr->getOther();
433 liveSplitCells_.found(slavePtr->cellLabel())
434 && splitPtr->isUnrefined()
435 && slavePtr->isUnrefined()
438 // Both master and slave are live and are not refined.
439 addedCells.insert(splitPtr->cellLabel(), slavePtr->cellLabel());
447 Foam::labelList Foam::undoableMeshCutter::removeSplitFaces
449 const labelList& splitFaces,
450 polyTopoChange& meshMod
455 FatalErrorIn("undoableMeshCutter::removeSplitFaces(const labelList&)")
456 << "Only call if constructed with unrefinement capability"
457 << abort(FatalError);
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;
466 faceRemover().compatibleRemoves
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.
474 if (facesToRemove.size() != splitFaces.size())
476 Pout<< "cellRegion:" << cellRegion << endl;
477 Pout<< "cellRegionMaster:" << cellRegionMaster << endl;
481 "undoableMeshCutter::removeSplitFaces(const labelList&)"
482 ) << "Faces to remove:" << splitFaces << endl
483 << "to be removed:" << facesToRemove
484 << abort(FatalError);
488 // Every face removed will result in neighbour and owner being merged
490 forAll(facesToRemove, facesToRemoveI)
492 label faceI = facesToRemove[facesToRemoveI];
494 if (!mesh().isInternalFace(faceI))
498 "undoableMeshCutter::removeSplitFaces(const labelList&)"
499 ) << "Trying to remove face that is not internal"
500 << abort(FatalError);
503 label own = mesh().faceOwner()[faceI];
505 label nbr = mesh().faceNeighbour()[faceI];
507 Map<splitCell*>::iterator ownFind = liveSplitCells_.find(own);
509 Map<splitCell*>::iterator nbrFind = liveSplitCells_.find(nbr);
513 (ownFind == liveSplitCells_.end())
514 || (nbrFind == liveSplitCells_.end())
517 // Can happen because of removeFaces adding extra faces to
518 // original splitFaces
522 // Face is original splitFace.
524 splitCell* ownPtr = ownFind();
526 splitCell* nbrPtr = nbrFind();
528 splitCell* parentPtr = ownPtr->parent();
530 // Various checks on sanity.
534 Pout<< "Updating for removed splitFace " << faceI
535 << " own:" << own << " nbr:" << nbr
536 << " ownPtr:" << ownPtr->cellLabel()
537 << " nbrPtr:" << nbrPtr->cellLabel()
544 "undoableMeshCutter::removeSplitFaces(const labelList&)"
545 ) << "No parent for owner " << ownPtr->cellLabel()
546 << abort(FatalError);
549 if (!nbrPtr->parent())
553 "undoableMeshCutter::removeSplitFaces(const labelList&)"
554 ) << "No parent for neighbour " << nbrPtr->cellLabel()
555 << abort(FatalError);
558 if (parentPtr != nbrPtr->parent())
562 "undoableMeshCutter::removeSplitFaces(const labelList&)"
563 ) << "Owner and neighbour liveSplitCell entries do not have"
564 << " same parent. faceI:" << faceI << " owner:" << own
565 << " ownparent:" << parentPtr->cellLabel()
566 << " neighbour:" << nbr
567 << " nbrparent:" << nbrPtr->parent()->cellLabel()
568 << abort(FatalError);
573 !ownPtr->isUnrefined()
574 || !nbrPtr->isUnrefined()
575 || parentPtr->isUnrefined()
578 // Live owner and neighbour are refined themselves.
581 "undoableMeshCutter::removeSplitFaces(const labelList&)"
582 ) << "Owner and neighbour liveSplitCell entries are"
583 << " refined themselves or the parent is not refined"
585 << "owner unrefined:" << ownPtr->isUnrefined()
586 << " neighbour unrefined:" << nbrPtr->isUnrefined()
587 << " master unrefined:" << parentPtr->isUnrefined()
588 << abort(FatalError);
591 // Delete from liveSplitCell
592 liveSplitCells_.erase(ownFind);
594 //!important: Redo search since ownFind entry deleted.
595 liveSplitCells_.erase(liveSplitCells_.find(nbr));
597 // Delete entries themselves
603 // - has parent itself: is part of split cell. Update cellLabel
604 // with merged cell one.
605 // - has no parent: is start of tree. Completely remove.
607 if (parentPtr->parent())
609 // Update parent cell label to be new merged cell label
611 parentPtr->cellLabel() = own;
613 // And insert into live cells (is ok since old entry with
614 // own as key has been removed above)
615 liveSplitCells_.insert(own, parentPtr);
619 // No parent so is start of tree. No need to keep splitCell
626 // Insert all commands to combine cells. Never fails so don't have to
628 faceRemover().setRefinement
636 return facesToRemove;
640 // ************************************************************************* //