FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

undoableMeshCutter.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 \*---------------------------------------------------------------------------*/
00025 
00026 #include "undoableMeshCutter.H"
00027 #include <OpenFOAM/polyMesh.H>
00028 #include <dynamicMesh/polyTopoChange.H>
00029 #include <OpenFOAM/DynamicList.H>
00030 #include <dynamicMesh/meshCutter.H>
00031 #include <dynamicMesh/cellCuts.H>
00032 #include <dynamicMesh/splitCell.H>
00033 #include <OpenFOAM/mapPolyMesh.H>
00034 #include <OpenFOAM/mathematicalConstants.H>
00035 #include <meshTools/meshTools.H>
00036 
00037 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00038 
00039 namespace Foam
00040 {
00041 
00042 defineTypeNameAndDebug(undoableMeshCutter, 0);
00043 
00044 }
00045 
00046 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00047 
00048 // For debugging
00049 void Foam::undoableMeshCutter::printCellRefTree
00050 (
00051     Ostream& os,
00052     const word& indent,
00053     const splitCell* splitCellPtr
00054 ) const
00055 {
00056     if (splitCellPtr)
00057     {
00058         os << indent << splitCellPtr->cellLabel() << endl;
00059 
00060         word subIndent = indent + "--";
00061 
00062         printCellRefTree(os, subIndent, splitCellPtr->master());
00063 
00064         printCellRefTree(os, subIndent, splitCellPtr->slave());
00065     }
00066 }
00067 
00068 
00069 // For debugging
00070 void Foam::undoableMeshCutter::printRefTree(Ostream& os) const
00071 {
00072     for
00073     (
00074         Map<splitCell*>::const_iterator iter = liveSplitCells_.begin();
00075         iter != liveSplitCells_.end();
00076         ++iter
00077     )
00078     {
00079         const splitCell* splitPtr = iter();
00080 
00081         // Walk to top (master path only)
00082         while (splitPtr->parent())
00083         {
00084             if (!splitPtr->isMaster())
00085             {
00086                 splitPtr = NULL;
00087 
00088                 break;
00089             }
00090             else
00091             {
00092                 splitPtr = splitPtr->parent();
00093             }
00094         }
00095 
00096         // If we have reached top along master path start printing.
00097         if (splitPtr)
00098         {
00099             // Print from top down
00100             printCellRefTree(os, word(""), splitPtr);
00101         }
00102     }
00103 }
00104 
00105 
00106 // Update all (cell) labels on splitCell structure.
00107 // Do in two passes to prevent allocation if nothing changed.
00108 void Foam::undoableMeshCutter::updateLabels
00109 (
00110     const labelList& map,
00111     Map<splitCell*>& liveSplitCells
00112 )
00113 {
00114     // Pass1 : check if changed
00115 
00116     bool changed = false;
00117 
00118     forAllConstIter(Map<splitCell*>,liveSplitCells, iter)
00119     {
00120         const splitCell* splitPtr = iter();
00121 
00122         if (!splitPtr)
00123         {
00124             FatalErrorIn
00125             (
00126                 "undoableMeshCutter::updateLabels"
00127                 "(const labelList&, Map<splitCell*>&)"
00128             )   << "Problem: null pointer on liveSplitCells list"
00129                 << abort(FatalError);
00130         }
00131 
00132         label cellI = splitPtr->cellLabel();
00133 
00134         if (cellI != map[cellI])
00135         {
00136             changed = true;
00137 
00138             break;
00139         }
00140     }
00141 
00142 
00143     // Pass2: relabel
00144 
00145     if (changed)
00146     {
00147         // Build new liveSplitCells
00148         // since new labels (= keys in Map) might clash with existing ones.
00149         Map<splitCell*> newLiveSplitCells(2*liveSplitCells.size());
00150 
00151         forAllIter(Map<splitCell*>, liveSplitCells, iter)
00152         {
00153             splitCell* splitPtr = iter();
00154 
00155             label cellI = splitPtr->cellLabel();
00156 
00157             label newCellI = map[cellI];
00158 
00159             if (debug && (cellI != newCellI))
00160             {
00161                 Pout<< "undoableMeshCutter::updateLabels :"
00162                     << " Updating live (split)cell from " << cellI
00163                     << " to " << newCellI << endl;
00164             }
00165 
00166             if (newCellI >= 0)
00167             {
00168                 // Update splitCell. Can do inplace since only one cellI will
00169                 // refer to this structure.
00170                 splitPtr->cellLabel() = newCellI;
00171 
00172                 // Update liveSplitCells
00173                 newLiveSplitCells.insert(newCellI, splitPtr);
00174             }
00175         }
00176         liveSplitCells = newLiveSplitCells;
00177     }
00178 }
00179 
00180 
00181 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00182 
00183 // Construct from components
00184 Foam::undoableMeshCutter::undoableMeshCutter
00185 (
00186     const polyMesh& mesh,
00187     const bool undoable
00188 )
00189 :
00190     meshCutter(mesh),
00191     undoable_(undoable),
00192     liveSplitCells_(mesh.nCells()/100 + 100),
00193     faceRemover_
00194     (
00195         mesh,   
00196         Foam::cos(30./180. * mathematicalConstant::pi)
00197     )
00198 {}
00199 
00200 
00201 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
00202 
00203 Foam::undoableMeshCutter::~undoableMeshCutter()
00204 {
00205     // Clean split cell tree.
00206 
00207     forAllIter(Map<splitCell*>, liveSplitCells_, iter)
00208     {
00209         splitCell* splitPtr = iter();
00210 
00211         while (splitPtr)
00212         {
00213             splitCell* parentPtr = splitPtr->parent();
00214 
00215             // Sever ties with parent. Also of other side of refinement since
00216             // we are handling rest of tree so other side will not have to.
00217             if (parentPtr)
00218             {
00219                 splitCell* otherSidePtr = splitPtr->getOther();
00220 
00221                 otherSidePtr->parent() = NULL;
00222 
00223                 splitPtr->parent() = NULL;
00224             }
00225 
00226             // Delete splitCell (updates pointer on parent to itself)
00227             delete splitPtr;
00228 
00229             splitPtr = parentPtr;
00230         }
00231     }
00232 }
00233 
00234 
00235 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00236 
00237 void Foam::undoableMeshCutter::setRefinement
00238 (
00239     const cellCuts& cuts,
00240     polyTopoChange& meshMod
00241 )
00242 {
00243     // Insert commands to actually cut cells
00244     meshCutter::setRefinement(cuts, meshMod);
00245 
00246     if (undoable_)
00247     {
00248         // Use cells cut in this iteration to update splitCell tree.
00249         forAllConstIter(Map<label>, addedCells(), iter)
00250         {
00251             label cellI = iter.key();
00252 
00253             label addedCellI = iter();
00254 
00255 
00256             // Newly created split cell. (cellI ->  cellI + addedCellI)
00257 
00258             // Check if cellI already part of split.
00259             Map<splitCell*>::iterator findCell =
00260                 liveSplitCells_.find(cellI);
00261 
00262             if (findCell == liveSplitCells_.end())
00263             {
00264                 // CellI not yet split. It cannot be unlive split cell
00265                 // since that would be illegal to split in the first
00266                 // place.
00267 
00268                 // Create 0th level. Null parent to denote this.
00269                 splitCell* parentPtr = new splitCell(cellI, NULL);
00270 
00271                 splitCell* masterPtr = new splitCell(cellI, parentPtr);
00272 
00273                 splitCell* slavePtr = new splitCell(addedCellI, parentPtr);
00274 
00275                 // Store newly created cells on parent together with face
00276                 // that splits them
00277                 parentPtr->master() = masterPtr;
00278                 parentPtr->slave() = slavePtr;
00279 
00280                 // Insert master and slave into live splitcell list
00281 
00282                 if (liveSplitCells_.found(addedCellI))
00283                 {
00284                     FatalErrorIn("undoableMeshCutter::setRefinement")
00285                         << "problem addedCell:" << addedCellI
00286                         << abort(FatalError);
00287                 }
00288 
00289                 liveSplitCells_.insert(cellI, masterPtr);
00290                 liveSplitCells_.insert(addedCellI, slavePtr);
00291             }
00292             else
00293             {
00294                 // Cell that was split has been split again.
00295                 splitCell* parentPtr = findCell();
00296 
00297                 // It is no longer live
00298                 liveSplitCells_.erase(findCell);
00299 
00300                 splitCell* masterPtr = new splitCell(cellI, parentPtr);
00301 
00302                 splitCell* slavePtr = new splitCell(addedCellI, parentPtr);
00303 
00304                 // Store newly created cells on parent together with face
00305                 // that splits them
00306                 parentPtr->master() = masterPtr;
00307                 parentPtr->slave() = slavePtr;
00308 
00309                 // Insert master and slave into live splitcell list
00310 
00311                 if (liveSplitCells_.found(addedCellI))
00312                 {
00313                     FatalErrorIn("undoableMeshCutter::setRefinement")
00314                         << "problem addedCell:" << addedCellI
00315                         << abort(FatalError);
00316                 }
00317 
00318                 liveSplitCells_.insert(cellI, masterPtr);
00319                 liveSplitCells_.insert(addedCellI, slavePtr);
00320             }
00321         }
00322 
00323         if (debug & 2)
00324         {
00325             Pout<< "** After refinement: liveSplitCells_:" << endl;
00326 
00327             printRefTree(Pout);
00328         }
00329     }
00330 }
00331 
00332 
00333 void Foam::undoableMeshCutter::updateMesh(const mapPolyMesh& morphMap)
00334 {
00335     // Update mesh cutter for new labels.
00336     meshCutter::updateMesh(morphMap);
00337 
00338     // No need to update cell walker for new labels since does not store any.
00339 
00340     // Update faceRemover for new labels
00341     faceRemover_.updateMesh(morphMap);
00342 
00343     if (undoable_)
00344     {
00345         // Update all live split cells for mesh mapper.
00346         updateLabels(morphMap.reverseCellMap(), liveSplitCells_);
00347     }
00348 }
00349 
00350 
00351 Foam::labelList Foam::undoableMeshCutter::getSplitFaces() const
00352 {
00353     if (!undoable_)
00354     {
00355         FatalErrorIn("undoableMeshCutter::getSplitFaces()")
00356             << "Only call if constructed with unrefinement capability"
00357             << abort(FatalError);
00358     }
00359 
00360     DynamicList<label> liveSplitFaces(liveSplitCells_.size());
00361 
00362     forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
00363     {
00364         const splitCell* splitPtr = iter();
00365 
00366         if (!splitPtr->parent())
00367         {
00368             FatalErrorIn("undoableMeshCutter::getSplitFaces()")
00369                 << "Live split cell without parent" << endl
00370                 << "splitCell:" << splitPtr->cellLabel()
00371                 << abort(FatalError);
00372         }
00373 
00374         // Check if not top of refinement and whether it is the master side
00375         if (splitPtr->isMaster())
00376         {
00377             splitCell* slavePtr = splitPtr->getOther();
00378 
00379             if
00380             (
00381                 liveSplitCells_.found(slavePtr->cellLabel())
00382              && splitPtr->isUnrefined()
00383              && slavePtr->isUnrefined()
00384             )
00385             {
00386                 // Both master and slave are live and are not refined.
00387                 // Find common face.
00388 
00389                 label cellI = splitPtr->cellLabel();
00390 
00391                 label slaveCellI = slavePtr->cellLabel();
00392 
00393                 label commonFaceI =
00394                     meshTools::getSharedFace
00395                     (
00396                         mesh(),
00397                         cellI,
00398                         slaveCellI
00399                     );
00400 
00401                 liveSplitFaces.append(commonFaceI);
00402             }
00403         }
00404     }
00405 
00406     return liveSplitFaces.shrink();
00407 }
00408 
00409 
00410 Foam::Map<Foam::label> Foam::undoableMeshCutter::getAddedCells() const
00411 {
00412     // (code copied from getSplitFaces)
00413 
00414     if (!undoable_)
00415     {
00416         FatalErrorIn("undoableMeshCutter::getAddedCells()")
00417             << "Only call if constructed with unrefinement capability"
00418             << abort(FatalError);
00419     }
00420 
00421     Map<label> addedCells(liveSplitCells_.size());
00422 
00423     forAllConstIter(Map<splitCell*>, liveSplitCells_, iter)
00424     {
00425         const splitCell* splitPtr = iter();
00426 
00427         if (!splitPtr->parent())
00428         {
00429             FatalErrorIn("undoableMeshCutter::getAddedCells()")
00430                 << "Live split cell without parent" << endl
00431                 << "splitCell:" << splitPtr->cellLabel()
00432                 << abort(FatalError);
00433         }
00434 
00435         // Check if not top of refinement and whether it is the master side
00436         if (splitPtr->isMaster())
00437         {
00438             splitCell* slavePtr = splitPtr->getOther();
00439 
00440             if
00441             (
00442                 liveSplitCells_.found(slavePtr->cellLabel())
00443              && splitPtr->isUnrefined()
00444              && slavePtr->isUnrefined()
00445             )
00446             {
00447                 // Both master and slave are live and are not refined.
00448                 addedCells.insert(splitPtr->cellLabel(), slavePtr->cellLabel());
00449             }
00450         }
00451     }
00452     return addedCells;
00453 }
00454 
00455 
00456 Foam::labelList Foam::undoableMeshCutter::removeSplitFaces
00457 (
00458     const labelList& splitFaces,
00459     polyTopoChange& meshMod
00460 )
00461 {
00462     if (!undoable_)
00463     {
00464         FatalErrorIn("undoableMeshCutter::removeSplitFaces(const labelList&)")
00465             << "Only call if constructed with unrefinement capability"
00466             << abort(FatalError);
00467     }
00468 
00469     // Check with faceRemover what faces will get removed. Note that this can
00470     // be more (but never less) than splitFaces provided.
00471     labelList cellRegion;
00472     labelList cellRegionMaster;
00473     labelList facesToRemove;
00474 
00475     faceRemover().compatibleRemoves
00476     (
00477         splitFaces,         // pierced faces
00478         cellRegion,         // per cell -1 or region it is merged into
00479         cellRegionMaster,   // per region the master cell
00480         facesToRemove       // new faces to be removed.
00481     );
00482 
00483     if (facesToRemove.size() != splitFaces.size())
00484     {
00485         Pout<< "cellRegion:" << cellRegion << endl;
00486         Pout<< "cellRegionMaster:" << cellRegionMaster << endl;
00487 
00488         FatalErrorIn
00489         (
00490             "undoableMeshCutter::removeSplitFaces(const labelList&)"
00491         )   << "Faces to remove:" << splitFaces << endl
00492             << "to be removed:" << facesToRemove
00493             << abort(FatalError);
00494     }
00495 
00496 
00497     // Every face removed will result in neighbour and owner being merged
00498     // into owner.
00499     forAll(facesToRemove, facesToRemoveI)
00500     {
00501         label faceI = facesToRemove[facesToRemoveI];
00502 
00503         if (!mesh().isInternalFace(faceI))
00504         {
00505             FatalErrorIn
00506             (
00507                 "undoableMeshCutter::removeSplitFaces(const labelList&)"
00508             )   << "Trying to remove face that is not internal"
00509                 << abort(FatalError);
00510         }
00511 
00512         label own = mesh().faceOwner()[faceI];
00513 
00514         label nbr = mesh().faceNeighbour()[faceI];
00515 
00516         Map<splitCell*>::iterator ownFind = liveSplitCells_.find(own);
00517 
00518         Map<splitCell*>::iterator nbrFind = liveSplitCells_.find(nbr);
00519 
00520         if
00521         (
00522             (ownFind == liveSplitCells_.end())
00523          || (nbrFind == liveSplitCells_.end())
00524         )
00525         {
00526             // Can happen because of removeFaces adding extra faces to
00527             // original splitFaces
00528         }
00529         else
00530         {
00531             // Face is original splitFace.
00532 
00533             splitCell* ownPtr = ownFind();
00534 
00535             splitCell* nbrPtr = nbrFind();
00536 
00537             splitCell* parentPtr = ownPtr->parent();
00538 
00539             // Various checks on sanity.
00540 
00541             if (debug)
00542             {
00543                 Pout<< "Updating for removed splitFace " << faceI
00544                     << " own:" << own <<  " nbr:" << nbr
00545                     << " ownPtr:" << ownPtr->cellLabel()
00546                     << " nbrPtr:" << nbrPtr->cellLabel()
00547                     << endl;
00548             }
00549             if (!parentPtr)
00550             {
00551                 FatalErrorIn
00552                 (
00553                     "undoableMeshCutter::removeSplitFaces(const labelList&)"
00554                 )   << "No parent for owner " << ownPtr->cellLabel()
00555                     << abort(FatalError);
00556             }
00557 
00558             if (!nbrPtr->parent())
00559             {
00560                 FatalErrorIn
00561                 (
00562                     "undoableMeshCutter::removeSplitFaces(const labelList&)"
00563                 )   << "No parent for neighbour " << nbrPtr->cellLabel()
00564                     << abort(FatalError);
00565             }
00566 
00567             if (parentPtr != nbrPtr->parent())
00568             {
00569                 FatalErrorIn
00570                 (
00571                     "undoableMeshCutter::removeSplitFaces(const labelList&)"
00572                 )   << "Owner and neighbour liveSplitCell entries do not have"
00573                     << " same parent. faceI:" << faceI << "  owner:" << own
00574                     << "  ownparent:" << parentPtr->cellLabel()
00575                     << " neighbour:" << nbr
00576                     << "  nbrparent:" << nbrPtr->parent()->cellLabel()
00577                     << abort(FatalError);
00578             }
00579 
00580             if
00581             (
00582                 !ownPtr->isUnrefined()
00583              || !nbrPtr->isUnrefined()
00584              || parentPtr->isUnrefined()
00585             )
00586             {
00587                 // Live owner and neighbour are refined themselves.
00588                 FatalErrorIn
00589                 (
00590                     "undoableMeshCutter::removeSplitFaces(const labelList&)"
00591                 )   << "Owner and neighbour liveSplitCell entries are"
00592                     << " refined themselves or the parent is not refined"
00593                     << endl
00594                     << "owner unrefined:" << ownPtr->isUnrefined()
00595                     << "  neighbour unrefined:" << nbrPtr->isUnrefined()
00596                     << "  master unrefined:" << parentPtr->isUnrefined()
00597                     << abort(FatalError);
00598             }
00599 
00600             // Delete from liveSplitCell
00601             liveSplitCells_.erase(ownFind);
00602 
00604             liveSplitCells_.erase(liveSplitCells_.find(nbr));
00605 
00606             // Delete entries themselves
00607             delete ownPtr;
00608             delete nbrPtr;
00609 
00610             //
00611             // Update parent:
00612             //   - has parent itself: is part of split cell. Update cellLabel
00613             //     with merged cell one.
00614             //   - has no parent: is start of tree. Completely remove.
00615 
00616             if (parentPtr->parent())
00617             {
00618                 // Update parent cell label to be new merged cell label
00619                 // (will be owner)
00620                 parentPtr->cellLabel() = own;
00621 
00622                 // And insert into live cells (is ok since old entry with
00623                 // own as key has been removed above)
00624                 liveSplitCells_.insert(own, parentPtr);
00625             }
00626             else
00627             {
00628                 // No parent so is start of tree. No need to keep splitCell
00629                 // tree.
00630                 delete parentPtr;
00631             }
00632         }
00633     }
00634 
00635     // Insert all commands to combine cells. Never fails so don't have to
00636     // test for success.
00637     faceRemover().setRefinement
00638     (
00639         facesToRemove,
00640         cellRegion,
00641         cellRegionMaster,
00642         meshMod
00643     );
00644 
00645     return facesToRemove;
00646 }
00647 
00648 
00649 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines