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

removeFaces.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 "removeFaces.H"
00027 #include <OpenFOAM/polyMesh.H>
00028 #include "polyTopoChange.H"
00029 #include <meshTools/meshTools.H>
00030 #include <dynamicMesh/polyModifyFace.H>
00031 #include <dynamicMesh/polyRemoveFace.H>
00032 #include <dynamicMesh/polyRemoveCell.H>
00033 #include <dynamicMesh/polyRemovePoint.H>
00034 #include <OpenFOAM/syncTools.H>
00035 #include <OpenFOAM/OFstream.H>
00036 #include <OpenFOAM/indirectPrimitivePatch.H>
00037 #include <OpenFOAM/Time.H>
00038 #include <meshTools/faceSet.H>
00039 
00040 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00041 
00042 namespace Foam
00043 {
00044 
00045 defineTypeNameAndDebug(removeFaces, 0);
00046 
00047 }
00048 
00049 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00050 
00051 // Changes region of connected set of cells. Can be recursive since hopefully
00052 // only small area of faces removed in one go.
00053 void Foam::removeFaces::changeCellRegion
00054 (
00055     const label cellI,
00056     const label oldRegion,
00057     const label newRegion,
00058     labelList& cellRegion
00059 ) const
00060 {
00061     if (cellRegion[cellI] == oldRegion)
00062     {
00063         cellRegion[cellI] = newRegion;
00064 
00065         // Step to neighbouring cells
00066 
00067         const labelList& cCells = mesh_.cellCells()[cellI];
00068 
00069         forAll(cCells, i)
00070         {
00071             changeCellRegion(cCells[i], oldRegion, newRegion, cellRegion);
00072         }
00073     }
00074 }
00075 
00076 
00077 // Changes region of connected set of faces. Returns number of changed faces.
00078 Foam::label Foam::removeFaces::changeFaceRegion
00079 (
00080     const labelList& cellRegion,
00081     const boolList& removedFace,
00082     const labelList& nFacesPerEdge,
00083     const label faceI,
00084     const label newRegion,
00085     const labelList& fEdges,
00086     labelList& faceRegion
00087 ) const
00088 {
00089     label nChanged = 0;
00090 
00091     if (faceRegion[faceI] == -1 && !removedFace[faceI])
00092     {
00093         faceRegion[faceI] = newRegion;
00094 
00095         nChanged = 1;
00096 
00097         // Storage for on-the-fly addressing
00098         DynamicList<label> fe;
00099         DynamicList<label> ef;
00100 
00101         // Step to neighbouring faces across edges that will get removed
00102         forAll(fEdges, i)
00103         {
00104             label edgeI = fEdges[i];
00105 
00106             if (nFacesPerEdge[edgeI] >= 0 && nFacesPerEdge[edgeI] <= 2)
00107             {
00108                 const labelList& eFaces = mesh_.edgeFaces(edgeI, ef);
00109 
00110                 forAll(eFaces, j)
00111                 {
00112                     label nbrFaceI = eFaces[j];
00113 
00114                     const labelList& fEdges1 = mesh_.faceEdges(nbrFaceI, fe);
00115 
00116                     nChanged += changeFaceRegion
00117                     (
00118                         cellRegion,
00119                         removedFace,
00120                         nFacesPerEdge,
00121                         nbrFaceI,
00122                         newRegion,
00123                         fEdges1,
00124                         faceRegion
00125                     );
00126                 }
00127             }
00128         }
00129     }
00130     return nChanged;
00131 }
00132 
00133 
00134 // Mark all faces affected in any way by
00135 // - removal of cells
00136 // - removal of faces
00137 // - removal of edges
00138 // - removal of points
00139 Foam::boolList Foam::removeFaces::getFacesAffected
00140 (
00141     const labelList& cellRegion,
00142     const labelList& cellRegionMaster,
00143     const labelList& facesToRemove,
00144     const labelHashSet& edgesToRemove,
00145     const labelHashSet& pointsToRemove
00146 ) const
00147 {
00148     boolList affectedFace(mesh_.nFaces(), false);
00149 
00150     // Mark faces affected by removal of cells
00151     forAll(cellRegion, cellI)
00152     {
00153         label region = cellRegion[cellI];
00154 
00155         if (region != -1 && (cellI != cellRegionMaster[region]))
00156         {
00157             const labelList& cFaces = mesh_.cells()[cellI];
00158 
00159             forAll(cFaces, cFaceI)
00160             {
00161                 affectedFace[cFaces[cFaceI]] = true;
00162             }
00163         }
00164     }
00165 
00166     // Mark faces affected by removal of face.
00167     forAll(facesToRemove, i)
00168     {
00169          affectedFace[facesToRemove[i]] = true;
00170     }
00171 
00172     //  Mark faces affected by removal of edges
00173     forAllConstIter(labelHashSet, edgesToRemove, iter)
00174     {
00175         const labelList& eFaces = mesh_.edgeFaces(iter.key());
00176 
00177         forAll(eFaces, eFaceI)
00178         {
00179             affectedFace[eFaces[eFaceI]] = true;
00180         }
00181     }
00182 
00183     // Mark faces affected by removal of points
00184     forAllConstIter(labelHashSet, pointsToRemove, iter)
00185     {
00186         label pointI = iter.key();
00187 
00188         const labelList& pFaces = mesh_.pointFaces()[pointI];
00189 
00190         forAll(pFaces, pFaceI)
00191         {
00192             affectedFace[pFaces[pFaceI]] = true;
00193         }
00194     }
00195     return affectedFace;
00196 }
00197 
00198 
00199 void Foam::removeFaces::writeOBJ
00200 (
00201     const indirectPrimitivePatch& fp,
00202     const fileName& fName
00203 )
00204 {
00205     OFstream str(fName);
00206     Pout<< "removeFaces::writeOBJ : Writing faces to file "
00207         << str.name() << endl;
00208 
00209     const pointField& localPoints = fp.localPoints();
00210 
00211     forAll(localPoints, i)
00212     {
00213         meshTools::writeOBJ(str, localPoints[i]);
00214     }
00215 
00216     const faceList& localFaces = fp.localFaces();
00217 
00218     forAll(localFaces, i)
00219     {
00220         const face& f = localFaces[i];
00221 
00222         str<< 'f';
00223 
00224         forAll(f, fp)
00225         {
00226             str<< ' ' << f[fp]+1;
00227         }
00228         str<< nl;
00229     }
00230 }
00231 
00232 
00233 // Inserts commands to merge faceLabels into one face.
00234 void Foam::removeFaces::mergeFaces
00235 (
00236     const labelList& cellRegion,
00237     const labelList& cellRegionMaster,
00238     const labelHashSet& pointsToRemove,
00239     const labelList& faceLabels,
00240     polyTopoChange& meshMod
00241 ) const
00242 {
00243     // Construct addressing engine from faceLabels (in order of faceLabels as
00244     // well)
00245     indirectPrimitivePatch fp
00246     (
00247         IndirectList<face>
00248         (
00249             mesh_.faces(),
00250             faceLabels
00251         ),
00252         mesh_.points()
00253     );
00254 
00255     // Get outside vertices (in local vertex numbering)
00256 
00257     if (fp.edgeLoops().size() != 1)
00258     {
00259         writeOBJ(fp, mesh_.time().path()/"facesToBeMerged.obj");
00260         FatalErrorIn("removeFaces::mergeFaces")
00261             << "Cannot merge faces " << faceLabels
00262             << " into single face since outside vertices " << fp.edgeLoops()
00263             << " do not form single loop but form " << fp.edgeLoops().size()
00264             << " loops instead." << abort(FatalError);
00265     }
00266 
00267     const labelList& edgeLoop = fp.edgeLoops()[0];
00268 
00269     // Get outside vertices in order of one of the faces in faceLabels.
00270     // (this becomes the master face)
00271     // Find the first face that uses edgeLoop[0] and edgeLoop[1] as consecutive
00272     // vertices.
00273 
00274     label masterIndex = -1;
00275     bool reverseLoop = false;
00276 
00277     const labelList& pFaces = fp.pointFaces()[edgeLoop[0]];
00278 
00279     // Find face among pFaces which uses edgeLoop[1]
00280     forAll(pFaces, i)
00281     {
00282         label faceI = pFaces[i];
00283 
00284         const face& f = fp.localFaces()[faceI];
00285 
00286         label index1 = findIndex(f, edgeLoop[1]);
00287 
00288         if (index1 != -1)
00289         {
00290             // Check whether consecutive to edgeLoop[0]
00291             label index0 = findIndex(f, edgeLoop[0]);
00292 
00293             if (index0 != -1)
00294             {
00295                 if (index1 == f.fcIndex(index0))
00296                 {
00297                     masterIndex = faceI;
00298                     reverseLoop = false;
00299                     break;
00300                 }
00301                 else if (index1 == f.rcIndex(index0))
00302                 {
00303                     masterIndex = faceI;
00304                     reverseLoop = true;
00305                     break;
00306                 }
00307             }
00308         }
00309     }
00310 
00311     if (masterIndex == -1)
00312     {
00313         writeOBJ(fp, mesh_.time().path()/"facesToBeMerged.obj");
00314         FatalErrorIn("removeFaces::mergeFaces")
00315             << "Problem" << abort(FatalError);
00316     }
00317 
00318 
00319     // Modify the master face.
00320     // ~~~~~~~~~~~~~~~~~~~~~~~
00321 
00322     // Modify first face.
00323     label faceI = faceLabels[masterIndex];
00324 
00325     label own = mesh_.faceOwner()[faceI];
00326 
00327     if (cellRegion[own] != -1)
00328     {
00329         own = cellRegionMaster[cellRegion[own]];
00330     }
00331 
00332     label patchID, zoneID, zoneFlip;
00333 
00334     getFaceInfo(faceI, patchID, zoneID, zoneFlip);
00335 
00336     label nei = -1;
00337 
00338     if (mesh_.isInternalFace(faceI))
00339     {
00340         nei = mesh_.faceNeighbour()[faceI];
00341 
00342         if (cellRegion[nei] != -1)
00343         {
00344             nei = cellRegionMaster[cellRegion[nei]];
00345         }
00346     }
00347 
00348 
00349     DynamicList<label> faceVerts(edgeLoop.size());
00350 
00351     forAll(edgeLoop, i)
00352     {
00353         label pointI = fp.meshPoints()[edgeLoop[i]];
00354 
00355         if (pointsToRemove.found(pointI))
00356         {
00357             //Pout<< "**Removing point " << pointI << " from "
00358             //    << edgeLoop << endl;
00359         }
00360         else
00361         {
00362             faceVerts.append(pointI);
00363         }
00364     }
00365 
00366     face mergedFace;
00367     mergedFace.transfer(faceVerts);
00368 
00369     if (reverseLoop)
00370     {
00371         reverse(mergedFace);
00372     }
00373 
00374     //{
00375     //    Pout<< "Modifying masterface " << faceI
00376     //        << " from faces:" << faceLabels
00377     //        << " old verts:" << UIndirectList<face>(mesh_.faces(), faceLabels)
00378     //        << " for new verts:"
00379     //        << mergedFace
00380     //        << " possibly new owner " << own
00381     //        << " or new nei " << nei
00382     //        << endl;
00383     //}
00384 
00385     modFace
00386     (
00387         mergedFace,         // modified face
00388         faceI,              // label of face being modified
00389         own,                // owner
00390         nei,                // neighbour
00391         false,              // face flip
00392         patchID,            // patch for face
00393         false,              // remove from zone
00394         zoneID,             // zone for face
00395         zoneFlip,           // face flip in zone
00396 
00397         meshMod
00398     );
00399 
00400 
00401     // Remove all but master face.
00402     forAll(faceLabels, patchFaceI)
00403     {
00404         if (patchFaceI != masterIndex)
00405         {
00406             //Pout<< "Removing face " << faceLabels[patchFaceI] << endl;
00407 
00408             meshMod.setAction(polyRemoveFace(faceLabels[patchFaceI], faceI));
00409         }
00410     }
00411 }
00412 
00413 
00414 // Get patch, zone info for faceI
00415 void Foam::removeFaces::getFaceInfo
00416 (
00417     const label faceI,
00418 
00419     label& patchID,
00420     label& zoneID,
00421     label& zoneFlip
00422 ) const
00423 {
00424     patchID = -1;
00425 
00426     if (!mesh_.isInternalFace(faceI))
00427     {
00428         patchID = mesh_.boundaryMesh().whichPatch(faceI);
00429     }
00430 
00431     zoneID = mesh_.faceZones().whichZone(faceI);
00432 
00433     zoneFlip = false;
00434 
00435     if (zoneID >= 0)
00436     {
00437         const faceZone& fZone = mesh_.faceZones()[zoneID];
00438 
00439         zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
00440     }
00441 }
00442 
00443 
00444 // Return face with all pointsToRemove removed.
00445 Foam::face Foam::removeFaces::filterFace
00446 (
00447     const labelHashSet& pointsToRemove,
00448     const label faceI
00449 ) const
00450 {
00451     const face& f = mesh_.faces()[faceI];
00452 
00453     labelList newFace(f.size(), -1);
00454 
00455     label newFp = 0;
00456 
00457     forAll(f, fp)
00458     {
00459         label vertI = f[fp];
00460 
00461         if (!pointsToRemove.found(vertI))
00462         {
00463             newFace[newFp++] = vertI;
00464         }
00465     }
00466 
00467     newFace.setSize(newFp);
00468 
00469     return face(newFace);
00470 }
00471 
00472 
00473 // Wrapper for meshMod.modifyFace. Reverses face if own>nei.
00474 void Foam::removeFaces::modFace
00475 (
00476     const face& f,
00477     const label masterFaceID,
00478     const label own,
00479     const label nei,
00480     const bool flipFaceFlux,
00481     const label newPatchID,
00482     const bool removeFromZone,
00483     const label zoneID,
00484     const bool zoneFlip,
00485 
00486     polyTopoChange& meshMod
00487 ) const
00488 {
00489     if ((nei == -1) || (own < nei))
00490     {
00491 //        if (debug)
00492 //        {
00493 //            Pout<< "ModifyFace (unreversed) :"
00494 //                << "  faceI:" << masterFaceID
00495 //                << "  f:" << f
00496 //                << "  own:" << own
00497 //                << "  nei:" << nei
00498 //                << "  flipFaceFlux:" << flipFaceFlux
00499 //                << "  newPatchID:" << newPatchID
00500 //                << "  removeFromZone:" << removeFromZone
00501 //                << "  zoneID:" << zoneID
00502 //                << "  zoneFlip:" << zoneFlip
00503 //                << endl;
00504 //        }
00505 
00506         meshMod.setAction
00507         (
00508             polyModifyFace
00509             (
00510                 f,              // modified face
00511                 masterFaceID,   // label of face being modified
00512                 own,            // owner
00513                 nei,            // neighbour
00514                 flipFaceFlux,   // face flip
00515                 newPatchID,     // patch for face
00516                 removeFromZone, // remove from zone
00517                 zoneID,         // zone for face
00518                 zoneFlip        // face flip in zone
00519             )
00520         );
00521     }
00522     else
00523     {
00524 //        if (debug)
00525 //        {
00526 //            Pout<< "ModifyFace (!reversed) :"
00527 //                << "  faceI:" << masterFaceID
00528 //                << "  f:" << f.reverseFace()
00529 //                << "  own:" << nei
00530 //                << "  nei:" << own
00531 //                << "  flipFaceFlux:" << flipFaceFlux
00532 //                << "  newPatchID:" << newPatchID
00533 //                << "  removeFromZone:" << removeFromZone
00534 //                << "  zoneID:" << zoneID
00535 //                << "  zoneFlip:" << zoneFlip
00536 //                << endl;
00537 //        }
00538 
00539         meshMod.setAction
00540         (
00541             polyModifyFace
00542             (
00543                 f.reverseFace(),// modified face
00544                 masterFaceID,   // label of face being modified
00545                 nei,            // owner
00546                 own,            // neighbour
00547                 flipFaceFlux,   // face flip
00548                 newPatchID,     // patch for face
00549                 removeFromZone, // remove from zone
00550                 zoneID,         // zone for face
00551                 zoneFlip        // face flip in zone
00552             )
00553         );
00554     }
00555 }
00556 
00557 
00558 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00559 
00560 // Construct from mesh
00561 Foam::removeFaces::removeFaces
00562 (
00563     const polyMesh& mesh,
00564     const scalar minCos
00565 )
00566 :
00567     mesh_(mesh),
00568     minCos_(minCos)
00569 {}
00570 
00571 
00572 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00573 
00574 // Removing face connects cells. This function works out a consistent set of
00575 // cell regions.
00576 // - returns faces to remove. Can be extended with additional faces
00577 //   (if owner would become neighbour)
00578 // - sets cellRegion to -1 or to region number
00579 // - regionMaster contains for every region number a master cell.
00580 Foam::label Foam::removeFaces::compatibleRemoves
00581 (
00582     const labelList& facesToRemove,
00583     labelList& cellRegion,
00584     labelList& regionMaster,
00585     labelList& newFacesToRemove
00586 ) const
00587 {
00588     const labelList& faceOwner = mesh_.faceOwner();
00589     const labelList& faceNeighbour = mesh_.faceNeighbour();
00590 
00591     cellRegion.setSize(mesh_.nCells());
00592     cellRegion = -1;
00593 
00594     regionMaster.setSize(mesh_.nCells());
00595     regionMaster = -1;
00596 
00597     label nRegions = 0;
00598 
00599     forAll(facesToRemove, i)
00600     {
00601         label faceI = facesToRemove[i];
00602 
00603         if (!mesh_.isInternalFace(faceI))
00604         {
00605             FatalErrorIn
00606             (
00607                 "removeFaces::compatibleRemoves(const labelList&"
00608                 ", labelList&, labelList&, labelList&)"
00609             )   << "Not internal face:" << faceI << abort(FatalError);
00610         }
00611 
00612 
00613         label own = faceOwner[faceI];
00614         label nei = faceNeighbour[faceI];
00615 
00616         label region0 = cellRegion[own];
00617         label region1 = cellRegion[nei];
00618 
00619         if (region0 == -1)
00620         {
00621             if (region1 == -1)
00622             {
00623                 // Create new region
00624                 cellRegion[own] = nRegions;
00625                 cellRegion[nei] = nRegions;
00626 
00627                 // Make owner (lowest numbered!) the master of the region
00628                 regionMaster[nRegions] = own;
00629                 nRegions++;
00630             }
00631             else
00632             {
00633                 // Add owner to neighbour region
00634                 cellRegion[own] = region1;
00635                 // See if owner becomes the master of the region
00636                 regionMaster[region1] = min(own, regionMaster[region1]);
00637             }
00638         }
00639         else
00640         {
00641             if (region1 == -1)
00642             {
00643                 // Add neighbour to owner region
00644                 cellRegion[nei] = region0;
00645                 // nei is higher numbered than own so guaranteed not lower
00646                 // than master of region0.
00647             }
00648             else if (region0 != region1)
00649             {
00650                 // Both have regions. Keep lowest numbered region and master.
00651                 label freedRegion = -1;
00652                 label keptRegion = -1;
00653 
00654                 if (region0 < region1)
00655                 {
00656                     changeCellRegion
00657                     (
00658                         nei,
00659                         region1,    // old region
00660                         region0,    // new region
00661                         cellRegion
00662                     );
00663 
00664                     keptRegion = region0;
00665                     freedRegion = region1;
00666                 }
00667                 else if (region1 < region0)
00668                 {
00669                     changeCellRegion
00670                     (
00671                         own,
00672                         region0,    // old region
00673                         region1,    // new region
00674                         cellRegion
00675                     );
00676 
00677                     keptRegion = region1;
00678                     freedRegion = region0;
00679                 }
00680 
00681                 label master0 = regionMaster[region0];
00682                 label master1 = regionMaster[region1];
00683 
00684                 regionMaster[freedRegion] = -1;
00685                 regionMaster[keptRegion] = min(master0, master1);
00686             }
00687         }
00688     }
00689 
00690     regionMaster.setSize(nRegions);
00691 
00692 
00693     // Various checks
00694     // - master is lowest numbered in any region
00695     // - regions have more than 1 cell
00696     {
00697         labelList nCells(regionMaster.size(), 0);
00698 
00699         forAll(cellRegion, cellI)
00700         {
00701             label r = cellRegion[cellI];
00702 
00703             if (r != -1)
00704             {
00705                 nCells[r]++;
00706 
00707                 if (cellI < regionMaster[r])
00708                 {
00709                     FatalErrorIn
00710                     (
00711                         "removeFaces::compatibleRemoves(const labelList&"
00712                         ", labelList&, labelList&, labelList&)"
00713                     )   << "Not lowest numbered : cell:" << cellI
00714                         << " region:" << r
00715                         << " regionmaster:" << regionMaster[r]
00716                         << abort(FatalError);
00717                 }
00718             }
00719         }
00720 
00721         forAll(nCells, region)
00722         {
00723             if (nCells[region] == 1)
00724             {
00725                 FatalErrorIn
00726                 (
00727                     "removeFaces::compatibleRemoves(const labelList&"
00728                     ", labelList&, labelList&, labelList&)"
00729                 )   << "Region " << region
00730                     << " has only " << nCells[region] << " cells in it"
00731                     << abort(FatalError);
00732             }
00733         }
00734     }
00735 
00736 
00737     // Count number of used regions
00738     label nUsedRegions = 0;
00739 
00740     forAll(regionMaster, i)
00741     {
00742         if (regionMaster[i] != -1)
00743         {
00744             nUsedRegions++;
00745         }
00746     }
00747 
00748     // Recreate facesToRemove to be consistent with the cellRegions.
00749     DynamicList<label> allFacesToRemove(facesToRemove.size());
00750 
00751     for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
00752     {
00753         label own = faceOwner[faceI];
00754         label nei = faceNeighbour[faceI];
00755 
00756         if (cellRegion[own] != -1 && cellRegion[own] == cellRegion[nei])
00757         {
00758             // Both will become the same cell so add face to list of faces
00759             // to be removed.
00760             allFacesToRemove.append(faceI);
00761         }
00762     }
00763 
00764     newFacesToRemove.transfer(allFacesToRemove);
00765 
00766     return nUsedRegions;
00767 }
00768 
00769 
00770 void Foam::removeFaces::setRefinement
00771 (
00772     const labelList& faceLabels,
00773     const labelList& cellRegion,
00774     const labelList& cellRegionMaster,
00775     polyTopoChange& meshMod
00776 ) const
00777 {
00778     if (debug)
00779     {
00780         faceSet facesToRemove(mesh_, "facesToRemove", faceLabels);
00781         Pout<< "Writing faces to remove to faceSet " << facesToRemove.name()
00782             << endl;
00783         facesToRemove.write();
00784     }
00785 
00786     // Make map of all faces to be removed
00787     boolList removedFace(mesh_.nFaces(), false);
00788 
00789     forAll(faceLabels, i)
00790     {
00791         label faceI = faceLabels[i];
00792 
00793         if (!mesh_.isInternalFace(faceI))
00794         {
00795             FatalErrorIn
00796             (
00797                 "removeFaces::setRefinement(const labelList&"
00798                 ", const labelList&, const labelList&, polyTopoChange&)"
00799             )   << "Face to remove is not internal face:" << faceI
00800                 << abort(FatalError);
00801         }
00802 
00803         removedFace[faceI] = true;
00804     }
00805 
00806 
00807     // Edges to be removed
00808     // ~~~~~~~~~~~~~~~~~~~
00809 
00810 
00811     // Edges to remove
00812     labelHashSet edgesToRemove(faceLabels.size());
00813 
00814     // Per face the region it is in. -1 for removed faces, -2 for regions
00815     // consisting of single face only.
00816     labelList faceRegion(mesh_.nFaces(), -1);
00817 
00818     // Number of connected face regions
00819     label nRegions = 0;
00820 
00821     // Storage for on-the-fly addressing
00822     DynamicList<label> fe;
00823     DynamicList<label> ef;
00824 
00825 
00826     {
00827         const polyBoundaryMesh& patches = mesh_.boundaryMesh();
00828 
00829         // Usage of edges by non-removed faces.
00830         // See below about initialization.
00831         labelList nFacesPerEdge(mesh_.nEdges(), -1);
00832 
00833         // Count usage of edges by non-removed faces.
00834         forAll(faceLabels, i)
00835         {
00836             label faceI = faceLabels[i];
00837 
00838             const labelList& fEdges = mesh_.faceEdges(faceI, fe);
00839 
00840             forAll(fEdges, i)
00841             {
00842                 label edgeI = fEdges[i];
00843 
00844                 if (nFacesPerEdge[edgeI] == -1)
00845                 {
00846                     nFacesPerEdge[edgeI] = mesh_.edgeFaces(edgeI, ef).size()-1;
00847                 }
00848                 else
00849                 {
00850                     nFacesPerEdge[edgeI]--;
00851                 }
00852             }
00853         }
00854 
00855         // Count usage for edges not on faces-to-be-removed.
00856         // Note that this only needs to be done for possibly coupled edges
00857         // so we could choose to loop only over boundary faces and use faceEdges
00858         // of those.
00859 
00860         forAll(mesh_.edges(), edgeI)
00861         {
00862             if (nFacesPerEdge[edgeI] == -1)
00863             {
00864                 // Edge not yet handled in loop above so is not used by any
00865                 // face to be removed.
00866 
00867                 const labelList& eFaces = mesh_.edgeFaces(edgeI, ef);
00868 
00869                 if (eFaces.size() > 2)
00870                 {
00871                     nFacesPerEdge[edgeI] = eFaces.size();
00872                 }
00873                 else if (eFaces.size() == 2)
00874                 {
00875                     // nFacesPerEdge already -1 so do nothing.
00876                 }
00877                 else
00878                 {
00879                     const edge& e = mesh_.edges()[edgeI];
00880 
00881                     FatalErrorIn("removeFaces::setRefinement")
00882                         << "Problem : edge has too few face neighbours:"
00883                         << eFaces << endl
00884                         << "edge:" << edgeI
00885                         << " vertices:" << e
00886                         << " coords:" << mesh_.points()[e[0]]
00887                         << mesh_.points()[e[1]]
00888                         << abort(FatalError);
00889                 }
00890             }
00891         }
00892 
00893 
00894 
00895         if (debug)
00896         {
00897             OFstream str(mesh_.time().path()/"edgesWithTwoFaces.obj");
00898             Pout<< "Dumping edgesWithTwoFaces to " << str.name() << endl;
00899             label vertI = 0;
00900 
00901             forAll(nFacesPerEdge, edgeI)
00902             {
00903                 if (nFacesPerEdge[edgeI] == 2)
00904                 {
00905                     // Edge will get removed.
00906                     const edge& e = mesh_.edges()[edgeI];
00907 
00908                     meshTools::writeOBJ(str, mesh_.points()[e[0]]);
00909                     vertI++;
00910                     meshTools::writeOBJ(str, mesh_.points()[e[1]]);
00911                     vertI++;
00912                     str<< "l " << vertI-1 << ' ' << vertI << nl;
00913                 }
00914             }
00915         }
00916 
00917 
00918         // Now all unaffected edges will have labelMax, all affected edges the
00919         // number of unremoved faces.
00920 
00921         // Filter for edges inbetween two remaining boundary faces that
00922         // make too big an angle.
00923         forAll(nFacesPerEdge, edgeI)
00924         {
00925             if (nFacesPerEdge[edgeI] == 2)
00926             {
00927                 // See if they are two boundary faces
00928                 label f0 = -1;
00929                 label f1 = -1;
00930 
00931                 const labelList& eFaces = mesh_.edgeFaces(edgeI, ef);
00932 
00933                 forAll(eFaces, i)
00934                 {
00935                     label faceI = eFaces[i];
00936 
00937                     if (!removedFace[faceI] && !mesh_.isInternalFace(faceI))
00938                     {
00939                         if (f0 == -1)
00940                         {
00941                             f0 = faceI;
00942                         }
00943                         else
00944                         {
00945                             f1 = faceI;
00946                             break;
00947                         }
00948                     }
00949                 }
00950 
00951                 if (f0 != -1 && f1 != -1)
00952                 {
00953                     // Edge has two boundary faces remaining.
00954                     // See if should be merged.
00955 
00956                     label patch0 = patches.whichPatch(f0);
00957                     label patch1 = patches.whichPatch(f1);
00958 
00959                     if (patch0 != patch1)
00960                     {
00961                         // Different patches. Do not merge edge.
00962                         WarningIn("removeFaces::setRefinement")
00963                             << "not merging faces " << f0 << " and "
00964                             << f1 << " across patch boundary edge " << edgeI
00965                             << endl;
00966 
00967                         // Mark so it gets preserved
00968                         nFacesPerEdge[edgeI] = 3;
00969                     }
00970                     else if (minCos_ < 1 && minCos_ > -1)
00971                     {
00972                         const polyPatch& pp0 = patches[patch0];
00973                         const vectorField& n0 = pp0.faceNormals();
00974 
00975                         if
00976                         (
00977                             mag
00978                             (
00979                                 n0[f0 - pp0.start()]
00980                               & n0[f1 - pp0.start()]
00981                             )
00982                             < minCos_
00983                         )
00984                         {
00985                             WarningIn("removeFaces::setRefinement")
00986                                 << "not merging faces " << f0 << " and "
00987                                 << f1 << " across edge " << edgeI
00988                                 << endl;
00989 
00990                             // Angle between two remaining faces too large.
00991                             // Mark so it gets preserved
00992                             nFacesPerEdge[edgeI] = 3;
00993                         }
00994                     }
00995                 }
00996                 else if (f0 != -1 || f1 != -1)
00997                 {
00998                     const edge& e = mesh_.edges()[edgeI];
00999 
01000                     // Only found one boundary face. Problem.
01001                     FatalErrorIn("removeFaces::setRefinement")
01002                         << "Problem : edge would have one boundary face"
01003                         << " and one internal face using it." << endl
01004                         << "Your remove pattern is probably incorrect." << endl
01005                         << "edge:" << edgeI
01006                         << " nFaces:" << nFacesPerEdge[edgeI]
01007                         << " vertices:" << e
01008                         << " coords:" << mesh_.points()[e[0]]
01009                         << mesh_.points()[e[1]]
01010                         << " face0:" << f0
01011                         << " face1:" << f1
01012                         << abort(FatalError);
01013                 }
01014             }
01015         }
01016 
01017 
01018 
01019         // Check locally (before synchronizing) for strangeness
01020         forAll(nFacesPerEdge, edgeI)
01021         {
01022             if (nFacesPerEdge[edgeI] == 1)
01023             {
01024                 const edge& e = mesh_.edges()[edgeI];
01025 
01026                 FatalErrorIn("removeFaces::setRefinement")
01027                     << "Problem : edge would get 1 face using it only"
01028                     << " edge:" << edgeI
01029                     << " nFaces:" << nFacesPerEdge[edgeI]
01030                     << " vertices:" << e
01031                     << " coords:" << mesh_.points()[e[0]]
01032                     << ' ' << mesh_.points()[e[1]]
01033                     << abort(FatalError);
01034             }
01035             // Could check here for boundary edge with <=1 faces remaining.
01036         }
01037 
01038 
01039         // Synchronize edge usage. This is to make sure that both sides remove
01040         // (or not remove) an edge on the boundary at the same time.
01041         //
01042         // Coupled edges (edge0, edge1 are opposite each other)
01043         // a. edge not on face to be removed, edge has >= 3 faces
01044         // b.  ,,                             edge has 2 faces
01045         // c. edge has >= 3 remaining faces
01046         // d. edge has 2 remaining faces (assume angle>minCos already handled)
01047         //
01048         // - a + a: do not remove edge
01049         // - a + b: do not remove edge
01050         // - a + c: do not remove edge
01051         // - a + d: do not remove edge
01052         //
01053         // - b + b: do not remove edge
01054         // - b + c: do not remove edge
01055         // - b + d: remove edge
01056         //
01057         // - c + c: do not remove edge
01058         // - c + d: do not remove edge
01059         // - d + d: remove edge
01060         //
01061         //
01062         // So code situation a. with >= 3
01063         //                   b. with -1
01064         //                   c. with >=3
01065         //                   d. with 2
01066         // then do max and check result.
01067         //
01068         // a+a : max(3,3) = 3. do not remove
01069         // a+b : max(3,-1) = 3. do not remove
01070         // a+c : max(3,3) = 3. do not remove
01071         // a+d : max(3,2) = 3. do not remove
01072         //
01073         // b+b : max(-1,-1) = -1. do not remove
01074         // b+c : max(-1,3) = 3. do not remove
01075         // b+d : max(-1,2) = 2. remove
01076         //
01077         // c+c : max(3,3) = 3. do not remove
01078         // c+d : max(3,2) = 3. do not remove
01079         //
01080         // d+d : max(2,2) = 2. remove
01081 
01082         syncTools::syncEdgeList
01083         (
01084             mesh_,
01085             nFacesPerEdge,
01086             maxEqOp<label>(),
01087             labelMin,               // guaranteed to be overridden by maxEqOp
01088             false                   // no separation
01089         );
01090 
01091         // Convert to labelHashSet
01092         forAll(nFacesPerEdge, edgeI)
01093         {
01094             if (nFacesPerEdge[edgeI] == 0)
01095             {
01096                 // 0: edge not used anymore.
01097                 edgesToRemove.insert(edgeI);
01098             }
01099             else if (nFacesPerEdge[edgeI] == 1)
01100             {
01101                 // 1: illegal. Tested above.
01102             }
01103             else if (nFacesPerEdge[edgeI] == 2)
01104             {
01105                 // 2: merge faces.
01106                 edgesToRemove.insert(edgeI);
01107             }
01108         }
01109 
01110         if (debug)
01111         {
01112             OFstream str(mesh_.time().path()/"edgesToRemove.obj");
01113             Pout<< "Dumping edgesToRemove to " << str.name() << endl;
01114             label vertI = 0;
01115 
01116             forAllConstIter(labelHashSet, edgesToRemove, iter)
01117             {
01118                 // Edge will get removed.
01119                 const edge& e = mesh_.edges()[iter.key()];
01120 
01121                 meshTools::writeOBJ(str, mesh_.points()[e[0]]);
01122                 vertI++;
01123                 meshTools::writeOBJ(str, mesh_.points()[e[1]]);
01124                 vertI++;
01125                 str<< "l " << vertI-1 << ' ' << vertI << nl;
01126             }
01127         }
01128 
01129 
01130         // Walk to fill faceRegion with faces that will be connected across
01131         // edges that will be removed.
01132 
01133         label startFaceI = 0;
01134 
01135         while (true)
01136         {
01137             // Find unset region.
01138             for (; startFaceI < mesh_.nFaces(); startFaceI++)
01139             {
01140                 if (faceRegion[startFaceI] == -1 && !removedFace[startFaceI])
01141                 {
01142                     break;
01143                 }
01144             }
01145 
01146             if (startFaceI == mesh_.nFaces())
01147             {
01148                 break;
01149             }
01150 
01151             // Start walking face-edge-face, crossing edges that will get
01152             // removed. Every thus connected region will get single region
01153             // number.
01154             label nRegion = changeFaceRegion
01155             (
01156                 cellRegion,
01157                 removedFace,
01158                 nFacesPerEdge,
01159                 startFaceI,
01160                 nRegions,
01161                 mesh_.faceEdges(startFaceI, fe),
01162                 faceRegion
01163             );
01164 
01165             if (nRegion < 1)
01166             {
01167                 FatalErrorIn("setRefinement") << "Problem" << abort(FatalError);
01168             }
01169             else if (nRegion == 1)
01170             {
01171                 // Reset face to be single region.
01172                 faceRegion[startFaceI] = -2;
01173             }
01174             else
01175             {
01176                 nRegions++;
01177             }
01178         }
01179 
01180 
01181         // Check we're deciding the same on both sides. Since the regioning
01182         // is done based on nFacesPerEdge (which is synced) this should
01183         // indeed be the case.
01184 
01185         labelList nbrFaceRegion(faceRegion);
01186 
01187         syncTools::swapFaceList
01188         (
01189             mesh_,
01190             nbrFaceRegion,
01191             false                   // no separation
01192         );
01193 
01194         labelList toNbrRegion(nRegions, -1);
01195 
01196         for
01197         (
01198             label faceI = mesh_.nInternalFaces();
01199             faceI < mesh_.nFaces();
01200             faceI++
01201         )
01202         {
01203             // Get the neighbouring region.
01204             label nbrRegion = nbrFaceRegion[faceI];
01205             label myRegion = faceRegion[faceI];
01206 
01207             if (myRegion <= -1 || nbrRegion <= -1)
01208             {
01209                 if (nbrRegion != myRegion)
01210                 {
01211                     FatalErrorIn("removeFaces::setRefinement")
01212                         << "Inconsistent face region across coupled patches."
01213                         << endl
01214                         << "This side has for faceI:" << faceI
01215                         << " region:" << myRegion << endl
01216                         << "The other side has region:" << nbrRegion
01217                         << endl
01218                         << "(region -1 means face is to be deleted)"
01219                         << abort(FatalError);
01220                 }
01221             }
01222             else if (toNbrRegion[myRegion] == -1)
01223             {
01224                 // First visit of region. Store correspondence.
01225                 toNbrRegion[myRegion] = nbrRegion;
01226             }
01227             else
01228             {
01229                 // Second visit of this region.
01230                 if (toNbrRegion[myRegion] != nbrRegion)
01231                 {
01232                     FatalErrorIn("removeFaces::setRefinement")
01233                         << "Inconsistent face region across coupled patches."
01234                         << endl
01235                         << "This side has for faceI:" << faceI
01236                         << " region:" << myRegion
01237                         << " with coupled neighbouring regions:"
01238                         << toNbrRegion[myRegion] << " and "
01239                         << nbrRegion
01240                         << abort(FatalError);
01241                 }
01242             }
01243         }
01244     }
01245 
01246     //if (debug)
01247     //{
01248     //    labelListList regionToFaces(invertOneToMany(nRegions, faceRegion));
01249     //
01250     //    forAll(regionToFaces, regionI)
01251     //    {
01252     //        Pout<< "    " << regionI << " faces:" << regionToFaces[regionI]
01253     //            << endl;
01254     //    }
01255     //}
01256 
01257 
01258     // Points to be removed
01259     // ~~~~~~~~~~~~~~~~~~~~
01260 
01261     labelHashSet pointsToRemove(4*faceLabels.size());
01262 
01263 
01264     // Per point count the number of unremoved edges. Store the ones that
01265     // are only used by 2 unremoved edges.
01266     {
01267         // Usage of points by non-removed edges.
01268         labelList nEdgesPerPoint(mesh_.nPoints());
01269 
01270         const labelListList& pointEdges = mesh_.pointEdges();
01271 
01272         forAll(pointEdges, pointI)
01273         {
01274             nEdgesPerPoint[pointI] = pointEdges[pointI].size();
01275         }
01276 
01277         forAllConstIter(labelHashSet, edgesToRemove, iter)
01278         {
01279             // Edge will get removed.
01280             const edge& e = mesh_.edges()[iter.key()];
01281 
01282             forAll(e, i)
01283             {
01284                 nEdgesPerPoint[e[i]]--;
01285             }
01286         }
01287 
01288         // Check locally (before synchronizing) for strangeness
01289         forAll(nEdgesPerPoint, pointI)
01290         {
01291             if (nEdgesPerPoint[pointI] == 1)
01292             {
01293                 FatalErrorIn("removeFaces::setRefinement")
01294                     << "Problem : point would get 1 edge using it only."
01295                     << " pointI:" << pointI
01296                     << " coord:" << mesh_.points()[pointI]
01297                     << abort(FatalError);
01298             }
01299         }
01300 
01301         // Synchronize point usage. This is to make sure that both sides remove
01302         // (or not remove) a point on the boundary at the same time.
01303         syncTools::syncPointList
01304         (
01305             mesh_,
01306             nEdgesPerPoint,
01307             maxEqOp<label>(),
01308             labelMin,
01309             false                   // no separation
01310         );
01311 
01312         forAll(nEdgesPerPoint, pointI)
01313         {
01314             if (nEdgesPerPoint[pointI] == 0)
01315             {
01316                 pointsToRemove.insert(pointI);
01317             }
01318             else if (nEdgesPerPoint[pointI] == 1)
01319             {
01320                 // Already checked before
01321             }
01322             else if (nEdgesPerPoint[pointI] == 2)
01323             {
01324                 // Remove point and merge edges.
01325                 pointsToRemove.insert(pointI);
01326             }
01327         }
01328     }
01329 
01330 
01331     if (debug)
01332     {
01333         OFstream str(mesh_.time().path()/"pointsToRemove.obj");
01334         Pout<< "Dumping pointsToRemove to " << str.name() << endl;
01335 
01336         forAllConstIter(labelHashSet, pointsToRemove, iter)
01337         {
01338             meshTools::writeOBJ(str, mesh_.points()[iter.key()]);
01339         }
01340     }
01341 
01342 
01343     // All faces affected in any way
01344     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01345 
01346     // Get all faces affected in any way by removal of points/edges/faces/cells
01347     boolList affectedFace
01348     (
01349         getFacesAffected
01350         (
01351             cellRegion,
01352             cellRegionMaster,
01353             faceLabels,
01354             edgesToRemove,
01355             pointsToRemove
01356         )
01357     );
01358 
01359     //
01360     // Now we know
01361     // - faceLabels         : faces to remove (sync since no boundary faces)
01362     // - cellRegion/Master  : cells to remove (sync since cells)
01363     // - pointsToRemove     : points to remove (sync)
01364     // - faceRegion         : connected face region of faces to be merged (sync)
01365     // - affectedFace       : faces with points removed and/or owner/neighbour
01366     //                        changed (non sync)
01367 
01368 
01369     // Start modifying mesh and keep track of faces changed.
01370 
01371 
01372     // Do all removals
01373     // ~~~~~~~~~~~~~~~
01374 
01375     // Remove split faces.
01376     forAll(faceLabels, labelI)
01377     {
01378         label faceI = faceLabels[labelI];
01379 
01380         // Remove face if not yet uptodate (which is never; but want to be
01381         // consistent with rest of face removals/modifications)
01382         if (affectedFace[faceI])
01383         {
01384             affectedFace[faceI] = false;
01385 
01386             meshMod.setAction(polyRemoveFace(faceI, -1));
01387         }
01388     }
01389 
01390 
01391     // Remove points.
01392     forAllConstIter(labelHashSet, pointsToRemove, iter)
01393     {
01394         label pointI = iter.key();
01395 
01396         meshMod.setAction(polyRemovePoint(pointI, -1));
01397     }
01398 
01399 
01400     // Remove cells.
01401     forAll(cellRegion, cellI)
01402     {
01403         label region = cellRegion[cellI];
01404 
01405         if (region != -1 && (cellI != cellRegionMaster[region]))
01406         {
01407             meshMod.setAction(polyRemoveCell(cellI, cellRegionMaster[region]));
01408         }
01409     }
01410 
01411 
01412 
01413     // Merge faces across edges to be merged
01414     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01415 
01416     // Invert faceRegion so we get region to faces.
01417     {
01418         labelListList regionToFaces(invertOneToMany(nRegions, faceRegion));
01419 
01420         forAll(regionToFaces, regionI)
01421         {
01422             const labelList& rFaces = regionToFaces[regionI];
01423 
01424             if (rFaces.size() <= 1)
01425             {
01426                 FatalErrorIn("setRefinement")
01427                     << "Region:" << regionI
01428                     << " contains only faces " << rFaces
01429                     << abort(FatalError);
01430             }
01431 
01432             // rFaces[0] is master, rest gets removed.
01433             mergeFaces
01434             (
01435                 cellRegion,
01436                 cellRegionMaster,
01437                 pointsToRemove,
01438                 rFaces,
01439                 meshMod
01440             );
01441 
01442             forAll(rFaces, i)
01443             {
01444                 affectedFace[rFaces[i]] = false;
01445             }
01446         }
01447     }
01448 
01449 
01450     // Remaining affected faces
01451     // ~~~~~~~~~~~~~~~~~~~~~~~~
01452 
01453     // Check if any remaining faces have not been updated for new slave/master
01454     // or points removed.
01455     forAll(affectedFace, faceI)
01456     {
01457         if (affectedFace[faceI])
01458         {
01459             affectedFace[faceI] = false;
01460 
01461             face f(filterFace(pointsToRemove, faceI));
01462 
01463             label own = mesh_.faceOwner()[faceI];
01464 
01465             if (cellRegion[own] != -1)
01466             {
01467                 own = cellRegionMaster[cellRegion[own]];
01468             }
01469 
01470             label patchID, zoneID, zoneFlip;
01471 
01472             getFaceInfo(faceI, patchID, zoneID, zoneFlip);
01473 
01474             label nei = -1;
01475 
01476             if (mesh_.isInternalFace(faceI))
01477             {
01478                 nei = mesh_.faceNeighbour()[faceI];
01479 
01480                 if (cellRegion[nei] != -1)
01481                 {
01482                     nei = cellRegionMaster[cellRegion[nei]];
01483                 }
01484             }
01485 
01486 //            if (debug)
01487 //            {
01488 //                Pout<< "Modifying " << faceI
01489 //                    << " old verts:" << mesh_.faces()[faceI]
01490 //                    << " for new verts:" << f
01491 //                    << " or for new owner " << own << " or for new nei "
01492 //                    << nei
01493 //                    << endl;
01494 //            }
01495 
01496             modFace
01497             (
01498                 f,                  // modified face
01499                 faceI,              // label of face being modified
01500                 own,                // owner
01501                 nei,                // neighbour
01502                 false,              // face flip
01503                 patchID,            // patch for face
01504                 false,              // remove from zone
01505                 zoneID,             // zone for face
01506                 zoneFlip,           // face flip in zone
01507 
01508                 meshMod
01509             );
01510         }
01511     }
01512 }
01513 
01514 
01515 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines