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

autoLayerDriver.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     All to do with adding cell layers
00026 
00027 \*----------------------------------------------------------------------------*/
00028 
00029 #include "autoLayerDriver.H"
00030 #include <finiteVolume/fvMesh.H>
00031 #include <OpenFOAM/Time.H>
00032 #include <autoMesh/meshRefinement.H>
00033 #include <dynamicMesh/removePoints.H>
00034 #include <OpenFOAM/pointFields.H>
00035 #include <dynamicMesh/motionSmoother.H>
00036 #include <OpenFOAM/mathematicalConstants.H>
00037 #include <meshTools/pointSet.H>
00038 #include <meshTools/faceSet.H>
00039 #include <meshTools/cellSet.H>
00040 #include <dynamicMesh/polyTopoChange.H>
00041 #include <OpenFOAM/mapPolyMesh.H>
00042 #include <dynamicMesh/addPatchCellLayer.H>
00043 #include <OpenFOAM/mapDistributePolyMesh.H>
00044 #include <OpenFOAM/OFstream.H>
00045 #include <autoMesh/layerParameters.H>
00046 #include <dynamicMesh/combineFaces.H>
00047 #include <OpenFOAM/IOmanip.H>
00048 
00049 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00050 
00051 namespace Foam
00052 {
00053 
00054 defineTypeNameAndDebug(autoLayerDriver, 0);
00055 
00056 } // End namespace Foam
00057 
00058 
00059 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00060 
00061 Foam::label Foam::autoLayerDriver::mergePatchFacesUndo
00062 (
00063     const scalar minCos,
00064     const scalar concaveCos,
00065     const dictionary& motionDict
00066 )
00067 {
00068     fvMesh& mesh = meshRefiner_.mesh();
00069 
00070     // Patch face merging engine
00071     combineFaces faceCombiner(mesh, true);
00072 
00073     // Pick up all candidate cells on boundary
00074     labelHashSet boundaryCells(mesh.nFaces()-mesh.nInternalFaces());
00075 
00076     {
00077         labelList patchIDs(meshRefiner_.meshedPatches());
00078 
00079         const polyBoundaryMesh& patches = mesh.boundaryMesh();
00080 
00081         forAll(patchIDs, i)
00082         {
00083             label patchI = patchIDs[i];
00084 
00085             const polyPatch& patch = patches[patchI];
00086 
00087             if (!patch.coupled())
00088             {
00089                 forAll(patch, i)
00090                 {
00091                     boundaryCells.insert(mesh.faceOwner()[patch.start()+i]);
00092                 }
00093             }
00094         }
00095     }
00096 
00097     // Get all sets of faces that can be merged
00098     labelListList allFaceSets
00099     (
00100         faceCombiner.getMergeSets
00101         (
00102             minCos,
00103             concaveCos,
00104             boundaryCells
00105         )
00106     );
00107 
00108     label nFaceSets = returnReduce(allFaceSets.size(), sumOp<label>());
00109 
00110     Info<< "Merging " << nFaceSets << " sets of faces." << nl << endl;
00111 
00112     if (nFaceSets > 0)
00113     {
00114         if (debug)
00115         {
00116             faceSet allSets(mesh, "allFaceSets", allFaceSets.size());
00117             forAll(allFaceSets, setI)
00118             {
00119                 forAll(allFaceSets[setI], i)
00120                 {
00121                     allSets.insert(allFaceSets[setI][i]);
00122                 }
00123             }
00124             Pout<< "Writing all faces to be merged to set "
00125                 << allSets.objectPath() << endl;
00126             allSets.write();
00127         }
00128 
00129 
00130         // Topology changes container
00131         polyTopoChange meshMod(mesh);
00132 
00133         // Merge all faces of a set into the first face of the set.
00134         faceCombiner.setRefinement(allFaceSets, meshMod);
00135 
00136         // Experimental: store data for all the points that have been deleted
00137         meshRefiner_.storeData
00138         (
00139             faceCombiner.savedPointLabels(),    // points to store
00140             labelList(0),                       // faces to store
00141             labelList(0)                        // cells to store
00142         );
00143 
00144         // Change the mesh (no inflation)
00145         autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
00146 
00147         // Update fields
00148         mesh.updateMesh(map);
00149 
00150         // Move mesh (since morphing does not do this)
00151         if (map().hasMotionPoints())
00152         {
00153             mesh.movePoints(map().preMotionPoints());
00154         }
00155         else
00156         {
00157             // Delete mesh volumes.
00158             mesh.clearOut();
00159         }
00160 
00161         if (meshRefiner_.overwrite())
00162         {
00163             mesh.setInstance(meshRefiner_.oldInstance());
00164         }
00165 
00166         faceCombiner.updateMesh(map);
00167 
00168         meshRefiner_.updateMesh(map, labelList(0));
00169 
00170 
00171         for (label iteration = 0; iteration < 100; iteration++)
00172         {
00173             Info<< nl
00174                 << "Undo iteration " << iteration << nl
00175                 << "----------------" << endl;
00176 
00177 
00178             // Check mesh for errors
00179             // ~~~~~~~~~~~~~~~~~~~~~
00180 
00181             faceSet errorFaces
00182             (
00183                 mesh,
00184                 "errorFaces",
00185                 mesh.nFaces()-mesh.nInternalFaces()
00186             );
00187             bool hasErrors = motionSmoother::checkMesh
00188             (
00189                 false,  // report
00190                 mesh,
00191                 motionDict,
00192                 errorFaces
00193             );
00194             //if (checkEdgeConnectivity)
00195             //{
00196             //    Info<< "Checking edge-face connectivity (duplicate faces"
00197             //        << " or non-consecutive shared vertices)" << endl;
00198             //
00199             //    label nOldSize = errorFaces.size();
00200             //
00201             //    hasErrors =
00202             //        mesh.checkFaceFaces
00203             //        (
00204             //            false,
00205             //            &errorFaces
00206             //        )
00207             //     || hasErrors;
00208             //
00209             //    Info<< "Detected additional "
00210             //        << returnReduce(errorFaces.size()-nOldSize, sumOp<label>())
00211             //        << " faces with illegal face-face connectivity"
00212             //        << endl;
00213             //}
00214 
00215             if (!hasErrors)
00216             {
00217                 break;
00218             }
00219 
00220 
00221             if (debug)
00222             {
00223                 Pout<< "Writing all faces in error to faceSet "
00224                     << errorFaces.objectPath() << nl << endl;
00225                 errorFaces.write();
00226             }
00227 
00228 
00229             // Check any master cells for using any of the error faces
00230             // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00231 
00232             DynamicList<label> mastersToRestore(allFaceSets.size());
00233 
00234             forAll(allFaceSets, setI)
00235             {
00236                 label masterFaceI = faceCombiner.masterFace()[setI];
00237 
00238                 if (masterFaceI != -1)
00239                 {
00240                     label masterCellII = mesh.faceOwner()[masterFaceI];
00241 
00242                     const cell& cFaces = mesh.cells()[masterCellII];
00243 
00244                     forAll(cFaces, i)
00245                     {
00246                         if (errorFaces.found(cFaces[i]))
00247                         {
00248                             mastersToRestore.append(masterFaceI);
00249                             break;
00250                         }
00251                     }
00252                 }
00253             }
00254             mastersToRestore.shrink();
00255 
00256             label nRestore = returnReduce
00257             (
00258                 mastersToRestore.size(),
00259                 sumOp<label>()
00260             );
00261 
00262             Info<< "Masters that need to be restored:"
00263                 << nRestore << endl;
00264 
00265             if (debug)
00266             {
00267                 faceSet restoreSet(mesh, "mastersToRestore", mastersToRestore);
00268                 Pout<< "Writing all " << mastersToRestore.size()
00269                     << " masterfaces to be restored to set "
00270                     << restoreSet.objectPath() << endl;
00271                 restoreSet.write();
00272             }
00273 
00274 
00275             if (nRestore == 0)
00276             {
00277                 break;
00278             }
00279 
00280 
00281             // Undo
00282             // ~~~~
00283 
00284             // Topology changes container
00285             polyTopoChange meshMod(mesh);
00286 
00287             // Merge all faces of a set into the first face of the set.
00288             // Experimental:mark all points/faces/cells that have been restored.
00289             Map<label> restoredPoints(0);
00290             Map<label> restoredFaces(0);
00291             Map<label> restoredCells(0);
00292 
00293             faceCombiner.setUnrefinement
00294             (
00295                 mastersToRestore,
00296                 meshMod,
00297                 restoredPoints,
00298                 restoredFaces,
00299                 restoredCells
00300             );
00301 
00302             // Change the mesh (no inflation)
00303             autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
00304 
00305             // Update fields
00306             mesh.updateMesh(map);
00307 
00308             // Move mesh (since morphing does not do this)
00309             if (map().hasMotionPoints())
00310             {
00311                 mesh.movePoints(map().preMotionPoints());
00312             }
00313             else
00314             {
00315                 // Delete mesh volumes.
00316                 mesh.clearOut();
00317             }
00318 
00319             if (meshRefiner_.overwrite())
00320             {
00321                 mesh.setInstance(meshRefiner_.oldInstance());
00322             }
00323 
00324             faceCombiner.updateMesh(map);
00325 
00326             // Renumber restore maps
00327             inplaceMapKey(map().reversePointMap(), restoredPoints);
00328             inplaceMapKey(map().reverseFaceMap(), restoredFaces);
00329             inplaceMapKey(map().reverseCellMap(), restoredCells);
00330 
00331             // Experimental:restore all points/face/cells in maps
00332             meshRefiner_.updateMesh
00333             (
00334                 map,
00335                 labelList(0),       // changedFaces
00336                 restoredPoints,
00337                 restoredFaces,
00338                 restoredCells
00339             );
00340 
00341             Info<< endl;
00342         }
00343 
00344         if (debug)
00345         {
00346             Pout<< "Writing merged-faces mesh to time "
00347                 << meshRefiner_.timeName() << nl << endl;
00348             mesh.write();
00349         }
00350     }
00351     else
00352     {
00353         Info<< "No faces merged ..." << endl;
00354     }
00355 
00356     return nFaceSets;
00357 }
00358 
00359 
00360 // Remove points. pointCanBeDeleted is parallel synchronised.
00361 Foam::autoPtr<Foam::mapPolyMesh> Foam::autoLayerDriver::doRemovePoints
00362 (
00363     removePoints& pointRemover,
00364     const boolList& pointCanBeDeleted
00365 )
00366 {
00367     fvMesh& mesh = meshRefiner_.mesh();
00368 
00369     // Topology changes container
00370     polyTopoChange meshMod(mesh);
00371 
00372     pointRemover.setRefinement(pointCanBeDeleted, meshMod);
00373 
00374     // Change the mesh (no inflation)
00375     autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
00376 
00377     // Update fields
00378     mesh.updateMesh(map);
00379 
00380     // Move mesh (since morphing does not do this)
00381     if (map().hasMotionPoints())
00382     {
00383         mesh.movePoints(map().preMotionPoints());
00384     }
00385     else
00386     {
00387         // Delete mesh volumes.
00388         mesh.clearOut();
00389     }
00390 
00391     if (meshRefiner_.overwrite())
00392     {
00393         mesh.setInstance(meshRefiner_.oldInstance());
00394     }
00395 
00396     pointRemover.updateMesh(map);
00397     meshRefiner_.updateMesh(map, labelList(0));
00398 
00399     return map;
00400 }
00401 
00402 
00403 // Restore faces (which contain removed points)
00404 Foam::autoPtr<Foam::mapPolyMesh> Foam::autoLayerDriver::doRestorePoints
00405 (
00406     removePoints& pointRemover,
00407     const labelList& facesToRestore
00408 )
00409 {
00410     fvMesh& mesh = meshRefiner_.mesh();
00411 
00412     // Topology changes container
00413     polyTopoChange meshMod(mesh);
00414 
00415     // Determine sets of points and faces to restore
00416     labelList localFaces, localPoints;
00417     pointRemover.getUnrefimentSet
00418     (
00419         facesToRestore,
00420         localFaces,
00421         localPoints
00422     );
00423 
00424     // Undo the changes on the faces that are in error.
00425     pointRemover.setUnrefinement
00426     (
00427         localFaces,
00428         localPoints,
00429         meshMod
00430     );
00431 
00432     // Change the mesh (no inflation)
00433     autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
00434 
00435     // Update fields
00436     mesh.updateMesh(map);
00437 
00438     // Move mesh (since morphing does not do this)
00439     if (map().hasMotionPoints())
00440     {
00441         mesh.movePoints(map().preMotionPoints());
00442     }
00443     else
00444     {
00445         // Delete mesh volumes.
00446         mesh.clearOut();
00447     }
00448 
00449     if (meshRefiner_.overwrite())
00450     {
00451         mesh.setInstance(meshRefiner_.oldInstance());
00452     }
00453 
00454     pointRemover.updateMesh(map);
00455     meshRefiner_.updateMesh(map, labelList(0));
00456 
00457     return map;
00458 }
00459 
00460 
00461 // Collect all faces that are both in candidateFaces and in the set.
00462 // If coupled face also collects the coupled face.
00463 Foam::labelList Foam::autoLayerDriver::collectFaces
00464 (
00465     const labelList& candidateFaces,
00466     const labelHashSet& set
00467 ) const
00468 {
00469     const fvMesh& mesh = meshRefiner_.mesh();
00470 
00471     // Has face been selected?
00472     boolList selected(mesh.nFaces(), false);
00473 
00474     forAll(candidateFaces, i)
00475     {
00476         label faceI = candidateFaces[i];
00477 
00478         if (set.found(faceI))
00479         {
00480             selected[faceI] = true;
00481         }
00482     }
00483     syncTools::syncFaceList
00484     (
00485         mesh,
00486         selected,
00487         orEqOp<bool>(),     // combine operator
00488         false               // separation
00489     );
00490 
00491     labelList selectedFaces(findIndices(selected, true));
00492 
00493     return selectedFaces;
00494 }
00495 
00496 
00497 // Pick up faces of cells of faces in set.
00498 Foam::labelList Foam::autoLayerDriver::growFaceCellFace
00499 (
00500     const labelHashSet& set
00501 ) const
00502 {
00503     const fvMesh& mesh = meshRefiner_.mesh();
00504 
00505     boolList selected(mesh.nFaces(), false);
00506 
00507     forAllConstIter(faceSet, set, iter)
00508     {
00509         label faceI = iter.key();
00510 
00511         label own = mesh.faceOwner()[faceI];
00512 
00513         const cell& ownFaces = mesh.cells()[own];
00514         forAll(ownFaces, ownFaceI)
00515         {
00516             selected[ownFaces[ownFaceI]] = true;
00517         }
00518 
00519         if (mesh.isInternalFace(faceI))
00520         {
00521             label nbr = mesh.faceNeighbour()[faceI];
00522 
00523             const cell& nbrFaces = mesh.cells()[nbr];
00524             forAll(nbrFaces, nbrFaceI)
00525             {
00526                 selected[nbrFaces[nbrFaceI]] = true;
00527             }
00528         }
00529     }
00530     syncTools::syncFaceList
00531     (
00532         mesh,
00533         selected,
00534         orEqOp<bool>(),     // combine operator
00535         false               // separation
00536     );
00537     return findIndices(selected, true);
00538 }
00539 
00540 
00541 // Remove points not used by any face or points used by only two faces where
00542 // the edges are in line
00543 Foam::label Foam::autoLayerDriver::mergeEdgesUndo
00544 (
00545     const scalar minCos,
00546     const dictionary& motionDict
00547 )
00548 {
00549     fvMesh& mesh = meshRefiner_.mesh();
00550 
00551     Info<< nl
00552         << "Merging all points on surface that" << nl
00553         << "- are used by only two boundary faces and" << nl
00554         << "- make an angle with a cosine of more than " << minCos
00555         << "." << nl << endl;
00556 
00557     // Point removal analysis engine with undo
00558     removePoints pointRemover(mesh, true);
00559 
00560     // Count usage of points
00561     boolList pointCanBeDeleted;
00562     label nRemove = pointRemover.countPointUsage(minCos, pointCanBeDeleted);
00563 
00564     if (nRemove > 0)
00565     {
00566         Info<< "Removing " << nRemove
00567             << " straight edge points ..." << nl << endl;
00568 
00569         // Remove points
00570         // ~~~~~~~~~~~~~
00571 
00572         doRemovePoints(pointRemover, pointCanBeDeleted);
00573 
00574 
00575         for (label iteration = 0; iteration < 100; iteration++)
00576         {
00577             Info<< nl
00578                 << "Undo iteration " << iteration << nl
00579                 << "----------------" << endl;
00580 
00581 
00582             // Check mesh for errors
00583             // ~~~~~~~~~~~~~~~~~~~~~
00584 
00585             faceSet errorFaces
00586             (
00587                 mesh,
00588                 "errorFaces",
00589                 mesh.nFaces()-mesh.nInternalFaces()
00590             );
00591             bool hasErrors = motionSmoother::checkMesh
00592             (
00593                 false,  // report
00594                 mesh,
00595                 motionDict,
00596                 errorFaces
00597             );
00598             //if (checkEdgeConnectivity)
00599             //{
00600             //    Info<< "Checking edge-face connectivity (duplicate faces"
00601             //        << " or non-consecutive shared vertices)" << endl;
00602             //
00603             //    label nOldSize = errorFaces.size();
00604             //
00605             //    hasErrors =
00606             //        mesh.checkFaceFaces
00607             //        (
00608             //            false,
00609             //            &errorFaces
00610             //        )
00611             //     || hasErrors;
00612             //
00613             //    Info<< "Detected additional "
00614             //        << returnReduce(errorFaces.size()-nOldSize,sumOp<label>())
00615             //        << " faces with illegal face-face connectivity"
00616             //        << endl;
00617             //}
00618 
00619             if (!hasErrors)
00620             {
00621                 break;
00622             }
00623 
00624             if (debug)
00625             {
00626                 Pout<< "**Writing all faces in error to faceSet "
00627                     << errorFaces.objectPath() << nl << endl;
00628                 errorFaces.write();
00629             }
00630 
00631             labelList masterErrorFaces
00632             (
00633                 collectFaces
00634                 (
00635                     pointRemover.savedFaceLabels(),
00636                     errorFaces
00637                 )
00638             );
00639 
00640             label n = returnReduce(masterErrorFaces.size(), sumOp<label>());
00641 
00642             Info<< "Detected " << n
00643                 << " error faces on boundaries that have been merged."
00644                 << " These will be restored to their original faces." << nl
00645                 << endl;
00646 
00647             if (n == 0)
00648             {
00649                 if (hasErrors)
00650                 {
00651                     Info<< "Detected "
00652                         << returnReduce(errorFaces.size(), sumOp<label>())
00653                         << " error faces in mesh."
00654                         << " Restoring neighbours of faces in error." << nl
00655                         << endl;
00656 
00657                     labelList expandedErrorFaces
00658                     (
00659                         growFaceCellFace
00660                         (
00661                             errorFaces
00662                         )
00663                     );
00664 
00665                     doRestorePoints(pointRemover, expandedErrorFaces);
00666                 }
00667 
00668                 break;
00669             }
00670 
00671             doRestorePoints(pointRemover, masterErrorFaces);
00672         }
00673 
00674         if (debug)
00675         {
00676             Pout<< "Writing merged-edges mesh to time "
00677                 << meshRefiner_.timeName() << nl << endl;
00678             mesh.write();
00679         }
00680     }
00681     else
00682     {
00683         Info<< "No straight edges simplified and no points removed ..." << endl;
00684     }
00685 
00686     return nRemove;
00687 }
00688 
00689 
00690 // For debugging: Dump displacement to .obj files
00691 void Foam::autoLayerDriver::dumpDisplacement
00692 (
00693     const fileName& prefix,
00694     const indirectPrimitivePatch& pp,
00695     const vectorField& patchDisp,
00696     const List<extrudeMode>& extrudeStatus
00697 )
00698 {
00699     OFstream dispStr(prefix + "_disp.obj");
00700     Info<< "Writing all displacements to " << dispStr.name() << nl << endl;
00701 
00702     label vertI = 0;
00703 
00704     forAll(patchDisp, patchPointI)
00705     {
00706         const point& pt = pp.localPoints()[patchPointI];
00707 
00708         meshTools::writeOBJ(dispStr, pt); vertI++;
00709         meshTools::writeOBJ(dispStr, pt + patchDisp[patchPointI]); vertI++;
00710 
00711         dispStr << "l " << vertI-1 << ' ' << vertI << nl;
00712     }
00713 
00714 
00715     OFstream illStr(prefix + "_illegal.obj");
00716     Info<< "Writing invalid displacements to " << illStr.name() << nl << endl;
00717 
00718     vertI = 0;
00719 
00720     forAll(patchDisp, patchPointI)
00721     {
00722         if (extrudeStatus[patchPointI] != EXTRUDE)
00723         {
00724             const point& pt = pp.localPoints()[patchPointI];
00725 
00726             meshTools::writeOBJ(illStr, pt); vertI++;
00727             meshTools::writeOBJ(illStr, pt + patchDisp[patchPointI]); vertI++;
00728 
00729             illStr << "l " << vertI-1 << ' ' << vertI << nl;
00730         }
00731     }
00732 }
00733 
00734 
00735 // Check that primitivePatch is not multiply connected. Collect non-manifold
00736 // points in pointSet.
00737 void Foam::autoLayerDriver::checkManifold
00738 (
00739     const indirectPrimitivePatch& fp,
00740     pointSet& nonManifoldPoints
00741 )
00742 {
00743     // Check for non-manifold points (surface pinched at point)
00744     fp.checkPointManifold(false, &nonManifoldPoints);
00745 
00746     // Check for edge-faces (surface pinched at edge)
00747     const labelListList& edgeFaces = fp.edgeFaces();
00748 
00749     forAll(edgeFaces, edgeI)
00750     {
00751         const labelList& eFaces = edgeFaces[edgeI];
00752 
00753         if (eFaces.size() > 2)
00754         {
00755             const edge& e = fp.edges()[edgeI];
00756 
00757             nonManifoldPoints.insert(fp.meshPoints()[e[0]]);
00758             nonManifoldPoints.insert(fp.meshPoints()[e[1]]);
00759         }
00760     }
00761 }
00762 
00763 
00764 void Foam::autoLayerDriver::checkMeshManifold() const
00765 {
00766     const fvMesh& mesh = meshRefiner_.mesh();
00767 
00768     Info<< nl << "Checking mesh manifoldness ..." << endl;
00769 
00770     // Get all outside faces
00771     labelList outsideFaces(mesh.nFaces() - mesh.nInternalFaces());
00772 
00773     for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
00774     {
00775          outsideFaces[faceI - mesh.nInternalFaces()] = faceI;
00776     }
00777 
00778     pointSet nonManifoldPoints
00779     (
00780         mesh,
00781         "nonManifoldPoints",
00782         mesh.nPoints() / 100
00783     );
00784 
00785     // Build primitivePatch out of faces and check it for problems.
00786     checkManifold
00787     (
00788         indirectPrimitivePatch
00789         (
00790             IndirectList<face>(mesh.faces(), outsideFaces),
00791             mesh.points()
00792         ),
00793         nonManifoldPoints
00794     );
00795 
00796     label nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
00797 
00798     if (nNonManif > 0)
00799     {
00800         Info<< "Outside of mesh is multiply connected across edges or"
00801             << " points." << nl
00802             << "This is not a fatal error but might cause some unexpected"
00803             << " behaviour." << nl
00804             << "Writing " << nNonManif
00805             << " points where this happens to pointSet "
00806             << nonManifoldPoints.name() << endl;
00807 
00808         nonManifoldPoints.write();
00809     }
00810     Info<< endl;
00811 }
00812 
00813 
00814 
00815 // Unset extrusion on point. Returns true if anything unset.
00816 bool Foam::autoLayerDriver::unmarkExtrusion
00817 (
00818     const label patchPointI,
00819     pointField& patchDisp,
00820     labelList& patchNLayers,
00821     List<extrudeMode>& extrudeStatus
00822 )
00823 {
00824     if (extrudeStatus[patchPointI] == EXTRUDE)
00825     {
00826         extrudeStatus[patchPointI] = NOEXTRUDE;
00827         patchNLayers[patchPointI] = 0;
00828         patchDisp[patchPointI] = vector::zero;
00829         return true;
00830     }
00831     else if (extrudeStatus[patchPointI] == EXTRUDEREMOVE)
00832     {
00833         extrudeStatus[patchPointI] = NOEXTRUDE;
00834         patchNLayers[patchPointI] = 0;
00835         patchDisp[patchPointI] = vector::zero;
00836         return true;
00837     }
00838     else
00839     {
00840         return false;
00841     }
00842 }
00843 
00844 
00845 // Unset extrusion on face. Returns true if anything unset.
00846 bool Foam::autoLayerDriver::unmarkExtrusion
00847 (
00848     const face& localFace,
00849     pointField& patchDisp,
00850     labelList& patchNLayers,
00851     List<extrudeMode>& extrudeStatus
00852 )
00853 {
00854     bool unextruded = false;
00855 
00856     forAll(localFace, fp)
00857     {
00858         if
00859         (
00860             unmarkExtrusion
00861             (
00862                 localFace[fp],
00863                 patchDisp,
00864                 patchNLayers,
00865                 extrudeStatus
00866             )
00867         )
00868         {
00869             unextruded = true;
00870         }
00871     }
00872     return unextruded;
00873 }
00874 
00875 
00876 // No extrusion at non-manifold points.
00877 void Foam::autoLayerDriver::handleNonManifolds
00878 (
00879     const indirectPrimitivePatch& pp,
00880     const labelList& meshEdges,
00881     pointField& patchDisp,
00882     labelList& patchNLayers,
00883     List<extrudeMode>& extrudeStatus
00884 ) const
00885 {
00886     const fvMesh& mesh = meshRefiner_.mesh();
00887 
00888     Info<< nl << "Handling non-manifold points ..." << endl;
00889 
00890     // Detect non-manifold points
00891     Info<< nl << "Checking patch manifoldness ..." << endl;
00892 
00893     pointSet nonManifoldPoints(mesh, "nonManifoldPoints", pp.nPoints());
00894 
00895     // 1. Local check
00896     checkManifold(pp, nonManifoldPoints);
00897 
00898     label nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
00899 
00900     Info<< "Outside of local patch is multiply connected across edges or"
00901         << " points at " << nNonManif << " points." << endl;
00902 
00903 
00904     const labelList& meshPoints = pp.meshPoints();
00905 
00906 
00907     // 2. Parallel check
00908     // For now disable extrusion at any shared edges.
00909     const labelHashSet sharedEdgeSet(mesh.globalData().sharedEdgeLabels());
00910 
00911     forAll(pp.edges(), edgeI)
00912     {
00913         if (sharedEdgeSet.found(meshEdges[edgeI]))
00914         {
00915             const edge& e = mesh.edges()[meshEdges[edgeI]];
00916 
00917             Pout<< "Disabling extrusion at edge "
00918                 << mesh.points()[e[0]] << mesh.points()[e[1]]
00919                 << " since it is non-manifold across coupled patches."
00920                 << endl;
00921 
00922             nonManifoldPoints.insert(e[0]);
00923             nonManifoldPoints.insert(e[1]);
00924         }
00925     }
00926 
00927     // 3b. extrusion can produce multiple faces between 2 cells
00928     // across processor boundary
00929     // This occurs when a coupled face shares more than 1 edge with a
00930     // non-coupled boundary face.
00931     // This is now correctly handled by addPatchCellLayer in that it
00932     // extrudes a single face from the stringed up edges.
00933 
00934 
00935     nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
00936 
00937     if (nNonManif > 0)
00938     {
00939         Info<< "Outside of patches is multiply connected across edges or"
00940             << " points at " << nNonManif << " points." << nl
00941             << "Writing " << nNonManif
00942             << " points where this happens to pointSet "
00943             << nonManifoldPoints.name() << nl
00944             << "and setting layer thickness to zero on these points."
00945             << endl;
00946 
00947         nonManifoldPoints.write();
00948 
00949         forAll(meshPoints, patchPointI)
00950         {
00951             if (nonManifoldPoints.found(meshPoints[patchPointI]))
00952             {
00953                 unmarkExtrusion
00954                 (
00955                     patchPointI,
00956                     patchDisp,
00957                     patchNLayers,
00958                     extrudeStatus
00959                 );
00960             }
00961         }
00962     }
00963 
00964     Info<< "Set displacement to zero for all " << nNonManif
00965         << " non-manifold points" << endl;
00966 }
00967 
00968 
00969 // Parallel feature edge detection. Assumes non-manifold edges already handled.
00970 void Foam::autoLayerDriver::handleFeatureAngle
00971 (
00972     const indirectPrimitivePatch& pp,
00973     const labelList& meshEdges,
00974     const scalar minCos,
00975     pointField& patchDisp,
00976     labelList& patchNLayers,
00977     List<extrudeMode>& extrudeStatus
00978 ) const
00979 {
00980     const fvMesh& mesh = meshRefiner_.mesh();
00981 
00982     Info<< nl << "Handling feature edges ..." << endl;
00983 
00984     if (minCos < 1-SMALL)
00985     {
00986         // Normal component of normals of connected faces.
00987         vectorField edgeNormal(mesh.nEdges(), wallPoint::greatPoint);
00988 
00989         const labelListList& edgeFaces = pp.edgeFaces();
00990 
00991         forAll(edgeFaces, edgeI)
00992         {
00993             const labelList& eFaces = pp.edgeFaces()[edgeI];
00994 
00995             label meshEdgeI = meshEdges[edgeI];
00996 
00997             forAll(eFaces, i)
00998             {
00999                 nomalsCombine()
01000                 (
01001                     edgeNormal[meshEdgeI],
01002                     pp.faceNormals()[eFaces[i]]
01003                 );
01004             }
01005         }
01006 
01007         syncTools::syncEdgeList
01008         (
01009             mesh,
01010             edgeNormal,
01011             nomalsCombine(),
01012             wallPoint::greatPoint,  // null value
01013             false                   // no separation
01014         );
01015 
01016         label vertI = 0;
01017         autoPtr<OFstream> str;
01018         if (debug)
01019         {
01020             str.reset(new OFstream(mesh.time().path()/"featureEdges.obj"));
01021             Info<< "Writing feature edges to " << str().name() << endl;
01022         }
01023 
01024         label nFeats = 0;
01025 
01026         // Now on coupled edges the edgeNormal will have been truncated and
01027         // only be still be the old value where two faces have the same normal
01028         forAll(edgeFaces, edgeI)
01029         {
01030             const labelList& eFaces = pp.edgeFaces()[edgeI];
01031 
01032             label meshEdgeI = meshEdges[edgeI];
01033 
01034             const vector& n = edgeNormal[meshEdgeI];
01035 
01036             if (n != wallPoint::greatPoint)
01037             {
01038                 scalar cos = n & pp.faceNormals()[eFaces[0]];
01039 
01040                 if (cos < minCos)
01041                 {
01042                     const edge& e = pp.edges()[edgeI];
01043 
01044                     unmarkExtrusion
01045                     (
01046                         e[0],
01047                         patchDisp,
01048                         patchNLayers,
01049                         extrudeStatus
01050                     );
01051                     unmarkExtrusion
01052                     (
01053                         e[1],
01054                         patchDisp,
01055                         patchNLayers,
01056                         extrudeStatus
01057                     );
01058 
01059                     nFeats++;
01060 
01061                     if (str.valid())
01062                     {
01063                         meshTools::writeOBJ(str(), pp.localPoints()[e[0]]);
01064                         vertI++;
01065                         meshTools::writeOBJ(str(), pp.localPoints()[e[1]]);
01066                         vertI++;
01067                         str()<< "l " << vertI-1 << ' ' << vertI << nl;
01068                     }
01069                 }
01070             }
01071         }
01072 
01073         Info<< "Set displacement to zero for points on "
01074             << returnReduce(nFeats, sumOp<label>())
01075             << " feature edges" << endl;
01076     }
01077 }
01078 
01079 
01080 // No extrusion on cells with warped faces. Calculates the thickness of the
01081 // layer and compares it to the space the warped face takes up. Disables
01082 // extrusion if layer thickness is more than faceRatio of the thickness of
01083 // the face.
01084 void Foam::autoLayerDriver::handleWarpedFaces
01085 (
01086     const indirectPrimitivePatch& pp,
01087     const scalar faceRatio,
01088     const scalar edge0Len,
01089     const labelList& cellLevel,
01090     pointField& patchDisp,
01091     labelList& patchNLayers,
01092     List<extrudeMode>& extrudeStatus
01093 ) const
01094 {
01095     const fvMesh& mesh = meshRefiner_.mesh();
01096 
01097     Info<< nl << "Handling cells with warped patch faces ..." << nl;
01098 
01099     const pointField& points = mesh.points();
01100 
01101     label nWarpedFaces = 0;
01102 
01103     forAll(pp, i)
01104     {
01105         const face& f = pp[i];
01106 
01107         if (f.size() > 3)
01108         {
01109             label faceI = pp.addressing()[i];
01110 
01111             label ownLevel = cellLevel[mesh.faceOwner()[faceI]];
01112             scalar edgeLen = edge0Len/(1<<ownLevel);
01113 
01114             // Normal distance to face centre plane
01115             const point& fc = mesh.faceCentres()[faceI];
01116             const vector& fn = pp.faceNormals()[i];
01117 
01118             scalarField vProj(f.size());
01119 
01120             forAll(f, fp)
01121             {
01122                 vector n = points[f[fp]] - fc;
01123                 vProj[fp] = (n & fn);
01124             }
01125 
01126             // Get normal 'span' of face
01127             scalar minVal = min(vProj);
01128             scalar maxVal = max(vProj);
01129 
01130             if ((maxVal - minVal) > faceRatio * edgeLen)
01131             {
01132                 if
01133                 (
01134                     unmarkExtrusion
01135                     (
01136                         pp.localFaces()[i],
01137                         patchDisp,
01138                         patchNLayers,
01139                         extrudeStatus
01140                     )
01141                 )
01142                 {
01143                     nWarpedFaces++;
01144                 }
01145             }
01146         }
01147     }
01148 
01149     Info<< "Set displacement to zero on "
01150         << returnReduce(nWarpedFaces, sumOp<label>())
01151         << " warped faces since layer would be > " << faceRatio
01152         << " of the size of the bounding box." << endl;
01153 }
01154 
01155 
01156 
01159 //void Foam::autoLayerDriver::handleMultiplePatchFaces
01160 //(
01161 //    const indirectPrimitivePatch& pp,
01162 //    pointField& patchDisp,
01163 //    labelList& patchNLayers,
01164 //    List<extrudeMode>& extrudeStatus
01165 //) const
01166 //{
01167 //    const fvMesh& mesh = meshRefiner_.mesh();
01168 //
01169 //    Info<< nl << "Handling cells with multiple patch faces ..." << nl;
01170 //
01171 //    const labelListList& pointFaces = pp.pointFaces();
01172 //
01173 //    // Cells that should not get an extrusion layer
01174 //    cellSet multiPatchCells(mesh, "multiPatchCells", pp.size());
01175 //
01176 //    // Detect points that use multiple faces on same cell.
01177 //    forAll(pointFaces, patchPointI)
01178 //    {
01179 //        const labelList& pFaces = pointFaces[patchPointI];
01180 //
01181 //        labelHashSet pointCells(pFaces.size());
01182 //
01183 //        forAll(pFaces, i)
01184 //        {
01185 //            label cellI = mesh.faceOwner()[pp.addressing()[pFaces[i]]];
01186 //
01187 //            if (!pointCells.insert(cellI))
01188 //            {
01189 //                // Second or more occurrence of cell so cell has two or more
01190 //                // pp faces connected to this point.
01191 //                multiPatchCells.insert(cellI);
01192 //            }
01193 //        }
01194 //    }
01195 //
01196 //    label nMultiPatchCells = returnReduce
01197 //    (
01198 //        multiPatchCells.size(),
01199 //        sumOp<label>()
01200 //    );
01201 //
01202 //    Info<< "Detected " << nMultiPatchCells
01203 //        << " cells with multiple (connected) patch faces." << endl;
01204 //
01205 //    label nChanged = 0;
01206 //
01207 //    if (nMultiPatchCells > 0)
01208 //    {
01209 //        Info<< "Writing " << nMultiPatchCells
01210 //            << " cells with multiple (connected) patch faces to cellSet "
01211 //            << multiPatchCells.objectPath() << endl;
01212 //        multiPatchCells.write();
01213 //
01214 //
01215 //        // Go through all points and remove extrusion on any cell in
01216 //        // multiPatchCells
01217 //        // (has to be done in separate loop since having one point on
01218 //        // multipatches has to reset extrusion on all points of cell)
01219 //
01220 //        forAll(pointFaces, patchPointI)
01221 //        {
01222 //            if (extrudeStatus[patchPointI] != NOEXTRUDE)
01223 //            {
01224 //                const labelList& pFaces = pointFaces[patchPointI];
01225 //
01226 //                forAll(pFaces, i)
01227 //                {
01228 //                    label cellI =
01229 //                        mesh.faceOwner()[pp.addressing()[pFaces[i]]];
01230 //
01231 //                    if (multiPatchCells.found(cellI))
01232 //                    {
01233 //                        if
01234 //                        (
01235 //                            unmarkExtrusion
01236 //                            (
01237 //                                patchPointI,
01238 //                                patchDisp,
01239 //                                patchNLayers,
01240 //                                extrudeStatus
01241 //                            )
01242 //                        )
01243 //                        {
01244 //                            nChanged++;
01245 //                        }
01246 //                    }
01247 //                }
01248 //            }
01249 //        }
01250 //
01251 //        reduce(nChanged, sumOp<label>());
01252 //    }
01253 //
01254 //    Info<< "Prevented extrusion on " << nChanged
01255 //        << " points due to multiple patch faces." << nl << endl;
01256 //}
01257 
01258 
01259 // No extrusion on faces with differing number of layers for points
01260 void Foam::autoLayerDriver::setNumLayers
01261 (
01262     const labelList& patchToNLayers,
01263     const labelList& patchIDs,
01264     const indirectPrimitivePatch& pp,
01265     pointField& patchDisp,
01266     labelList& patchNLayers,
01267     List<extrudeMode>& extrudeStatus
01268 ) const
01269 {
01270     const fvMesh& mesh = meshRefiner_.mesh();
01271 
01272     Info<< nl << "Handling points with inconsistent layer specification ..."
01273         << endl;
01274 
01275     // Get for every point (really only nessecary on patch external points)
01276     // the max and min of any patch faces using it.
01277     labelList maxLayers(patchNLayers.size(), labelMin);
01278     labelList minLayers(patchNLayers.size(), labelMax);
01279 
01280     forAll(patchIDs, i)
01281     {
01282         label patchI = patchIDs[i];
01283 
01284         const labelList& meshPoints = mesh.boundaryMesh()[patchI].meshPoints();
01285 
01286         label wantedLayers = patchToNLayers[patchI];
01287 
01288         forAll(meshPoints, patchPointI)
01289         {
01290             label ppPointI = pp.meshPointMap()[meshPoints[patchPointI]];
01291 
01292             maxLayers[ppPointI] = max(wantedLayers, maxLayers[ppPointI]);
01293             minLayers[ppPointI] = min(wantedLayers, minLayers[ppPointI]);
01294         }
01295     }
01296 
01297     syncTools::syncPointList
01298     (
01299         mesh,
01300         pp.meshPoints(),
01301         maxLayers,
01302         maxEqOp<label>(),
01303         labelMin,           // null value
01304         false               // no separation
01305     );
01306     syncTools::syncPointList
01307     (
01308         mesh,
01309         pp.meshPoints(),
01310         minLayers,
01311         minEqOp<label>(),
01312         labelMax,           // null value
01313         false               // no separation
01314     );
01315 
01316     // Unmark any point with different min and max
01317     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01318 
01319     //label nConflicts = 0;
01320 
01321     forAll(maxLayers, i)
01322     {
01323         if (maxLayers[i] == labelMin || minLayers[i] == labelMax)
01324         {
01325             FatalErrorIn("setNumLayers(..)")
01326                 << "Patchpoint:" << i << " coord:" << pp.localPoints()[i]
01327                 << " maxLayers:" << maxLayers
01328                 << " minLayers:" << minLayers
01329                 << abort(FatalError);
01330         }
01331         else if (maxLayers[i] == minLayers[i])
01332         {
01333             // Ok setting.
01334             patchNLayers[i] = maxLayers[i];
01335         }
01336         else
01337         {
01338             // Inconsistent num layers between patch faces using point
01339             //if
01340             //(
01341             //    unmarkExtrusion
01342             //    (
01343             //        i,
01344             //        patchDisp,
01345             //        patchNLayers,
01346             //        extrudeStatus
01347             //    )
01348             //)
01349             //{
01350             //    nConflicts++;
01351             //}
01352             patchNLayers[i] = maxLayers[i];
01353         }
01354     }
01355 
01356     //reduce(nConflicts, sumOp<label>());
01357     //
01358     //Info<< "Set displacement to zero for " << nConflicts
01359     //    << " points due to points being on multiple regions"
01360     //    << " with inconsistent nLayers specification." << endl;
01361 }
01362 
01363 
01364 // Grow no-extrusion layer
01365 void Foam::autoLayerDriver::growNoExtrusion
01366 (
01367     const indirectPrimitivePatch& pp,
01368     pointField& patchDisp,
01369     labelList& patchNLayers,
01370     List<extrudeMode>& extrudeStatus
01371 )
01372 {
01373     Info<< nl << "Growing non-extrusion points by one layer ..." << endl;
01374 
01375     List<extrudeMode> grownExtrudeStatus(extrudeStatus);
01376 
01377     const faceList& localFaces = pp.localFaces();
01378 
01379     label nGrown = 0;
01380 
01381     forAll(localFaces, faceI)
01382     {
01383         const face& f = localFaces[faceI];
01384 
01385         bool hasSqueeze = false;
01386         forAll(f, fp)
01387         {
01388             if (extrudeStatus[f[fp]] == NOEXTRUDE)
01389             {
01390                 hasSqueeze = true;
01391                 break;
01392             }
01393         }
01394 
01395         if (hasSqueeze)
01396         {
01397             // Squeeze all points of face
01398             forAll(f, fp)
01399             {
01400                 if
01401                 (
01402                     extrudeStatus[f[fp]] == NOEXTRUDE
01403                  && grownExtrudeStatus[f[fp]] != NOEXTRUDE
01404                 )
01405                 {
01406                     grownExtrudeStatus[f[fp]] = NOEXTRUDE;
01407                     nGrown++;
01408                 }
01409             }
01410         }
01411     }
01412 
01413     extrudeStatus.transfer(grownExtrudeStatus);
01414 
01415     forAll(extrudeStatus, patchPointI)
01416     {
01417         if (extrudeStatus[patchPointI] == NOEXTRUDE)
01418         {
01419             patchDisp[patchPointI] = vector::zero;
01420             patchNLayers[patchPointI] = 0;
01421         }
01422     }
01423 
01424     reduce(nGrown, sumOp<label>());
01425 
01426     Info<< "Set displacement to zero for an additional " << nGrown
01427         << " points." << endl;
01428 }
01429 
01430 
01431 void Foam::autoLayerDriver::calculateLayerThickness
01432 (
01433     const indirectPrimitivePatch& pp,
01434     const labelList& patchIDs,
01435     const scalarField& patchExpansionRatio,
01436 
01437     const bool relativeSizes,
01438     const scalarField& patchFinalLayerThickness,
01439     const scalarField& patchMinThickness,
01440 
01441     const labelList& cellLevel,
01442     const labelList& patchNLayers,
01443     const scalar edge0Len,
01444 
01445     scalarField& thickness,
01446     scalarField& minThickness,
01447     scalarField& expansionRatio
01448 ) const
01449 {
01450     const fvMesh& mesh = meshRefiner_.mesh();
01451     const polyBoundaryMesh& patches = mesh.boundaryMesh();
01452 
01453 
01454     // Rework patch-wise layer parameters into minimum per point
01455     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01456 
01457     // Reuse input fields
01458     expansionRatio.setSize(pp.nPoints());
01459     expansionRatio = GREAT;
01460     thickness.setSize(pp.nPoints());
01461     thickness = GREAT;
01462     minThickness.setSize(pp.nPoints());
01463     minThickness = GREAT;
01464 
01465     forAll(patchIDs, i)
01466     {
01467         label patchI = patchIDs[i];
01468 
01469         const labelList& meshPoints = patches[patchI].meshPoints();
01470 
01471         forAll(meshPoints, patchPointI)
01472         {
01473             label ppPointI = pp.meshPointMap()[meshPoints[patchPointI]];
01474 
01475             expansionRatio[ppPointI] = min
01476             (
01477                 expansionRatio[ppPointI],
01478                 patchExpansionRatio[patchI]
01479             );
01480             thickness[ppPointI] = min
01481             (
01482                 thickness[ppPointI],
01483                 patchFinalLayerThickness[patchI]
01484             );
01485             minThickness[ppPointI] = min
01486             (
01487                 minThickness[ppPointI],
01488                 patchMinThickness[patchI]
01489             );
01490         }
01491     }
01492 
01493     syncTools::syncPointList
01494     (
01495         mesh,
01496         pp.meshPoints(),
01497         expansionRatio,
01498         minEqOp<scalar>(),
01499         GREAT,              // null value
01500         false               // no separation
01501     );
01502     syncTools::syncPointList
01503     (
01504         mesh,
01505         pp.meshPoints(),
01506         thickness,
01507         minEqOp<scalar>(),
01508         GREAT,              // null value
01509         false               // no separation
01510     );
01511     syncTools::syncPointList
01512     (
01513         mesh,
01514         pp.meshPoints(),
01515         minThickness,
01516         minEqOp<scalar>(),
01517         GREAT,              // null value
01518         false               // no separation
01519     );
01520 
01521 
01522     // Now the thicknesses are set according to the minimum of connected
01523     // patches.
01524 
01525 
01526     // Rework relative thickness into absolute
01527     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01528     // by multiplying with the internal cell size.
01529 
01530     if (relativeSizes)
01531     {
01532         if (min(patchMinThickness) < 0 || max(patchMinThickness) > 2)
01533         {
01534             FatalErrorIn("calculateLayerThickness(..)")
01535                 << "Thickness should be factor of local undistorted cell size."
01536                 << " Valid values are [0..2]." << nl
01537                 << " minThickness:" << patchMinThickness
01538                 << exit(FatalError);
01539         }
01540 
01541 
01542         // Determine per point the max cell level of connected cells
01543         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01544 
01545         labelList maxPointLevel(pp.nPoints(), labelMin);
01546 
01547         forAll(pp, i)
01548         {
01549             label ownLevel = cellLevel[mesh.faceOwner()[pp.addressing()[i]]];
01550 
01551             const face& f = pp.localFaces()[i];
01552 
01553             forAll(f, fp)
01554             {
01555                 maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel);
01556             }
01557         }
01558 
01559         syncTools::syncPointList
01560         (
01561             mesh,
01562             pp.meshPoints(),
01563             maxPointLevel,
01564             maxEqOp<label>(),
01565             labelMin,           // null value
01566             false               // no separation
01567         );
01568 
01569 
01570         forAll(maxPointLevel, pointI)
01571         {
01572             // Find undistorted edge size for this level.
01573             scalar edgeLen = edge0Len/(1<<maxPointLevel[pointI]);
01574             thickness[pointI] *= edgeLen;
01575             minThickness[pointI] *= edgeLen;
01576         }
01577     }
01578 
01579 
01580 
01581     // Rework thickness (of final layer) into overall thickness of all layers
01582     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01583 
01584     forAll(thickness, pointI)
01585     {
01586         // Calculate layer thickness based on expansion ratio
01587         // and final layer height
01588         if (expansionRatio[pointI] == 1)
01589         {
01590             thickness[pointI] *= patchNLayers[pointI];
01591         }
01592         else
01593         {
01594 
01595             scalar invExpansion = 1.0 / expansionRatio[pointI];
01596             label nLay = patchNLayers[pointI];
01597             thickness[pointI] *=
01598                 (1.0 - pow(invExpansion, nLay))
01599               / (1.0 - invExpansion);
01600         }
01601     }
01602 
01603 
01604     //Info<< "calculateLayerThickness : min:" << gMin(thickness)
01605     //    << " max:" << gMax(thickness) << endl;
01606 }
01607 
01608 
01609 // Synchronize displacement among coupled patches.
01610 void Foam::autoLayerDriver::syncPatchDisplacement
01611 (
01612     const motionSmoother& meshMover,
01613     const scalarField& minThickness,
01614     pointField& patchDisp,
01615     labelList& patchNLayers,
01616     List<extrudeMode>& extrudeStatus
01617 ) const
01618 {
01619     const fvMesh& mesh = meshRefiner_.mesh();
01620     const labelList& meshPoints = meshMover.patch().meshPoints();
01621 
01622     label nChangedTotal = 0;
01623 
01624     while (true)
01625     {
01626         label nChanged = 0;
01627 
01628         // Sync displacement (by taking min)
01629         syncTools::syncPointList
01630         (
01631             mesh,
01632             meshPoints,
01633             patchDisp,
01634             minEqOp<vector>(),
01635             wallPoint::greatPoint,          // null value
01636             false                           // no separation
01637         );
01638 
01639         // Unmark if displacement too small
01640         forAll(patchDisp, i)
01641         {
01642             if (mag(patchDisp[i]) < minThickness[i])
01643             {
01644                 if
01645                 (
01646                     unmarkExtrusion
01647                     (
01648                         i,
01649                         patchDisp,
01650                         patchNLayers,
01651                         extrudeStatus
01652                     )
01653                 )
01654                 {
01655                     nChanged++;
01656                 }
01657             }
01658         }
01659 
01660         labelList syncPatchNLayers(patchNLayers);
01661 
01662         syncTools::syncPointList
01663         (
01664             mesh,
01665             meshPoints,
01666             syncPatchNLayers,
01667             minEqOp<label>(),
01668             labelMax,           // null value
01669             false               // no separation
01670         );
01671 
01672         // Reset if differs
01673         forAll(syncPatchNLayers, i)
01674         {
01675             if (syncPatchNLayers[i] != patchNLayers[i])
01676             {
01677                 if
01678                 (
01679                     unmarkExtrusion
01680                     (
01681                         i,
01682                         patchDisp,
01683                         patchNLayers,
01684                         extrudeStatus
01685                     )
01686                 )
01687                 {
01688                     nChanged++;
01689                 }
01690             }
01691         }
01692 
01693         syncTools::syncPointList
01694         (
01695             mesh,
01696             meshPoints,
01697             syncPatchNLayers,
01698             maxEqOp<label>(),
01699             labelMin,           // null value
01700             false               // no separation
01701         );
01702 
01703         // Reset if differs
01704         forAll(syncPatchNLayers, i)
01705         {
01706             if (syncPatchNLayers[i] != patchNLayers[i])
01707             {
01708                 if
01709                 (
01710                     unmarkExtrusion
01711                     (
01712                         i,
01713                         patchDisp,
01714                         patchNLayers,
01715                         extrudeStatus
01716                     )
01717                 )
01718                 {
01719                     nChanged++;
01720                 }
01721             }
01722         }
01723         nChangedTotal += nChanged;
01724 
01725         if (!returnReduce(nChanged, sumOp<label>()))
01726         {
01727             break;
01728         }
01729     }
01730 
01731     Info<< "Prevented extrusion on "
01732         << returnReduce(nChangedTotal, sumOp<label>())
01733         << " coupled patch points during syncPatchDisplacement." << endl;
01734 }
01735 
01736 
01737 // Calculate displacement vector for all patch points. Uses pointNormal.
01738 // Checks that displaced patch point would be visible from all centres
01739 // of the faces using it.
01740 // extrudeStatus is both input and output and gives the status of each
01741 // patch point.
01742 void Foam::autoLayerDriver::getPatchDisplacement
01743 (
01744     const motionSmoother& meshMover,
01745     const scalarField& thickness,
01746     const scalarField& minThickness,
01747     pointField& patchDisp,
01748     labelList& patchNLayers,
01749     List<extrudeMode>& extrudeStatus
01750 ) const
01751 {
01752     Info<< nl << "Determining displacement for added points"
01753         << " according to pointNormal ..." << endl;
01754 
01755     const fvMesh& mesh = meshRefiner_.mesh();
01756     const indirectPrimitivePatch& pp = meshMover.patch();
01757     const vectorField& faceNormals = pp.faceNormals();
01758     const labelListList& pointFaces = pp.pointFaces();
01759     const pointField& localPoints = pp.localPoints();
01760     const labelList& meshPoints = pp.meshPoints();
01761 
01762     // Determine pointNormal
01763     // ~~~~~~~~~~~~~~~~~~~~~
01764 
01765     pointField pointNormals(pp.nPoints(), vector::zero);
01766     {
01767         labelList nPointFaces(pp.nPoints(), 0);
01768 
01769         forAll(faceNormals, faceI)
01770         {
01771             const face& f = pp.localFaces()[faceI];
01772 
01773             forAll(f, fp)
01774             {
01775                 pointNormals[f[fp]] += faceNormals[faceI];
01776                 nPointFaces[f[fp]] ++;
01777             }
01778         }
01779 
01780         syncTools::syncPointList
01781         (
01782             mesh,
01783             meshPoints,
01784             pointNormals,
01785             plusEqOp<vector>(),
01786             vector::zero,       // null value
01787             false               // no separation
01788         );
01789 
01790         syncTools::syncPointList
01791         (
01792             mesh,
01793             meshPoints,
01794             nPointFaces,
01795             plusEqOp<label>(),
01796             0,                  // null value
01797             false               // no separation
01798         );
01799 
01800         forAll(pointNormals, i)
01801         {
01802             pointNormals[i] /= nPointFaces[i];
01803         }
01804     }
01805 
01806 
01807     // Determine local length scale on patch
01808     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01809 
01810     // Start off from same thickness everywhere (except where no extrusion)
01811     patchDisp = thickness*pointNormals;
01812 
01813     // Check if no extrude possible.
01814     forAll(pointNormals, patchPointI)
01815     {
01816         label meshPointI = pp.meshPoints()[patchPointI];
01817 
01818         if (extrudeStatus[patchPointI] == NOEXTRUDE)
01819         {
01820             // Do not use unmarkExtrusion; forcibly set to zero extrusion.
01821             patchNLayers[patchPointI] = 0;
01822             patchDisp[patchPointI] = vector::zero;
01823         }
01824         else
01825         {
01826             // Get normal
01827             const vector& n = pointNormals[patchPointI];
01828 
01829             if (!meshTools::visNormal(n, faceNormals, pointFaces[patchPointI]))
01830             {
01831                 Pout<< "No valid normal for point " << meshPointI
01832                     << ' ' << pp.points()[meshPointI]
01833                     << "; setting displacement to " << patchDisp[patchPointI]
01834                     << endl;
01835 
01836                 extrudeStatus[patchPointI] = EXTRUDEREMOVE;
01837             }
01838         }
01839     }
01840 
01841     // At illegal points make displacement average of new neighbour positions
01842     forAll(extrudeStatus, patchPointI)
01843     {
01844         if (extrudeStatus[patchPointI] == EXTRUDEREMOVE)
01845         {
01846             point avg(vector::zero);
01847             label nPoints = 0;
01848 
01849             const labelList& pEdges = pp.pointEdges()[patchPointI];
01850 
01851             forAll(pEdges, i)
01852             {
01853                 label edgeI = pEdges[i];
01854 
01855                 label otherPointI = pp.edges()[edgeI].otherVertex(patchPointI);
01856 
01857                 if (extrudeStatus[otherPointI] != NOEXTRUDE)
01858                 {
01859                     avg += localPoints[otherPointI] + patchDisp[otherPointI];
01860                     nPoints++;
01861                 }
01862             }
01863 
01864             if (nPoints > 0)
01865             {
01866                 Pout<< "Displacement at illegal point "
01867                     << localPoints[patchPointI]
01868                     << " set to " << (avg / nPoints - localPoints[patchPointI])
01869                     << endl;
01870 
01871                 patchDisp[patchPointI] =
01872                     avg / nPoints
01873                   - localPoints[patchPointI];
01874             }
01875         }
01876     }
01877 
01878     // Make sure displacement is equal on both sides of coupled patches.
01879     syncPatchDisplacement
01880     (
01881         meshMover,
01882         minThickness,
01883         patchDisp,
01884         patchNLayers,
01885         extrudeStatus
01886     );
01887 
01888     Info<< endl;
01889 }
01890 
01891 
01892 // Truncates displacement
01893 // - for all patchFaces in the faceset displacement gets set to zero
01894 // - all displacement < minThickness gets set to zero
01895 Foam::label Foam::autoLayerDriver::truncateDisplacement
01896 (
01897     const motionSmoother& meshMover,
01898     const scalarField& minThickness,
01899     const faceSet& illegalPatchFaces,
01900     pointField& patchDisp,
01901     labelList& patchNLayers,
01902     List<extrudeMode>& extrudeStatus
01903 ) const
01904 {
01905     const polyMesh& mesh = meshMover.mesh();
01906     const indirectPrimitivePatch& pp = meshMover.patch();
01907 
01908     label nChanged = 0;
01909 
01910     const Map<label>& meshPointMap = pp.meshPointMap();
01911 
01912     forAllConstIter(faceSet, illegalPatchFaces, iter)
01913     {
01914         label faceI = iter.key();
01915 
01916         if (mesh.isInternalFace(faceI))
01917         {
01918             FatalErrorIn("truncateDisplacement(..)")
01919                 << "Faceset " << illegalPatchFaces.name()
01920                 << " contains internal face " << faceI << nl
01921                 << "It should only contain patch faces" << abort(FatalError);
01922         }
01923 
01924         const face& f = mesh.faces()[faceI];
01925 
01926 
01927         forAll(f, fp)
01928         {
01929             if (meshPointMap.found(f[fp]))
01930             {
01931                 label patchPointI = meshPointMap[f[fp]];
01932 
01933                 if (extrudeStatus[patchPointI] != NOEXTRUDE)
01934                 {
01935                     unmarkExtrusion
01936                     (
01937                         patchPointI,
01938                         patchDisp,
01939                         patchNLayers,
01940                         extrudeStatus
01941                     );
01942                     nChanged++;
01943                 }
01944             }
01945         }
01946     }
01947 
01948     forAll(patchDisp, patchPointI)
01949     {
01950         if (mag(patchDisp[patchPointI]) < minThickness[patchPointI])
01951         {
01952             if
01953             (
01954                 unmarkExtrusion
01955                 (
01956                     patchPointI,
01957                     patchDisp,
01958                     patchNLayers,
01959                     extrudeStatus
01960                 )
01961             )
01962             {
01963                 nChanged++;
01964             }
01965         }
01966         else if (extrudeStatus[patchPointI] == NOEXTRUDE)
01967         {
01968             // Make sure displacement is 0. Should already be so but ...
01969             patchDisp[patchPointI] = vector::zero;
01970             patchNLayers[patchPointI] = 0;
01971         }
01972     }
01973 
01974 
01975     const faceList& localFaces = pp.localFaces();
01976 
01977     while (true)
01978     {
01979         syncPatchDisplacement
01980         (
01981             meshMover,
01982             minThickness,
01983             patchDisp,
01984             patchNLayers,
01985             extrudeStatus
01986         );
01987 
01988         // Make sure that a face doesn't have two non-consecutive areas
01989         // not extruded (e.g. quad where vertex 0 and 2 are not extruded
01990         // but 1 and 3 are) since this gives topological errors.
01991 
01992         label nPinched = 0;
01993 
01994         forAll(localFaces, i)
01995         {
01996             const face& localF = localFaces[i];
01997 
01998             // Count number of transitions from unsnapped to snapped.
01999             label nTrans = 0;
02000 
02001             extrudeMode prevMode = extrudeStatus[localF.prevLabel(0)];
02002 
02003             forAll(localF, fp)
02004             {
02005                 extrudeMode fpMode = extrudeStatus[localF[fp]];
02006 
02007                 if (prevMode == NOEXTRUDE && fpMode != NOEXTRUDE)
02008                 {
02009                     nTrans++;
02010                 }
02011                 prevMode = fpMode;
02012             }
02013 
02014             if (nTrans > 1)
02015             {
02016                 // Multiple pinches. Reset whole face as unextruded.
02017                 if
02018                 (
02019                     unmarkExtrusion
02020                     (
02021                         localF,
02022                         patchDisp,
02023                         patchNLayers,
02024                         extrudeStatus
02025                     )
02026                 )
02027                 {
02028                     nPinched++;
02029                     nChanged++;
02030                 }
02031             }
02032         }
02033 
02034         reduce(nPinched, sumOp<label>());
02035 
02036         Info<< "truncateDisplacement : Unextruded " << nPinched
02037             << " faces due to non-consecutive vertices being extruded." << endl;
02038 
02039 
02040         // Make sure that a face has consistent number of layers for all
02041         // its vertices.
02042 
02043         label nDiffering = 0;
02044 
02045         //forAll(localFaces, i)
02046         //{
02047         //    const face& localF = localFaces[i];
02048         //
02049         //    label numLayers = -1;
02050         //
02051         //    forAll(localF, fp)
02052         //    {
02053         //        if (patchNLayers[localF[fp]] > 0)
02054         //        {
02055         //            if (numLayers == -1)
02056         //            {
02057         //                numLayers = patchNLayers[localF[fp]];
02058         //            }
02059         //            else if (numLayers != patchNLayers[localF[fp]])
02060         //            {
02061         //                // Differing number of layers
02062         //                if
02063         //                (
02064         //                    unmarkExtrusion
02065         //                    (
02066         //                        localF,
02067         //                        patchDisp,
02068         //                        patchNLayers,
02069         //                        extrudeStatus
02070         //                    )
02071         //                )
02072         //                {
02073         //                    nDiffering++;
02074         //                    nChanged++;
02075         //                }
02076         //                break;
02077         //            }
02078         //        }
02079         //    }
02080         //}
02081         //
02082         //reduce(nDiffering, sumOp<label>());
02083         //
02084         //Info<< "truncateDisplacement : Unextruded " << nDiffering
02085         //    << " faces due to having differing number of layers." << endl;
02086 
02087         if (nPinched+nDiffering == 0)
02088         {
02089             break;
02090         }
02091     }
02092 
02093     return nChanged;
02094 }
02095 
02096 
02097 // Setup layer information (at points and faces) to modify mesh topology in
02098 // regions where layer mesh terminates.
02099 void Foam::autoLayerDriver::setupLayerInfoTruncation
02100 (
02101     const motionSmoother& meshMover,
02102     const labelList& patchNLayers,
02103     const List<extrudeMode>& extrudeStatus,
02104     const label nBufferCellsNoExtrude,
02105     labelList& nPatchPointLayers,
02106     labelList& nPatchFaceLayers
02107 ) const
02108 {
02109     Info<< nl << "Setting up information for layer truncation ..." << endl;
02110 
02111     const indirectPrimitivePatch& pp = meshMover.patch();
02112     const polyMesh& mesh = meshMover.mesh();
02113 
02114     if (nBufferCellsNoExtrude < 0)
02115     {
02116         Info<< nl << "Performing no layer truncation."
02117             << " nBufferCellsNoExtrude set to less than 0  ..." << endl;
02118 
02119         // Face layers if any point get extruded
02120         forAll(pp.localFaces(), patchFaceI)
02121         {
02122             const face& f = pp.localFaces()[patchFaceI];
02123 
02124             forAll(f, fp)
02125             {
02126                 if (patchNLayers[f[fp]] > 0)
02127                 {
02128                     nPatchFaceLayers[patchFaceI] = patchNLayers[f[fp]];
02129                     break;
02130                 }
02131             }
02132         }
02133         nPatchPointLayers = patchNLayers;
02134     }
02135     else
02136     {
02137         // Determine max point layers per face.
02138         labelList maxLevel(pp.size(), 0);
02139 
02140         forAll(pp.localFaces(), patchFaceI)
02141         {
02142             const face& f = pp.localFaces()[patchFaceI];
02143 
02144             // find patch faces where layer terminates (i.e contains extrude
02145             // and noextrude points).
02146 
02147             bool noExtrude = false;
02148             label mLevel = 0;
02149 
02150             forAll(f, fp)
02151             {
02152                 if (extrudeStatus[f[fp]] == NOEXTRUDE)
02153                 {
02154                     noExtrude = true;
02155                 }
02156                 mLevel = max(mLevel, patchNLayers[f[fp]]);
02157             }
02158 
02159             if (mLevel > 0)
02160             {
02161                 // So one of the points is extruded. Check if all are extruded
02162                 // or is a mix.
02163 
02164                 if (noExtrude)
02165                 {
02166                     nPatchFaceLayers[patchFaceI] = 1;
02167                     maxLevel[patchFaceI] = mLevel;
02168                 }
02169                 else
02170                 {
02171                     maxLevel[patchFaceI] = mLevel;
02172                 }
02173             }
02174         }
02175 
02176         // We have the seed faces (faces with nPatchFaceLayers != maxLevel)
02177         // Now do a meshwave across the patch where we pick up neighbours
02178         // of seed faces.
02179         // Note: quite inefficient. Could probably be coded better.
02180 
02181         const labelListList& pointFaces = pp.pointFaces();
02182 
02183         label nLevels = gMax(patchNLayers);
02184 
02185         // flag neighbouring patch faces with number of layers to grow
02186         for (label ilevel = 1; ilevel < nLevels; ilevel++)
02187         {
02188             label nBuffer;
02189 
02190             if (ilevel == 1)
02191             {
02192                 nBuffer = nBufferCellsNoExtrude - 1;
02193             }
02194             else
02195             {
02196                 nBuffer = nBufferCellsNoExtrude;
02197             }
02198 
02199             for (label ibuffer = 0; ibuffer < nBuffer + 1; ibuffer++)
02200             {
02201                 labelList tempCounter(nPatchFaceLayers);
02202 
02203                 boolList foundNeighbour(pp.nPoints(), false);
02204 
02205                 forAll(pp.meshPoints(), patchPointI)
02206                 {
02207                     forAll(pointFaces[patchPointI], pointFaceI)
02208                     {
02209                         label faceI = pointFaces[patchPointI][pointFaceI];
02210 
02211                         if
02212                         (
02213                             nPatchFaceLayers[faceI] != -1
02214                          && maxLevel[faceI] > 0
02215                         )
02216                         {
02217                             foundNeighbour[patchPointI] = true;
02218                             break;
02219                         }
02220                     }
02221                 }
02222 
02223                 syncTools::syncPointList
02224                 (
02225                     mesh,
02226                     pp.meshPoints(),
02227                     foundNeighbour,
02228                     orEqOp<bool>(),
02229                     false,              // null value
02230                     false               // no separation
02231                 );
02232 
02233                 forAll(pp.meshPoints(), patchPointI)
02234                 {
02235                     if (foundNeighbour[patchPointI])
02236                     {
02237                         forAll(pointFaces[patchPointI], pointFaceI)
02238                         {
02239                             label faceI = pointFaces[patchPointI][pointFaceI];
02240                             if
02241                             (
02242                                 nPatchFaceLayers[faceI] == -1
02243                              && maxLevel[faceI] > 0
02244                              && ilevel < maxLevel[faceI]
02245                             )
02246                             {
02247                                 tempCounter[faceI] = ilevel;
02248                             }
02249                         }
02250                     }
02251                 }
02252                 nPatchFaceLayers = tempCounter;
02253             }
02254         }
02255 
02256         forAll(pp.localFaces(), patchFaceI)
02257         {
02258             if (nPatchFaceLayers[patchFaceI] == -1)
02259             {
02260                 nPatchFaceLayers[patchFaceI] = maxLevel[patchFaceI];
02261             }
02262         }
02263 
02264         forAll(pp.meshPoints(), patchPointI)
02265         {
02266             if (extrudeStatus[patchPointI] != NOEXTRUDE)
02267             {
02268                 forAll(pointFaces[patchPointI], pointFaceI)
02269                 {
02270                     label face = pointFaces[patchPointI][pointFaceI];
02271                     nPatchPointLayers[patchPointI] = max
02272                     (
02273                         nPatchPointLayers[patchPointI],
02274                         nPatchFaceLayers[face]
02275                     );
02276                 }
02277             }
02278             else
02279             {
02280                 nPatchPointLayers[patchPointI] = 0;
02281             }
02282         }
02283         syncTools::syncPointList
02284         (
02285             mesh,
02286             pp.meshPoints(),
02287             nPatchPointLayers,
02288             maxEqOp<label>(),
02289             0,                  // null value
02290             false               // no separation
02291         );
02292     }
02293 }
02294 
02295 
02296 // Does any of the cells use a face from faces?
02297 bool Foam::autoLayerDriver::cellsUseFace
02298 (
02299     const polyMesh& mesh,
02300     const labelList& cellLabels,
02301     const labelHashSet& faces
02302 )
02303 {
02304     forAll(cellLabels, i)
02305     {
02306         const cell& cFaces = mesh.cells()[cellLabels[i]];
02307 
02308         forAll(cFaces, cFaceI)
02309         {
02310             if (faces.found(cFaces[cFaceI]))
02311             {
02312                 return true;
02313             }
02314         }
02315     }
02316     return false;
02317 }
02318 
02319 
02320 // Checks the newly added cells and locally unmarks points so they
02321 // will not get extruded next time round. Returns global number of unmarked
02322 // points (0 if all was fine)
02323 Foam::label Foam::autoLayerDriver::checkAndUnmark
02324 (
02325     const addPatchCellLayer& addLayer,
02326     const dictionary& meshQualityDict,
02327     const indirectPrimitivePatch& pp,
02328     const fvMesh& newMesh,
02329 
02330     pointField& patchDisp,
02331     labelList& patchNLayers,
02332     List<extrudeMode>& extrudeStatus
02333 )
02334 {
02335     // Check the resulting mesh for errors
02336     Info<< nl << "Checking mesh with layer ..." << endl;
02337     faceSet wrongFaces(newMesh, "wrongFaces", newMesh.nFaces()/1000);
02338     motionSmoother::checkMesh(false, newMesh, meshQualityDict, wrongFaces);
02339     Info<< "Detected " << returnReduce(wrongFaces.size(), sumOp<label>())
02340         << " illegal faces"
02341         << " (concave, zero area or negative cell pyramid volume)"
02342         << endl;
02343 
02344     // Undo local extrusion if
02345     // - any of the added cells in error
02346 
02347     label nChanged = 0;
02348 
02349     // Get all cells in the layer.
02350     labelListList addedCells
02351     (
02352         addPatchCellLayer::addedCells
02353         (
02354             newMesh,
02355             addLayer.layerFaces()
02356         )
02357     );
02358 
02359     // Check if any of the faces in error uses any face of an added cell
02360     forAll(addedCells, oldPatchFaceI)
02361     {
02362         // Get the cells (in newMesh labels) per old patch face (in mesh
02363         // labels)
02364         const labelList& fCells = addedCells[oldPatchFaceI];
02365 
02366         if (cellsUseFace(newMesh, fCells, wrongFaces))
02367         {
02368             // Unmark points on old mesh
02369             if
02370             (
02371                 unmarkExtrusion
02372                 (
02373                     pp.localFaces()[oldPatchFaceI],
02374                     patchDisp,
02375                     patchNLayers,
02376                     extrudeStatus
02377                 )
02378             )
02379             {
02380                 nChanged++;
02381             }
02382         }
02383     }
02384 
02385     return returnReduce(nChanged, sumOp<label>());
02386 }
02387 
02388 
02389 //- Count global number of extruded faces
02390 Foam::label Foam::autoLayerDriver::countExtrusion
02391 (
02392     const indirectPrimitivePatch& pp,
02393     const List<extrudeMode>& extrudeStatus
02394 )
02395 {
02396     // Count number of extruded patch faces
02397     label nExtruded = 0;
02398     {
02399         const faceList& localFaces = pp.localFaces();
02400 
02401         forAll(localFaces, i)
02402         {
02403             const face& localFace = localFaces[i];
02404 
02405             forAll(localFace, fp)
02406             {
02407                 if (extrudeStatus[localFace[fp]] != NOEXTRUDE)
02408                 {
02409                     nExtruded++;
02410                     break;
02411                 }
02412             }
02413         }
02414     }
02415 
02416     return returnReduce(nExtruded, sumOp<label>());
02417 }
02418 
02419 
02420 // Collect layer faces and layer cells into bools for ease of handling
02421 void Foam::autoLayerDriver::getLayerCellsFaces
02422 (
02423     const polyMesh& mesh,
02424     const addPatchCellLayer& addLayer,
02425     boolList& flaggedCells,
02426     boolList& flaggedFaces
02427 )
02428 {
02429     flaggedCells.setSize(mesh.nCells());
02430     flaggedCells = false;
02431     flaggedFaces.setSize(mesh.nFaces());
02432     flaggedFaces = false;
02433 
02434     // Mark all faces in the layer
02435     const labelListList& layerFaces = addLayer.layerFaces();
02436 
02437     // Mark all cells in the layer.
02438     labelListList addedCells(addPatchCellLayer::addedCells(mesh, layerFaces));
02439 
02440     forAll(addedCells, oldPatchFaceI)
02441     {
02442         const labelList& added = addedCells[oldPatchFaceI];
02443 
02444         forAll(added, i)
02445         {
02446             flaggedCells[added[i]] = true;
02447         }
02448     }
02449 
02450     forAll(layerFaces, oldPatchFaceI)
02451     {
02452         const labelList& layer = layerFaces[oldPatchFaceI];
02453 
02454         if (layer.size())
02455         {
02456             for (label i = 1; i < layer.size()-1; i++)
02457             {
02458                 flaggedFaces[layer[i]] = true;
02459             }
02460         }
02461     }
02462 }
02463 
02464 
02465 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
02466 
02467 Foam::autoLayerDriver::autoLayerDriver(meshRefinement& meshRefiner)
02468 :
02469     meshRefiner_(meshRefiner)
02470 {}
02471 
02472 
02473 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
02474 
02475 void Foam::autoLayerDriver::mergePatchFacesUndo
02476 (
02477     const layerParameters& layerParams,
02478     const dictionary& motionDict
02479 )
02480 {
02481     scalar minCos = Foam::cos
02482     (
02483         layerParams.featureAngle()
02484       * mathematicalConstant::pi/180.0
02485     );
02486 
02487     scalar concaveCos = Foam::cos
02488     (
02489         layerParams.concaveAngle()
02490       * mathematicalConstant::pi/180.0
02491     );
02492 
02493     Info<< nl
02494         << "Merging all faces of a cell" << nl
02495         << "---------------------------" << nl
02496         << "    - which are on the same patch" << nl
02497         << "    - which make an angle < " << layerParams.featureAngle()
02498         << " degrees"
02499         << nl
02500         << "      (cos:" << minCos << ')' << nl
02501         << "    - as long as the resulting face doesn't become concave"
02502         << " by more than "
02503         << layerParams.concaveAngle() << " degrees" << nl
02504         << "      (0=straight, 180=fully concave)" << nl
02505         << endl;
02506 
02507     label nChanged = mergePatchFacesUndo(minCos, concaveCos, motionDict);
02508 
02509     nChanged += mergeEdgesUndo(minCos, motionDict);
02510 }
02511 
02512 
02513 void Foam::autoLayerDriver::addLayers
02514 (
02515     const layerParameters& layerParams,
02516     const dictionary& motionDict,
02517     const labelList& patchIDs,
02518     const label nAllowableErrors,
02519     decompositionMethod& decomposer,
02520     fvMeshDistribute& distributor
02521 )
02522 {
02523     fvMesh& mesh = meshRefiner_.mesh();
02524 
02525     autoPtr<indirectPrimitivePatch> pp
02526     (
02527         meshRefinement::makePatch
02528         (
02529             mesh,
02530             patchIDs
02531         )
02532     );
02533 
02534     // Construct iterative mesh mover.
02535     Info<< "Constructing mesh displacer ..." << endl;
02536 
02537     autoPtr<motionSmoother> meshMover
02538     (
02539         new motionSmoother
02540         (
02541             mesh,
02542             pp(),
02543             patchIDs,
02544             meshRefinement::makeDisplacementField
02545             (
02546                 pointMesh::New(mesh),
02547                 patchIDs
02548             ),
02549             motionDict
02550         )
02551     );
02552 
02553 
02554     // Point-wise extrusion data
02555     // ~~~~~~~~~~~~~~~~~~~~~~~~~
02556 
02557     // Displacement for all pp.localPoints.
02558     vectorField patchDisp(pp().nPoints(), vector::one);
02559 
02560     // Number of layers for all pp.localPoints. Note: only valid if
02561     // extrudeStatus = EXTRUDE.
02562     labelList patchNLayers(pp().nPoints(), 0);
02563 
02564     // Whether to add edge for all pp.localPoints.
02565     List<extrudeMode> extrudeStatus(pp().nPoints(), EXTRUDE);
02566 
02567     {
02568         // Get number of layer per point from number of layers per patch
02569         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02570 
02571         setNumLayers
02572         (
02573             layerParams.numLayers(),    // per patch the num layers
02574             meshMover().adaptPatchIDs(),// patches that are being moved
02575             pp,                         // indirectpatch for all faces moving
02576 
02577             patchDisp,
02578             patchNLayers,
02579             extrudeStatus
02580         );
02581 
02582         // Precalculate mesh edge labels for patch edges
02583         labelList meshEdges(pp().meshEdges(mesh.edges(), mesh.pointEdges()));
02584 
02585         // Disable extrusion on non-manifold points
02586         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02587 
02588         handleNonManifolds
02589         (
02590             pp,
02591             meshEdges,
02592 
02593             patchDisp,
02594             patchNLayers,
02595             extrudeStatus
02596         );
02597 
02598         // Disable extrusion on feature angles
02599         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02600 
02601         handleFeatureAngle
02602         (
02603             pp,
02604             meshEdges,
02605             layerParams.featureAngle()*mathematicalConstant::pi/180.0,
02606 
02607             patchDisp,
02608             patchNLayers,
02609             extrudeStatus
02610         );
02611 
02612         // Disable extrusion on warped faces
02613         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02614 
02615         // Undistorted edge length
02616         const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength();
02617         const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel();
02618 
02619         handleWarpedFaces
02620         (
02621             pp,
02622             layerParams.maxFaceThicknessRatio(),
02623             edge0Len,
02624             cellLevel,
02625 
02626             patchDisp,
02627             patchNLayers,
02628             extrudeStatus
02629         );
02630 
02633         //
02634         //handleMultiplePatchFaces
02635         //(
02636         //    pp,
02637         //
02638         //    patchDisp,
02639         //    patchNLayers,
02640         //    extrudeStatus
02641         //);
02642 
02643 
02644         // Grow out region of non-extrusion
02645         for (label i = 0; i < layerParams.nGrow(); i++)
02646         {
02647             growNoExtrusion
02648             (
02649                 pp,
02650                 patchDisp,
02651                 patchNLayers,
02652                 extrudeStatus
02653             );
02654         }
02655     }
02656 
02657 
02658     // Undistorted edge length
02659     const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength();
02660     const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel();
02661 
02662     // Determine (wanted) point-wise layer thickness and expansion ratio
02663     scalarField thickness(pp().nPoints());
02664     scalarField minThickness(pp().nPoints());
02665     scalarField expansionRatio(pp().nPoints());
02666     calculateLayerThickness
02667     (
02668         pp,
02669         meshMover().adaptPatchIDs(),
02670         layerParams.expansionRatio(),
02671 
02672         layerParams.relativeSizes(),        // thickness relative to cellsize?
02673         layerParams.finalLayerThickness(),  // wanted thicknes
02674         layerParams.minThickness(),         // minimum thickness
02675 
02676         cellLevel,
02677         patchNLayers,
02678         edge0Len,
02679 
02680         thickness,
02681         minThickness,
02682         expansionRatio
02683     );
02684 
02685 
02686     // Print a bit
02687     {
02688         const polyBoundaryMesh& patches = mesh.boundaryMesh();
02689 
02690         // Find maximum length of a patch name, for a nicer output
02691         label maxPatchNameLen = 0;
02692         forAll(meshMover().adaptPatchIDs(), i)
02693         {
02694             label patchI = meshMover().adaptPatchIDs()[i];
02695             word patchName = patches[patchI].name();
02696             maxPatchNameLen = max(maxPatchNameLen, label(patchName.size()));
02697         }
02698 
02699         Info<< nl
02700             << setf(ios_base::left) << setw(maxPatchNameLen) << "patch"
02701             << setw(0) << " faces    layers avg thickness[m]" << nl
02702             << setf(ios_base::left) << setw(maxPatchNameLen) << " "
02703             << setw(0) << "                 near-wall overall" << nl
02704             << setf(ios_base::left) << setw(maxPatchNameLen) << "-----"
02705             << setw(0) << " -----    ------ --------- -------" << endl;
02706 
02707         forAll(meshMover().adaptPatchIDs(), i)
02708         {
02709             label patchI = meshMover().adaptPatchIDs()[i];
02710 
02711             const labelList& meshPoints = patches[patchI].meshPoints();
02712 
02713             //scalar maxThickness = -VGREAT;
02714             //scalar minThickness = VGREAT;
02715             scalar sumThickness = 0;
02716             scalar sumNearWallThickness = 0;
02717 
02718             forAll(meshPoints, patchPointI)
02719             {
02720                 label ppPointI = pp().meshPointMap()[meshPoints[patchPointI]];
02721 
02722                 //maxThickness = max(maxThickness, thickness[ppPointI]);
02723                 //minThickness = min(minThickness, thickness[ppPointI]);
02724                 sumThickness += thickness[ppPointI];
02725 
02726                 label nLay = patchNLayers[ppPointI];
02727                 if (nLay > 0)
02728                 {
02729                     if (expansionRatio[ppPointI] == 1)
02730                     {
02731                         sumNearWallThickness += thickness[ppPointI]/nLay;
02732                     }
02733                     else
02734                     {
02735                         scalar s =
02736                             (1.0-pow(expansionRatio[ppPointI], nLay))
02737                           / (1.0-expansionRatio[ppPointI]);
02738                         sumNearWallThickness += thickness[ppPointI]/s;
02739                     }
02740                 }
02741             }
02742 
02743             label totNPoints = returnReduce(meshPoints.size(), sumOp<label>());
02744 
02745             // For empty patches, totNPoints is 0.
02746             scalar avgThickness = 0;
02747             scalar avgNearWallThickness = 0;
02748 
02749             if (totNPoints > 0)
02750             {
02751                 //reduce(maxThickness, maxOp<scalar>());
02752                 //reduce(minThickness, minOp<scalar>());
02753                 avgThickness =
02754                     returnReduce(sumThickness, sumOp<scalar>())
02755                   / totNPoints;
02756                 avgNearWallThickness =
02757                     returnReduce(sumNearWallThickness, sumOp<scalar>())
02758                   / totNPoints;
02759             }
02760 
02761             Info<< setf(ios_base::left) << setw(maxPatchNameLen)
02762                 << patches[patchI].name() << setprecision(3)
02763                 << " " << setw(8)
02764                 << returnReduce(patches[patchI].size(), sumOp<scalar>())
02765                 << " " << setw(6) << layerParams.numLayers()[patchI]
02766                 << " " << setw(8) << avgNearWallThickness
02767                 << "  " << setw(8) << avgThickness
02768                 //<< " " << setw(8) << minThickness
02769                 //<< " " << setw(8) << maxThickness
02770                 << endl;
02771         }
02772         Info<< endl;
02773     }
02774 
02775 
02776     // Calculate wall to medial axis distance for smoothing displacement
02777     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02778 
02779     pointScalarField pointMedialDist
02780     (
02781         IOobject
02782         (
02783             "pointMedialDist",
02784             meshRefiner_.timeName(),
02785             mesh,
02786             IOobject::NO_READ,
02787             IOobject::NO_WRITE,
02788             false
02789         ),
02790         meshMover().pMesh(),
02791         dimensionedScalar("pointMedialDist", dimless, 0.0)
02792     );
02793 
02794     pointVectorField dispVec
02795     (
02796         IOobject
02797         (
02798             "dispVec",
02799             meshRefiner_.timeName(),
02800             mesh,
02801             IOobject::NO_READ,
02802             IOobject::NO_WRITE,
02803             false
02804         ),
02805         meshMover().pMesh(),
02806         dimensionedVector("dispVec", dimless, vector::zero)
02807     );
02808 
02809     pointScalarField medialRatio
02810     (
02811         IOobject
02812         (
02813             "medialRatio",
02814             meshRefiner_.timeName(),
02815             mesh,
02816             IOobject::NO_READ,
02817             IOobject::NO_WRITE,
02818             false
02819         ),
02820         meshMover().pMesh(),
02821         dimensionedScalar("medialRatio", dimless, 0.0)
02822     );
02823 
02824     // Setup information for medial axis smoothing. Calculates medial axis
02825     // and a smoothed displacement direction.
02826     // - pointMedialDist : distance to medial axis
02827     // - dispVec : normalised direction of nearest displacement
02828     // - medialRatio : ratio of medial distance to wall distance.
02829     //   (1 at wall, 0 at medial axis)
02830     medialAxisSmoothingInfo
02831     (
02832         meshMover,
02833         layerParams.nSmoothNormals(),
02834         layerParams.nSmoothSurfaceNormals(),
02835         layerParams.minMedianAxisAngleCos(),
02836 
02837         dispVec,
02838         medialRatio,
02839         pointMedialDist
02840     );
02841 
02842 
02843 
02844     // Saved old points
02845     pointField oldPoints(mesh.points());
02846 
02847     // Last set of topology changes. (changing mesh clears out polyTopoChange)
02848     polyTopoChange savedMeshMod(mesh.boundaryMesh().size());
02849 
02850     boolList flaggedCells;
02851     boolList flaggedFaces;
02852 
02853     for (label iteration = 0; iteration < layerParams.nLayerIter(); iteration++)
02854     {
02855         Info<< nl
02856             << "Layer addition iteration " << iteration << nl
02857             << "--------------------------" << endl;
02858 
02859 
02860         // Unset the extrusion at the pp.
02861         const dictionary& meshQualityDict =
02862         (
02863             iteration < layerParams.nRelaxedIter()
02864           ? motionDict
02865           : motionDict.subDict("relaxed")
02866         );
02867 
02868         if (iteration >= layerParams.nRelaxedIter())
02869         {
02870             Info<< "Switched to relaxed meshQuality constraints." << endl;
02871         }
02872 
02873 
02874 
02875         // Make sure displacement is equal on both sides of coupled patches.
02876         syncPatchDisplacement
02877         (
02878             meshMover,
02879             minThickness,
02880             patchDisp,
02881             patchNLayers,
02882             extrudeStatus
02883         );
02884 
02885         // Displacement acc. to pointnormals
02886         getPatchDisplacement
02887         (
02888             meshMover,
02889             thickness,
02890             minThickness,
02891             patchDisp,
02892             patchNLayers,
02893             extrudeStatus
02894         );
02895 
02896         // Shrink mesh by displacement value first.
02897         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02898 
02899         {
02900             pointField oldPatchPos(pp().localPoints());
02901 
02903             //shrinkMeshDistance
02904             //(
02905             //    debug,
02906             //    meshMover,
02907             //    -patchDisp,     // Shrink in opposite direction of addedPoints
02908             //    layerParams.nSmoothDisp(),
02909             //    layerParams.nSnap()
02910             //);
02911 
02912             // Medial axis based shrinking
02913             shrinkMeshMedialDistance
02914             (
02915                 meshMover(),
02916                 meshQualityDict,
02917 
02918                 layerParams.nSmoothThickness(),
02919                 layerParams.maxThicknessToMedialRatio(),
02920                 nAllowableErrors,
02921                 layerParams.nSnap(),
02922                 layerParams.layerTerminationCos(),
02923 
02924                 thickness,
02925                 minThickness,
02926 
02927                 dispVec,
02928                 medialRatio,
02929                 pointMedialDist,
02930 
02931                 extrudeStatus,
02932                 patchDisp,
02933                 patchNLayers
02934             );
02935 
02936             // Update patchDisp (since not all might have been honoured)
02937             patchDisp = oldPatchPos - pp().localPoints();
02938         }
02939 
02940         // Truncate displacements that are too small (this will do internal
02941         // ones, coupled ones have already been truncated by syncPatch)
02942         faceSet dummySet(mesh, "wrongPatchFaces", 0);
02943         truncateDisplacement
02944         (
02945             meshMover(),
02946             minThickness,
02947             dummySet,
02948             patchDisp,
02949             patchNLayers,
02950             extrudeStatus
02951         );
02952 
02953 
02954         // Dump to .obj file for debugging.
02955         if (debug)
02956         {
02957             dumpDisplacement
02958             (
02959                 mesh.time().path()/"layer",
02960                 pp(),
02961                 patchDisp,
02962                 extrudeStatus
02963             );
02964 
02965             const_cast<Time&>(mesh.time())++;
02966             Info<< "Writing shrunk mesh to " << meshRefiner_.timeName() << endl;
02967 
02968             // See comment in autoSnapDriver why we should not remove meshPhi
02969             // using mesh.clearPout().
02970 
02971             mesh.write();
02972         }
02973 
02974 
02975         // Mesh topo change engine
02976         polyTopoChange meshMod(mesh);
02977 
02978         // Grow layer of cells on to patch. Handles zero sized displacement.
02979         addPatchCellLayer addLayer(mesh);
02980 
02981         // Determine per point/per face number of layers to extrude. Also
02982         // handles the slow termination of layers when going switching layers
02983 
02984         labelList nPatchPointLayers(pp().nPoints(),-1);
02985         labelList nPatchFaceLayers(pp().localFaces().size(),-1);
02986         setupLayerInfoTruncation
02987         (
02988             meshMover(),
02989             patchNLayers,
02990             extrudeStatus,
02991             layerParams.nBufferCellsNoExtrude(),
02992             nPatchPointLayers,
02993             nPatchFaceLayers
02994         );
02995 
02996         // Calculate displacement for first layer for addPatchLayer.
02997         // (first layer = layer of cells next to the original mesh)
02998         vectorField firstDisp(patchNLayers.size(), vector::zero);
02999 
03000         forAll(patchNLayers, i)
03001         {
03002             if (patchNLayers[i] > 0)
03003             {
03004                 if (expansionRatio[i] == 1.0)
03005                 {
03006                     firstDisp[i] = patchDisp[i]/nPatchPointLayers[i];
03007                 }
03008                 else
03009                 {
03010                     label nLay = nPatchPointLayers[i];
03011                     scalar h =
03012                         pow(expansionRatio[i], nLay - 1)
03013                       * (1.0 - expansionRatio[i])
03014                       / (1.0 - pow(expansionRatio[i], nLay));
03015                     firstDisp[i] = h*patchDisp[i];
03016                 }
03017             }
03018         }
03019 
03020         scalarField invExpansionRatio = 1.0 / expansionRatio;
03021 
03022         // Add topo regardless of whether extrudeStatus is extruderemove.
03023         // Not add layer if patchDisp is zero.
03024         addLayer.setRefinement
03025         (
03026             invExpansionRatio,
03027             pp(),
03028             nPatchFaceLayers,   // layers per face
03029             nPatchPointLayers,  // layers per point
03030             firstDisp,          // thickness of layer nearest internal mesh
03031             meshMod
03032         );
03033 
03034         if (debug)
03035         {
03036             const_cast<Time&>(mesh.time())++;
03037         }
03038 
03039         // Store mesh changes for if mesh is correct.
03040         savedMeshMod = meshMod;
03041 
03042 
03043         // With the stored topo changes we create a new mesh so we can
03044         // undo if necessary.
03045 
03046         autoPtr<fvMesh> newMeshPtr;
03047         autoPtr<mapPolyMesh> map = meshMod.makeMesh
03048         (
03049             newMeshPtr,
03050             IOobject
03051             (
03052                 //mesh.name()+"_layer",
03053                 mesh.name(),
03054                 static_cast<polyMesh&>(mesh).instance(),
03055                 mesh.time(),  // register with runTime
03056                 static_cast<polyMesh&>(mesh).readOpt(),
03057                 static_cast<polyMesh&>(mesh).writeOpt()
03058             ),              // io params from original mesh but new name
03059             mesh,           // original mesh
03060             true            // parallel sync
03061         );
03062         fvMesh& newMesh = newMeshPtr();
03063 
03064         //?neccesary? Update fields
03065         newMesh.updateMesh(map);
03066 
03067         if (meshRefiner_.overwrite())
03068         {
03069             newMesh.setInstance(meshRefiner_.oldInstance());
03070         }
03071 
03072         // Update numbering on addLayer:
03073         // - cell/point labels to be newMesh.
03074         // - patchFaces to remain in oldMesh order.
03075         addLayer.updateMesh
03076         (
03077             map,
03078             identity(pp().size()),
03079             identity(pp().nPoints())
03080         );
03081 
03082         // Collect layer faces and cells for outside loop.
03083         getLayerCellsFaces
03084         (
03085             newMesh,
03086             addLayer,
03087             flaggedCells,
03088             flaggedFaces
03089         );
03090 
03091 
03092         if (debug)
03093         {
03094             Info<< "Writing layer mesh to " << meshRefiner_.timeName() << endl;
03095             newMesh.write();
03096             cellSet addedCellSet
03097             (
03098                 newMesh,
03099                 "addedCells",
03100                 findIndices(flaggedCells, true)
03101             );
03102             Info<< "Writing "
03103                 << returnReduce(addedCellSet.size(), sumOp<label>())
03104                 << " added cells to cellSet "
03105                 << addedCellSet.name() << endl;
03106             addedCellSet.write();
03107 
03108             faceSet layerFacesSet
03109             (
03110                 newMesh,
03111                 "layerFaces",
03112                 findIndices(flaggedCells, true)
03113             );
03114             Info<< "Writing "
03115                 << returnReduce(layerFacesSet.size(), sumOp<label>())
03116                 << " faces inside added layer to faceSet "
03117                 << layerFacesSet.name() << endl;
03118             layerFacesSet.write();
03119         }
03120 
03121 
03122         label nTotChanged = checkAndUnmark
03123         (
03124             addLayer,
03125             meshQualityDict,
03126             pp(),
03127             newMesh,
03128 
03129             patchDisp,
03130             patchNLayers,
03131             extrudeStatus
03132         );
03133 
03134         Info<< "Extruding " << countExtrusion(pp, extrudeStatus)
03135             << " out of " << returnReduce(pp().size(), sumOp<label>())
03136             << " faces. Removed extrusion at " << nTotChanged << " faces."
03137             << endl;
03138 
03139         if (nTotChanged == 0)
03140         {
03141             break;
03142         }
03143 
03144         // Reset mesh points and start again
03145         meshMover().movePoints(oldPoints);
03146         meshMover().correct();
03147 
03148         Info<< endl;
03149     }
03150 
03151 
03152     // At this point we have a (shrunk) mesh and a set of topology changes
03153     // which will make a valid mesh with layer. Apply these changes to the
03154     // current mesh.
03155 
03156     // Apply the stored topo changes to the current mesh.
03157     autoPtr<mapPolyMesh> map = savedMeshMod.changeMesh(mesh, false);
03158 
03159     // Update fields
03160     mesh.updateMesh(map);
03161 
03162     // Move mesh (since morphing does not do this)
03163     if (map().hasMotionPoints())
03164     {
03165         mesh.movePoints(map().preMotionPoints());
03166     }
03167     else
03168     {
03169         // Delete mesh volumes.
03170         mesh.clearOut();
03171     }
03172 
03173     if (meshRefiner_.overwrite())
03174     {
03175         mesh.setInstance(meshRefiner_.oldInstance());
03176     }
03177 
03178     meshRefiner_.updateMesh(map, labelList(0));
03179 
03180 
03181     // Do final balancing
03182     // ~~~~~~~~~~~~~~~~~~
03183 
03184     if (Pstream::parRun())
03185     {
03186         Info<< nl
03187             << "Doing final balancing" << nl
03188             << "---------------------" << nl
03189             << endl;
03190 
03191         if (debug)
03192         {
03193             const_cast<Time&>(mesh.time())++;
03194         }
03195 
03196         // Balance. No restriction on face zones and baffles.
03197         autoPtr<mapDistributePolyMesh> map = meshRefiner_.balance
03198         (
03199             false,
03200             false,
03201             scalarField(mesh.nCells(), 1.0),
03202             decomposer,
03203             distributor
03204         );
03205 
03206         // Re-distribute flag of layer faces and cells
03207         map().distributeCellData(flaggedCells);
03208         map().distributeFaceData(flaggedFaces);
03209     }
03210 
03211 
03212     // Write mesh
03213     // ~~~~~~~~~~
03214 
03215     cellSet addedCellSet(mesh, "addedCells", findIndices(flaggedCells, true));
03216     Info<< "Writing "
03217         << returnReduce(addedCellSet.size(), sumOp<label>())
03218         << " added cells to cellSet "
03219         << addedCellSet.name() << endl;
03220     addedCellSet.write();
03221 
03222     faceSet layerFacesSet(mesh, "layerFaces", findIndices(flaggedFaces, true));
03223     Info<< "Writing "
03224         << returnReduce(layerFacesSet.size(), sumOp<label>())
03225         << " faces inside added layer to faceSet "
03226         << layerFacesSet.name() << endl;
03227     layerFacesSet.write();
03228 }
03229 
03230 
03231 void Foam::autoLayerDriver::doLayers
03232 (
03233     const dictionary& shrinkDict,
03234     const dictionary& motionDict,
03235     const layerParameters& layerParams,
03236     const bool preBalance,
03237     decompositionMethod& decomposer,
03238     fvMeshDistribute& distributor
03239 )
03240 {
03241     const fvMesh& mesh = meshRefiner_.mesh();
03242 
03243     Info<< nl
03244         << "Shrinking and layer addition phase" << nl
03245         << "----------------------------------" << nl
03246         << endl;
03247 
03248     Info<< "Using mesh parameters " << motionDict << nl << endl;
03249 
03250     // Merge coplanar boundary faces
03251     mergePatchFacesUndo(layerParams, motionDict);
03252 
03253     // Per patch the number of layers (0 if no layer)
03254     const labelList& numLayers = layerParams.numLayers();
03255 
03256     // Patches that need to get a layer
03257     DynamicList<label> patchIDs(numLayers.size());
03258     label nFacesWithLayers = 0;
03259     forAll(numLayers, patchI)
03260     {
03261         if (numLayers[patchI] > 0)
03262         {
03263             patchIDs.append(patchI);
03264             nFacesWithLayers += mesh.boundaryMesh()[patchI].size();
03265         }
03266     }
03267     patchIDs.shrink();
03268 
03269     if (returnReduce(nFacesWithLayers, sumOp<label>()) == 0)
03270     {
03271         Info<< nl << "No layers to generate ..." << endl;
03272     }
03273     else
03274     {
03275         // Check that outside of mesh is not multiply connected.
03276         checkMeshManifold();
03277 
03278         // Check initial mesh
03279         Info<< "Checking initial mesh ..." << endl;
03280         labelHashSet wrongFaces(mesh.nFaces()/100);
03281         motionSmoother::checkMesh(false, mesh, motionDict, wrongFaces);
03282         const label nInitErrors = returnReduce
03283         (
03284             wrongFaces.size(),
03285             sumOp<label>()
03286         );
03287 
03288         Info<< "Detected " << nInitErrors << " illegal faces"
03289             << " (concave, zero area or negative cell pyramid volume)"
03290             << endl;
03291 
03292 
03293         // Balance
03294         if (Pstream::parRun() && preBalance)
03295         {
03296             Info<< nl
03297                 << "Doing initial balancing" << nl
03298                 << "-----------------------" << nl
03299                 << endl;
03300 
03301             scalarField cellWeights(mesh.nCells(), 1);
03302             forAll(numLayers, patchI)
03303             {
03304                 if (numLayers[patchI] > 0)
03305                 {
03306                     const polyPatch& pp = mesh.boundaryMesh()[patchI];
03307                     forAll(pp.faceCells(), i)
03308                     {
03309                         cellWeights[pp.faceCells()[i]] += numLayers[patchI];
03310                     }
03311                 }
03312             }
03313 
03314             // Balance mesh (and meshRefinement). No restriction on face zones
03315             // and baffles.
03316             autoPtr<mapDistributePolyMesh> map = meshRefiner_.balance
03317             (
03318                 false,
03319                 false,
03320                 cellWeights,
03321                 decomposer,
03322                 distributor
03323             );
03324 
03325             //{
03326             //    globalIndex globalCells(mesh.nCells());
03327             //
03328             //    Info<< "** Distribution after balancing:" << endl;
03329             //    for (label procI = 0; procI < Pstream::nProcs(); procI++)
03330             //    {
03331             //        Info<< "    " << procI << '\t'
03332             //            << globalCells.localSize(procI) << endl;
03333             //    }
03334             //    Info<< endl;
03335             //}
03336         }
03337 
03338 
03339         // Do all topo changes
03340         addLayers
03341         (
03342             layerParams,
03343             motionDict,
03344             patchIDs,
03345             nInitErrors,
03346             decomposer,
03347             distributor
03348         );
03349     }
03350 }
03351 
03352 
03353 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines