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

polyDualMeshApp.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 Application
00025     polyDualMesh
00026 
00027 Description
00028     Calculate the dual of a polyMesh. Adheres to all the feature and patch
00029     edges.
00030 
00031     Detects any boundary edge > angle and creates multiple boundary faces
00032     for it. Normal behaviour is to have each point become a cell
00033     (1.5 behaviour)
00034 
00035 Usage
00036 
00037     - polyDualMesh [OPTIONS] <feature angle [0-180]>
00038 
00039     @param -concaveMultiCells
00040     Creates multiple cells for each point on a concave edge. Might limit
00041     the amount of distortion on some meshes.
00042 
00043     @param -splitAllFaces
00044     Normally only constructs a single face between two cells. This single face
00045     might be too distorted. splitAllFaces will create a single face for every
00046     original cell the face passes through. The mesh will thus have
00047     multiple faces inbetween two cells! (so is not strictly upper-triangular
00048     anymore - checkMesh will complain)
00049 
00050     @param -doNotPreserveFaceZones:
00051     By default all faceZones are preserved by marking all faces, edges and
00052     points on them as features. The -doNotPreserveFaceZones disables this
00053     behaviour.
00054 
00055     @param -overwrite \n
00056     Overwrite existing data.
00057 
00058     @param -case <dir>\n
00059     Case directory.
00060 
00061     @param -help \n
00062     Display help message.
00063 
00064     @param -doc \n
00065     Display Doxygen API documentation page for this application.
00066 
00067     @param -srcDoc \n
00068     Display Doxygen source documentation page for this application.
00069 
00070 Note
00071     This is just a driver for meshDualiser. Substitute your own
00072     simpleMarkFeatures to have different behaviour.
00073 
00074 \*---------------------------------------------------------------------------*/
00075 
00076 #include <OpenFOAM/argList.H>
00077 #include <OpenFOAM/Time.H>
00078 #include <OpenFOAM/timeSelector.H>
00079 #include <finiteVolume/fvMesh.H>
00080 #include <OpenFOAM/mathematicalConstants.H>
00081 #include <dynamicMesh/polyTopoChange.H>
00082 #include <OpenFOAM/mapPolyMesh.H>
00083 #include <OpenFOAM/PackedBoolList.H>
00084 #include <meshTools/meshTools.H>
00085 #include <OpenFOAM/OFstream.H>
00086 #include "meshDualiser.H"
00087 #include <OpenFOAM/ReadFields.H>
00088 #include <finiteVolume/volFields.H>
00089 #include <finiteVolume/surfaceFields.H>
00090 
00091 using namespace Foam;
00092 
00093 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00094 
00095 // Naive feature detection. All boundary edges with angle > featureAngle become
00096 // feature edges. All points on feature edges become feature points. All
00097 // boundary faces become feature faces.
00098 void simpleMarkFeatures
00099 (
00100     const polyMesh& mesh,
00101     const PackedBoolList& isBoundaryEdge,
00102     const scalar featureAngle,
00103     const bool concaveMultiCells,
00104     const bool doNotPreserveFaceZones,
00105 
00106     labelList& featureFaces,
00107     labelList& featureEdges,
00108     labelList& singleCellFeaturePoints,
00109     labelList& multiCellFeaturePoints
00110 )
00111 {
00112     scalar minCos = Foam::cos(featureAngle * mathematicalConstant::pi/180.0);
00113 
00114     const polyBoundaryMesh& patches = mesh.boundaryMesh();
00115 
00116     // Working sets
00117     labelHashSet featureEdgeSet;
00118     labelHashSet singleCellFeaturePointSet;
00119     labelHashSet multiCellFeaturePointSet;
00120 
00121 
00122     // 1. Mark all edges between patches
00123     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00124 
00125     forAll(patches, patchI)
00126     {
00127         const polyPatch& pp = patches[patchI];
00128         const labelList& meshEdges = pp.meshEdges();
00129 
00130         // All patch corner edges. These need to be feature points & edges!
00131         for (label edgeI = pp.nInternalEdges(); edgeI < pp.nEdges(); edgeI++)
00132         {
00133             label meshEdgeI = meshEdges[edgeI];
00134             featureEdgeSet.insert(meshEdgeI);
00135             singleCellFeaturePointSet.insert(mesh.edges()[meshEdgeI][0]);
00136             singleCellFeaturePointSet.insert(mesh.edges()[meshEdgeI][1]);
00137         }
00138     }
00139 
00140 
00141 
00142     // 2. Mark all geometric feature edges
00143     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00144     // Make distinction between convex features where the boundary point becomes
00145     // a single cell and concave features where the boundary point becomes
00146     // multiple 'half' cells.
00147 
00148     // Addressing for all outside faces
00149     primitivePatch allBoundary
00150     (
00151         SubList<face>
00152         (
00153             mesh.faces(),
00154             mesh.nFaces()-mesh.nInternalFaces(),
00155             mesh.nInternalFaces()
00156         ),
00157         mesh.points()
00158     );
00159 
00160     // Check for non-manifold points (surface pinched at point)
00161     allBoundary.checkPointManifold(false, &singleCellFeaturePointSet);
00162 
00163     // Check for non-manifold edges (surface pinched at edge)
00164     const labelListList& edgeFaces = allBoundary.edgeFaces();
00165     const labelList& meshPoints = allBoundary.meshPoints();
00166 
00167     forAll(edgeFaces, edgeI)
00168     {
00169         const labelList& eFaces = edgeFaces[edgeI];
00170 
00171         if (eFaces.size() > 2)
00172         {
00173             const edge& e = allBoundary.edges()[edgeI];
00174 
00175             //Info<< "Detected non-manifold boundary edge:" << edgeI
00176             //    << " coords:"
00177             //    << allBoundary.points()[meshPoints[e[0]]]
00178             //    << allBoundary.points()[meshPoints[e[1]]] << endl;
00179 
00180             singleCellFeaturePointSet.insert(meshPoints[e[0]]);
00181             singleCellFeaturePointSet.insert(meshPoints[e[1]]);
00182         }
00183     }
00184 
00185     // Check for features.
00186     forAll(edgeFaces, edgeI)
00187     {
00188         const labelList& eFaces = edgeFaces[edgeI];
00189 
00190         if (eFaces.size() == 2)
00191         {
00192             label f0 = eFaces[0];
00193             label f1 = eFaces[1];
00194 
00195             // check angle
00196             const vector& n0 = allBoundary.faceNormals()[f0];
00197             const vector& n1 = allBoundary.faceNormals()[f1];
00198 
00199             if ((n0 & n1) < minCos)
00200             {
00201                 const edge& e = allBoundary.edges()[edgeI];
00202                 label v0 = meshPoints[e[0]];
00203                 label v1 = meshPoints[e[1]];
00204 
00205                 label meshEdgeI = meshTools::findEdge(mesh, v0, v1);
00206                 featureEdgeSet.insert(meshEdgeI);
00207 
00208                 // Check if convex or concave by looking at angle
00209                 // between face centres and normal
00210                 vector c1c0
00211                 (
00212                     allBoundary[f1].centre(allBoundary.points())
00213                   - allBoundary[f0].centre(allBoundary.points())
00214                 );
00215 
00216                 if (concaveMultiCells && (c1c0 & n0) > SMALL)
00217                 {
00218                     // Found concave edge. Make into multiCell features
00219                     Info<< "Detected concave feature edge:" << edgeI
00220                         << " cos:" << (c1c0 & n0)
00221                         << " coords:"
00222                         << allBoundary.points()[v0]
00223                         << allBoundary.points()[v1]
00224                         << endl;
00225 
00226                     singleCellFeaturePointSet.erase(v0);
00227                     multiCellFeaturePointSet.insert(v0);
00228                     singleCellFeaturePointSet.erase(v1);
00229                     multiCellFeaturePointSet.insert(v1);
00230                 }
00231                 else
00232                 {
00233                     // Convex. singleCell feature.
00234                     if (!multiCellFeaturePointSet.found(v0))
00235                     {
00236                         singleCellFeaturePointSet.insert(v0);
00237                     }
00238                     if (!multiCellFeaturePointSet.found(v1))
00239                     {
00240                         singleCellFeaturePointSet.insert(v1);
00241                     }
00242                 }
00243             }
00244         }
00245     }
00246 
00247 
00248     // 3. Mark all feature faces
00249     // ~~~~~~~~~~~~~~~~~~~~~~~~~
00250 
00251     // Face centres that need inclusion in the dual mesh
00252     labelHashSet featureFaceSet(mesh.nFaces()-mesh.nInternalFaces());
00253     // A. boundary faces.
00254     for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
00255     {
00256         featureFaceSet.insert(faceI);
00257     }
00258 
00259     // B. face zones.
00260     const faceZoneMesh& faceZones = mesh.faceZones();
00261 
00262     if (doNotPreserveFaceZones)
00263     {
00264         if (faceZones.size() > 0)
00265         {
00266             WarningIn("simpleMarkFeatures(..)")
00267                 << "Detected " << faceZones.size()
00268                 << " faceZones. These will not be preserved."
00269                 << endl;
00270         }
00271     }
00272     else
00273     {
00274         if (faceZones.size() > 0)
00275         {
00276             Info<< "Detected " << faceZones.size()
00277                 << " faceZones. Preserving these by marking their"
00278                 << " points, edges and faces as features." << endl;
00279         }
00280 
00281         forAll(faceZones, zoneI)
00282         {
00283             const faceZone& fz = faceZones[zoneI];
00284 
00285             Info<< "Inserting all faces in faceZone " << fz.name()
00286                 << " as features." << endl;
00287 
00288             forAll(fz, i)
00289             {
00290                 label faceI = fz[i];
00291                 const face& f = mesh.faces()[faceI];
00292                 const labelList& fEdges = mesh.faceEdges()[faceI];
00293 
00294                 featureFaceSet.insert(faceI);
00295                 forAll(f, fp)
00296                 {
00297                     // Mark point as multi cell point (since both sides of
00298                     // face should have different cells)
00299                     singleCellFeaturePointSet.erase(f[fp]);
00300                     multiCellFeaturePointSet.insert(f[fp]);
00301 
00302                     // Make sure there are points on the edges.
00303                     featureEdgeSet.insert(fEdges[fp]);
00304                 }
00305             }
00306         }
00307     }
00308 
00309     // Transfer to arguments
00310     featureFaces = featureFaceSet.toc();
00311     featureEdges = featureEdgeSet.toc();
00312     singleCellFeaturePoints = singleCellFeaturePointSet.toc();
00313     multiCellFeaturePoints = multiCellFeaturePointSet.toc();
00314 }
00315 
00316 
00317 // Dump features to .obj files
00318 void dumpFeatures
00319 (
00320     const polyMesh& mesh,
00321     const labelList& featureFaces,
00322     const labelList& featureEdges,
00323     const labelList& singleCellFeaturePoints,
00324     const labelList& multiCellFeaturePoints
00325 )
00326 {
00327     {
00328         OFstream str("featureFaces.obj");
00329         Info<< "Dumping centres of featureFaces to obj file " << str.name()
00330             << endl;
00331         forAll(featureFaces, i)
00332         {
00333             meshTools::writeOBJ(str, mesh.faceCentres()[featureFaces[i]]);
00334         }
00335     }
00336     {
00337         OFstream str("featureEdges.obj");
00338         Info<< "Dumping featureEdges to obj file " << str.name() << endl;
00339         label vertI = 0;
00340 
00341         forAll(featureEdges, i)
00342         {
00343             const edge& e = mesh.edges()[featureEdges[i]];
00344             meshTools::writeOBJ(str, mesh.points()[e[0]]);
00345             vertI++;
00346             meshTools::writeOBJ(str, mesh.points()[e[1]]);
00347             vertI++;
00348             str<< "l " << vertI-1 << ' ' << vertI << nl;
00349         }
00350     }
00351     {
00352         OFstream str("singleCellFeaturePoints.obj");
00353         Info<< "Dumping featurePoints that become a single cell to obj file "
00354             << str.name() << endl;
00355         forAll(singleCellFeaturePoints, i)
00356         {
00357             meshTools::writeOBJ(str, mesh.points()[singleCellFeaturePoints[i]]);
00358         }
00359     }
00360     {
00361         OFstream str("multiCellFeaturePoints.obj");
00362         Info<< "Dumping featurePoints that become multiple cells to obj file "
00363             << str.name() << endl;
00364         forAll(multiCellFeaturePoints, i)
00365         {
00366             meshTools::writeOBJ(str, mesh.points()[multiCellFeaturePoints[i]]);
00367         }
00368     }
00369 }
00370 
00371 
00372 int main(int argc, char *argv[])
00373 {
00374     argList::noParallel();
00375     timeSelector::addOptions(true, false);
00376 
00377     argList::validArgs.append("feature angle[0-180]");
00378     argList::validOptions.insert("splitAllFaces", "");
00379     argList::validOptions.insert("concaveMultiCells", "");
00380     argList::validOptions.insert("doNotPreserveFaceZones", "");
00381     argList::validOptions.insert("overwrite", "");
00382 
00383 #   include <OpenFOAM/setRootCase.H>
00384 #   include <OpenFOAM/createTime.H>
00385 
00386     instantList timeDirs = timeSelector::select0(runTime, args);
00387 
00388 #   include <OpenFOAM/createMesh.H>
00389 
00390     const word oldInstance = mesh.pointsInstance();
00391 
00392     // Mark boundary edges and points.
00393     // (Note: in 1.4.2 we can use the built-in mesh point ordering
00394     //  facility instead)
00395     PackedBoolList isBoundaryEdge(mesh.nEdges());
00396     for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
00397     {
00398         const labelList& fEdges = mesh.faceEdges()[faceI];
00399 
00400         forAll(fEdges, i)
00401         {
00402             isBoundaryEdge.set(fEdges[i], 1);
00403         }
00404     }
00405 
00406     scalar featureAngle(readScalar(IStringStream(args.additionalArgs()[0])()));
00407 
00408     scalar minCos = Foam::cos(featureAngle * mathematicalConstant::pi/180.0);
00409 
00410     Info<< "Feature:" << featureAngle << endl
00411         << "minCos :" << minCos << endl
00412         << endl;
00413 
00414 
00415     const bool splitAllFaces = args.optionFound("splitAllFaces");
00416     if (splitAllFaces)
00417     {
00418         Info<< "Splitting all internal faces to create multiple faces"
00419             << " between two cells." << nl
00420             << endl;
00421     }
00422 
00423     const bool overwrite = args.optionFound("overwrite");
00424     const bool doNotPreserveFaceZones = args.optionFound
00425     (
00426         "doNotPreserveFaceZones"
00427     );
00428     const bool concaveMultiCells = args.optionFound("concaveMultiCells");
00429     if (concaveMultiCells)
00430     {
00431         Info<< "Generating multiple cells for points on concave feature edges."
00432             << nl << endl;
00433     }
00434 
00435 
00436     // Face(centre)s that need inclusion in the dual mesh
00437     labelList featureFaces;
00438     // Edge(centre)s  ,,
00439     labelList featureEdges;
00440     // Points (that become a single cell) that need inclusion in the dual mesh
00441     labelList singleCellFeaturePoints;
00442     // Points (that become a multiple cells)        ,,
00443     labelList multiCellFeaturePoints;
00444 
00445     // Sample implementation of feature detection.
00446     simpleMarkFeatures
00447     (
00448         mesh,
00449         isBoundaryEdge,
00450         featureAngle,
00451         concaveMultiCells,
00452         doNotPreserveFaceZones,
00453 
00454         featureFaces,
00455         featureEdges,
00456         singleCellFeaturePoints,
00457         multiCellFeaturePoints
00458     );
00459 
00460     // If we want to split all polyMesh faces into one dualface per cell
00461     // we are passing through we also need a point
00462     // at the polyMesh facecentre and edgemid of the faces we want to
00463     // split.
00464     if (splitAllFaces)
00465     {
00466         featureEdges = identity(mesh.nEdges());
00467         featureFaces = identity(mesh.nFaces());
00468     }
00469 
00470     // Write obj files for debugging
00471     dumpFeatures
00472     (
00473         mesh,
00474         featureFaces,
00475         featureEdges,
00476         singleCellFeaturePoints,
00477         multiCellFeaturePoints
00478     );
00479 
00480 
00481 
00482     // Read objects in time directory
00483     IOobjectList objects(mesh, runTime.timeName());
00484 
00485     // Read vol fields.
00486     PtrList<volScalarField> vsFlds;
00487     ReadFields(mesh, objects, vsFlds);
00488 
00489     PtrList<volVectorField> vvFlds;
00490     ReadFields(mesh, objects, vvFlds);
00491 
00492     PtrList<volSphericalTensorField> vstFlds;
00493     ReadFields(mesh, objects, vstFlds);
00494 
00495     PtrList<volSymmTensorField> vsymtFlds;
00496     ReadFields(mesh, objects, vsymtFlds);
00497 
00498     PtrList<volTensorField> vtFlds;
00499     ReadFields(mesh, objects, vtFlds);
00500 
00501     // Read surface fields.
00502     PtrList<surfaceScalarField> ssFlds;
00503     ReadFields(mesh, objects, ssFlds);
00504 
00505     PtrList<surfaceVectorField> svFlds;
00506     ReadFields(mesh, objects, svFlds);
00507 
00508     PtrList<surfaceSphericalTensorField> sstFlds;
00509     ReadFields(mesh, objects, sstFlds);
00510 
00511     PtrList<surfaceSymmTensorField> ssymtFlds;
00512     ReadFields(mesh, objects, ssymtFlds);
00513 
00514     PtrList<surfaceTensorField> stFlds;
00515     ReadFields(mesh, objects, stFlds);
00516 
00517 
00518     // Topo change container
00519     polyTopoChange meshMod(mesh.boundaryMesh().size());
00520 
00521     // Mesh dualiser engine
00522     meshDualiser dualMaker(mesh);
00523 
00524     // Insert all commands into polyTopoChange to create dual of mesh. This does
00525     // all the hard work.
00526     dualMaker.setRefinement
00527     (
00528         splitAllFaces,
00529         featureFaces,
00530         featureEdges,
00531         singleCellFeaturePoints,
00532         multiCellFeaturePoints,
00533         meshMod
00534     );
00535 
00536     // Create mesh, return map from old to new mesh.
00537     autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
00538 
00539     // Update fields
00540     mesh.updateMesh(map);
00541 
00542     // Optionally inflate mesh
00543     if (map().hasMotionPoints())
00544     {
00545         mesh.movePoints(map().preMotionPoints());
00546     }
00547 
00548     if (!overwrite)
00549     {
00550         runTime++;
00551     }
00552     else
00553     {
00554         mesh.setInstance(oldInstance);
00555     }
00556 
00557     Info<< "Writing dual mesh to " << runTime.timeName() << endl;
00558 
00559     mesh.write();
00560 
00561     Info<< "End\n" << endl;
00562 
00563     return 0;
00564 }
00565 
00566 
00567 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines