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

autoLayerDriverShrink.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 Description
00025     Shrinking mesh (part of adding cell layers)
00026 
00027 \*----------------------------------------------------------------------------*/
00028 
00029 #include "autoLayerDriver.H"
00030 #include <finiteVolume/fvMesh.H>
00031 #include <OpenFOAM/Time.H>
00032 #include <OpenFOAM/pointFields.H>
00033 #include <dynamicMesh/motionSmoother.H>
00034 #include <autoMesh/pointData.H>
00035 #include <meshTools/PointEdgeWave.H>
00036 
00037 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00038 
00039 // Calculate inverse sum of edge weights (currently always 1.0)
00040 void Foam::autoLayerDriver::sumWeights
00041 (
00042     const PackedBoolList& isMasterEdge,
00043     const labelList& meshEdges,
00044     const labelList& meshPoints,
00045     const edgeList& edges,
00046     scalarField& invSumWeight
00047 ) const
00048 {
00049     invSumWeight = 0;
00050 
00051     forAll(edges, edgeI)
00052     {
00053         if (isMasterEdge.get(meshEdges[edgeI]) == 1)
00054         {
00055             const edge& e = edges[edgeI];
00056             //scalar eWeight = edgeWeights[edgeI];
00057             scalar eWeight = 1.0;
00058 
00059             invSumWeight[e[0]] += eWeight;
00060             invSumWeight[e[1]] += eWeight;
00061         }
00062     }
00063 
00064     syncTools::syncPointList
00065     (
00066         meshRefiner_.mesh(),
00067         meshPoints,
00068         invSumWeight,
00069         plusEqOp<scalar>(),
00070         scalar(0.0),        // null value
00071         false               // no separation
00072     );
00073 
00074     forAll(invSumWeight, pointI)
00075     {
00076         scalar w = invSumWeight[pointI];
00077 
00078         if (w > 0.0)
00079         {
00080             invSumWeight[pointI] = 1.0/w;
00081         }
00082     }
00083 }
00084 
00085 
00086 // Smooth field on moving patch
00087 void Foam::autoLayerDriver::smoothField
00088 (
00089     const motionSmoother& meshMover,
00090     const PackedBoolList& isMasterEdge,
00091     const labelList& meshEdges,
00092     const scalarField& fieldMin,
00093     const label nSmoothDisp,
00094     scalarField& field
00095 ) const
00096 {
00097     const indirectPrimitivePatch& pp = meshMover.patch();
00098     const edgeList& edges = pp.edges();
00099     const labelList& meshPoints = pp.meshPoints();
00100 
00101     scalarField invSumWeight(pp.nPoints());
00102     sumWeights
00103     (
00104         isMasterEdge,
00105         meshEdges,
00106         meshPoints,
00107         edges,
00108         invSumWeight
00109     );
00110 
00111     // Get smoothly varying patch field.
00112     Info<< "shrinkMeshDistance : Smoothing field ..." << endl;
00113 
00114     for (label iter = 0; iter < nSmoothDisp; iter++)
00115     {
00116         scalarField average(pp.nPoints());
00117         averageNeighbours
00118         (
00119             meshMover.mesh(),
00120             isMasterEdge,
00121             meshEdges,
00122             meshPoints,
00123             pp.edges(),
00124             invSumWeight,
00125             field,
00126             average
00127         );
00128 
00129         // Transfer to field
00130         forAll(field, pointI)
00131         {
00132             //full smoothing neighbours + point value
00133             average[pointI] = 0.5*(field[pointI]+average[pointI]);
00134 
00135             // perform monotonic smoothing
00136             if
00137             (
00138                 average[pointI] < field[pointI]
00139              && average[pointI] >= fieldMin[pointI]
00140             )
00141             {
00142                 field[pointI] = average[pointI];
00143             }
00144         }
00145 
00146         // Do residual calculation every so often.
00147         if ((iter % 10) == 0)
00148         {
00149             Info<< "    Iteration " << iter << "   residual "
00150                 <<  gSum(mag(field-average))
00151                    /returnReduce(average.size(), sumOp<label>())
00152                 << endl;
00153         }
00154     }
00155 }
00156 
00157 
00158 // Smooth normals on moving patch.
00159 void Foam::autoLayerDriver::smoothPatchNormals
00160 (
00161     const motionSmoother& meshMover,
00162     const PackedBoolList& isMasterEdge,
00163     const labelList& meshEdges,
00164     const label nSmoothDisp,
00165     pointField& normals
00166 ) const
00167 {
00168     const indirectPrimitivePatch& pp = meshMover.patch();
00169     const edgeList& edges = pp.edges();
00170     const labelList& meshPoints = pp.meshPoints();
00171 
00172     // Calculate inverse sum of weights
00173 
00174     scalarField invSumWeight(pp.nPoints());
00175     sumWeights
00176     (
00177         isMasterEdge,
00178         meshEdges,
00179         meshPoints,
00180         edges,
00181         invSumWeight
00182     );
00183 
00184     // Get smoothly varying internal normals field.
00185     Info<< "shrinkMeshDistance : Smoothing normals ..." << endl;
00186 
00187     for (label iter = 0; iter < nSmoothDisp; iter++)
00188     {
00189         vectorField average(pp.nPoints());
00190         averageNeighbours
00191         (
00192             meshMover.mesh(),
00193             isMasterEdge,
00194             meshEdges,
00195             meshPoints,
00196             pp.edges(),
00197             invSumWeight,
00198             normals,
00199             average
00200         );
00201 
00202         // Do residual calculation every so often.
00203         if ((iter % 10) == 0)
00204         {
00205             Info<< "    Iteration " << iter << "   residual "
00206                 <<  gSum(mag(normals-average))
00207                    /returnReduce(average.size(), sumOp<label>())
00208                 << endl;
00209         }
00210 
00211         // Transfer to normals vector field
00212         forAll(average, pointI)
00213         {
00214             // full smoothing neighbours + point value
00215             average[pointI] = 0.5*(normals[pointI]+average[pointI]);
00216             normals[pointI] = average[pointI];
00217             normals[pointI] /= mag(normals[pointI]) + VSMALL;
00218         }
00219     }
00220 }
00221 
00222 
00223 // Smooth normals in interior.
00224 void Foam::autoLayerDriver::smoothNormals
00225 (
00226     const label nSmoothDisp,
00227     const PackedBoolList& isMasterEdge,
00228     const labelList& fixedPoints,
00229     pointVectorField& normals
00230 ) const
00231 {
00232     // Get smoothly varying internal normals field.
00233     Info<< "shrinkMeshDistance : Smoothing normals ..." << endl;
00234 
00235     const fvMesh& mesh = meshRefiner_.mesh();
00236     const edgeList& edges = mesh.edges();
00237 
00238     // Points that do not change.
00239     PackedBoolList isFixedPoint(mesh.nPoints());
00240 
00241     // Internal points that are fixed
00242     forAll(fixedPoints, i)
00243     {
00244         label meshPointI = fixedPoints[i];
00245         isFixedPoint.set(meshPointI, 1);
00246     }
00247 
00248     // Correspondence between local edges/points and mesh edges/points
00249     const labelList meshEdges(identity(mesh.nEdges()));
00250     const labelList meshPoints(identity(mesh.nPoints()));
00251 
00252     // Calculate inverse sum of weights
00253 
00254     scalarField invSumWeight(mesh.nPoints(), 0);
00255     sumWeights
00256     (
00257         isMasterEdge,
00258         meshEdges,
00259         meshPoints,
00260         edges,
00261         invSumWeight
00262     );
00263 
00264     Info<< "shrinkMeshDistance : Smoothing normals in interior ..." << endl;
00265 
00266     for (label iter = 0; iter < nSmoothDisp; iter++)
00267     {
00268         vectorField average(mesh.nPoints());
00269         averageNeighbours
00270         (
00271             mesh,
00272             isMasterEdge,
00273             meshEdges,
00274             meshPoints,
00275             edges,
00276             invSumWeight,
00277             normals,
00278             average
00279         );
00280 
00281         // Do residual calculation every so often.
00282         if ((iter % 10) == 0)
00283         {
00284             Info<< "    Iteration " << iter << "   residual "
00285                 <<  gSum(mag(normals-average))
00286                    /returnReduce(average.size(), sumOp<label>())
00287                 << endl;
00288         }
00289 
00290 
00291         // Transfer to normals vector field
00292         forAll(average, pointI)
00293         {
00294             if (isFixedPoint.get(pointI) == 0)
00295             {
00296                 //full smoothing neighbours + point value
00297                 average[pointI] = 0.5*(normals[pointI]+average[pointI]);
00298                 normals[pointI] = average[pointI];
00299                 normals[pointI] /= mag(normals[pointI]) + VSMALL;
00300             }
00301         }
00302     }
00303 }
00304 
00305 
00306 // Tries and find a medial axis point. Done by comparing vectors to nearest
00307 // wall point for both vertices of edge.
00308 bool Foam::autoLayerDriver::isMaxEdge
00309 (
00310     const List<pointData>& pointWallDist,
00311     const label edgeI,
00312     const scalar minCos
00313 ) const
00314 {
00315     const fvMesh& mesh = meshRefiner_.mesh();
00316     const pointField& points = mesh.points();
00317 
00318     // Do not mark edges with one side on moving wall.
00319 
00320     const edge& e = mesh.edges()[edgeI];
00321 
00322     vector v0(points[e[0]] - pointWallDist[e[0]].origin());
00323     scalar magV0(mag(v0));
00324 
00325     if (magV0 < SMALL)
00326     {
00327         return false;
00328     }
00329 
00330     vector v1(points[e[1]] - pointWallDist[e[1]].origin());
00331     scalar magV1(mag(v1));
00332 
00333     if (magV1 < SMALL)
00334     {
00335         return false;
00336     }
00337 
00338     v0 /= magV0;
00339     v1 /= magV1;
00340 
00341     // Test angle.
00342     if ((v0 & v1) < minCos)
00343     {
00344         return true;
00345     }
00346     else
00347     {
00348         return false;
00349     }
00350 }
00351 
00352 
00353 // Stop layer growth where mesh wraps around edge with a
00354 // large feature angle
00355 void Foam::autoLayerDriver::handleFeatureAngleLayerTerminations
00356 (
00357     const indirectPrimitivePatch& pp,
00358     const scalar minCos,
00359     List<extrudeMode>& extrudeStatus,
00360     pointField& patchDisp,
00361     labelList& patchNLayers,
00362     label& nPointCounter
00363 ) const
00364 {
00365     // Mark faces that have all points extruded
00366     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00367 
00368     boolList extrudedFaces(pp.size(), true);
00369 
00370     forAll(pp.localFaces(), faceI)
00371     {
00372         const face& f = pp.localFaces()[faceI];
00373 
00374         forAll(f, fp)
00375         {
00376             if (extrudeStatus[f[fp]] == NOEXTRUDE)
00377             {
00378                 extrudedFaces[faceI] = false;
00379                 break;
00380             }
00381         }
00382     }
00383 
00384 
00385     // Detect situation where two featureedge-neighbouring faces are partly or
00386     // not extruded and the edge itself is extruded. In this case unmark the
00387     // edge for extrusion.
00388 
00389     forAll(pp.edgeFaces(), edgeI)
00390     {
00391         const labelList& eFaces = pp.edgeFaces()[edgeI];
00392 
00393         if (eFaces.size() == 2)
00394         {
00395             const edge& e = pp.edges()[edgeI];
00396             label v0 = e[0];
00397             label v1 = e[1];
00398 
00399             if
00400             (
00401                 extrudeStatus[v0] != NOEXTRUDE
00402              || extrudeStatus[v1] != NOEXTRUDE
00403             )
00404             {
00405                 if (!extrudedFaces[eFaces[0]] || !extrudedFaces[eFaces[1]])
00406                 {
00407                     const vector& n0 = pp.faceNormals()[eFaces[0]];
00408                     const vector& n1 = pp.faceNormals()[eFaces[1]];
00409 
00410                     if ((n0 & n1) < minCos)
00411                     {
00412                         if
00413                         (
00414                             unmarkExtrusion
00415                             (
00416                                 v0,
00417                                 patchDisp,
00418                                 patchNLayers,
00419                                 extrudeStatus
00420                             )
00421                         )
00422                         {
00423                             nPointCounter++;
00424                         }
00425                         if
00426                         (
00427                             unmarkExtrusion
00428                             (
00429                                 v1,
00430                                 patchDisp,
00431                                 patchNLayers,
00432                                 extrudeStatus
00433                             )
00434                         )
00435                         {
00436                             nPointCounter++;
00437                         }
00438                     }
00439                 }
00440             }
00441         }
00442     }
00443 }
00444 
00445 
00446 // Find isolated islands (points, edges and faces and layer terminations)
00447 // in the layer mesh and stop any layer growth at these points.
00448 void Foam::autoLayerDriver::findIsolatedRegions
00449 (
00450     const indirectPrimitivePatch& pp,
00451     const PackedBoolList& isMasterEdge,
00452     const labelList& meshEdges,
00453     const scalar minCosLayerTermination,
00454     scalarField& field,
00455     List<extrudeMode>& extrudeStatus,
00456     pointField& patchDisp,
00457     labelList& patchNLayers
00458 ) const
00459 {
00460     const fvMesh& mesh = meshRefiner_.mesh();
00461 
00462     Info<< "shrinkMeshDistance : Removing isolated regions ..." << endl;
00463 
00464     // Keep count of number of points unextruded
00465     label nPointCounter = 0;
00466 
00467     while (true)
00468     {
00469         // Stop layer growth where mesh wraps around edge with a
00470         // large feature angle
00471         handleFeatureAngleLayerTerminations
00472         (
00473             pp,
00474             minCosLayerTermination,
00475 
00476             extrudeStatus,
00477             patchDisp,
00478             patchNLayers,
00479             nPointCounter
00480         );
00481 
00482 
00483         // Do not extrude from point where all neighbouring
00484         // faces are not grown
00485         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00486         boolList extrudedFaces(pp.size(), true);
00487         forAll(pp.localFaces(), faceI)
00488         {
00489             const face& f = pp.localFaces()[faceI];
00490             forAll(f, fp)
00491             {
00492                 if (extrudeStatus[f[fp]] == NOEXTRUDE)
00493                 {
00494                     extrudedFaces[faceI] = false;
00495                     break;
00496                 }
00497             }
00498         }
00499 
00500         const labelListList& pointFaces = pp.pointFaces();
00501 
00502         boolList keptPoints(pp.nPoints(), false);
00503         forAll(keptPoints, patchPointI)
00504         {
00505             const labelList& pFaces = pointFaces[patchPointI];
00506 
00507             forAll(pFaces, i)
00508             {
00509                 label faceI = pFaces[i];
00510                 if (extrudedFaces[faceI])
00511                 {
00512                     keptPoints[patchPointI] = true;
00513                     break;
00514                 }
00515             }
00516         }
00517 
00518         syncTools::syncPointList
00519         (
00520             mesh,
00521             pp.meshPoints(),
00522             keptPoints,
00523             orEqOp<bool>(),
00524             false,              // null value
00525             false               // no separation
00526         );
00527 
00528         label nChanged = 0;
00529 
00530         forAll(keptPoints, patchPointI)
00531         {
00532             if (!keptPoints[patchPointI])
00533             {
00534                 if
00535                 (
00536                     unmarkExtrusion
00537                     (
00538                         patchPointI,
00539                         patchDisp,
00540                         patchNLayers,
00541                         extrudeStatus
00542                     )
00543                 )
00544                 {
00545                    nPointCounter++;
00546                    nChanged++;
00547                 }
00548            }
00549        }
00550 
00551 
00552        if (returnReduce(nChanged, sumOp<label>()) == 0)
00553        {
00554            break;
00555        }
00556    }
00557 
00558     const edgeList& edges = pp.edges();
00559 
00560 
00561     // Count number of mesh edges using a point
00562     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00563 
00564     labelList isolatedPoint(pp.nPoints(),0);
00565 
00566     forAll(edges, edgeI)
00567     {
00568         if (isMasterEdge.get(meshEdges[edgeI]) == 1)
00569         {
00570             const edge& e = edges[edgeI];
00571 
00572             label v0 = e[0];
00573             label v1 = e[1];
00574 
00575             if (extrudeStatus[v1] != NOEXTRUDE)
00576             {
00577                 isolatedPoint[v0] += 1;
00578             }
00579             if (extrudeStatus[v0] != NOEXTRUDE)
00580             {
00581                 isolatedPoint[v1] += 1;
00582             }
00583         }
00584     }
00585 
00586     syncTools::syncPointList
00587     (
00588         mesh,
00589         pp.meshPoints(),
00590         isolatedPoint,
00591         plusEqOp<label>(),
00592         0,       // null value
00593         false    // no separation
00594     );
00595 
00596     // stop layer growth on isolated faces
00597     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00598     forAll(pp, faceI)
00599     {
00600         const face& f = pp.localFaces()[faceI];
00601         bool failed = false;
00602         forAll(f, fp)
00603         {
00604             if (isolatedPoint[f[fp]] > 2)
00605             {
00606                 failed = true;
00607                 break;
00608             }
00609         }
00610         bool allPointsExtruded = true;
00611         if (!failed)
00612         {
00613             forAll(f, fp)
00614             {
00615                 if (extrudeStatus[f[fp]] == NOEXTRUDE)
00616                 {
00617                     allPointsExtruded = false;
00618                     break;
00619                 }
00620             }
00621 
00622             if (allPointsExtruded)
00623             {
00624                 forAll(f, fp)
00625                 {
00626                     if
00627                     (
00628                         unmarkExtrusion
00629                         (
00630                             f[fp],
00631                             patchDisp,
00632                             patchNLayers,
00633                             extrudeStatus
00634                         )
00635                     )
00636                     {
00637                         field[f[fp]] = 0.0;
00638                         nPointCounter++;
00639                     }
00640                 }
00641             }
00642         }
00643     }
00644 
00645     reduce(nPointCounter, sumOp<label>());
00646     Info<< "Number isolated points extrusion stopped : "<< nPointCounter<< endl;
00647 }
00648 
00649 
00650 // Calculates medial axis fields:
00651 // dispVec     : normal of nearest wall. Where this normal changes direction
00652 //               defines the medial axis
00653 // medialDist  : distance to medial axis
00654 // medialRatio : ratio of medial distance to wall distance.
00655 //               (1 at wall, 0 at medial axis)
00656 void Foam::autoLayerDriver::medialAxisSmoothingInfo
00657 (
00658     const motionSmoother& meshMover,
00659     const label nSmoothNormals,
00660     const label nSmoothSurfaceNormals,
00661     const scalar minMedianAxisAngleCos,
00662 
00663     pointVectorField& dispVec,
00664     pointScalarField& medialRatio,
00665     pointScalarField& medialDist
00666 ) const
00667 {
00668 
00669     Info<< "medialAxisSmoothingInfo :"
00670         << " Calculate distance to Medial Axis ..." << endl;
00671 
00672     const polyMesh& mesh = meshMover.mesh();
00673     const pointField& points = mesh.points();
00674 
00675     const indirectPrimitivePatch& pp = meshMover.patch();
00676     const vectorField& faceNormals = pp.faceNormals();
00677     const labelList& meshPoints = pp.meshPoints();
00678 
00679     // Predetermine mesh edges
00680     // ~~~~~~~~~~~~~~~~~~~~~~~
00681 
00682     // Precalulate master edge (only relevant for shared edges)
00683     PackedBoolList isMasterEdge(syncTools::getMasterEdges(mesh));
00684     // Precalculate meshEdge per pp edge
00685     labelList meshEdges(pp.nEdges());
00686 
00687     forAll(meshEdges, patchEdgeI)
00688     {
00689         const edge& e = pp.edges()[patchEdgeI];
00690 
00691         label v0 = pp.meshPoints()[e[0]];
00692         label v1 = pp.meshPoints()[e[1]];
00693         meshEdges[patchEdgeI] = meshTools::findEdge
00694         (
00695             mesh.edges(),
00696             mesh.pointEdges()[v0],
00697             v0,
00698             v1
00699         );
00700     }
00701 
00702 
00703     // Determine pointNormal
00704     // ~~~~~~~~~~~~~~~~~~~~~
00705 
00706     pointField pointNormals(pp.nPoints(), vector::zero);
00707     {
00708         labelList nPointFaces(pp.nPoints(), 0);
00709 
00710         forAll(faceNormals, faceI)
00711         {
00712             const face& f = pp.localFaces()[faceI];
00713 
00714             forAll(f, fp)
00715             {
00716                 pointNormals[f[fp]] += faceNormals[faceI];
00717                 nPointFaces[f[fp]] ++;
00718             }
00719         }
00720 
00721         syncTools::syncPointList
00722         (
00723             mesh,
00724             meshPoints,
00725             pointNormals,
00726             plusEqOp<vector>(),
00727             vector::zero,       // null value
00728             false               // no separation
00729         );
00730 
00731         syncTools::syncPointList
00732         (
00733             mesh,
00734             meshPoints,
00735             nPointFaces,
00736             plusEqOp<label>(),
00737             0,                  // null value
00738             false               // no separation
00739         );
00740 
00741         forAll(pointNormals, i)
00742         {
00743             pointNormals[i] /= nPointFaces[i];
00744         }
00745     }
00746 
00747     // Smooth patch normal vectors
00748     smoothPatchNormals
00749     (
00750         meshMover,
00751         isMasterEdge,
00752         meshEdges,
00753         nSmoothSurfaceNormals,
00754         pointNormals
00755     );
00756 
00757 
00758     // Calculate distance to pp points
00759     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00760 
00761     // Distance to wall
00762     List<pointData> pointWallDist(mesh.nPoints());
00763 
00764 
00765     // 1. Calculate distance to points where displacement is specified.
00766     {
00767         // Seed data.
00768         List<pointData> wallInfo(meshPoints.size());
00769 
00770         forAll(meshPoints, patchPointI)
00771         {
00772             label pointI = meshPoints[patchPointI];
00773             wallInfo[patchPointI] = pointData
00774             (
00775                 points[pointI],
00776                 0.0,
00777                 pointI,                       // passive scalar
00778                 pointNormals[patchPointI]     // surface normals
00779             );
00780         }
00781 
00782         // Do all calculations
00783         List<pointData> edgeWallDist(mesh.nEdges());
00784         PointEdgeWave<pointData> wallDistCalc
00785         (
00786             mesh,
00787             meshPoints,
00788             wallInfo,
00789             pointWallDist,
00790             edgeWallDist,
00791             mesh.globalData().nTotalPoints()    // max iterations
00792         );
00793     }
00794 
00795     // 2. Find points with max distance and transport information back to
00796     //    wall.
00797     {
00798         List<pointData> pointMedialDist(mesh.nPoints());
00799         List<pointData> edgeMedialDist(mesh.nEdges());
00800 
00801         // Seed point data.
00802         DynamicList<pointData> maxInfo(meshPoints.size());
00803         DynamicList<label> maxPoints(meshPoints.size());
00804 
00805         // 1. Medial axis points
00806 
00807         const edgeList& edges = mesh.edges();
00808 
00809         forAll(edges, edgeI)
00810         {
00811             if (isMaxEdge(pointWallDist, edgeI, minMedianAxisAngleCos))
00812             {
00813                 // Both end points of edge have very different nearest wall
00814                 // point. Mark both points as medial axis points.
00815                 const edge& e = edges[edgeI];
00816 
00817                 forAll(e, ep)
00818                 {
00819                     label pointI = e[ep];
00820 
00821                     if (!pointMedialDist[pointI].valid())
00822                     {
00823                         maxPoints.append(pointI);
00824                         maxInfo.append
00825                         (
00826                             pointData
00827                             (
00828                                 points[pointI],
00829                                 0.0,
00830                                 pointI,         // passive data
00831                                 vector::zero    // passive data
00832                             )
00833                         );
00834                         pointMedialDist[pointI] = maxInfo[maxInfo.size()-1];
00835                     }
00836                 }
00837             }
00838         }
00839 
00840 
00841         // 2. Seed non-adapt patches
00842         const polyBoundaryMesh& patches = mesh.boundaryMesh();
00843 
00844         labelHashSet adaptPatches(meshMover.adaptPatchIDs());
00845 
00846         forAll(patches, patchI)
00847         {
00848             const polyPatch& pp = patches[patchI];
00849 
00850             if
00851             (
00852                 !pp.coupled()
00853              && !isA<emptyPolyPatch>(pp)
00854              && !adaptPatches.found(patchI)
00855             )
00856             {
00857                 Info<< "Inserting points on patch " << pp.name() << endl;
00858 
00859                 const labelList& meshPoints = pp.meshPoints();
00860 
00861                 forAll(meshPoints, i)
00862                 {
00863                     label pointI = meshPoints[i];
00864 
00865                     if (!pointMedialDist[pointI].valid())
00866                     {
00867                         maxPoints.append(pointI);
00868                         maxInfo.append
00869                         (
00870                             pointData
00871                             (
00872                                 points[pointI],
00873                                 0.0,
00874                                 pointI,         // passive data
00875                                 vector::zero    // passive data
00876                             )
00877                         );
00878                         pointMedialDist[pointI] = maxInfo[maxInfo.size()-1];
00879                     }
00880                 }
00881             }
00882         }
00883 
00884         maxInfo.shrink();
00885         maxPoints.shrink();
00886 
00887         // Do all calculations
00888         PointEdgeWave<pointData> medialDistCalc
00889         (
00890             mesh,
00891             maxPoints,
00892             maxInfo,
00893 
00894             pointMedialDist,
00895             edgeMedialDist,
00896             mesh.globalData().nTotalPoints()    // max iterations
00897         );
00898 
00899         // Extract medial axis distance as pointScalarField
00900         forAll(pointMedialDist, pointI)
00901         {
00902             medialDist[pointI] = Foam::sqrt(pointMedialDist[pointI].distSqr());
00903         }
00904     }
00905 
00906     // Extract transported surface normals as pointVectorField
00907     forAll(dispVec, i)
00908     {
00909         dispVec[i] = pointWallDist[i].v();
00910     }
00911 
00912     // Smooth normal vectors. Do not change normals on pp.meshPoints
00913     smoothNormals(nSmoothNormals, isMasterEdge, meshPoints, dispVec);
00914 
00915     // Calculate ratio point medial distance to point wall distance
00916     forAll(medialRatio, pointI)
00917     {
00918         scalar wDist2 = pointWallDist[pointI].distSqr();
00919         scalar mDist = medialDist[pointI];
00920 
00921         if (wDist2 < sqr(SMALL) && mDist < SMALL)
00922         {
00923             medialRatio[pointI] = 0.0;
00924         }
00925         else
00926         {
00927             medialRatio[pointI] = mDist / (Foam::sqrt(wDist2) + mDist);
00928         }
00929     }
00930 
00931     if (debug)
00932     {
00933         Info<< "medialAxisSmoothingInfo :"
00934             << " Writing:" << nl
00935             << "    " << dispVec.name()
00936             << " : normalised direction of nearest displacement" << nl
00937             << "    " << medialDist.name()
00938             << " : distance to medial axis" << nl
00939             << "    " << medialRatio.name()
00940             << " : ratio of medial distance to wall distance" << nl
00941             << endl;
00942         dispVec.write();
00943         medialDist.write();
00944         medialRatio.write();
00945     }
00946 }
00947 
00948 
00949 void Foam::autoLayerDriver::shrinkMeshMedialDistance
00950 (
00951     motionSmoother& meshMover,
00952     const dictionary& meshQualityDict,
00953     const label nSmoothThickness,
00954     const scalar maxThicknessToMedialRatio,
00955     const label nAllowableErrors,
00956     const label nSnap,
00957     const scalar minCosLayerTermination,
00958 
00959     const scalarField& layerThickness,
00960     const scalarField& minThickness,
00961 
00962     const pointVectorField& dispVec,
00963     const pointScalarField& medialRatio,
00964     const pointScalarField& medialDist,
00965 
00966     List<extrudeMode>& extrudeStatus,
00967     pointField& patchDisp,
00968     labelList& patchNLayers
00969 ) const
00970 {
00971     Info<< "shrinkMeshMedialDistance : Smoothing using Medial Axis ..." << endl;
00972 
00973     const polyMesh& mesh = meshMover.mesh();
00974 
00975     const indirectPrimitivePatch& pp = meshMover.patch();
00976     const labelList& meshPoints = pp.meshPoints();
00977 
00978     // Precalulate master edge (only relevant for shared edges)
00979     PackedBoolList isMasterEdge(syncTools::getMasterEdges(mesh));
00980     // Precalculate meshEdge per pp edge
00981     labelList meshEdges(pp.nEdges());
00982 
00983     forAll(meshEdges, patchEdgeI)
00984     {
00985         const edge& e = pp.edges()[patchEdgeI];
00986 
00987         label v0 = pp.meshPoints()[e[0]];
00988         label v1 = pp.meshPoints()[e[1]];
00989         meshEdges[patchEdgeI] = meshTools::findEdge
00990         (
00991             mesh.edges(),
00992             mesh.pointEdges()[v0],
00993             v0,
00994             v1
00995         );
00996     }
00997 
00998 
00999     scalarField thickness(layerThickness.size());
01000 
01001     thickness = mag(patchDisp);
01002 
01003     forAll(thickness, patchPointI)
01004     {
01005         if (extrudeStatus[patchPointI] == NOEXTRUDE)
01006         {
01007             thickness[patchPointI] = 0.0;
01008         }
01009     }
01010 
01011     label numThicknessRatioExclude = 0;
01012 
01013     // reduce thickness where thickness/medial axis distance large
01014     forAll(meshPoints, patchPointI)
01015     {
01016         if (extrudeStatus[patchPointI] != NOEXTRUDE)
01017         {
01018             label pointI = meshPoints[patchPointI];
01019 
01020             scalar mDist = medialDist[pointI];
01021 
01022             scalar thicknessRatio = thickness[patchPointI]/(mDist+VSMALL);
01023 
01024             if (thicknessRatio > maxThicknessToMedialRatio)
01025             {
01026                 // Truncate thickness.
01027                 thickness[patchPointI] =
01028                     0.5*(minThickness[patchPointI]+thickness[patchPointI]);
01029 
01030                 patchDisp[patchPointI] =
01031                     thickness[patchPointI]
01032                   * patchDisp[patchPointI]
01033                   / (mag(patchDisp[patchPointI]) + VSMALL);
01034                 numThicknessRatioExclude++;
01035             }
01036         }
01037     }
01038 
01039     reduce(numThicknessRatioExclude, sumOp<label>());
01040     Info<< "shrinkMeshMedialDistance : Reduce layer thickness at "
01041         << numThicknessRatioExclude
01042         << " nodes where thickness to medial axis distance is large " << endl;
01043 
01044     // find points where layer growth isolated to a lone point, edge or face
01045 
01046     findIsolatedRegions
01047     (
01048         pp,
01049         isMasterEdge,
01050         meshEdges,
01051         minCosLayerTermination,
01052         thickness,
01053         extrudeStatus,
01054         patchDisp,
01055         patchNLayers
01056     );
01057 
01058     // smooth layer thickness on moving patch
01059     smoothField
01060     (
01061         meshMover,
01062         isMasterEdge,
01063         meshEdges,
01064         minThickness,
01065         nSmoothThickness,
01066         thickness
01067     );
01068 
01069     List<pointData> pointWallDist(mesh.nPoints());
01070 
01071     const pointField& points = mesh.points();
01072     // 1. Calculate distance to points where displacement is specified.
01073     // This wave is used to transport layer thickness
01074     {
01075         // Distance to wall and medial axis on edges.
01076         List<pointData> edgeWallDist(mesh.nEdges());
01077         labelList wallPoints(meshPoints.size());
01078 
01079         // Seed data.
01080         List<pointData> wallInfo(meshPoints.size());
01081 
01082         forAll(meshPoints, patchPointI)
01083         {
01084             label pointI = meshPoints[patchPointI];
01085             wallPoints[patchPointI] = pointI;
01086             wallInfo[patchPointI] = pointData
01087             (
01088                 points[pointI],
01089                 0.0,
01090                 thickness[patchPointI],       // transport layer thickness
01091                 vector::zero                  // passive vector
01092             );
01093         }
01094 
01095         // Do all calculations
01096         PointEdgeWave<pointData> wallDistCalc
01097         (
01098             mesh,
01099             wallPoints,
01100             wallInfo,
01101             pointWallDist,
01102             edgeWallDist,
01103             mesh.globalData().nTotalPoints()    // max iterations
01104         );
01105     }
01106 
01107     // Calculate scaled displacement vector
01108     pointVectorField& displacement = meshMover.displacement();
01109 
01110     forAll(displacement, pointI)
01111     {
01112         // 1) displacement on nearest wall point, scaled by medialRatio
01113         //    (wall distance / medial distance)
01114         // 2) pointWallDist[pointI].s() is layer thickness transported
01115         //    from closest wall point.
01116         // 3) shrink in opposite direction of addedPoints
01117         displacement[pointI] =
01118             -medialRatio[pointI]
01119             *pointWallDist[pointI].s()
01120             *dispVec[pointI];
01121     }
01122 
01123     // Current faces to check. Gets modified in meshMover.scaleMesh
01124     labelList checkFaces(identity(mesh.nFaces()));
01125 
01126     Info<< "shrinkMeshMedialDistance : Moving mesh ..." << endl;
01127     scalar oldErrorReduction = -1;
01128 
01129     for (label iter = 0; iter < 2*nSnap ; iter++)
01130     {
01131         Info<< "Iteration " << iter << endl;
01132         if (iter == nSnap)
01133         {
01134             Info<< "Displacement scaling for error reduction set to 0." << endl;
01135             oldErrorReduction = meshMover.setErrorReduction(0.0);
01136         }
01137 
01138         if
01139         (
01140             meshMover.scaleMesh
01141             (
01142                 checkFaces,
01143                 List<labelPair>(0),
01144                 meshMover.paramDict(),
01145                 meshQualityDict,
01146                 true,
01147                 nAllowableErrors
01148             )
01149         )
01150         {
01151             Info<< "shrinkMeshMedialDistance : Successfully moved mesh" << endl;
01152             break;
01153         }
01154     }
01155 
01156     if (oldErrorReduction >= 0)
01157     {
01158         meshMover.setErrorReduction(oldErrorReduction);
01159     }
01160 
01161     Info<< "shrinkMeshMedialDistance : Finished moving mesh ..." << endl;
01162 }
01163 
01164 
01165 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines