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

edgeCollapser.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 "edgeCollapser.H"
00027 #include <OpenFOAM/polyMesh.H>
00028 #include "polyTopoChange.H"
00029 #include <OpenFOAM/ListOps.H>
00030 
00031 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00032 
00033 Foam::label Foam::edgeCollapser::findIndex
00034 (
00035     const labelList& elems,
00036     const label start,
00037     const label size,
00038     const label val
00039 )
00040 {
00041     for (label i = start; i < size; i++)
00042     {
00043         if (elems[i] == val)
00044         {
00045             return i;
00046         }
00047     }
00048     return -1;
00049 }
00050 
00051 
00052 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00053 
00054 // Changes region of connected set of points
00055 Foam::label Foam::edgeCollapser::changePointRegion
00056 (
00057     const label pointI,
00058     const label oldRegion,
00059     const label newRegion
00060 )
00061 {
00062     label nChanged = 0;
00063 
00064     if (pointRegion_[pointI] == oldRegion)
00065     {
00066         pointRegion_[pointI] = newRegion;
00067         nChanged++;
00068 
00069         // Step to neighbouring point across edges with same region number
00070 
00071         const labelList& pEdges = mesh_.pointEdges()[pointI];
00072 
00073         forAll(pEdges, i)
00074         {
00075             label otherPointI = mesh_.edges()[pEdges[i]].otherVertex(pointI);
00076 
00077             nChanged += changePointRegion(otherPointI, oldRegion, newRegion);
00078         }
00079     }
00080     return nChanged;
00081 }
00082 
00083 
00084 bool Foam::edgeCollapser::pointRemoved(const label pointI) const
00085 {
00086     label region = pointRegion_[pointI];
00087 
00088     if (region == -1 || pointRegionMaster_[region] == pointI)
00089     {
00090         return false;
00091     }
00092     else
00093     {
00094         return true;
00095     }
00096 }
00097 
00098 
00099 void Foam::edgeCollapser::filterFace(const label faceI, face& f) const
00100 {
00101     label newFp = 0;
00102 
00103     forAll(f, fp)
00104     {
00105         label pointI = f[fp];
00106 
00107         label region = pointRegion_[pointI];
00108 
00109         if (region == -1)
00110         {
00111             f[newFp++] = pointI;
00112         }
00113         else
00114         {
00115             label master = pointRegionMaster_[region];
00116 
00117             if (findIndex(f, 0, newFp, master) == -1)
00118             {
00119                 f[newFp++] = master;
00120             }
00121         }
00122     }
00123 
00124     // Check for pinched face. Tries to correct
00125     // - consecutive duplicate vertex. Removes duplicate vertex.
00126     // - duplicate vertex with one other vertex in between (spike).
00127     // Both of these should not really occur! and should be checked before
00128     // collapsing edges.
00129 
00130     const label size = newFp;
00131 
00132     newFp = 2;
00133 
00134     for (label fp = 2; fp < size; fp++)
00135     {
00136         label fp1 = fp-1;
00137         label fp2 = fp-2;
00138 
00139         label pointI = f[fp];
00140 
00141         // Search for previous occurrence.
00142         label index = findIndex(f, 0, fp, pointI);
00143 
00144         if (index == fp1)
00145         {
00146             WarningIn
00147             (
00148                 "Foam::edgeCollapser::filterFace(const label faceI, "
00149                 "face& f) const"
00150             )   << "Removing consecutive duplicate vertex in face "
00151                 << f << endl;
00152             // Don't store current pointI
00153         }
00154         else if (index == fp2)
00155         {
00156             WarningIn
00157             (
00158                 "Foam::edgeCollapser::filterFace(const label faceI, "
00159                 "face& f) const"
00160             )   << "Removing non-consecutive duplicate vertex in face "
00161                 << f << endl;
00162             // Don't store current pointI and remove previous
00163             newFp--;
00164         }
00165         else if (index != -1)
00166         {
00167             WarningIn
00168             (
00169                 "Foam::edgeCollapser::filterFace(const label faceI, "
00170                 "face& f) const"
00171             )   << "Pinched face " << f << endl;
00172             f[newFp++] = pointI;
00173         }
00174         else
00175         {
00176             f[newFp++] = pointI;
00177         }
00178     }
00179 
00180     f.setSize(newFp);
00181 }
00182 
00183 
00184 // Debugging.
00185 void Foam::edgeCollapser::printRegions() const
00186 {
00187     forAll(pointRegionMaster_, regionI)
00188     {
00189         label master = pointRegionMaster_[regionI];
00190 
00191         if (master != -1)
00192         {
00193             Info<< "Region:" << regionI << nl
00194                 << "    master:" << master
00195                 << ' ' << mesh_.points()[master] << nl;
00196 
00197             forAll(pointRegion_, pointI)
00198             {
00199                 if (pointRegion_[pointI] == regionI && pointI != master)
00200                 {
00201                     Info<< "    slave:" << pointI
00202                         << ' ' <<  mesh_.points()[pointI] << nl;
00203                 }
00204             }
00205         }
00206     }
00207 }
00208 
00209 
00210 
00211 // Collapse list of edges
00212 void Foam::edgeCollapser::collapseEdges(const labelList& edgeLabels)
00213 {
00214     const edgeList& edges = mesh_.edges();
00215 
00216     forAll(edgeLabels, i)
00217     {
00218         label edgeI = edgeLabels[i];
00219         const edge& e = edges[edgeI];
00220 
00221         label region0 = pointRegion_[e[0]];
00222         label region1 = pointRegion_[e[1]];
00223 
00224         if (region0 == -1)
00225         {
00226             if (region1 == -1)
00227             {
00228                 // Both unaffected. Choose ad lib.
00229                 collapseEdge(edgeI, e[0]);
00230             }
00231             else
00232             {
00233                 // Collapse to whatever e[1] collapses
00234                 collapseEdge(edgeI, e[1]);
00235             }
00236         }
00237         else
00238         {
00239             if (region1 == -1)
00240             {
00241                 // Collapse to whatever e[0] collapses
00242                 collapseEdge(edgeI, e[0]);
00243             }
00244             else
00245             {
00246                 // Both collapsed.
00247                 if (pointRegionMaster_[region0] == e[0])
00248                 {
00249                     // e[0] is a master
00250                     collapseEdge(edgeI, e[0]);
00251                 }
00252                 else if (pointRegionMaster_[region1] == e[1])
00253                 {
00254                     // e[1] is a master
00255                     collapseEdge(edgeI, e[1]);
00256                 }
00257                 else
00258                 {
00259                     // Dont know
00260                     collapseEdge(edgeI, e[0]);
00261                 }
00262             }
00263         }
00264     }
00265 }
00266 
00267 
00268 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00269 
00270 // Construct from mesh
00271 Foam::edgeCollapser::edgeCollapser(const polyMesh& mesh)
00272 :
00273     mesh_(mesh),
00274     pointRegion_(mesh.nPoints(), -1),
00275     pointRegionMaster_(mesh.nPoints() / 100),
00276     freeRegions_()
00277 {}
00278 
00279 
00280 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00281 
00282 bool Foam::edgeCollapser::unaffectedEdge(const label edgeI) const
00283 {
00284     const edge& e = mesh_.edges()[edgeI];
00285 
00286     return (pointRegion_[e[0]] == -1) && (pointRegion_[e[1]] == -1);
00287 }
00288 
00289 
00290 bool Foam::edgeCollapser::collapseEdge(const label edgeI, const label master)
00291 {
00292     const edge& e = mesh_.edges()[edgeI];
00293 
00294     label pointRegion0 = pointRegion_[e[0]];
00295     label pointRegion1 = pointRegion_[e[1]];
00296 
00297     if (pointRegion0 == -1)
00298     {
00299         if (pointRegion1 == -1)
00300         {
00301             // Both endpoints not collapsed. Create new region.
00302 
00303             label freeRegion = -1;
00304 
00305             if (freeRegions_.size())
00306             {
00307                 freeRegion = freeRegions_.removeHead();
00308 
00309                 if (pointRegionMaster_[freeRegion] != -1)
00310                 {
00311                     FatalErrorIn
00312                     ("edgeCollapser::collapseEdge(const label, const label)")
00313                         << "Problem : freeed region :" << freeRegion
00314                         << " has already master "
00315                         << pointRegionMaster_[freeRegion]
00316                         << abort(FatalError);
00317                 }
00318             }
00319             else
00320             {
00321                 // If no region found create one. This is the only place where
00322                 // new regions are created.
00323                 freeRegion = pointRegionMaster_.size();
00324             }
00325 
00326             pointRegion_[e[0]] = freeRegion;
00327             pointRegion_[e[1]] = freeRegion;
00328 
00329             pointRegionMaster_(freeRegion) = master;
00330         }
00331         else
00332         {
00333             // e[1] is part of collapse network, e[0] not. Add e0 to e1 region.
00334             pointRegion_[e[0]] = pointRegion1;
00335 
00336             pointRegionMaster_[pointRegion1] = master;
00337         }
00338     }
00339     else
00340     {
00341         if (pointRegion1 == -1)
00342         {
00343             // e[0] is part of collapse network. Add e1 to e0 region
00344             pointRegion_[e[1]] = pointRegion0;
00345 
00346             pointRegionMaster_[pointRegion0] = master;
00347         }
00348         else if (pointRegion0 != pointRegion1)
00349         {
00350             // Both part of collapse network. Merge the two regions.
00351 
00352             // Use the smaller region number for the whole network.
00353             label minRegion = min(pointRegion0, pointRegion1);
00354             label maxRegion = max(pointRegion0, pointRegion1);
00355     
00356             // Use minRegion as region for combined net, free maxRegion.
00357             pointRegionMaster_[minRegion] = master;
00358             pointRegionMaster_[maxRegion] = -1;
00359             freeRegions_.insert(maxRegion);
00360 
00361             if (minRegion != pointRegion0)
00362             {
00363                 changePointRegion(e[0], pointRegion0, minRegion);
00364             }
00365             if (minRegion != pointRegion1)
00366             {
00367                 changePointRegion(e[1], pointRegion1, minRegion);
00368             }
00369         }
00370     }
00371 
00372     return true;
00373 }
00374 
00375 
00376 bool Foam::edgeCollapser::setRefinement(polyTopoChange& meshMod)
00377 {
00378     const cellList& cells = mesh_.cells();
00379     const labelList& faceOwner = mesh_.faceOwner();
00380     const labelList& faceNeighbour = mesh_.faceNeighbour();
00381     const labelListList& pointFaces = mesh_.pointFaces();
00382     const labelListList& cellEdges = mesh_.cellEdges();
00383 
00384     // Print regions:
00385     //printRegions()
00386 
00387     bool meshChanged = false;
00388 
00389 
00390     // Current faces (is also collapseStatus: f.size() < 3)
00391     faceList newFaces(mesh_.faces());
00392 
00393     // Current cellCollapse status
00394     boolList cellRemoved(mesh_.nCells(), false);
00395 
00396 
00397     do
00398     {
00399         // Update face collapse from edge collapses
00400         forAll(newFaces, faceI)
00401         {
00402             filterFace(faceI, newFaces[faceI]);
00403         }
00404 
00405         // Check if faces to be collapsed cause cells to become collapsed.
00406         label nCellCollapsed = 0;
00407 
00408         forAll(cells, cellI)
00409         {
00410             if (!cellRemoved[cellI])
00411             {
00412                 const cell& cFaces = cells[cellI];
00413 
00414                 label nFaces = cFaces.size();
00415 
00416                 forAll(cFaces, i)
00417                 {
00418                     label faceI = cFaces[i];
00419 
00420                     if (newFaces[faceI].size() < 3)
00421                     {
00422                         --nFaces;
00423 
00424                         if (nFaces < 4)
00425                         {
00426                             Info<< "Cell:" << cellI
00427                                 << " uses faces:" << cFaces
00428                                 << " of which too many are marked for removal:"
00429                                 << endl
00430                                 << "   ";
00431                             forAll(cFaces, j)
00432                             {
00433                                 if (newFaces[cFaces[j]].size() < 3)
00434                                 {
00435                                     Info<< ' '<< cFaces[j];
00436                                 }
00437                             }
00438                             Info<< endl;
00439 
00440                             cellRemoved[cellI] = true;
00441 
00442                             // Collapse all edges of cell to nothing
00443                             collapseEdges(cellEdges[cellI]);
00444 
00445                             nCellCollapsed++;
00446 
00447                             break;
00448                         }
00449                     }
00450                 }
00451             }
00452         }
00453 
00454         if (nCellCollapsed == 0)
00455         {
00456             break;
00457         }
00458     } while(true);
00459 
00460 
00461     // Keep track of faces that have been done already.
00462     boolList doneFace(mesh_.nFaces(), false);
00463 
00464     {
00465         // Mark points used.
00466         boolList usedPoint(mesh_.nPoints(), false);
00467 
00468 
00469         forAll(cellRemoved, cellI)
00470         {
00471             if (cellRemoved[cellI])
00472             {
00473                 meshMod.removeCell(cellI, -1);
00474             }
00475         }
00476 
00477 
00478         // Remove faces
00479         forAll(newFaces, faceI)
00480         {
00481             const face& f = newFaces[faceI];
00482 
00483             if (f.size() < 3)
00484             {
00485                 meshMod.removeFace(faceI, -1);
00486                 meshChanged = true;
00487 
00488                 // Mark face as been done.
00489                 doneFace[faceI] = true;
00490             }
00491             else
00492             {
00493                 // Kept face. Mark vertices
00494                 forAll(f, fp)
00495                 {
00496                     usedPoint[f[fp]] = true;
00497                 }
00498             }
00499         }
00500 
00501         // Remove unused vertices that have not been marked for removal already
00502         forAll(usedPoint, pointI)
00503         {
00504             if (!usedPoint[pointI] && !pointRemoved(pointI))
00505             {
00506                 meshMod.removePoint(pointI, -1);
00507                 meshChanged = true;
00508             }
00509         }
00510     }
00511 
00512         
00513 
00514     // Remove points.
00515     forAll(pointRegion_, pointI)
00516     {
00517         if (pointRemoved(pointI))
00518         {
00519             meshMod.removePoint(pointI, -1);
00520             meshChanged = true;
00521         }
00522     }
00523 
00524 
00525 
00526     const polyBoundaryMesh& boundaryMesh = mesh_.boundaryMesh();
00527     const faceZoneMesh& faceZones = mesh_.faceZones();
00528       
00529 
00530     // Renumber faces that use points
00531     forAll(pointRegion_, pointI)
00532     {
00533         if (pointRemoved(pointI))
00534         {
00535             const labelList& changedFaces = pointFaces[pointI];
00536 
00537             forAll(changedFaces, changedFaceI)
00538             {
00539                 label faceI = changedFaces[changedFaceI];
00540 
00541                 if (!doneFace[faceI])
00542                 {
00543                     doneFace[faceI] = true;
00544 
00545                     // Get current zone info
00546                     label zoneID = faceZones.whichZone(faceI);
00547 
00548                     bool zoneFlip = false;
00549 
00550                     if (zoneID >= 0)
00551                     {
00552                         const faceZone& fZone = faceZones[zoneID];
00553 
00554                         zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
00555                     }
00556 
00557                     // Get current connectivity
00558                     label own = faceOwner[faceI];
00559                     label nei = -1;
00560                     label patchID = -1;
00561 
00562                     if (mesh_.isInternalFace(faceI))
00563                     {
00564                         nei = faceNeighbour[faceI];
00565                     }
00566                     else
00567                     {
00568                         patchID = boundaryMesh.whichPatch(faceI);
00569                     }
00570 
00571                     meshMod.modifyFace
00572                     (
00573                         newFaces[faceI],            // face
00574                         faceI,                      // faceI to change
00575                         own,                        // owner
00576                         nei,                        // neighbour
00577                         false,                      // flipFaceFlux
00578                         patchID,                    // patch
00579                         zoneID,
00580                         zoneFlip
00581                     );
00582                     meshChanged = true;
00583                 }
00584             }
00585         }
00586     }
00587 
00588     return meshChanged;
00589 }
00590 
00591 
00592 void Foam::edgeCollapser::updateMesh(const mapPolyMesh& map)
00593 {
00594     pointRegion_.setSize(mesh_.nPoints());
00595     pointRegion_ = -1;
00596     // Reset count, do not remove underlying storage
00597     pointRegionMaster_.clear();
00598     freeRegions_.clear();
00599 }
00600 
00601 
00602 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines