diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C index bd655dc2512fb3529d73e1ad79bdbacc55b75657..15be3f9c1d0e5c195602f49549f69e4e1950729b 100644 --- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C +++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\ / A nd | Copyright (C) 1991-2007 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -33,12 +33,86 @@ Description #include "argList.H" #include "Time.H" #include "fvMesh.H" -#include "autoHexMeshDriver.H" +#include "autoRefineDriver.H" +#include "autoSnapDriver.H" +#include "autoLayerDriver.H" +#include "searchableSurfaces.H" +#include "refinementSurfaces.H" +#include "shellSurfaces.H" +#include "decompositionMethod.H" +#include "fvMeshDistribute.H" +#include "wallPolyPatch.H" +#include "refinementParameters.H" +#include "snapParameters.H" +#include "layerParameters.H" + using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Check writing tolerance before doing any serious work +scalar getMergeDistance(const polyMesh& mesh, const scalar mergeTol) +{ + const boundBox& meshBb = mesh.bounds(); + scalar mergeDist = mergeTol*mag(meshBb.max() - meshBb.min()); + scalar writeTol = std::pow + ( + scalar(10.0), + -scalar(IOstream::defaultPrecision()) + ); + + Info<< nl + << "Overall mesh bounding box : " << meshBb << nl + << "Relative tolerance : " << mergeTol << nl + << "Absolute matching distance : " << mergeDist << nl + << endl; + + if (mesh.time().writeFormat() == IOstream::ASCII && mergeTol < writeTol) + { + FatalErrorIn("getMergeDistance(const polyMesh&, const scalar)") + << "Your current settings specify ASCII writing with " + << IOstream::defaultPrecision() << " digits precision." << endl + << "Your merging tolerance (" << mergeTol << ") is finer than this." + << endl + << "Please change your writeFormat to binary" + << " or increase the writePrecision" << endl + << "or adjust the merge tolerance (-mergeTol)." + << exit(FatalError); + } + + return mergeDist; +} + + +// Write mesh and additional information +void writeMesh +( + const string& msg, + const meshRefinement& meshRefiner, + const label debug +) +{ + const fvMesh& mesh = meshRefiner.mesh(); + + meshRefiner.printMeshInfo(debug, msg); + Info<< "Writing mesh to time " << mesh.time().timeName() << endl; + + meshRefiner.write(meshRefinement::MESH|meshRefinement::SCALARLEVELS, ""); + if (debug & meshRefinement::OBJINTERSECTIONS) + { + meshRefiner.write + ( + meshRefinement::OBJINTERSECTIONS, + mesh.time().path()/mesh.time().timeName() + ); + } + Info<< "Written mesh in = " + << mesh.time().cpuTimeIncrement() << " s." << endl; +} + + + int main(int argc, char *argv[]) { # include "setRootCase.H" @@ -49,6 +123,11 @@ int main(int argc, char *argv[]) Info<< "Read mesh in = " << runTime.cpuTimeIncrement() << " s" << endl; + // Check patches and faceZones are synchronised + mesh.boundaryMesh().checkParallelSync(true); + meshRefinement::checkCoupledFaceZones(mesh); + + // Read decomposePar dictionary IOdictionary decomposeDict ( @@ -75,47 +154,282 @@ int main(int argc, char *argv[]) ) ); - // refinement parameters - const dictionary& refineDict = meshDict.subDict("refineDict"); + // all surface geometry + const dictionary& geometryDict = meshDict.subDict("geometry"); - // snap-to-surface parameters - const dictionary& snapDict = meshDict.subDict("snapDict"); + // refinement parameters + const dictionary& refineDict = meshDict.subDict("castellatedMeshControls"); // mesh motion and mesh quality parameters - const dictionary& motionDict = meshDict.subDict("motionDict"); + const dictionary& motionDict = meshDict.subDict("meshQualityControls"); + + // snap-to-surface parameters + const dictionary& snapDict = meshDict.subDict("snapControls"); // layer addition parameters - const dictionary& layerDict = meshDict.subDict("layerDict"); + const dictionary& layerDict = meshDict.subDict("addLayersControls"); + + + + // Debug + // ~~~~~ + + const label debug(readLabel(meshDict.lookup("debug"))); + if (debug > 0) + { + meshRefinement::debug = debug; + autoRefineDriver::debug = debug; + autoSnapDriver::debug = debug; + autoLayerDriver::debug = debug; + } + + + // Read geometry + // ~~~~~~~~~~~~~ + + searchableSurfaces allGeometry + ( + IOobject + ( + "abc", // dummy name + mesh.time().constant(), // directory + "triSurface", // instance + mesh.time(), // registry + IOobject::MUST_READ, + IOobject::NO_WRITE + ), + geometryDict + ); + + + // Read refinement surfaces + // ~~~~~~~~~~~~~~~~~~~~~~~~ + + Info<< "Reading refinement surfaces." << endl; + refinementSurfaces surfaces + ( + allGeometry, + refineDict.subDict("refinementSurfaces") + ); + Info<< "Read refinement surfaces in = " + << mesh.time().cpuTimeIncrement() << " s" << nl << endl; + + + // Read refinement shells + // ~~~~~~~~~~~~~~~~~~~~~~ + + Info<< "Reading refinement shells." << endl; + shellSurfaces shells + ( + allGeometry, + refineDict.subDict("refinementRegions") + ); + Info<< "Read refinement shells in = " + << mesh.time().cpuTimeIncrement() << " s" << nl << endl; + + + Info<< "Setting refinement level of surface to be consistent" + << " with shells." << endl; + surfaces.setMinLevelFields(shells); + Info<< "Checked shell refinement in = " + << mesh.time().cpuTimeIncrement() << " s" << nl << endl; + + - // Main meshing driver. Read surfaces. Determine initial intersections. - autoHexMeshDriver meshEngine + // Add all the surface regions as patches + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + labelList globalToPatch; + { + Info<< nl + << "Adding patches for surface regions" << nl + << "----------------------------------" << nl + << endl; + + // From global region number to mesh patch. + globalToPatch.setSize(surfaces.nRegions(), -1); + + Info<< "Patch\tRegion" << nl + << "-----\t------" + << endl; + + const labelList& surfaceGeometry = surfaces.surfaces(); + forAll(surfaceGeometry, surfI) + { + label geomI = surfaceGeometry[surfI]; + + const wordList& regNames = allGeometry.regionNames()[geomI]; + + Info<< surfaces.names()[surfI] << ':' << nl << nl; + + forAll(regNames, i) + { + label patchI = meshRefinement::addPatch + ( + mesh, + regNames[i], + wallPolyPatch::typeName + ); + + Info<< patchI << '\t' << regNames[i] << nl; + + globalToPatch[surfaces.globalRegion(surfI, i)] = patchI; + } + + Info<< nl; + } + Info<< "Added patches in = " + << mesh.time().cpuTimeIncrement() << " s" << nl << endl; + } + + + // Parallel + // ~~~~~~~~ + + // Decomposition + autoPtr<decompositionMethod> decomposerPtr + ( + decompositionMethod::New + ( + decomposeDict, + mesh + ) + ); + decompositionMethod& decomposer = decomposerPtr(); + + if (Pstream::parRun() && !decomposer.parallelAware()) + { + FatalErrorIn(args.executable()) + << "You have selected decomposition method " + << decomposer.typeName + << " which is not parallel aware." << endl + << "Please select one that is (hierarchical, parMetis)" + << exit(FatalError); + } + + const scalar mergeDist = getMergeDistance ( mesh, - meshDict, // global control parameters - refineDict, // refinement parameters - decomposeDict + readScalar(meshDict.lookup("mergeTolerance")) ); - Switch wantRefine(meshDict.lookup("doRefine")); - Switch wantSnap(meshDict.lookup("doSnap")); - Switch wantLayers(meshDict.lookup("doLayers")); + + // Mesh distribution engine (uses tolerance to reconstruct meshes) + fvMeshDistribute distributor(mesh, mergeDist); + + + // Refinement engine + // ~~~~~~~~~~~~~~~~~ + + Info<< nl + << "Determining initial surface intersections" << nl + << "-----------------------------------------" << nl + << endl; + + // Main refinement engine + meshRefinement meshRefiner + ( + mesh, + mergeDist, // tolerance used in sorting coordinates + surfaces, // for surface intersection refinement + shells // for volume (inside/outside) refinement + ); + Info<< "Calculated surface intersections in = " + << mesh.time().cpuTimeIncrement() << " s" << nl << endl; + + // Some stats + meshRefiner.printMeshInfo(debug, "Initial mesh"); + + meshRefiner.write + ( + debug&meshRefinement::OBJINTERSECTIONS, + mesh.time().path()/mesh.time().timeName() + ); + + + + + // Now do the real work -refinement -snapping -layers + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Switch wantRefine(meshDict.lookup("castellatedMesh")); + Switch wantSnap(meshDict.lookup("snap")); + Switch wantLayers(meshDict.lookup("addLayers")); if (wantRefine) { - meshEngine.doRefine(refineDict, wantSnap); + autoRefineDriver refineDriver + ( + meshRefiner, + decomposer, + distributor, + globalToPatch + ); + + // Refinement parameters + refinementParameters refineParams(refineDict); + + refineDriver.doRefine(refineDict, refineParams, wantSnap); + + writeMesh + ( + "Refined mesh", + meshRefiner, + debug + ); } if (wantSnap) { - meshEngine.doSnap(snapDict, motionDict); + autoSnapDriver snapDriver + ( + meshRefiner, + globalToPatch + ); + + // Snap parameters + snapParameters snapParams(snapDict); + + snapDriver.doSnap(snapDict, motionDict, snapParams); + + writeMesh + ( + "Snapped mesh", + meshRefiner, + debug + ); } if (wantLayers) { - meshEngine.doLayers(layerDict, motionDict); + autoLayerDriver layerDriver + ( + meshRefiner, + globalToPatch + ); + + // Layer addition parameters + layerParameters layerParams(layerDict, mesh.boundaryMesh()); + + layerDriver.doLayers + ( + layerDict, + motionDict, + layerParams, + decomposer, + distributor + ); + + writeMesh + ( + "Layer mesh", + meshRefiner, + debug + ); } + Info<< "Finished meshing in = " << runTime.elapsedCpuTime() << " s." << endl; diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict index e9aa8f189d9d748994d1f564cabedb37c55a30ec..e97b1ee9a756bc9d0e42de449a28e596566f60a6 100644 --- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict +++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict @@ -22,161 +22,171 @@ FoamFile // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Which phases to run. -doRefine true; -doSnap true; -doLayers true; // includes autoMergeFaces +// Which of the steps to run +castellatedMesh true; +snap true; +addLayers false; + + +// Geometry. Definition of all surfaces. All surfaces are of class +// searchableSurface. +// Surfaces are used +// - to specify refinement for any mesh cell intersecting it +// - to specify refinement for any mesh cell inside/outside/near +// - to 'snap' the mesh boundary to the surface +geometry +{ + box1x1x1 + { + type searchableBox; + min (1.5 1 -0.5); + max (3.5 2 0.5); + } + + sphere.stl + { + type triSurfaceMesh; + + // Per region the patchname. If not provided will be <name>_<region>. + regions + { + secondSolid + { + name mySecondPatch; + } + } + } + sphere2 + { + type searchableSphere; + centre (1.5 1.5 1.5); + radius 1.03; + } +}; -// Whether to dump intermediate meshes and print lots -// 1 : write mesh -// 2 : write volScalarField with cellLevel for postprocessing -// 4 : write current intersections as .obj files -debug 0; -refineDict -{ - // Which part to keep. - // NOTE: This point should never be on a face, always inside a cell, even - // after refinement. - keepPoints ((3 0.28 0.43)); - // Whether to remove/split cells likely to give problems when snapping - handleSnapProblems on; +// Settings for the castellatedMesh generation. +castellatedMeshControls +{ - // Merge tolerance. Is fraction of overall bounding box of initial mesh - mergeTolerance 1E-6; + // Refinement parameters + // ~~~~~~~~~~~~~~~~~~~~~ // While refining maximum number of cells per processor. This is basically // the number of cells that fit on a processor. If you choose this too small // it will do just more refinement iterations to obtain a similar mesh. - procCellLimit 1000000; - + maxLocalCells 1000000; // Overall cell limit (approximately). Refinement will stop immediately // upon reaching this number so a refinement level might not complete. // Note that this is the number of cells before removing the part which - // is not 'visible' from the keepPoint. The final number of cells might actually - // be a lot less. - cellLimit 2000000; - + // is not 'visible' from the keepPoint. The final number of cells might + // actually be a lot less. + maxGlobalCells 2000000; // The surface refinement loop might spend lots of iterations refining just a // few cells. This setting will cause refinement to stop if <= minimumRefine // are selected for refinement. Note: it will at least do one iteration // (unless the number of cells to refine is 0) - minimumRefine 0; - - - + minRefinementCells 0; // Number of buffer layers between different levels. // 1 means normal 2:1 refinement restriction, larger means slower // refinement. - nBufferLayers 1; + nCellsBetweenLevels 1; - // Feature Edge Refinement - // ~~~~~~~~~~~~~~~~~~~~~~~ - // External feature file. Read from constant/triSurface for now. - // Limitations: - // - either start or edge of any feature line has to be inside domain - // and be visible from keepPoint on starting mesh. - // - refining cells containing features is separate phase before refining - // based on surface. - // - no load balancing, no check for cellLimit is done while doing this. + // Explicit feature edge refinement + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies a level for any cell intersected by its edges. + // This is a featureEdgeMesh, read from constant/triSurface for now. features ( - // { - // file "someLine.eMesh"; - // level 2; - // } + //{ + // file "someLine.eMesh"; + // level 2; + //} ); - // Internal Mesh Refinement + + // Surface based refinement // ~~~~~~~~~~~~~~~~~~~~~~~~ - // Specifies the areas where the refinement has to be a certain level. - // These surfaces have to be closed. Refinement is either inside - // (refineInside = true) or outside. (note:insideness or outsideness - // is with respect to far away) - // Note:that even using these the transition can never be faster than - // nBufferLayers! - // Note:the refinement level can never be higher than any of the surfaces - // they overlap with. See below for the surface refinement level specification. - refinementShells - ( + // Specifies two levels for every surface. The first is the minimum level, + // every cell intersecting a surface gets refined up to the minimum level. + // The second level is the maximum level. Cells that 'see' multiple + // intersections where the intersections make an + // angle > resolveFeatureAngle get refined up to the maximum level. + + refinementSurfaces + { + sphere.stl { - //type triSurfaceMesh; - //name cube1x1x1.stl; - type searchableBox; - name box1x1x1; - min (2.5 -0.5 -0.5); - max (3.5 0.5 0.5); - - level 4; - refineInside true; + // Surface-wise min and max refinement level + level (2 2); + + // Optional region-wise level specification + regions + { + secondSolid + { + level (3 3); + } + } } - ); + } + resolveFeatureAngle 30; - // Surface based refinement - // ~~~~~~~~~~~~~~~~~~~~~~~~ - - // Curvature. Cosine of angle between two neighbouring surface intersections. - // Only used if cell level > minLevel and < maxLevel. - curvature 0.5; + // Region-wise refinement + // ~~~~~~~~~~~~~~~~~~~~~~ - // Overall the refinement is according to the following rules: - // - if the cell-cell vector intersects a surface any cell that - // is less refined than the minRefinementLevel of the surface gets refined. - // - else if the refinement level of the cell is between the - // minRefinementLevel and maxRefinementLevel the cell gets refined if - // - the normal of neighbouring surface intersections differ by more - // than above curvature - // - or if neighbouring surface intersections are on different surfaces or - // different surface regions. + // Specifies refinement level for cells in relation to a surface. One of + // three modes + // - distance. 'levels' specifies per distance to the surface the + // wanted refinement level. The distances need to be specified in + // descending order. + // - inside. 'levels' is only one entry and only the level is used. All + // cells inside the surface get refined up to the level. The surface + // needs to be closed for this to be possible. + // - outside. Same but cells outside. - - // surfaces - surfaces - ( + refinementRegions + { + box1x1x1 { - name sphere; - file "sphere.stl"; + mode inside; + levels ((1.0 4)); + } + //sphere.stl + //{ + // mode distance; + // levels ((1.0 5) (2.0 3)); + //} + } - // Surface wide refinement level - minRefinementLevel 1; - maxRefinementLevel 1; - // Layers - surfaceLayers 1; + // Mesh selection + // ~~~~~~~~~~~~~~ - // Region specific refinement level - regions - ( - { - name firstSolid; - minRefinementLevel 3; - maxRefinementLevel 3; - surfaceLayers 2; - } - { - name secondSolid; - minRefinementLevel 1; - maxRefinementLevel 1; - surfaceLayers 1; - } - ); - } - ); + // After refinement patches get added for all refinementSurfaces and + // all cells intersecting the surfaces get put into these patches. The + // section reachable from the locationInMesh is kept. + // NOTE: This point should never be on a face, always inside a cell, even + // after refinement. + locationInMesh (5 0.28 0.43); } -// For snapping -snapDict + + +// Settings for the snapping. +snapControls { //- Number of patch smoothing iterations before finding correspondence // to surface @@ -185,47 +195,64 @@ snapDict //- Relative distance for points to be attracted by surface feature point // or edge. True distance is this factor times local // maximum edge length. - snapTol 4.0; + tolerance 4.0; - //- Whether to move internal mesh as well as boundary - smoothMesh true; - - //- Number of mesh displacement smoothing iterations. - nSmoothDispl 30; + //- Number of mesh displacement relaxation iterations. + nSolveIter 30; //- Maximum number of snapping relaxation iterations. Should stop // before upon reaching a correct mesh. - nSnap 5; + nRelaxIter 5; } -// For cell layers -layerDict + +// Settings for the layer addition. +addLayersControls { - //- When not to extrude surface. 0 is flat surface, 90 is when two faces - // make straight angle. - featureAngle 60; + // Per final patch (so not geometry!) the layer information + layers + { + sphere.stl_firstSolid + { + nSurfaceLayers 1; - //- Maximum number of snapping relaxation iterations. Should stop - // before upon reaching a correct mesh. - nSnap 5; + } + maxY + { + nSurfaceLayers 1; + } + } + // Expansion factor for layer mesh + expansionRatio 1.0; - //- Minimum thickness of cell layer. If for any reason layer cannot be - // above minThickness do not add layer if thickness below minThickNess. - // Relative to undistorted cell size + //- Wanted thickness of final added cell layer. If multiple layers + // is the + // thickness of the layer furthest away from the wall. + // Relative to undistorted size of cell outside layer. + finalLayerRatio 0.3; + + //- Minimum thickness of cell layer. If for any reason layer + // cannot be above minThickness do not add layer. + // Relative to undistorted size of cell outside layer. minThickness 0.25; //- If points get not extruded do nGrow layers of connected faces that are - // not grown. Is used to not do layers at all close to features. + // also not grown. This helps convergence of the layer addition process + // close to features. nGrow 1; - // Expansion factor for layer mesh - expansionRatio 1.3; - // Ratio of cell size in final added cell layer to cell size - // outside layer - finalLayerRatio 0.3; + // Advanced settings + + //- When not to extrude surface. 0 is flat surface, 90 is when two faces + // make straight angle. + featureAngle 60; + + //- Maximum number of snapping relaxation iterations. Should stop + // before upon reaching a correct mesh. + nRelaxIter 5; // Number of smoothing iterations of surface normals nSmoothSurfaceNormals 1; @@ -248,20 +275,14 @@ layerDict // Create buffer region for new layer terminations nBufferCellsNoExtrude 0; - - thickness 0.5; - nSmoothDispl 4; } -// For mesh motion -motionDict -{ - // - // Mesh Quality Parameters. Decide when mesh is good enough to stop - // smoothing. - // +// Generic mesh quality settings. At any undoable phase these determine +// where to undo. +meshQualityControls +{ //- Maximum non-orthogonality allowed. Set to 180 to disable. maxNonOrtho 65; @@ -298,10 +319,10 @@ motionDict //- minVolRatio (0 -> 1) minVolRatio 0.01; - //must be >0 for Fluent compatibility minTriangleTwist -1; + // Advanced //- Number of error distribution iterations @@ -311,4 +332,19 @@ motionDict } +// Advanced + +// Flags for optional output +// 0 : only write final meshes +// 1 : write intermediate meshes +// 2 : write volScalarField with cellLevel for postprocessing +// 4 : write current intersections as .obj files +debug 0; + + +// Merge tolerance. Is fraction of overall bounding box of initial mesh. +// Note: the write tolerance needs to be higher than this. +mergeTolerance 1E-6; + + // ************************************************************************* // diff --git a/bin/foamPackSource b/bin/foamPackSource index 30e52c72daed9d7dc846f9ebed7b0844df028d41..519d18929dea979894c366a2e5c16c8d35635ce3 100755 --- a/bin/foamPackSource +++ b/bin/foamPackSource @@ -73,13 +73,16 @@ find -H $packDir \ -a ! -name "core" \ -a ! -name "core.[1-9]*" \ -a ! -name "log[0-9]*" \ + -a ! -name "libccmio*" \ -a ! -name "\.ebrowse" \ | sed \ -e "\@$packDir/.git/@d" \ -e "\@$packDir/lib/@d" \ - -e '\@applications/bin/@d' \ - -e '\@/t/@d' \ - -e '\@Make[.A-Za-z]*/[^/]*/@d' \ + -e "\@libccmio.*/@d" \ + -e '\@applications/bin/@d' \ + -e '\@/t/@d' \ + -e '\@Make[.A-Za-z]*/[^/]*/@d'\ + -e '\@/platforms/@d' \ > $tmpFile tar czpf $packFile --files-from $tmpFile diff --git a/bin/foamPackThirdPartyBin b/bin/foamPackThirdPartyBin new file mode 100755 index 0000000000000000000000000000000000000000..484c0c1e4b9251b718ac04bfe93e8e84d21c1536 --- /dev/null +++ b/bin/foamPackThirdPartyBin @@ -0,0 +1,78 @@ +#!/bin/sh +#------------------------------------------------------------------------------ +# ========= | +# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox +# \\ / O peration | +# \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. +# \\/ M anipulation | +#------------------------------------------------------------------------------- +# License +# This file is part of OpenFOAM. +# +# OpenFOAM is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# OpenFOAM is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with OpenFOAM; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# Script +# foamPackThirdPartyBin <archOptions> [outputDir] +# +# Description +# Packs and compresses binary version of OpenFOAM ThirdParty for release +# +#------------------------------------------------------------------------------ + +if [ $# = 0 ] +then + echo "Error: archOptionsitecture type expected, exiting" + echo + echo "Usage : ${0##*/} <archOptions> [outputDir]" + echo + exit 1 +fi +archOptions=$1 +arch=${archOptions%%G*} +arch3264=$(echo "$arch" | sed 's@64@-64@') + +timeStamp=$(date +%Y-%m-%d) +packDir=ThirdParty +packFile=${packDir}.${archOptions}_${timeStamp}.gtgz + +# add optional output directory +if [ -d "$2" ] +then + packFile="$2/$packFile" +fi + +if [ -f $packFile ] +then + echo "Error: $packFile already exists" + exit 1 +fi + +# get list of directories +dirList=`find $packDir -type d -name $arch -o -type d -name $archOptions -o -type l -name $arch3264` +echo +echo "Packing $archOptions port of $packDir into $packFile" +echo + +tar czpf $packFile $dirList + +if [ $? = 0 ] +then + echo "Finished packing and compressing file $packFile" +else + echo "Error: failure packing $packFile" + rm -f $packFile 2>/dev/null +fi + +#------------------------------------------------------------------------------ diff --git a/bin/foamPackThirdPartyGeneral b/bin/foamPackThirdPartyGeneral new file mode 100755 index 0000000000000000000000000000000000000000..b874e4a0bdb8b3207a191ce1303ebcdfc137bf63 --- /dev/null +++ b/bin/foamPackThirdPartyGeneral @@ -0,0 +1,70 @@ +#!/bin/sh +#------------------------------------------------------------------------------ +# ========= | +# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox +# \\ / O peration | +# \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. +# \\/ M anipulation | +#------------------------------------------------------------------------------- +# License +# This file is part of OpenFOAM. +# +# OpenFOAM is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# OpenFOAM is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with OpenFOAM; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# Script +# foamPackThirdPartyGeneral [outputDir] +# +# Description +# Packs and compresses the OpenFOAM ThirdParty directory for release +# +#------------------------------------------------------------------------------ + +timeStamp=$(date +%Y-%m-%d) +packDir=ThirdParty +packFile=${packDir}.General_${timeStamp}.gtgz + +if [ ! -d $packDir ] +then + echo "Error: directory $packDir does not exist" + exit 1 +fi + +# add optional output directory +if [ -d "$1" ] +then + packFile="$1/$packFile" +fi + +if [ -f $packFile ] +then + echo "Error: $packFile already exists" + exit 1 +fi + +# Create time stamp file +# ~~~~~~~~~~~~~~~~~~~~~~ + +echo $timeStamp 2>/dev/null > $packDir/.timeStamp + +# Pack and compress the packFile +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +echo +echo "Packing $packDir into $packFile" +echo + +foamPackSource $packDir $packFile + +#------------------------------------------------------------------------------ diff --git a/src/autoMesh/Make/files b/src/autoMesh/Make/files index c562ee5c6de5bbb273ba95decce1e88dc70eda2e..96141445bea1ba3e2928715d3a50880f693d29b6 100644 --- a/src/autoMesh/Make/files +++ b/src/autoMesh/Make/files @@ -1,15 +1,23 @@ autoHexMesh = autoHexMesh +autoHexMeshDriver = $(autoHexMesh)/autoHexMeshDriver + +$(autoHexMeshDriver)/autoLayerDriver.C +$(autoHexMeshDriver)/autoLayerDriverShrink.C +$(autoHexMeshDriver)/autoSnapDriver.C +$(autoHexMeshDriver)/autoRefineDriver.C +$(autoHexMeshDriver)/autoHexMeshDriver.C + +$(autoHexMeshDriver)/layerParameters/layerParameters.C +$(autoHexMeshDriver)/refinementParameters/refinementParameters.C +$(autoHexMeshDriver)/snapParameters/snapParameters.C +$(autoHexMeshDriver)/pointData/pointData.C -$(autoHexMesh)/autoHexMeshDriver/autoHexMeshDriver.C -$(autoHexMesh)/autoHexMeshDriver/autoHexMeshDriverLayers.C -$(autoHexMesh)/autoHexMeshDriver/autoHexMeshDriverShrink.C -$(autoHexMesh)/autoHexMeshDriver/autoHexMeshDriverSnap.C -$(autoHexMesh)/autoHexMeshDriver/pointData/pointData.C $(autoHexMesh)/meshRefinement/meshRefinementBaffles.C $(autoHexMesh)/meshRefinement/meshRefinement.C $(autoHexMesh)/meshRefinement/meshRefinementMerge.C $(autoHexMesh)/meshRefinement/meshRefinementRefine.C $(autoHexMesh)/refinementSurfaces/refinementSurfaces.C +$(autoHexMesh)/shellSurfaces/shellSurfaces.C $(autoHexMesh)/trackedParticle/trackedParticle.C $(autoHexMesh)/trackedParticle/trackedParticleCloud.C diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C index a15b4220324da337c72f24b4003735a255f20ede..48f52d7880cebe3c905afc26e752479af6991fd9 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C @@ -35,6 +35,13 @@ License #include "syncTools.H" #include "motionSmoother.H" #include "pointMesh.H" +#include "refinementParameters.H" +#include "snapParameters.H" +#include "layerParameters.H" +#include "autoRefineDriver.H" +#include "autoSnapDriver.H" +#include "autoLayerDriver.H" +#include "triSurfaceMesh.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -60,7 +67,8 @@ Foam::scalar Foam::autoHexMeshDriver::getMergeDistance(const scalar mergeTol) -scalar(IOstream::defaultPrecision()) ); - Info<< "Overall mesh bounding box : " << meshBb << nl + Info<< nl + << "Overall mesh bounding box : " << meshBb << nl << "Relative tolerance : " << mergeTol << nl << "Absolute matching distance : " << mergeDist << nl << endl; @@ -82,206 +90,63 @@ Foam::scalar Foam::autoHexMeshDriver::getMergeDistance(const scalar mergeTol) } -// Return per keeppoint -1 or the local cell label the point is in. Guaranteed -// to be only on one processor. -Foam::labelList Foam::autoHexMeshDriver::findCells(const pointField& keepPoints) - const -{ - // Global calculation engine - globalIndex globalCells(mesh_.nCells()); - - // Cell label per point - labelList cellLabels(keepPoints.size()); - - forAll(keepPoints, i) - { - const point& keepPoint = keepPoints[i]; - - label localCellI = mesh_.findCell(keepPoint); - - label globalCellI = -1; - - if (localCellI != -1) - { - Pout<< "Found point " << keepPoint << " in cell " << localCellI - << " on processor " << Pstream::myProcNo() << endl; - globalCellI = globalCells.toGlobal(localCellI); - } - - reduce(globalCellI, maxOp<label>()); - - if (globalCellI == -1) - { - FatalErrorIn - ( - "autoHexMeshDriver::findCells(const pointField&) const" - ) << "Point " << keepPoint << " is not inside the mesh." << nl - << "Bounding box of the mesh:" << mesh_.bounds() - << exit(FatalError); - } - - if (globalCells.isLocal(globalCellI)) - { - cellLabels[i] = localCellI; - } - else - { - cellLabels[i] = -1; - } - } - return cellLabels; -} - - -// Specifically orient using a calculated point outside -void Foam::autoHexMeshDriver::orientOutside(PtrList<searchableSurface>& shells) -{ - // Determine outside point. - boundBox overallBb - ( - point(GREAT, GREAT, GREAT), - point(-GREAT, -GREAT, -GREAT) - ); - - bool hasSurface = false; - - forAll(shells, shellI) - { - if (isA<triSurfaceMesh>(shells[shellI])) - { - const triSurfaceMesh& shell = - refCast<const triSurfaceMesh>(shells[shellI]); - - hasSurface = true; - - boundBox shellBb(shell.localPoints(), false); - - overallBb.min() = min(overallBb.min(), shellBb.min()); - overallBb.max() = max(overallBb.max(), shellBb.max()); - } - } - - if (hasSurface) - { - const point outsidePt(2*overallBb.max() - overallBb.min()); - - //Info<< "Using point " << outsidePt << " to orient shells" << endl; - - forAll(shells, shellI) - { - if (isA<triSurfaceMesh>(shells[shellI])) - { - triSurfaceMesh& shell = refCast<triSurfaceMesh>(shells[shellI]); - - if (!refinementSurfaces::isSurfaceClosed(shell)) - { - FatalErrorIn("orientOutside(PtrList<searchableSurface>&)") - << "Refinement shell " - << shell.searchableSurface::name() - << " is not closed." << exit(FatalError); - } - - refinementSurfaces::orientSurface(outsidePt, shell); - } - } - } -} - - -// Check that face zones are synced -void Foam::autoHexMeshDriver::checkCoupledFaceZones() const -{ - const faceZoneMesh& fZones = mesh_.faceZones(); - - // Check any zones are present anywhere and in same order - - { - List<wordList> zoneNames(Pstream::nProcs()); - zoneNames[Pstream::myProcNo()] = fZones.names(); - Pstream::gatherList(zoneNames); - Pstream::scatterList(zoneNames); - // All have same data now. Check. - forAll(zoneNames, procI) - { - if (procI != Pstream::myProcNo()) - { - if (zoneNames[procI] != zoneNames[Pstream::myProcNo()]) - { - FatalErrorIn - ( - "autoHexMeshDriver::checkCoupledFaceZones() const" - ) << "faceZones are not synchronised on processors." << nl - << "Processor " << procI << " has faceZones " - << zoneNames[procI] << nl - << "Processor " << Pstream::myProcNo() - << " has faceZones " - << zoneNames[Pstream::myProcNo()] << nl - << exit(FatalError); - } - } - } - } - - // Check that coupled faces are present on both sides. - - labelList faceToZone(mesh_.nFaces()-mesh_.nInternalFaces(), -1); - - forAll(fZones, zoneI) - { - const faceZone& fZone = fZones[zoneI]; - - forAll(fZone, i) - { - label bFaceI = fZone[i]-mesh_.nInternalFaces(); - - if (bFaceI >= 0) - { - if (faceToZone[bFaceI] == -1) - { - faceToZone[bFaceI] = zoneI; - } - else if (faceToZone[bFaceI] == zoneI) - { - FatalErrorIn - ( - "autoHexMeshDriver::checkCoupledFaceZones()" - ) << "Face " << fZone[i] << " in zone " - << fZone.name() - << " is twice in zone!" - << abort(FatalError); - } - else - { - FatalErrorIn - ( - "autoHexMeshDriver::checkCoupledFaceZones()" - ) << "Face " << fZone[i] << " in zone " - << fZone.name() - << " is also in zone " - << fZones[faceToZone[bFaceI]].name() - << abort(FatalError); - } - } - } - } - - labelList neiFaceToZone(faceToZone); - syncTools::swapBoundaryFaceList(mesh_, neiFaceToZone, false); - - forAll(faceToZone, i) - { - if (faceToZone[i] != neiFaceToZone[i]) - { - FatalErrorIn - ( - "autoHexMeshDriver::checkCoupledFaceZones()" - ) << "Face " << mesh_.nInternalFaces()+i - << " is in zone " << faceToZone[i] - << ", its coupled face is in zone " << neiFaceToZone[i] - << abort(FatalError); - } - } -} +//// Specifically orient using a calculated point outside +//void Foam::autoHexMeshDriver::orientOutside +//( +// PtrList<searchableSurface>& shells +//) +//{ +// // Determine outside point. +// boundBox overallBb +// ( +// point(GREAT, GREAT, GREAT), +// point(-GREAT, -GREAT, -GREAT) +// ); +// +// bool hasSurface = false; +// +// forAll(shells, shellI) +// { +// if (isA<triSurfaceMesh>(shells[shellI])) +// { +// const triSurfaceMesh& shell = +// refCast<const triSurfaceMesh>(shells[shellI]); +// +// hasSurface = true; +// +// boundBox shellBb(shell.localPoints(), false); +// +// overallBb.min() = min(overallBb.min(), shellBb.min()); +// overallBb.max() = max(overallBb.max(), shellBb.max()); +// } +// } +// +// if (hasSurface) +// { +// const point outsidePt(2*overallBb.max() - overallBb.min()); +// +// //Info<< "Using point " << outsidePt << " to orient shells" << endl; +// +// forAll(shells, shellI) +// { +// if (isA<triSurfaceMesh>(shells[shellI])) +// { +// triSurfaceMesh& shell = +// refCast<triSurfaceMesh>(shells[shellI]); +// +// if (!refinementSurfaces::isSurfaceClosed(shell)) +// { +// FatalErrorIn("orientOutside(PtrList<searchableSurface>&)") +// << "Refinement shell " +// << shell.searchableSurface::name() +// << " is not closed." << exit(FatalError); +// } +// +// refinementSurfaces::orientSurface(outsidePt, shell); +// } +// } +// } +//} // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // @@ -297,85 +162,86 @@ Foam::autoHexMeshDriver::autoHexMeshDriver mesh_(mesh), dict_(dict), debug_(readLabel(dict_.lookup("debug"))), - maxGlobalCells_(readLabel(dict_.lookup("cellLimit"))), - maxLocalCells_(readLabel(dict_.lookup("procCellLimit"))), - minRefineCells_(readLabel(dict_.lookup("minimumRefine"))), - curvature_(readScalar(dict_.lookup("curvature"))), - nBufferLayers_(readLabel(dict_.lookup("nBufferLayers"))), - keepPoints_(dict_.lookup("keepPoints")), mergeDist_(getMergeDistance(readScalar(dict_.lookup("mergeTolerance")))) { if (debug_ > 0) { meshRefinement::debug = debug_; autoHexMeshDriver::debug = debug_; + autoRefineDriver::debug = debug; + autoSnapDriver::debug = debug; + autoLayerDriver::debug = debug; } - Info<< "Overall cell limit : " << maxGlobalCells_ - << endl; - Info<< "Per processor cell limit : " << maxLocalCells_ - << endl; - Info<< "Minimum number of cells to refine : " << minRefineCells_ - << endl; - Info<< "Curvature : " << curvature_ - << nl << endl; - Info<< "Layers between different refinement levels : " << nBufferLayers_ - << endl; + refinementParameters refineParams(dict, 1); - // Check keepPoints are sensible - findCells(keepPoints_); + Info<< "Overall cell limit : " + << refineParams.maxGlobalCells() << endl; + Info<< "Per processor cell limit : " + << refineParams.maxLocalCells() << endl; + Info<< "Minimum number of cells to refine : " + << refineParams.minRefineCells() << endl; + Info<< "Curvature : " + << refineParams.curvature() << nl << endl; + Info<< "Layers between different refinement levels : " + << refineParams.nBufferLayers() << endl; + PtrList<dictionary> shellDicts(dict_.lookup("refinementShells")); - // Read refinement shells - // ~~~~~~~~~~~~~~~~~~~~~~ + PtrList<dictionary> surfaceDicts(dict_.lookup("surfaces")); - { - Info<< "Reading refinement shells." << endl; - PtrList<dictionary> shellDicts(dict_.lookup("refinementShells")); + // Read geometry + // ~~~~~~~~~~~~~ + + { + Info<< "Reading all geometry." << endl; - shells_.setSize(shellDicts.size()); - shellLevels_.setSize(shellDicts.size()); - shellRefineInside_.setSize(shellDicts.size()); + // Construct dictionary with all shells and all refinement surfaces + dictionary geometryDict; - forAll(shellDicts, i) + forAll(shellDicts, shellI) { - const dictionary& dict = shellDicts[i]; + dictionary shellDict = shellDicts[shellI]; + const word name(shellDict.lookup("name")); + shellDict.remove("name"); + shellDict.remove("level"); + shellDict.remove("refineInside"); + geometryDict.add(name, shellDict); + } - shells_.set - ( - i, - searchableSurface::New - ( - dict.lookup("type"), - dict.lookup("name"), - mesh_.time(), - dict - ) - ); - shellLevels_[i] = readLabel(dict.lookup("level")); - shellRefineInside_[i] = Switch(dict.lookup("refineInside")); - - if (shellRefineInside_[i]) - { - Info<< "Refinement level " << shellLevels_[i] - << " for all cells inside " << shells_[i].name() << endl; - } - else + forAll(surfaceDicts, surfI) + { + dictionary surfDict = surfaceDicts[surfI]; + const word name(string::validate<word>(surfDict.lookup("file"))); + surfDict.remove("file"); + surfDict.remove("regions"); + if (!surfDict.found("name")) { - Info<< "Refinement level " << shellLevels_[i] - << " for all cells outside " << shells_[i].name() << endl; + surfDict.add("name", name); } + surfDict.add("type", triSurfaceMesh::typeName); + geometryDict.add(name, surfDict); } - Info<< "Read refinement shells in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; + allGeometryPtr_.reset + ( + new searchableSurfaces + ( + IOobject + ( + "abc", // dummy name + mesh_.time().constant(), // directory + "triSurface", // instance + mesh_.time(), // registry + IOobject::MUST_READ, + IOobject::NO_WRITE + ), + geometryDict + ) + ); - // Orient shell surfaces before any searching is done. - Info<< "Orienting triSurface shells so point far away is outside." - << endl; - orientOutside(shells_); - Info<< "Oriented shells in = " + Info<< "Read geometry in = " << mesh_.time().cpuTimeIncrement() << " s" << endl; } @@ -390,51 +256,47 @@ Foam::autoHexMeshDriver::autoHexMeshDriver ( new refinementSurfaces ( - IOobject - ( - "", // dummy name - mesh_.time().constant(), // directory - "triSurface", // instance - mesh_.time(), // registry - IOobject::MUST_READ, - IOobject::NO_WRITE - ), - dict_.lookup("surfaces") + allGeometryPtr_(), + surfaceDicts ) ); Info<< "Read surfaces in = " << mesh_.time().cpuTimeIncrement() << " s" << endl; + } - // Orient surfaces (if they're closed) before any searching is done. - Info<< "Orienting (closed) surfaces so keepPoint is outside." << endl; - forAll(surfaces(), i) - { - if (refinementSurfaces::isSurfaceClosed(surfaces()[i])) - { - refinementSurfaces::orientSurface - ( - keepPoints_[0], - surfacesPtr_()[i] - ); - } - } - Info<< "Oriented closed surfaces in = " + // Read refinement shells + // ~~~~~~~~~~~~~~~~~~~~~~ + + { + Info<< "Reading refinement shells." << endl; + shellsPtr_.reset + ( + new shellSurfaces + ( + allGeometryPtr_(), + shellDicts + ) + ); + Info<< "Read refinement shells in = " << mesh_.time().cpuTimeIncrement() << " s" << endl; + //// Orient shell surfaces before any searching is done. + //Info<< "Orienting triSurface shells so point far away is outside." + // << endl; + //orientOutside(shells_); + //Info<< "Oriented shells in = " + // << mesh_.time().cpuTimeIncrement() << " s" << endl; + Info<< "Setting refinement level of surface to be consistent" << " with shells." << endl; - surfacesPtr_().setMinLevelFields - ( - shells_, - shellLevels_, - shellRefineInside_ - ); + surfacesPtr_().setMinLevelFields(shells()); Info<< "Checked shell refinement in = " << mesh_.time().cpuTimeIncrement() << " s" << endl; } + // Check faceZones are synchronised - checkCoupledFaceZones(); + meshRefinement::checkCoupledFaceZones(mesh_); // Add all the surface regions as patches @@ -453,55 +315,40 @@ Foam::autoHexMeshDriver::autoHexMeshDriver << "-----\t------" << endl; - forAll(surfaces(), surfI) + const labelList& surfaceGeometry = surfaces().surfaces(); + forAll(surfaceGeometry, surfI) { - const triSurfaceMesh& s = surfaces()[surfI]; + label geomI = surfaceGeometry[surfI]; - Info<< surfaces().names()[surfI] << ':' << nl << nl; + const wordList& regNames = allGeometryPtr_().regionNames()[geomI]; - const geometricSurfacePatchList& regions = s.patches(); + Info<< surfaces().names()[surfI] << ':' << nl << nl; - labelList nTrisPerRegion(surfaces().countRegions(s)); + //const triSurfaceMesh& s = surfaces()[surfI]; + //const geometricSurfacePatchList& regions = s.patches(); + //labelList nTrisPerRegion(surfaces().countRegions(s)); - forAll(regions, i) + forAll(regNames, i) { - if (nTrisPerRegion[i] > 0) - { - label globalRegionI = surfaces().globalRegion(surfI, i); - - // Use optionally specified patch type and name - word patchType = surfaces().patchType()[globalRegionI]; - if (patchType == "") - { - patchType = wallPolyPatch::typeName; - } - - word patchName = surfaces().patchName()[globalRegionI]; - if (patchName == "") - { - patchName = - surfaces().names()[surfI] - + '_' - + regions[i].name(); - } - + //if (nTrisPerRegion[i] > 0) + //{ label patchI = meshRefinement::addPatch ( mesh, - patchName, - patchType + regNames[i], + wallPolyPatch::typeName ); - Info<< patchI << '\t' << regions[i].name() << nl; + Info<< patchI << '\t' << regNames[i] << nl; - globalToPatch_[globalRegionI] = patchI; - } + globalToPatch_[surfaces().globalRegion(surfI, i)] = patchI; + //} } Info<< nl; } Info<< "Added patches in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; + << mesh_.time().cpuTimeIncrement() << " s" << nl << endl; } @@ -559,7 +406,8 @@ Foam::autoHexMeshDriver::autoHexMeshDriver if (Pstream::parRun() && !decomposer.parallelAware()) { - FatalErrorIn("autoHexMeshDriver::autoHexMeshDriver(const IOobject&, fvMesh&)") + FatalErrorIn("autoHexMeshDriver::autoHexMeshDriver" + "(const IOobject&, fvMesh&)") << "You have selected decomposition method " << decomposer.typeName << " which is not parallel aware." << endl @@ -588,7 +436,8 @@ Foam::autoHexMeshDriver::autoHexMeshDriver ( mesh, mergeDist_, // tolerance used in sorting coordinates - surfaces() + surfaces(), + shells() ) ); Info<< "Calculated surface intersections in = " @@ -606,1284 +455,109 @@ Foam::autoHexMeshDriver::autoHexMeshDriver } -// Construct from separate dictionaries. -Foam::autoHexMeshDriver::autoHexMeshDriver -( - fvMesh& mesh, - const dictionary& controlDict, - const dictionary& refineDict, - const dictionary& decomposeDict -) -: - mesh_(mesh), - dict_(controlDict), - debug_(readLabel(controlDict.lookup("debug"))), - maxGlobalCells_(readLabel(refineDict.lookup("cellLimit"))), - maxLocalCells_(readLabel(refineDict.lookup("procCellLimit"))), - minRefineCells_(readLabel(refineDict.lookup("minimumRefine"))), - curvature_(readScalar(refineDict.lookup("curvature"))), - nBufferLayers_(readLabel(refineDict.lookup("nBufferLayers"))), - keepPoints_(refineDict.lookup("keepPoints")), - mergeDist_ - ( - getMergeDistance(readScalar(refineDict.lookup("mergeTolerance"))) - ) +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::autoHexMeshDriver::writeMesh(const string& msg) const { - if (debug_ > 0) + const meshRefinement& meshRefiner = meshRefinerPtr_(); + + meshRefiner.printMeshInfo(debug_, msg); + Info<< "Writing mesh to time " << mesh_.time().timeName() << endl; + + meshRefiner.write(meshRefinement::MESH|meshRefinement::SCALARLEVELS, ""); + if (debug_ & meshRefinement::OBJINTERSECTIONS) { - meshRefinement::debug = debug_; - autoHexMeshDriver::debug = debug_; + meshRefiner.write + ( + meshRefinement::OBJINTERSECTIONS, + mesh_.time().path()/mesh_.time().timeName() + ); } + Info<< "Written mesh in = " + << mesh_.time().cpuTimeIncrement() << " s." << endl; +} - Info<< "Overall cell limit : " << maxGlobalCells_ - << endl; - Info<< "Per processor cell limit : " << maxLocalCells_ - << endl; - Info<< "Minimum number of cells to refine : " << minRefineCells_ - << endl; - Info<< "Curvature : " << curvature_ - << nl << endl; - Info<< "Layers between different refinement levels : " << nBufferLayers_ - << endl; - - // Check keepPoints are sensible - findCells(keepPoints_); +void Foam::autoHexMeshDriver::doMesh() +{ + Switch wantRefine(dict_.lookup("doRefine")); + Switch wantSnap(dict_.lookup("doSnap")); + Switch wantLayers(dict_.lookup("doLayers")); - // Read refinement shells - // ~~~~~~~~~~~~~~~~~~~~~~ + Info<< "Do refinement : " << wantRefine << nl + << "Do snapping : " << wantSnap << nl + << "Do layers : " << wantLayers << nl + << endl; + if (wantRefine) { - Info<< "Reading refinement shells." << endl; + autoRefineDriver refineDriver + ( + meshRefinerPtr_(), + decomposerPtr_(), + distributorPtr_(), + globalToPatch_ + ); - PtrList<dictionary> shellDicts(refineDict.lookup("refinementShells")); + // Get all the refinement specific params + refinementParameters refineParams(dict_, 1); - shells_.setSize(shellDicts.size()); - shellLevels_.setSize(shellDicts.size()); - shellRefineInside_.setSize(shellDicts.size()); + refineDriver.doRefine(dict_, refineParams, wantSnap); - forAll(shellDicts, i) - { - const dictionary& dict = shellDicts[i]; + // Write mesh + writeMesh("Refined mesh"); + } - shells_.set - ( - i, - searchableSurface::New - ( - dict.lookup("type"), - dict.lookup("name"), - mesh_.time(), - dict - ) - ); - shellLevels_[i] = readLabel(dict.lookup("level")); - shellRefineInside_[i] = Switch(dict.lookup("refineInside")); - - if (shellRefineInside_[i]) - { - Info<< "Refinement level " << shellLevels_[i] - << " for all cells inside " << shells_[i].name() << endl; - } - else - { - Info<< "Refinement level " << shellLevels_[i] - << " for all cells outside " << shells_[i].name() << endl; - } - } + if (wantSnap) + { + const dictionary& snapDict = dict_.subDict("snapDict"); + const dictionary& motionDict = dict_.subDict("motionDict"); - Info<< "Read refinement shells in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; + autoSnapDriver snapDriver + ( + meshRefinerPtr_(), + globalToPatch_ + ); - // Orient shell surfaces before any searching is done. - Info<< "Orienting triSurface shells so point far away is outside." - << endl; - orientOutside(shells_); - Info<< "Oriented shells in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; - } + // Get all the snapping specific params + snapParameters snapParams(snapDict, 1); + snapDriver.doSnap(snapDict, motionDict, snapParams); - // Read refinement surfaces - // ~~~~~~~~~~~~~~~~~~~~~~~~ + // Write mesh. + writeMesh("Snapped mesh"); + } + if (wantLayers) { - Info<< "Reading surfaces and constructing search trees." << endl; + const dictionary& motionDict = dict_.subDict("motionDict"); + const dictionary& shrinkDict = dict_.subDict("shrinkDict"); + PtrList<dictionary> surfaceDicts(dict_.lookup("surfaces")); - surfacesPtr_.reset + autoLayerDriver layerDriver ( - new refinementSurfaces - ( - IOobject - ( - "", // dummy name - mesh_.time().constant(), // directory - "triSurface", // instance - mesh_.time(), // registry - IOobject::MUST_READ, - IOobject::NO_WRITE - ), - refineDict.lookup("surfaces") - ) + meshRefinerPtr_(), + globalToPatch_ ); - Info<< "Read surfaces in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; - // Orient surfaces (if they're closed) before any searching is done. - Info<< "Orienting (closed) surfaces so keepPoint is outside." << endl; - forAll(surfaces(), i) - { - if (refinementSurfaces::isSurfaceClosed(surfaces()[i])) - { - refinementSurfaces::orientSurface - ( - keepPoints_[0], - surfacesPtr_()[i] - ); - } - } - Info<< "Oriented closed surfaces in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; - - Info<< "Setting refinement level of surface to be consistent" - << " with shells." << endl; - surfacesPtr_().setMinLevelFields + // Get all the layer specific params + layerParameters layerParams ( - shells_, - shellLevels_, - shellRefineInside_ + surfaceDicts, + surfacesPtr_(), + globalToPatch_, + shrinkDict, + mesh_.boundaryMesh() ); - Info<< "Checked shell refinement in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; - } - // Check faceZones are synchronised - checkCoupledFaceZones(); - - - // Add all the surface regions as patches - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - { - Info<< nl - << "Adding patches for surface regions" << nl - << "----------------------------------" << nl - << endl; - - // From global region number to mesh patch. - globalToPatch_.setSize(surfaces().nRegions(), -1); - - Info<< "Patch\tRegion" << nl - << "-----\t------" - << endl; - - forAll(surfaces(), surfI) - { - const triSurfaceMesh& s = surfaces()[surfI]; - - Info<< surfaces().names()[surfI] << ':' << nl << nl; - - const geometricSurfacePatchList& regions = s.patches(); - - labelList nTrisPerRegion(surfaces().countRegions(s)); - - forAll(regions, i) - { - if (nTrisPerRegion[i] > 0) - { - label patchI = meshRefinement::addPatch - ( - mesh, - //s.searchableSurface::name() + '_' + regions[i].name(), - surfaces().names()[surfI] + '_' + regions[i].name(), - wallPolyPatch::typeName - ); - - Info<< patchI << '\t' << regions[i].name() << nl; - - globalToPatch_[surfaces().globalRegion(surfI, i)] = patchI; - } - } - - Info<< nl; - } - Info<< "Added patches in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; - } - - // Parallel - // ~~~~~~~~ - - { - // Decomposition - decomposerPtr_ = decompositionMethod::New - ( - decomposeDict, - mesh_ - ); - decompositionMethod& decomposer = decomposerPtr_(); - - - if (Pstream::parRun() && !decomposer.parallelAware()) - { - FatalErrorIn("autoHexMeshDriver::autoHexMeshDriver(const IOobject&, fvMesh&)") - << "You have selected decomposition method " - << decomposer.typeName - << " which is not parallel aware." << endl - << "Please select one that is (parMetis, hierarchical)" - << exit(FatalError); - } - - // Mesh distribution engine (uses tolerance to reconstruct meshes) - distributorPtr_.reset(new fvMeshDistribute(mesh_, mergeDist_)); - } - - - // Refinement engine - // ~~~~~~~~~~~~~~~~~ - - { - Info<< nl - << "Determining initial surface intersections" << nl - << "-----------------------------------------" << nl - << endl; - - // Main refinement engine - meshRefinerPtr_.reset - ( - new meshRefinement - ( - mesh, - mergeDist_, // tolerance used in sorting coordinates - surfaces() - ) - ); - Info<< "Calculated surface intersections in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; - - // Some stats - meshRefinerPtr_().printMeshInfo(debug_, "Initial mesh"); - - meshRefinerPtr_().write - ( - debug_&meshRefinement::OBJINTERSECTIONS, - mesh_.time().path()/mesh_.time().timeName() - ); - } -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -// Read explicit feature edges -Foam::label Foam::autoHexMeshDriver::readFeatureEdges -( - const PtrList<dictionary>& featDicts -) -{ - Info<< "Reading external feature lines." << endl; - - featureMeshes_.setSize(featDicts.size()); - featureLevels_.setSize(featDicts.size()); - - forAll(featDicts, i) - { - const dictionary& dict = featDicts[i]; - - fileName featFileName(dict.lookup("file")); - - featureMeshes_.set - ( - i, - new featureEdgeMesh - ( - IOobject - ( - featFileName, // name - mesh_.time().constant(),// directory - "triSurface", // instance - mesh_.db(), // registry - IOobject::MUST_READ, - IOobject::NO_WRITE, - false - ) - ) - ); - - featureMeshes_[i].mergePoints(mergeDist_); - featureLevels_[i] = readLabel(dict.lookup("level")); - - Info<< "Refinement level " << featureLevels_[i] - << " for all cells crossed by feature " << featFileName - << " (" << featureMeshes_[i].points().size() << " points, " - << featureMeshes_[i].edges().size() << ")." << endl; - } - - Info<< "Read feature lines in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; - - return featureMeshes_.size(); -} - - -Foam::label Foam::autoHexMeshDriver::featureEdgeRefine -( - const PtrList<dictionary>& featDicts, - const label maxIter, - const label minRefine -) -{ - // Read explicit feature edges - readFeatureEdges(featDicts); - - meshRefinement& meshRefiner = meshRefinerPtr_(); - - label iter = 0; - - if (featureMeshes_.size() > 0 && maxIter > 0) - { - for (; iter < maxIter; iter++) - { - Info<< nl - << "Feature refinement iteration " << iter << nl - << "------------------------------" << nl - << endl; - - labelList candidateCells - ( - meshRefiner.refineCandidates - ( - keepPoints_[0], // For now only use one. - globalToPatch_, - curvature_, - - featureMeshes_, - featureLevels_, - - shells_, - shellLevels_, - shellRefineInside_, - - true, // featureRefinement - false, // internalRefinement - false, // surfaceRefinement - false, // curvatureRefinement - maxGlobalCells_, - maxLocalCells_ - ) - ); - labelList cellsToRefine - ( - meshRefiner.meshCutter().consistentRefinement - ( - candidateCells, - true - ) - ); - Info<< "Determined cells to refine in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; - - - - label nCellsToRefine = cellsToRefine.size(); - reduce(nCellsToRefine, sumOp<label>()); - - Info<< "Selected for feature refinement : " << nCellsToRefine - << " cells (out of " << mesh_.globalData().nTotalCells() - << ')' << endl; - - if (nCellsToRefine <= minRefine) - { - Info<< "Stopping refining since too few cells selected." - << nl << endl; - break; - } - - - if (debug_ > 0) - { - const_cast<Time&>(mesh_.time())++; - } - - meshRefiner.refineAndBalance - ( - "feature refinement iteration " + name(iter), - decomposerPtr_(), - distributorPtr_(), - cellsToRefine - ); - } - } - return iter; -} - - -Foam::label Foam::autoHexMeshDriver::surfaceOnlyRefine(const label maxIter) -{ - meshRefinement& meshRefiner = meshRefinerPtr_(); - - // Determine the maximum refinement level over all surfaces. This - // determines the minumum number of surface refinement iterations. - label overallMaxLevel = max(surfaces().maxLevel()); - - label iter; - for (iter = 0; iter < maxIter; iter++) - { - Info<< nl - << "Surface refinement iteration " << iter << nl - << "------------------------------" << nl - << endl; - - - // Determine cells to refine - // ~~~~~~~~~~~~~~~~~~~~~~~~~ - // Only look at surface intersections (minLevel and surface curvature), - // do not do internal refinement (refinementShells) - - labelList candidateCells - ( - meshRefiner.refineCandidates - ( - keepPoints_[0], - globalToPatch_, - curvature_, - - featureMeshes_, - featureLevels_, - - shells_, - shellLevels_, - shellRefineInside_, - - false, // featureRefinement - false, // internalRefinement - true, // surfaceRefinement - true, // curvatureRefinement - maxGlobalCells_, - maxLocalCells_ - ) - ); - labelList cellsToRefine - ( - meshRefiner.meshCutter().consistentRefinement - ( - candidateCells, - true - ) - ); - Info<< "Determined cells to refine in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; - - - label nCellsToRefine = cellsToRefine.size(); - reduce(nCellsToRefine, sumOp<label>()); - - Info<< "Selected for refinement : " << nCellsToRefine - << " cells (out of " << mesh_.globalData().nTotalCells() - << ')' << endl; - - // Stop when no cells to refine or have done minimum nessecary - // iterations and not enough cells to refine. - if - ( - nCellsToRefine == 0 - || ( - iter >= overallMaxLevel - && nCellsToRefine <= minRefineCells_ - ) - ) - { - Info<< "Stopping refining since too few cells selected." - << nl << endl; - break; - } - - - if (debug_) - { - const_cast<Time&>(mesh_.time())++; - } - - meshRefiner.refineAndBalance - ( - "surface refinement iteration " + name(iter), - decomposerPtr_(), - distributorPtr_(), - cellsToRefine - ); - } - return iter; -} - - -void Foam::autoHexMeshDriver::removeInsideCells(const label nBufferLayers) -{ - - meshRefinement& meshRefiner = meshRefinerPtr_(); - - Info<< nl - << "Removing mesh beyond surface intersections" << nl - << "------------------------------------------" << nl - << endl; - - if (debug_) - { - const_cast<Time&>(mesh_.time())++; - } - - meshRefiner.splitMesh - ( - nBufferLayers, // nBufferLayers - globalToPatch_, - keepPoints_[0] - ); - - if (debug_) - { - Pout<< "Writing subsetted mesh to time " - << mesh_.time().timeName() << '.' << endl; - meshRefiner.write(debug_, mesh_.time().path()/mesh_.time().timeName()); - Pout<< "Dumped mesh in = " - << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl; - } -} - - -Foam::label Foam::autoHexMeshDriver::shellRefine(const label maxIter) -{ - meshRefinement& meshRefiner = meshRefinerPtr_(); - - - // Mark current boundary faces with 0. Have meshRefiner maintain them. - meshRefiner.userFaceData().setSize(1); - - // mark list to remove any refined faces - meshRefiner.userFaceData()[0].first() = meshRefinement::REMOVE; - meshRefiner.userFaceData()[0].second() = createWithValues<labelList> - ( - mesh_.nFaces(), - -1, - meshRefiner.intersectedFaces(), - 0 - ); - - // Determine the maximum refinement level over all volume refinement - // regions. This determines the minumum number of shell refinement - // iterations. - label overallMaxShellLevel; - if (shellLevels_.size() == 0) - { - overallMaxShellLevel = 0; - } - else - { - overallMaxShellLevel = max(shellLevels_); - } - - label iter; - for (iter = 0; iter < maxIter; iter++) - { - Info<< nl - << "Shell refinement iteration " << iter << nl - << "----------------------------" << nl - << endl; - - labelList candidateCells - ( - meshRefiner.refineCandidates - ( - keepPoints_[0], - globalToPatch_, - curvature_, - - featureMeshes_, - featureLevels_, - - shells_, - shellLevels_, - shellRefineInside_, - - false, // featureRefinement - true, // internalRefinement - false, // surfaceRefinement - false, // curvatureRefinement - maxGlobalCells_, - maxLocalCells_ - ) - ); - - if (debug_) - { - Pout<< "Dumping " << candidateCells.size() - << " cells to cellSet candidateCellsFromShells." << endl; - - cellSet(mesh_, "candidateCellsFromShells", candidateCells).write(); - } - - // Problem choosing starting faces for bufferlayers (bFaces) - // - we can't use the current intersected boundary faces - // (intersectedFaces) since this grows indefinitely - // - if we use 0 faces we don't satisfy bufferLayers from the - // surface. - // - possibly we want to have bFaces only the initial set of faces - // and maintain the list while doing the refinement. - labelList bFaces - ( - findIndices(meshRefiner.userFaceData()[0].second(), 0) - ); - - Info<< "Collected boundary faces : " - << returnReduce(bFaces.size(), sumOp<label>()) << endl; - - labelList cellsToRefine; - - if (nBufferLayers_ <= 2) - { - cellsToRefine = meshRefiner.meshCutter().consistentSlowRefinement - ( - nBufferLayers_, - candidateCells, // cells to refine - bFaces, // faces for nBufferLayers - 1, // point difference - meshRefiner.intersectedPoints() // points to check - ); - } - else - { - cellsToRefine = meshRefiner.meshCutter().consistentSlowRefinement2 - ( - nBufferLayers_, - candidateCells, // cells to refine - bFaces // faces for nBufferLayers - ); - } - - Info<< "Determined cells to refine in = " - << mesh_.time().cpuTimeIncrement() << " s" << endl; - - - label nCellsToRefine = cellsToRefine.size(); - reduce(nCellsToRefine, sumOp<label>()); - - Info<< "Selected for internal refinement : " << nCellsToRefine - << " cells (out of " << mesh_.globalData().nTotalCells() - << ')' << endl; - - // Stop when no cells to refine or have done minimum nessecary - // iterations and not enough cells to refine. - if - ( - nCellsToRefine == 0 - || ( - iter >= overallMaxShellLevel - && nCellsToRefine <= minRefineCells_ - ) - ) - { - Info<< "Stopping refining since too few cells selected." - << nl << endl; - break; - } - - - if (debug_) - { - const_cast<Time&>(mesh_.time())++; - } - - meshRefiner.refineAndBalance - ( - "shell refinement iteration " + name(iter), - decomposerPtr_(), - distributorPtr_(), - cellsToRefine - ); - } - meshRefiner.userFaceData().clear(); - - return iter; -} - - -void Foam::autoHexMeshDriver::baffleAndSplitMesh(const bool handleSnapProblems) -{ - meshRefinement& meshRefiner = meshRefinerPtr_(); - - Info<< nl - << "Splitting mesh at surface intersections" << nl - << "---------------------------------------" << nl - << endl; - - // Introduce baffles at surface intersections. Note: - // meshRefiment::surfaceIndex() will - // be like boundary face from now on so not coupled anymore. - meshRefiner.baffleAndSplitMesh - ( - handleSnapProblems, - !handleSnapProblems, // merge free standing baffles? - const_cast<Time&>(mesh_.time()), - globalToPatch_, - keepPoints_[0] - ); -} - - -void Foam::autoHexMeshDriver::zonify() -{ - // Mesh is at its finest. Do zoning - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // This puts all faces with intersection across a zoneable surface - // into that surface's faceZone. All cells inside faceZone get given the - // same cellZone. - - - meshRefinement& meshRefiner = meshRefinerPtr_(); - - if (surfaces().getNamedSurfaces().size() > 0) - { - Info<< nl - << "Introducing zones for interfaces" << nl - << "--------------------------------" << nl - << endl; - - if (debug_) - { - const_cast<Time&>(mesh_.time())++; - } - - meshRefiner.zonify(keepPoints_[0]); - - if (debug_) - { - Pout<< "Writing zoned mesh to time " - << mesh_.time().timeName() << '.' << endl; - meshRefiner.write - ( - debug_, - mesh_.time().path()/mesh_.time().timeName() - ); - } - - // Check that all faces are synced - checkCoupledFaceZones(); - } -} - - -void Foam::autoHexMeshDriver::splitAndMergeBaffles -( - const bool handleSnapProblems -) -{ - Info<< nl - << "Handling cells with snap problems" << nl - << "---------------------------------" << nl - << endl; - - // Introduce baffles and split mesh - if (debug_) - { - const_cast<Time&>(mesh_.time())++; - } - - meshRefinement& meshRefiner = meshRefinerPtr_(); - - meshRefiner.baffleAndSplitMesh - ( - handleSnapProblems, - false, // merge free standing baffles? - const_cast<Time&>(mesh_.time()), - globalToPatch_, - keepPoints_[0] - ); - - if (debug_) - { - const_cast<Time&>(mesh_.time())++; - } - - // Duplicate points on baffles that are on more than one cell - // region. This will help snapping pull them to separate surfaces. - meshRefiner.dupNonManifoldPoints(); - - - // Merge all baffles that are still remaining after duplicating points. - List<labelPair> couples - ( - meshRefiner.getDuplicateFaces // get all baffles - ( - identity(mesh_.nFaces()-mesh_.nInternalFaces()) - +mesh_.nInternalFaces() - ) - ); - - label nCouples = returnReduce(couples.size(), sumOp<label>()); - - Info<< "Detected unsplittable baffles : " - << nCouples << endl; - - if (nCouples > 0) - { - // Actually merge baffles. Note: not exactly parallellized. Should - // convert baffle faces into processor faces if they resulted - // from them. - meshRefiner.mergeBaffles(couples); - - if (debug_) - { - // Debug:test all is still synced across proc patches - meshRefiner.checkData(); - } - Info<< "Merged free-standing baffles in = " - << mesh_.time().cpuTimeIncrement() << " s." << endl; - } - - if (debug_) - { - Pout<< "Writing handleProblemCells mesh to time " - << mesh_.time().timeName() << '.' << endl; - meshRefiner.write(debug_, mesh_.time().path()/mesh_.time().timeName()); - } -} - - -void Foam::autoHexMeshDriver::mergePatchFaces() -{ - Info<< nl - << "Merge refined boundary faces" << nl - << "----------------------------" << nl - << endl; - - if (debug_) - { - const_cast<Time&>(mesh_.time())++; - } - - meshRefinement& meshRefiner = meshRefinerPtr_(); - - meshRefiner.mergePatchFaces - ( - Foam::cos(45*mathematicalConstant::pi/180.0), - Foam::cos(45*mathematicalConstant::pi/180.0), - meshRefinement::addedPatches(globalToPatch_) - ); - - if (debug_) - { - meshRefiner.checkData(); - } - - meshRefiner.mergeEdges(Foam::cos(45*mathematicalConstant::pi/180.0)); - - if (debug_) - { - meshRefiner.checkData(); - } -} - - -Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::autoHexMeshDriver::balance -( - const bool keepZoneFaces, - const bool keepBaffles -) -{ - autoPtr<mapDistributePolyMesh> map; - - if (Pstream::parRun()) - { - Info<< nl - << "Doing final balancing" << nl - << "---------------------" << nl - << endl; - - if (debug_) - { - const_cast<Time&>(mesh_.time())++; - } - - meshRefinement& meshRefiner = meshRefinerPtr_(); - decompositionMethod& decomposer = decomposerPtr_(); - fvMeshDistribute& distributor = distributorPtr_(); - - // Wanted distribution - labelList distribution; - - if (keepZoneFaces || keepBaffles) - { - // Faces where owner and neighbour are not 'connected' so can - // go to different processors. - boolList blockedFace(mesh_.nFaces(), true); - // Pairs of baffles - List<labelPair> couples; - - if (keepZoneFaces) - { - label nNamed = surfaces().getNamedSurfaces().size(); - - Info<< "Found " << nNamed << " surfaces with faceZones." - << " Applying special decomposition to keep those together." - << endl; - - // Determine decomposition to keep/move surface zones - // on one processor. The reason is that snapping will make these - // into baffles, move and convert them back so if they were - // proc boundaries after baffling&moving the points might be no - // longer snychronised so recoupling will fail. To prevent this - // keep owner&neighbour of such a surface zone on the same - // processor. - - const wordList& fzNames = surfaces().faceZoneNames(); - const faceZoneMesh& fZones = mesh_.faceZones(); - - // Get faces whose owner and neighbour should stay together, i.e. - // they are not 'blocked'. - - label nZoned = 0; - - forAll(fzNames, surfI) - { - if (fzNames[surfI].size() > 0) - { - // Get zone - label zoneI = fZones.findZoneID(fzNames[surfI]); - - const faceZone& fZone = fZones[zoneI]; - - forAll(fZone, i) - { - if (blockedFace[fZone[i]]) - { - blockedFace[fZone[i]] = false; - nZoned++; - } - } - } - } - Info<< "Found " << returnReduce(nZoned, sumOp<label>()) - << " zoned faces to keep together." - << endl; - } - - if (keepBaffles) - { - // Get boundary baffles that need to stay together. - couples = meshRefiner.getDuplicateFaces // all baffles - ( - identity(mesh_.nFaces()-mesh_.nInternalFaces()) - +mesh_.nInternalFaces() - ); - - Info<< "Found " << returnReduce(couples.size(), sumOp<label>()) - << " baffles to keep together." - << endl; - } - - distribution = meshRefiner.decomposeCombineRegions - ( - blockedFace, - couples, - decomposer - ); - - labelList nProcCells(distributor.countCells(distribution)); - Pstream::listCombineGather(nProcCells, plusEqOp<label>()); - Pstream::listCombineScatter(nProcCells); - - Info<< "Calculated decomposition:" << endl; - forAll(nProcCells, procI) - { - Info<< " " << procI << '\t' << nProcCells[procI] << endl; - } - Info<< endl; - } - else - { - // Normal decomposition - distribution = decomposer.decompose(mesh_.cellCentres()); - } - - if (debug_) - { - Pout<< "Wanted distribution:" - << distributor.countCells(distribution) - << endl; - } - // Do actual sending/receiving of mesh - map = distributor.distribute(distribution); - - // Update numbering of meshRefiner - meshRefiner.distribute(map); - } - return map; -} - - -void Foam::autoHexMeshDriver::writeMesh(const string& msg) const -{ - const meshRefinement& meshRefiner = meshRefinerPtr_(); - - meshRefiner.printMeshInfo(debug_, msg); - Info<< "Writing mesh to time " << mesh_.time().timeName() << endl; - - meshRefiner.write(meshRefinement::MESH|meshRefinement::SCALARLEVELS, ""); - if (debug_ & meshRefinement::OBJINTERSECTIONS) - { - meshRefiner.write - ( - meshRefinement::OBJINTERSECTIONS, - mesh_.time().path()/mesh_.time().timeName() - ); - } - Info<< "Written mesh in = " - << mesh_.time().cpuTimeIncrement() << " s." << endl; -} - - - - -void Foam::autoHexMeshDriver::doRefine -( - const dictionary& refineDict, - const bool prepareForSnapping -) -{ - Info<< nl - << "Refinement phase" << nl - << "----------------" << nl - << endl; - - const_cast<Time&>(mesh_.time())++; - - PtrList<dictionary> featDicts(refineDict.lookup("features")); - - // Refine around feature edges - featureEdgeRefine - ( - featDicts, - 100, // maxIter - 0 // min cells to refine - ); - - // Refine based on surface - surfaceOnlyRefine - ( - 100 // maxIter - ); - - // Remove cells (a certain distance) beyond surface intersections - removeInsideCells - ( - 1 // nBufferLayers - ); - - // Internal mesh refinement - shellRefine - ( - 100 // maxIter - ); - - // Introduce baffles at surface intersections - baffleAndSplitMesh(prepareForSnapping); - - // Mesh is at its finest. Do optional zoning. - zonify(); - - // Pull baffles apart - splitAndMergeBaffles(prepareForSnapping); - - // Do something about cells with refined faces on the boundary - if (prepareForSnapping) - { - mergePatchFaces(); - } - - // Do final balancing. Keep zoned faces on one processor. - balance(true, false); - - // Write mesh - writeMesh("Refined mesh"); -} - - -void Foam::autoHexMeshDriver::doSnap -( - const dictionary& snapDict, - const dictionary& motionDict -) -{ - Info<< nl - << "Morphing phase" << nl - << "--------------" << nl - << endl; - - const_cast<Time&>(mesh_.time())++; - - // Get the labels of added patches. - labelList adaptPatchIDs(getSurfacePatches()); - - // Create baffles (pairs of faces that share the same points) - // Baffles stored as owner and neighbour face that have been created. - List<labelPair> baffles; - createZoneBaffles(baffles); - - { - autoPtr<indirectPrimitivePatch> ppPtr - ( - meshRefinement::makePatch - ( - mesh_, - adaptPatchIDs - ) - ); - indirectPrimitivePatch& pp = ppPtr(); - - // Distance to attact to nearest feature on surface - const scalarField snapDist(calcSnapDistance(snapDict, pp)); - - - // Construct iterative mesh mover. - Info<< "Constructing mesh displacer ..." << endl; - Info<< "Using mesh parameters " << motionDict << nl << endl; - - pointMesh pMesh(mesh_); - - motionSmoother meshMover - ( - mesh_, - pp, - adaptPatchIDs, - meshRefinement::makeDisplacementField(pMesh, adaptPatchIDs), - motionDict - ); - - - // Check initial mesh - Info<< "Checking initial mesh ..." << endl; - labelHashSet wrongFaces(mesh_.nFaces()/100); - motionSmoother::checkMesh(false, mesh_, motionDict, wrongFaces); - const label nInitErrors = returnReduce - ( - wrongFaces.size(), - sumOp<label>() - ); - - Info<< "Detected " << nInitErrors << " illegal faces" - << " (concave, zero area or negative cell pyramid volume)" - << endl; - - - Info<< "Checked initial mesh in = " - << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl; - - // Pre-smooth patch vertices (so before determining nearest) - preSmoothPatch(snapDict, nInitErrors, baffles, meshMover); - - // Calculate displacement at every patch point. Insert into - // meshMover. - calcNearestSurface(snapDist, meshMover); - - // Get smoothly varying internal displacement field. - smoothDisplacement(snapDict, meshMover); - - // Apply internal displacement to mesh. - scaleMesh(snapDict, nInitErrors, baffles, meshMover); - } - - // Merge any introduced baffles. - mergeZoneBaffles(baffles); - - // Write mesh. - writeMesh("Snapped mesh"); -} - - -void Foam::autoHexMeshDriver::doLayers -( - const dictionary& shrinkDict, - const dictionary& motionDict -) -{ - Info<< nl - << "Shrinking and layer addition phase" << nl - << "----------------------------------" << nl - << endl; - - const_cast<Time&>(mesh_.time())++; - - Info<< "Using mesh parameters " << motionDict << nl << endl; - - // Merge coplanar boundary faces - mergePatchFacesUndo(shrinkDict, motionDict); - - // Per global region the number of layers (0 if no layer) - const labelList& numLayers = surfaces().numLayers(); - - // Patches that need to get a layer - DynamicList<label> patchIDs(numLayers.size()); - label nFacesWithLayers = 0; - forAll(numLayers, region) - { - if (numLayers[region] > 0 && globalToPatch()[region] != -1) - { - label patchI = globalToPatch()[region]; - patchIDs.append(patchI); - nFacesWithLayers += mesh_.boundaryMesh()[patchI].size(); - } - } - patchIDs.shrink(); - - if (returnReduce(nFacesWithLayers, sumOp<label>()) == 0) - { - Info<< nl << "No layers to generate ..." << endl; - } - else - { - autoPtr<indirectPrimitivePatch> ppPtr - ( - meshRefinement::makePatch - ( - mesh_, - patchIDs - ) - ); - indirectPrimitivePatch& pp = ppPtr(); - - // Construct iterative mesh mover. - Info<< "Constructing mesh displacer ..." << endl; - - { - pointMesh pMesh(mesh_); - - motionSmoother meshMover - ( - mesh_, - pp, - patchIDs, - meshRefinement::makeDisplacementField(pMesh, patchIDs), - motionDict - ); - - // Check that outside of mesh is not multiply connected. - checkMeshManifold(); - - // Check initial mesh - Info<< "Checking initial mesh ..." << endl; - labelHashSet wrongFaces(mesh_.nFaces()/100); - motionSmoother::checkMesh(false, mesh_, motionDict, wrongFaces); - const label nInitErrors = returnReduce - ( - wrongFaces.size(), - sumOp<label>() - ); - - Info<< "Detected " << nInitErrors << " illegal faces" - << " (concave, zero area or negative cell pyramid volume)" - << endl; - - // Do all topo changes - addLayers(shrinkDict, motionDict, nInitErrors, meshMover); - } + layerDriver.doLayers + ( + shrinkDict, + motionDict, + layerParams, + decomposerPtr_(), + distributorPtr_() + ); // Write mesh. writeMesh("Layer mesh"); @@ -1891,38 +565,4 @@ void Foam::autoHexMeshDriver::doLayers } -void Foam::autoHexMeshDriver::doMesh() -{ - Switch wantRefine(dict_.lookup("doRefine")); - Switch wantSnap(dict_.lookup("doSnap")); - Switch wantLayers(dict_.lookup("doLayers")); - - Info<< "Do refinement : " << wantRefine << nl - << "Do snapping : " << wantSnap << nl - << "Do layers : " << wantLayers << nl - << endl; - - if (wantRefine) - { - doRefine(dict_, wantSnap); - } - - if (wantSnap) - { - const dictionary& snapDict = dict_.subDict("snapDict"); - const dictionary& motionDict = dict_.subDict("motionDict"); - - doSnap(snapDict, motionDict); - } - - if (wantLayers) - { - const dictionary& motionDict = dict_.subDict("motionDict"); - const dictionary& shrinkDict = dict_.subDict("shrinkDict"); - - doLayers(shrinkDict, motionDict); - } -} - - // ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H index 28a4845b9a81090d778dd8df172844fc53a7aaf5..553f1690b8e9837e3ee5264d8bb5ef433b3d0629 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H @@ -30,10 +30,6 @@ Description SourceFiles autoHexMeshDriver.C - autoHexMeshDriverSnap.C - autoHexMeshDriverLayers.C - autoHexMeshDriverShrink.C - autoHexMeshDriverTemplates.C \*---------------------------------------------------------------------------*/ @@ -44,13 +40,10 @@ SourceFiles #include "dictionary.H" #include "pointField.H" #include "boolList.H" -#include "Switch.H" -#include "PackedList.H" #include "wallPoint.H" -#include "indirectPrimitivePatch.H" -#include "featureEdgeMesh.H" -#include "searchableSurface.H" +#include "searchableSurfaces.H" #include "refinementSurfaces.H" +#include "shellSurfaces.H" #include "meshRefinement.H" #include "decompositionMethod.H" #include "fvMeshDistribute.H" @@ -62,14 +55,6 @@ namespace Foam // Class forward declarations class fvMesh; -class pointMesh; -class motionSmoother; -class removePoints; -class pointSet; -class pointData; -class faceSet; -class addPatchCellLayer; -class mapDistributePolyMesh; /*---------------------------------------------------------------------------*\ Class autoHexMeshDriver Declaration @@ -79,15 +64,13 @@ class autoHexMeshDriver { // Static data members - //- Default angle for faces to be convcave - static const scalar defaultConcaveAngle; - //- Extrusion controls enum extrudeMode { NOEXTRUDE, /*!< Do not extrude. No layers added. */ EXTRUDE, /*!< Extrude */ - EXTRUDEREMOVE /*!< Extrude but afterwards remove added faces locally */ + EXTRUDEREMOVE /*!< Extrude but afterwards remove added */ + /*!< faces locally */ }; @@ -141,42 +124,17 @@ class autoHexMeshDriver //- Debug level const label debug_; - //- Total number of cells - const label maxGlobalCells_; - - //- Per processor max number of cells - const label maxLocalCells_; - - //- When to stop refining - const label minRefineCells_; - - //- Curvature - const scalar curvature_; - - //- Number of layers between different refinement levels - const label nBufferLayers_; - - //- Areas to keep - const pointField keepPoints_; - //- Merge distance const scalar mergeDist_; + //- All surface based geometry + autoPtr<searchableSurfaces> allGeometryPtr_; - //- Explicit features - PtrList<featureEdgeMesh> featureMeshes_; - //- Per feature the refinement level - labelList featureLevels_; - - //- Shells - PtrList<searchableSurface> shells_; - //- Per shell the refinement level - labelList shellLevels_; - //- Per shell whether to refine inside or outside - boolList shellRefineInside_; + //- Shells (geometry for inside/outside refinement) + autoPtr<shellSurfaces> shellsPtr_; - //- Surfaces with refinement levels built-in + //- Surfaces (geometry for intersection based refinement) autoPtr<refinementSurfaces> surfacesPtr_; //- Per refinement surface region the patch @@ -195,434 +153,10 @@ class autoHexMeshDriver // Private Member Functions - // Refinement - - //- Calculate merge distance. Check against writing tolerance. - scalar getMergeDistance(const scalar mergeTol) const; - - // Return per keeppoint -1 or the local cell label the point is in. - // Guaranteed to be only on one processor. - labelList findCells(const pointField&) const; - - static void orientOutside(PtrList<searchableSurface>&); - - //- Read feature edges - label readFeatureEdges(const PtrList<dictionary>&); - - // Snapping - - //- Split surfaces into non-zoned and zones ones - void getZonedSurfaces(labelList&, labelList&) const; - - //- Get faces to repatch. Returns map from face to patch. - Map<label> getZoneBafflePatches(const bool allowBoundary) const; - - //- Calculates (geometric) shared points - static label getCollocatedPoints - ( - const scalar tol, - const pointField&, - PackedList<1>& - ); - - //- Calculate displacement per patch point to smooth out patch. - // Quite complicated in determining which points to move where. - pointField smoothPatchDisplacement(const motionSmoother&) const; - - //- Check that face zones are synced - void checkCoupledFaceZones() const; - - //- Per edge distance to patch - static tmp<scalarField> edgePatchDist - ( - const pointMesh&, - const indirectPrimitivePatch& - ); - - //- Write displacement as .obj file. - static void dumpMove - ( - const fileName&, - const pointField&, - const pointField& - ); - - //- Check displacement is outwards pointing - static bool outwardsDisplacement - ( - const indirectPrimitivePatch&, - const vectorField& - ); - - // Face merging - - //- Merge patch faces. Undo until no checkMesh errors. - label mergePatchFacesUndo - ( - const scalar minCos, - const scalar concaveCos, - const dictionary& - ); - - //- Remove points. - autoPtr<mapPolyMesh> doRemovePoints - ( - removePoints& pointRemover, - const boolList& pointCanBeDeleted - ); - - //- Restore faces (which contain removed points) - autoPtr<mapPolyMesh> doRestorePoints - ( - removePoints& pointRemover, - const labelList& facesToRestore - ); - - //- Return candidateFaces that are also in set. - labelList collectFaces - ( - const labelList& candidateFaces, - const labelHashSet& set - ) const; - - //- Pick up faces of cells of faces in set. - labelList growFaceCellFace(const labelHashSet&) const; - - //- Remove points not used by any face or points used by only - // two faces where the edges are in line - label mergeEdgesUndo(const scalar minCos, const dictionary&); - - - // Layers - - //- For debugging: Dump displacement to .obj files - static void dumpDisplacement - ( - const fileName&, - const indirectPrimitivePatch&, - const vectorField&, - const List<extrudeMode>& - ); - - //- Check that primitivePatch is not multiply connected. - // Collect non-manifold points in pointSet. - static void checkManifold - ( - const indirectPrimitivePatch&, - pointSet& nonManifoldPoints - ); - - - // Static extrusion setup - - //- Unset extrusion on point. Returns true if anything unset. - static bool unmarkExtrusion - ( - const label patchPointI, - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ); - - //- Unset extrusion on face. Returns true if anything unset. - static bool unmarkExtrusion - ( - const face& localFace, - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ); - - //- No extrusion at non-manifold points. - void handleNonManifolds - ( - const indirectPrimitivePatch& pp, - const labelList& meshEdges, - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ) const; - - //- No extrusion on feature edges. Assumes non-manifold - // edges already handled. - void handleFeatureAngle - ( - const indirectPrimitivePatch& pp, - const labelList& meshEdges, - const scalar minCos, - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ) const; - - //- No extrusion on warped faces - void handleWarpedFaces - ( - const indirectPrimitivePatch& pp, - const scalar faceRatio, - const scalar edge0Len, - const labelList& cellLevel, - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ) const; - - //- Determine the number of layers per point from the number of - // layers per surface. - void setNumLayers - ( - const labelList& patchIDs, - const indirectPrimitivePatch& pp, - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ) const; - - //- Grow no-extrusion layer. - static void growNoExtrusion - ( - const indirectPrimitivePatch& pp, - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ); - - //- Calculate pointwise wanted and minimum thickness. - // thickness: wanted thickness - // minthickness: when to give up and not extrude - void calculateLayerThickness - ( - const scalar expansionRatio, - const scalar finalLayerRatio, - const scalar relMinThickness, - const indirectPrimitivePatch& pp, - const labelList& cellLevel, - const labelList& patchNLayers, - const scalar edge0Len, - scalarField& thickness, - scalarField& minThickness - ) const; - - - // Extrusion execution - - //- Synchronize displacement among coupled patches. - void syncPatchDisplacement - ( - const motionSmoother& meshMover, - const scalarField& minThickness, - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ) const; - - //- Get nearest point on surface to snap to - void getPatchDisplacement - ( - const motionSmoother& meshMover, - const scalarField& thickness, - const scalarField& minThickness, - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ) const; - - //- Truncates displacement - // - for all patchFaces in the faceset displacement gets set - // to zero - // - all displacement < minThickness gets set to zero - label truncateDisplacement - ( - const motionSmoother& meshMover, - const scalarField& minThickness, - const faceSet& illegalPatchFaces, - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ) const; - - //- Setup layer information (at points and faces) to - // modify mesh topology in - // regions where layer mesh terminates. Guarantees an - // optional slow decreasing of the number of layers. - // Returns the number of layers per face and per point - // to go into the actual layer addition engine. - void setupLayerInfoTruncation - ( - const motionSmoother& meshMover, - const labelList& patchNLayers, - const List<extrudeMode>& extrudeStatus, - const label nBufferCellsNoExtrude, - labelList& nPatchPointLayers, - labelList& nPatchFaceLayers - ) const; - - //- Does any of the cells use a face from faces? - static bool cellsUseFace - ( - const polyMesh& mesh, - const labelList& cellLabels, - const labelHashSet& faces - ); - - //- Checks the newly added cells and locally unmarks points - // so they will not get extruded next time round. Returns - // global number of unmarked points (0 if all was fine) - static label checkAndUnmark - ( - const addPatchCellLayer& addLayer, - const dictionary& motionDict, - const indirectPrimitivePatch& pp, - const fvMesh&, - - pointField& patchDisp, - labelList& patchNLayers, - List<extrudeMode>& extrudeStatus - ); - - //- Count global number of extruded faces - static label countExtrusion - ( - const indirectPrimitivePatch& pp, - const List<extrudeMode>& extrudeStatus - ); - - //- Collect layer faces and layer cells into bools - // for ease of handling - static void getLayerCellsFaces - ( - const polyMesh&, - const addPatchCellLayer&, - boolList&, - boolList& - ); - - // Mesh shrinking (to create space for layers) - - //- Average field (over all subset of mesh points) by - // summing contribution from edges. Global parallel since only - // does master edges for coupled edges. - template<class Type> - void averageNeighbours - ( - const PackedList<1>& isMasterEdge, - const labelList& meshEdges, - const labelList& meshPoints, - const edgeList& edges, - const scalarField& invSumWeight, - const Field<Type>& data, - Field<Type>& average - ) const; - - //- Calculate inverse sum of edge weights (currently always 1.0) - void sumWeights - ( - const PackedList<1>& isMasterEdge, - const labelList& meshEdges, - const labelList& meshPoints, - const edgeList& edges, - scalarField& invSumWeight - ) const; - - //- Smooth scalar field on patch - void smoothField - ( - const motionSmoother& meshMover, - const PackedList<1>& isMasterEdge, - const labelList& meshEdges, - const scalarField& fieldMin, - const label& nSmoothDisp, - scalarField& field - ) const; - - //- Smooth normals on patch. - void smoothPatchNormals - ( - const motionSmoother& meshMover, - const PackedList<1>& isMasterEdge, - const labelList& meshEdges, - const label nSmoothDisp, - pointField& normals - ) const; - - //- Smooth normals in interior. - void smoothNormals - ( - const label nSmoothDisp, - const PackedList<1>& isMasterEdge, - const labelList& fixedPoints, - pointVectorField& normals - ) const; - - bool isMaxEdge - ( - const List<pointData>&, - const label edgeI, - const scalar minCos - ) const; - - //- Stop layer growth where mesh wraps around edge with a - // large feature angle - void handleFeatureAngleLayerTerminations - ( - const indirectPrimitivePatch& pp, - const scalar minCos, - List<extrudeMode>& extrudeStatus, - pointField& patchDisp, - labelList& patchNLayers, - label& nPointCounter - ) const; - - //- Find isolated islands (points, edges and faces and - // layer terminations) - // in the layer mesh and stop any layer growth at these points. - void findIsolatedRegions - ( - const indirectPrimitivePatch& pp, - const PackedList<1>& isMasterEdge, - const labelList& meshEdges, - const scalar minCosLayerTermination, - scalarField& field, - List<extrudeMode>& extrudeStatus, - pointField& patchDisp, - labelList& patchNLayers - ) const; - - // Calculate medial axis fields - void medialAxisSmoothingInfo - ( - const motionSmoother& meshMover, - const label nSmoothNormals, - const label nSmoothSurfaceNormals, - const scalar minMedianAxisAngleCos, - - pointVectorField& dispVec, - pointScalarField& medialRatio, - pointScalarField& medialDist - ) const; - - //- Main routine to shrink mesh - void shrinkMeshMedialDistance - ( - motionSmoother& meshMover, - const label nSmoothThickness, - const scalar maxThicknessToMedialRatio, - const label nAllowableErrors, - const label nSnap, - const scalar minCosLayerTermination, - - const scalarField& layerThickness, - const scalarField& minThickness, - - const pointVectorField& dispVec, - const pointScalarField& medialRatio, - const pointScalarField& medialDist, - - List<extrudeMode>& extrudeStatus, - pointField& patchDisp, - labelList& patchNLayers - ) const; + //- Calculate merge distance. Check against writing tolerance. + scalar getMergeDistance(const scalar mergeTol) const; + //static void orientOutside(PtrList<searchableSurface>&); //- Disallow default bitwise copy construct autoHexMeshDriver(const autoHexMeshDriver&); @@ -646,16 +180,6 @@ public: const dictionary& decomposeDict ); - //- Alternative constructor from top-level controldictionary and - // refinement specific dictionary - autoHexMeshDriver - ( - fvMesh& mesh, - const dictionary& controlDict, - const dictionary& refineDict, - const dictionary& decomposeDict - ); - // Member Functions @@ -677,6 +201,12 @@ public: return surfacesPtr_(); } + //- Surfaces to volume refinement on + const shellSurfaces& shells() const + { + return shellsPtr_(); + } + //- Per refinementsurface, per region the patch const labelList& globalToPatch() const { @@ -684,153 +214,11 @@ public: } - // Refinement - - //- Refine around explicit feature edges - label featureEdgeRefine - ( - const PtrList<dictionary>& featDicts, - const label maxIter, - const label minRefine - ); - - //- Refine at surface intersections - label surfaceOnlyRefine(const label maxIter); - - //- Remove cells not reachable from keep points - void removeInsideCells(const label nBufferLayers); - - //- Refine volume regions (interior of shells) - label shellRefine(const label maxIter); - - //- Introduce baffles; remove unreachable mesh parts - // handleSnapProblems : whether to remove free floating cells - void baffleAndSplitMesh(const bool handleSnapProblems); - - //- Move cells to zones - void zonify(); - - //- Split and recombine baffles to get rid of single face baffles. - void splitAndMergeBaffles(const bool handleSnapProblems); - - //- Merge multiple boundary faces on single cell - void mergePatchFaces(); - - //- Redecompose according to cell count - // keepZoneFaces : find all faceZones from zoned surfaces and keep - // owner and neighbour together - // keepBaffles : find all baffles and keep them together - autoPtr<mapDistributePolyMesh> balance - ( - const bool keepZoneFaces, - const bool keepBaffles - ); + // Meshing //- Write mesh void writeMesh(const string&) const; - - // Snapping - - //- Create baffles for faces straddling zoned surfaces. Return - // baffles. - autoPtr<mapPolyMesh> createZoneBaffles(List<labelPair>&); - - //- Merge baffles. - autoPtr<mapPolyMesh> mergeZoneBaffles(const List<labelPair>&); - - //- Calculate edge length per patch point. - scalarField calcSnapDistance - ( - const dictionary& snapDict, - const indirectPrimitivePatch& - ) const; - - //- Get patches generated for surfaces. - labelList getSurfacePatches() const; - - //- Smooth the mesh (patch and internal) to increase visibility - // of surface points (on castellated mesh) w.r.t. surface. - void preSmoothPatch - ( - const dictionary& snapDict, - const label nInitErrors, - const List<labelPair>& baffles, - motionSmoother& - ) const; - - //- Per patch point calculate point on nearest surface. Set as - // boundary conditions of motionSmoother displacement field. Return - // displacement of patch points. - vectorField calcNearestSurface - ( - const scalarField& snapDist, - motionSmoother& meshMover - ) const; - - //- Smooth the displacement field to the internal. - void smoothDisplacement - ( - const dictionary& snapDict, - motionSmoother& - ) const; - - //- Do the hard work: move the mesh according to displacement, - // locally relax the displacement. - void scaleMesh - ( - const dictionary& snapDict, - const label nInitErrors, - const List<labelPair>& baffles, - motionSmoother& - ); - - - // Layers - - //- Merge patch faces on same cell. - void mergePatchFacesUndo - ( - const dictionary& shrinkDict, - const dictionary& motionDict - ); - - //- Check that mesh outside is not multiply connected. - void checkMeshManifold() const; - - //- Add cell layers - void addLayers - ( - const dictionary& shrinkDict, - const dictionary& motionDict, - const label nAllowableErrors, - motionSmoother& - ); - - - // Other - - //- Do all refinement. - void doRefine - ( - const dictionary& refineDict, - const bool prepareForSnapping - ); - - //- Do all snapping. - void doSnap - ( - const dictionary& snapDict, - const dictionary& motionDict - ); - - //- Do alllayer addition. - void doLayers - ( - const dictionary& shrinkDict, - const dictionary& motionDict - ); - //- Do all : refine, snap, layers void doMesh(); }; @@ -842,12 +230,6 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -#ifdef NoRepository -# include "autoHexMeshDriverTemplates.C" -#endif - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverLayers.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C similarity index 80% rename from src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverLayers.C rename to src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C index 0615d504765172caa43557661955fb7b88cd09f7..7caa1af11e1fa895bfb54af6796cbdef72a51840 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverLayers.C +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C @@ -27,11 +27,10 @@ Description \*----------------------------------------------------------------------------*/ -#include "ListOps.H" -#include "autoHexMeshDriver.H" +#include "autoLayerDriver.H" #include "fvMesh.H" #include "Time.H" -#include "combineFaces.H" +#include "meshRefinement.H" #include "removePoints.H" #include "pointFields.H" #include "motionSmoother.H" @@ -43,31 +42,41 @@ Description #include "mapPolyMesh.H" #include "addPatchCellLayer.H" #include "mapDistributePolyMesh.H" +#include "OFstream.H" +#include "layerParameters.H" +#include "combineFaces.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // -const Foam::scalar Foam::autoHexMeshDriver::defaultConcaveAngle = 90; +namespace Foam +{ + +defineTypeNameAndDebug(autoLayerDriver, 0); + +} // End namespace Foam // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo +Foam::label Foam::autoLayerDriver::mergePatchFacesUndo ( const scalar minCos, const scalar concaveCos, const dictionary& motionDict ) { + fvMesh& mesh = meshRefiner_.mesh(); + // Patch face merging engine - combineFaces faceCombiner(mesh_, true); + combineFaces faceCombiner(mesh, true); // Pick up all candidate cells on boundary - labelHashSet boundaryCells(mesh_.nFaces()-mesh_.nInternalFaces()); + labelHashSet boundaryCells(mesh.nFaces()-mesh.nInternalFaces()); { labelList patchIDs(meshRefinement::addedPatches(globalToPatch_)); - const polyBoundaryMesh& patches = mesh_.boundaryMesh(); + const polyBoundaryMesh& patches = mesh.boundaryMesh(); forAll(patchIDs, i) { @@ -79,7 +88,7 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo { forAll(patch, i) { - boundaryCells.insert(mesh_.faceOwner()[patch.start()+i]); + boundaryCells.insert(mesh.faceOwner()[patch.start()+i]); } } } @@ -102,9 +111,9 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo if (nFaceSets > 0) { - if (debug_) + if (debug) { - faceSet allSets(mesh_, "allFaceSets", allFaceSets.size()); + faceSet allSets(mesh, "allFaceSets", allFaceSets.size()); forAll(allFaceSets, setI) { forAll(allFaceSets[setI], i) @@ -119,13 +128,13 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo // Topology changes container - polyTopoChange meshMod(mesh_); + polyTopoChange meshMod(mesh); // Merge all faces of a set into the first face of the set. faceCombiner.setRefinement(allFaceSets, meshMod); // Experimental: store data for all the points that have been deleted - meshRefinerPtr_().storeData + meshRefiner_.storeData ( faceCombiner.savedPointLabels(), // points to store labelList(0), // faces to store @@ -133,20 +142,20 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo ); // Change the mesh (no inflation) - autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true); + autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true); // Update fields - mesh_.updateMesh(map); + mesh.updateMesh(map); // Move mesh (since morphing does not do this) if (map().hasMotionPoints()) { - mesh_.movePoints(map().preMotionPoints()); + mesh.movePoints(map().preMotionPoints()); } faceCombiner.updateMesh(map); - meshRefinerPtr_().updateMesh(map, labelList(0)); + meshRefiner_.updateMesh(map, labelList(0)); @@ -162,14 +171,14 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo faceSet errorFaces ( - mesh_, + mesh, "errorFaces", - mesh_.nFaces()-mesh_.nInternalFaces() + mesh.nFaces()-mesh.nInternalFaces() ); bool hasErrors = motionSmoother::checkMesh ( false, // report - mesh_, + mesh, motionDict, errorFaces ); @@ -181,7 +190,7 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo // label nOldSize = errorFaces.size(); // // hasErrors = - // mesh_.checkFaceFaces + // mesh.checkFaceFaces // ( // false, // &errorFaces @@ -200,7 +209,7 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo } - if (debug_) + if (debug) { Pout<< "Writing all faces in error to faceSet " << errorFaces.objectPath() << nl << endl; @@ -219,9 +228,9 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo if (masterFaceI != -1) { - label masterCellII = mesh_.faceOwner()[masterFaceI]; + label masterCellII = mesh.faceOwner()[masterFaceI]; - const cell& cFaces = mesh_.cells()[masterCellII]; + const cell& cFaces = mesh.cells()[masterCellII]; forAll(cFaces, i) { @@ -244,9 +253,9 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo Info<< "Masters that need to be restored:" << nRestore << endl; - if (debug_) + if (debug) { - faceSet restoreSet(mesh_, "mastersToRestore", mastersToRestore); + faceSet restoreSet(mesh, "mastersToRestore", mastersToRestore); Pout<< "Writing all " << mastersToRestore.size() << " masterfaces to be restored to set " << restoreSet.objectPath() << endl; @@ -264,7 +273,7 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo // ~~~~ // Topology changes container - polyTopoChange meshMod(mesh_); + polyTopoChange meshMod(mesh); // Merge all faces of a set into the first face of the set. // Experimental:mark all points/faces/cells that have been restored. @@ -282,15 +291,15 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo ); // Change the mesh (no inflation) - autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true); + autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true); // Update fields - mesh_.updateMesh(map); + mesh.updateMesh(map); // Move mesh (since morphing does not do this) if (map().hasMotionPoints()) { - mesh_.movePoints(map().preMotionPoints()); + mesh.movePoints(map().preMotionPoints()); } faceCombiner.updateMesh(map); @@ -301,7 +310,7 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo inplaceMapKey(map().reverseCellMap(), restoredCells); // Experimental:restore all points/face/cells in maps - meshRefinerPtr_().updateMesh + meshRefiner_.updateMesh ( map, labelList(0), // changedFaces @@ -313,11 +322,11 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo Info<< endl; } - if (debug_) + if (debug) { Pout<< "Writing merged-faces mesh to time " - << mesh_.time().timeName() << nl << endl; - mesh_.write(); + << mesh.time().timeName() << nl << endl; + mesh.write(); } } else @@ -330,45 +339,49 @@ Foam::label Foam::autoHexMeshDriver::mergePatchFacesUndo // Remove points. pointCanBeDeleted is parallel synchronised. -Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::doRemovePoints +Foam::autoPtr<Foam::mapPolyMesh> Foam::autoLayerDriver::doRemovePoints ( removePoints& pointRemover, const boolList& pointCanBeDeleted ) { + fvMesh& mesh = meshRefiner_.mesh(); + // Topology changes container - polyTopoChange meshMod(mesh_); + polyTopoChange meshMod(mesh); pointRemover.setRefinement(pointCanBeDeleted, meshMod); // Change the mesh (no inflation) - autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true); + autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true); // Update fields - mesh_.updateMesh(map); + mesh.updateMesh(map); // Move mesh (since morphing does not do this) if (map().hasMotionPoints()) { - mesh_.movePoints(map().preMotionPoints()); + mesh.movePoints(map().preMotionPoints()); } pointRemover.updateMesh(map); - meshRefinerPtr_().updateMesh(map, labelList(0)); + meshRefiner_.updateMesh(map, labelList(0)); return map; } // Restore faces (which contain removed points) -Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::doRestorePoints +Foam::autoPtr<Foam::mapPolyMesh> Foam::autoLayerDriver::doRestorePoints ( removePoints& pointRemover, const labelList& facesToRestore ) { + fvMesh& mesh = meshRefiner_.mesh(); + // Topology changes container - polyTopoChange meshMod(mesh_); + polyTopoChange meshMod(mesh); // Determine sets of points and faces to restore labelList localFaces, localPoints; @@ -388,19 +401,19 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::doRestorePoints ); // Change the mesh (no inflation) - autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true); + autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true); // Update fields - mesh_.updateMesh(map); + mesh.updateMesh(map); // Move mesh (since morphing does not do this) if (map().hasMotionPoints()) { - mesh_.movePoints(map().preMotionPoints()); + mesh.movePoints(map().preMotionPoints()); } pointRemover.updateMesh(map); - meshRefinerPtr_().updateMesh(map, labelList(0)); + meshRefiner_.updateMesh(map, labelList(0)); return map; } @@ -408,14 +421,16 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::doRestorePoints // Collect all faces that are both in candidateFaces and in the set. // If coupled face also collects the coupled face. -Foam::labelList Foam::autoHexMeshDriver::collectFaces +Foam::labelList Foam::autoLayerDriver::collectFaces ( const labelList& candidateFaces, const labelHashSet& set ) const { + const fvMesh& mesh = meshRefiner_.mesh(); + // Has face been selected? - boolList selected(mesh_.nFaces(), false); + boolList selected(mesh.nFaces(), false); forAll(candidateFaces, i) { @@ -428,7 +443,7 @@ Foam::labelList Foam::autoHexMeshDriver::collectFaces } syncTools::syncFaceList ( - mesh_, + mesh, selected, orEqOp<bool>(), // combine operator false // separation @@ -441,30 +456,32 @@ Foam::labelList Foam::autoHexMeshDriver::collectFaces // Pick up faces of cells of faces in set. -Foam::labelList Foam::autoHexMeshDriver::growFaceCellFace +Foam::labelList Foam::autoLayerDriver::growFaceCellFace ( const labelHashSet& set ) const { - boolList selected(mesh_.nFaces(), false); + const fvMesh& mesh = meshRefiner_.mesh(); + + boolList selected(mesh.nFaces(), false); forAllConstIter(faceSet, set, iter) { label faceI = iter.key(); - label own = mesh_.faceOwner()[faceI]; + label own = mesh.faceOwner()[faceI]; - const cell& ownFaces = mesh_.cells()[own]; + const cell& ownFaces = mesh.cells()[own]; forAll(ownFaces, ownFaceI) { selected[ownFaces[ownFaceI]] = true; } - if (mesh_.isInternalFace(faceI)) + if (mesh.isInternalFace(faceI)) { - label nbr = mesh_.faceNeighbour()[faceI]; + label nbr = mesh.faceNeighbour()[faceI]; - const cell& nbrFaces = mesh_.cells()[nbr]; + const cell& nbrFaces = mesh.cells()[nbr]; forAll(nbrFaces, nbrFaceI) { selected[nbrFaces[nbrFaceI]] = true; @@ -473,7 +490,7 @@ Foam::labelList Foam::autoHexMeshDriver::growFaceCellFace } syncTools::syncFaceList ( - mesh_, + mesh, selected, orEqOp<bool>(), // combine operator false // separation @@ -484,12 +501,14 @@ Foam::labelList Foam::autoHexMeshDriver::growFaceCellFace // Remove points not used by any face or points used by only two faces where // the edges are in line -Foam::label Foam::autoHexMeshDriver::mergeEdgesUndo +Foam::label Foam::autoLayerDriver::mergeEdgesUndo ( const scalar minCos, const dictionary& motionDict ) { + fvMesh& mesh = meshRefiner_.mesh(); + Info<< nl << "Merging all points on surface that" << nl << "- are used by only two boundary faces and" << nl @@ -497,7 +516,7 @@ Foam::label Foam::autoHexMeshDriver::mergeEdgesUndo << "." << nl << endl; // Point removal analysis engine with undo - removePoints pointRemover(mesh_, true); + removePoints pointRemover(mesh, true); // Count usage of points boolList pointCanBeDeleted; @@ -526,14 +545,14 @@ Foam::label Foam::autoHexMeshDriver::mergeEdgesUndo faceSet errorFaces ( - mesh_, + mesh, "errorFaces", - mesh_.nFaces()-mesh_.nInternalFaces() + mesh.nFaces()-mesh.nInternalFaces() ); bool hasErrors = motionSmoother::checkMesh ( false, // report - mesh_, + mesh, motionDict, errorFaces ); @@ -545,7 +564,7 @@ Foam::label Foam::autoHexMeshDriver::mergeEdgesUndo // label nOldSize = errorFaces.size(); // // hasErrors = - // mesh_.checkFaceFaces + // mesh.checkFaceFaces // ( // false, // &errorFaces @@ -553,7 +572,7 @@ Foam::label Foam::autoHexMeshDriver::mergeEdgesUndo // || hasErrors; // // Info<< "Detected additional " - // << returnReduce(errorFaces.size()-nOldSize, sumOp<label>()) + // << returnReduce(errorFaces.size()-nOldSize,sumOp<label>()) // << " faces with illegal face-face connectivity" // << endl; //} @@ -563,7 +582,7 @@ Foam::label Foam::autoHexMeshDriver::mergeEdgesUndo break; } - if (debug_) + if (debug) { Pout<< "**Writing all faces in error to faceSet " << errorFaces.objectPath() << nl << endl; @@ -613,11 +632,11 @@ Foam::label Foam::autoHexMeshDriver::mergeEdgesUndo doRestorePoints(pointRemover, masterErrorFaces); } - if (debug_) + if (debug) { Pout<< "Writing merged-edges mesh to time " - << mesh_.time().timeName() << nl << endl; - mesh_.write(); + << mesh.time().timeName() << nl << endl; + mesh.write(); } } else @@ -630,7 +649,7 @@ Foam::label Foam::autoHexMeshDriver::mergeEdgesUndo // For debugging: Dump displacement to .obj files -void Foam::autoHexMeshDriver::dumpDisplacement +void Foam::autoLayerDriver::dumpDisplacement ( const fileName& prefix, const indirectPrimitivePatch& pp, @@ -676,7 +695,7 @@ void Foam::autoHexMeshDriver::dumpDisplacement // Check that primitivePatch is not multiply connected. Collect non-manifold // points in pointSet. -void Foam::autoHexMeshDriver::checkManifold +void Foam::autoLayerDriver::checkManifold ( const indirectPrimitivePatch& fp, pointSet& nonManifoldPoints @@ -703,23 +722,25 @@ void Foam::autoHexMeshDriver::checkManifold } -void Foam::autoHexMeshDriver::checkMeshManifold() const +void Foam::autoLayerDriver::checkMeshManifold() const { + const fvMesh& mesh = meshRefiner_.mesh(); + Info<< nl << "Checking mesh manifoldness ..." << endl; // Get all outside faces - labelList outsideFaces(mesh_.nFaces() - mesh_.nInternalFaces()); + labelList outsideFaces(mesh.nFaces() - mesh.nInternalFaces()); - for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++) + for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++) { - outsideFaces[faceI - mesh_.nInternalFaces()] = faceI; + outsideFaces[faceI - mesh.nInternalFaces()] = faceI; } pointSet nonManifoldPoints ( - mesh_, + mesh, "nonManifoldPoints", - mesh_.nPoints() / 100 + mesh.nPoints() / 100 ); // Build primitivePatch out of faces and check it for problems. @@ -727,8 +748,8 @@ void Foam::autoHexMeshDriver::checkMeshManifold() const ( indirectPrimitivePatch ( - IndirectList<face>(mesh_.faces(), outsideFaces), - mesh_.points() + IndirectList<face>(mesh.faces(), outsideFaces), + mesh.points() ), nonManifoldPoints ); @@ -753,7 +774,7 @@ void Foam::autoHexMeshDriver::checkMeshManifold() const // Unset extrusion on point. Returns true if anything unset. -bool Foam::autoHexMeshDriver::unmarkExtrusion +bool Foam::autoLayerDriver::unmarkExtrusion ( const label patchPointI, pointField& patchDisp, @@ -783,7 +804,7 @@ bool Foam::autoHexMeshDriver::unmarkExtrusion // Unset extrusion on face. Returns true if anything unset. -bool Foam::autoHexMeshDriver::unmarkExtrusion +bool Foam::autoLayerDriver::unmarkExtrusion ( const face& localFace, pointField& patchDisp, @@ -814,7 +835,7 @@ bool Foam::autoHexMeshDriver::unmarkExtrusion // No extrusion at non-manifold points. -void Foam::autoHexMeshDriver::handleNonManifolds +void Foam::autoLayerDriver::handleNonManifolds ( const indirectPrimitivePatch& pp, const labelList& meshEdges, @@ -823,12 +844,14 @@ void Foam::autoHexMeshDriver::handleNonManifolds List<extrudeMode>& extrudeStatus ) const { + const fvMesh& mesh = meshRefiner_.mesh(); + Info<< nl << "Handling non-manifold points ..." << endl; // Detect non-manifold points Info<< nl << "Checking patch manifoldness ..." << endl; - pointSet nonManifoldPoints(mesh_, "nonManifoldPoints", pp.nPoints()); + pointSet nonManifoldPoints(mesh, "nonManifoldPoints", pp.nPoints()); // 1. Local check checkManifold(pp, nonManifoldPoints); @@ -844,16 +867,16 @@ void Foam::autoHexMeshDriver::handleNonManifolds // 2. Parallel check // For now disable extrusion at any shared edges. - const labelHashSet sharedEdgeSet(mesh_.globalData().sharedEdgeLabels()); + const labelHashSet sharedEdgeSet(mesh.globalData().sharedEdgeLabels()); forAll(pp.edges(), edgeI) { if (sharedEdgeSet.found(meshEdges[edgeI])) { - const edge& e = mesh_.edges()[meshEdges[edgeI]]; + const edge& e = mesh.edges()[meshEdges[edgeI]]; Pout<< "Disabling extrusion at edge " - << mesh_.points()[e[0]] << mesh_.points()[e[1]] + << mesh.points()[e[0]] << mesh.points()[e[1]] << " since it is non-manifold across coupled patches." << endl; @@ -905,7 +928,7 @@ void Foam::autoHexMeshDriver::handleNonManifolds // Parallel feature edge detection. Assumes non-manifold edges already handled. -void Foam::autoHexMeshDriver::handleFeatureAngle +void Foam::autoLayerDriver::handleFeatureAngle ( const indirectPrimitivePatch& pp, const labelList& meshEdges, @@ -915,12 +938,14 @@ void Foam::autoHexMeshDriver::handleFeatureAngle List<extrudeMode>& extrudeStatus ) const { + const fvMesh& mesh = meshRefiner_.mesh(); + Info<< nl << "Handling feature edges ..." << endl; if (minCos < 1-SMALL) { // Normal component of normals of connected faces. - vectorField edgeNormal(mesh_.nEdges(), wallPoint::greatPoint); + vectorField edgeNormal(mesh.nEdges(), wallPoint::greatPoint); const labelListList& edgeFaces = pp.edgeFaces(); @@ -942,7 +967,7 @@ void Foam::autoHexMeshDriver::handleFeatureAngle syncTools::syncEdgeList ( - mesh_, + mesh, edgeNormal, nomalsCombine(), wallPoint::greatPoint, // null value @@ -951,9 +976,9 @@ void Foam::autoHexMeshDriver::handleFeatureAngle label vertI = 0; autoPtr<OFstream> str; - if (debug_) + if (debug) { - str.reset(new OFstream(mesh_.time().path()/"featureEdges.obj")); + str.reset(new OFstream(mesh.time().path()/"featureEdges.obj")); Info<< "Writing feature edges to " << str().name() << endl; } @@ -1017,7 +1042,7 @@ void Foam::autoHexMeshDriver::handleFeatureAngle // layer and compares it to the space the warped face takes up. Disables // extrusion if layer thickness is more than faceRatio of the thickness of // the face. -void Foam::autoHexMeshDriver::handleWarpedFaces +void Foam::autoLayerDriver::handleWarpedFaces ( const indirectPrimitivePatch& pp, const scalar faceRatio, @@ -1028,9 +1053,11 @@ void Foam::autoHexMeshDriver::handleWarpedFaces List<extrudeMode>& extrudeStatus ) const { + const fvMesh& mesh = meshRefiner_.mesh(); + Info<< nl << "Handling cells with warped patch faces ..." << nl; - const pointField& points = mesh_.points(); + const pointField& points = mesh.points(); label nWarpedFaces = 0; @@ -1042,11 +1069,11 @@ void Foam::autoHexMeshDriver::handleWarpedFaces { label faceI = pp.addressing()[i]; - label ownLevel = cellLevel[mesh_.faceOwner()[faceI]]; + label ownLevel = cellLevel[mesh.faceOwner()[faceI]]; scalar edgeLen = edge0Len/(1<<ownLevel); // Normal distance to face centre plane - const point& fc = mesh_.faceCentres()[faceI]; + const point& fc = mesh.faceCentres()[faceI]; const vector& fn = pp.faceNormals()[i]; scalarField vProj(f.size()); @@ -1090,7 +1117,7 @@ void Foam::autoHexMeshDriver::handleWarpedFaces //// No extrusion on cells with multiple patch faces. There ususally is a reason //// why combinePatchFaces hasn't succeeded. -//void Foam::autoHexMeshDriver::handleMultiplePatchFaces +//void Foam::autoLayerDriver::handleMultiplePatchFaces //( // const indirectPrimitivePatch& pp, // pointField& patchDisp, @@ -1098,12 +1125,14 @@ void Foam::autoHexMeshDriver::handleWarpedFaces // List<extrudeMode>& extrudeStatus //) const //{ +// const fvMesh& mesh = meshRefiner_.mesh(); +// // Info<< nl << "Handling cells with multiple patch faces ..." << nl; // // const labelListList& pointFaces = pp.pointFaces(); // // // Cells that should not get an extrusion layer -// cellSet multiPatchCells(mesh_, "multiPatchCells", pp.size()); +// cellSet multiPatchCells(mesh, "multiPatchCells", pp.size()); // // // Detect points that use multiple faces on same cell. // forAll(pointFaces, patchPointI) @@ -1114,7 +1143,7 @@ void Foam::autoHexMeshDriver::handleWarpedFaces // // forAll(pFaces, i) // { -// label cellI = mesh_.faceOwner()[pp.addressing()[pFaces[i]]]; +// label cellI = mesh.faceOwner()[pp.addressing()[pFaces[i]]]; // // if (!pointCells.insert(cellI)) // { @@ -1158,7 +1187,7 @@ void Foam::autoHexMeshDriver::handleWarpedFaces // forAll(pFaces, i) // { // label cellI = -// mesh_.faceOwner()[pp.addressing()[pFaces[i]]]; +// mesh.faceOwner()[pp.addressing()[pFaces[i]]]; // // if (multiPatchCells.found(cellI)) // { @@ -1189,8 +1218,9 @@ void Foam::autoHexMeshDriver::handleWarpedFaces // No extrusion on faces with differing number of layers for points -void Foam::autoHexMeshDriver::setNumLayers +void Foam::autoLayerDriver::setNumLayers ( + const labelList& patchToNLayers, const labelList& patchIDs, const indirectPrimitivePatch& pp, pointField& patchDisp, @@ -1198,21 +1228,11 @@ void Foam::autoHexMeshDriver::setNumLayers List<extrudeMode>& extrudeStatus ) const { + const fvMesh& mesh = meshRefiner_.mesh(); + Info<< nl << "Handling points with inconsistent layer specification ..." << endl; - const labelList& nSurfLayers = surfaces().numLayers(); - - // Build map from patch to layers - Map<label> patchToNLayers(nSurfLayers.size()); - forAll(nSurfLayers, region) - { - if (globalToPatch_[region] != -1) - { - patchToNLayers.insert(globalToPatch_[region], nSurfLayers[region]); - } - } - // Get for every point (really only nessecary on patch external points) // the max and min of any patch faces using it. labelList maxLayers(patchNLayers.size(), labelMin); @@ -1222,7 +1242,7 @@ void Foam::autoHexMeshDriver::setNumLayers { label patchI = patchIDs[i]; - const labelList& meshPoints = mesh_.boundaryMesh()[patchI].meshPoints(); + const labelList& meshPoints = mesh.boundaryMesh()[patchI].meshPoints(); label wantedLayers = patchToNLayers[patchI]; @@ -1237,7 +1257,7 @@ void Foam::autoHexMeshDriver::setNumLayers syncTools::syncPointList ( - mesh_, + mesh, pp.meshPoints(), maxLayers, maxEqOp<label>(), @@ -1246,7 +1266,7 @@ void Foam::autoHexMeshDriver::setNumLayers ); syncTools::syncPointList ( - mesh_, + mesh, pp.meshPoints(), minLayers, minEqOp<label>(), @@ -1257,7 +1277,7 @@ void Foam::autoHexMeshDriver::setNumLayers // Unmark any point with different min and max // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - label nConflicts = 0; + //label nConflicts = 0; forAll(maxLayers, i) { @@ -1294,16 +1314,16 @@ void Foam::autoHexMeshDriver::setNumLayers } } - reduce(nConflicts, sumOp<label>()); - - Info<< "Set displacement to zero for " << nConflicts - << " points due to points being on multiple regions" - << " with inconsistent nLayers specification." << endl; + //reduce(nConflicts, sumOp<label>()); + // + //Info<< "Set displacement to zero for " << nConflicts + // << " points due to points being on multiple regions" + // << " with inconsistent nLayers specification." << endl; } // Grow no-extrusion layer -void Foam::autoHexMeshDriver::growNoExtrusion +void Foam::autoLayerDriver::growNoExtrusion ( const indirectPrimitivePatch& pp, pointField& patchDisp, @@ -1369,60 +1389,139 @@ void Foam::autoHexMeshDriver::growNoExtrusion } - -// Calculate pointwise wanted and minimum thickness. -// thickness: wanted thickness per point -void Foam::autoHexMeshDriver::calculateLayerThickness +void Foam::autoLayerDriver::calculateLayerThickness ( - const scalar expansionRatio, - const scalar finalLayerRatio, - const scalar relMinThickness, const indirectPrimitivePatch& pp, + const labelList& patchIDs, + const scalarField& patchExpansionRatio, + const scalarField& patchFinalLayerRatio, + const scalarField& patchRelMinThickness, const labelList& cellLevel, const labelList& patchNLayers, const scalar edge0Len, + scalarField& thickness, - scalarField& minThickness + scalarField& minThickness, + scalarField& expansionRatio ) const { - if (relMinThickness < 0 || relMinThickness > 2) + const fvMesh& mesh = meshRefiner_.mesh(); + const polyBoundaryMesh& patches = mesh.boundaryMesh(); + + if (min(patchRelMinThickness) < 0 || max(patchRelMinThickness) > 2) { FatalErrorIn("calculateLayerThickness(..)") << "Thickness should be factor of local undistorted cell size." << " Valid values are [0..2]." << nl - << " minThickness:" << relMinThickness + << " minThickness:" << patchRelMinThickness << exit(FatalError); } - thickness.setSize(pp.nPoints()); - minThickness.setSize(pp.nPoints()); // Per point the max cell level of connected cells + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + labelList maxPointLevel(pp.nPoints(), labelMin); - forAll(pp, i) { - label ownLevel = cellLevel[mesh_.faceOwner()[pp.addressing()[i]]]; + forAll(pp, i) + { + label ownLevel = cellLevel[mesh.faceOwner()[pp.addressing()[i]]]; - const face& f = pp.localFaces()[i]; + const face& f = pp.localFaces()[i]; - forAll(f, fp) + forAll(f, fp) + { + maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel); + } + } + + syncTools::syncPointList + ( + mesh, + pp.meshPoints(), + maxPointLevel, + maxEqOp<label>(), + labelMin, // null value + false // no separation + ); + } + + + // Rework patch-wise layer parameters into minimum per point + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + expansionRatio.setSize(pp.nPoints()); + expansionRatio = GREAT; + scalarField finalLayerRatio(pp.nPoints(), GREAT); + scalarField relMinThickness(pp.nPoints(), GREAT); + + { + forAll(patchIDs, i) { - maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel); + label patchI = patchIDs[i]; + + const labelList& meshPoints = patches[patchI].meshPoints(); + + forAll(meshPoints, patchPointI) + { + label ppPointI = pp.meshPointMap()[meshPoints[patchPointI]]; + + expansionRatio[ppPointI] = min + ( + expansionRatio[ppPointI], + patchExpansionRatio[patchI] + ); + finalLayerRatio[ppPointI] = min + ( + finalLayerRatio[ppPointI], + patchFinalLayerRatio[patchI] + ); + relMinThickness[ppPointI] = min + ( + relMinThickness[ppPointI], + patchRelMinThickness[patchI] + ); + } } + + syncTools::syncPointList + ( + mesh, + pp.meshPoints(), + expansionRatio, + minEqOp<scalar>(), + GREAT, // null value + false // no separation + ); + syncTools::syncPointList + ( + mesh, + pp.meshPoints(), + finalLayerRatio, + minEqOp<scalar>(), + GREAT, // null value + false // no separation + ); + syncTools::syncPointList + ( + mesh, + pp.meshPoints(), + relMinThickness, + minEqOp<scalar>(), + GREAT, // null value + false // no separation + ); } - syncTools::syncPointList - ( - mesh_, - pp.meshPoints(), - maxPointLevel, - maxEqOp<label>(), - labelMin, // null value - false // no separation - ); + // Per mesh point the expansion parameters + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + thickness.setSize(pp.nPoints()); + minThickness.setSize(pp.nPoints()); + forAll(maxPointLevel, pointI) { // Find undistorted edge size for this level. @@ -1430,19 +1529,24 @@ void Foam::autoHexMeshDriver::calculateLayerThickness // Calculate layer thickness based on expansion ratio // and final layer height - if (expansionRatio == 1) + if (expansionRatio[pointI] == 1) { - thickness[pointI] = finalLayerRatio*patchNLayers[pointI]*edgeLen; - minThickness[pointI] = relMinThickness*edgeLen; + thickness[pointI] = + finalLayerRatio[pointI] + * patchNLayers[pointI] + * edgeLen; + minThickness[pointI] = relMinThickness[pointI]*edgeLen; } else { - scalar invExpansion = 1.0 / expansionRatio; + scalar invExpansion = 1.0 / expansionRatio[pointI]; label nLay = patchNLayers[pointI]; - thickness[pointI] = finalLayerRatio*edgeLen - * (1.0 - pow(invExpansion, nLay)) - / (1.0 - invExpansion); - minThickness[pointI] = relMinThickness*edgeLen; + thickness[pointI] = + finalLayerRatio[pointI] + * edgeLen + * (1.0 - pow(invExpansion, nLay)) + / (1.0 - invExpansion); + minThickness[pointI] = relMinThickness[pointI]*edgeLen; } } @@ -1452,7 +1556,7 @@ void Foam::autoHexMeshDriver::calculateLayerThickness // Synchronize displacement among coupled patches. -void Foam::autoHexMeshDriver::syncPatchDisplacement +void Foam::autoLayerDriver::syncPatchDisplacement ( const motionSmoother& meshMover, const scalarField& minThickness, @@ -1461,6 +1565,7 @@ void Foam::autoHexMeshDriver::syncPatchDisplacement List<extrudeMode>& extrudeStatus ) const { + const fvMesh& mesh = meshRefiner_.mesh(); const labelList& meshPoints = meshMover.patch().meshPoints(); label nChangedTotal = 0; @@ -1472,7 +1577,7 @@ void Foam::autoHexMeshDriver::syncPatchDisplacement // Sync displacement (by taking min) syncTools::syncPointList ( - mesh_, + mesh, meshPoints, patchDisp, minEqOp<vector>(), @@ -1505,7 +1610,7 @@ void Foam::autoHexMeshDriver::syncPatchDisplacement syncTools::syncPointList ( - mesh_, + mesh, meshPoints, syncPatchNLayers, minEqOp<label>(), @@ -1536,7 +1641,7 @@ void Foam::autoHexMeshDriver::syncPatchDisplacement syncTools::syncPointList ( - mesh_, + mesh, meshPoints, syncPatchNLayers, maxEqOp<label>(), @@ -1583,7 +1688,7 @@ void Foam::autoHexMeshDriver::syncPatchDisplacement // of the faces using it. // extrudeStatus is both input and output and gives the status of each // patch point. -void Foam::autoHexMeshDriver::getPatchDisplacement +void Foam::autoLayerDriver::getPatchDisplacement ( const motionSmoother& meshMover, const scalarField& thickness, @@ -1596,6 +1701,7 @@ void Foam::autoHexMeshDriver::getPatchDisplacement Info<< nl << "Determining displacement for added points" << " according to pointNormal ..." << endl; + const fvMesh& mesh = meshRefiner_.mesh(); const indirectPrimitivePatch& pp = meshMover.patch(); const vectorField& faceNormals = pp.faceNormals(); const labelListList& pointFaces = pp.pointFaces(); @@ -1622,7 +1728,7 @@ void Foam::autoHexMeshDriver::getPatchDisplacement syncTools::syncPointList ( - mesh_, + mesh, meshPoints, pointNormals, plusEqOp<vector>(), @@ -1632,7 +1738,7 @@ void Foam::autoHexMeshDriver::getPatchDisplacement syncTools::syncPointList ( - mesh_, + mesh, meshPoints, nPointFaces, plusEqOp<label>(), @@ -1735,7 +1841,7 @@ void Foam::autoHexMeshDriver::getPatchDisplacement // Truncates displacement // - for all patchFaces in the faceset displacement gets set to zero // - all displacement < minThickness gets set to zero -Foam::label Foam::autoHexMeshDriver::truncateDisplacement +Foam::label Foam::autoLayerDriver::truncateDisplacement ( const motionSmoother& meshMover, const scalarField& minThickness, @@ -1939,7 +2045,7 @@ Foam::label Foam::autoHexMeshDriver::truncateDisplacement // Setup layer information (at points and faces) to modify mesh topology in // regions where layer mesh terminates. -void Foam::autoHexMeshDriver::setupLayerInfoTruncation +void Foam::autoLayerDriver::setupLayerInfoTruncation ( const motionSmoother& meshMover, const labelList& patchNLayers, @@ -2137,7 +2243,7 @@ void Foam::autoHexMeshDriver::setupLayerInfoTruncation // Does any of the cells use a face from faces? -bool Foam::autoHexMeshDriver::cellsUseFace +bool Foam::autoLayerDriver::cellsUseFace ( const polyMesh& mesh, const labelList& cellLabels, @@ -2163,7 +2269,7 @@ bool Foam::autoHexMeshDriver::cellsUseFace // Checks the newly added cells and locally unmarks points so they // will not get extruded next time round. Returns global number of unmarked // points (0 if all was fine) -Foam::label Foam::autoHexMeshDriver::checkAndUnmark +Foam::label Foam::autoLayerDriver::checkAndUnmark ( const addPatchCellLayer& addLayer, const dictionary& motionDict, @@ -2230,7 +2336,7 @@ Foam::label Foam::autoHexMeshDriver::checkAndUnmark //- Count global number of extruded faces -Foam::label Foam::autoHexMeshDriver::countExtrusion +Foam::label Foam::autoLayerDriver::countExtrusion ( const indirectPrimitivePatch& pp, const List<extrudeMode>& extrudeStatus @@ -2261,7 +2367,7 @@ Foam::label Foam::autoHexMeshDriver::countExtrusion // Collect layer faces and layer cells into bools for ease of handling -void Foam::autoHexMeshDriver::getLayerCellsFaces +void Foam::autoLayerDriver::getLayerCellsFaces ( const polyMesh& mesh, const addPatchCellLayer& addLayer, @@ -2305,35 +2411,51 @@ void Foam::autoHexMeshDriver::getLayerCellsFaces } +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::autoLayerDriver::autoLayerDriver +( + meshRefinement& meshRefiner, + const labelList& globalToPatch +) +: + meshRefiner_(meshRefiner), + globalToPatch_(globalToPatch) +{} + + // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -void Foam::autoHexMeshDriver::mergePatchFacesUndo +void Foam::autoLayerDriver::mergePatchFacesUndo ( - const dictionary& shrinkDict, + const layerParameters& layerParams, const dictionary& motionDict ) { - const scalar featureAngle(readScalar(shrinkDict.lookup("featureAngle"))); - scalar minCos = Foam::cos(featureAngle*mathematicalConstant::pi/180.0); - - scalar concaveAngle = defaultConcaveAngle; + scalar minCos = Foam::cos + ( + layerParams.featureAngle() + * mathematicalConstant::pi/180.0 + ); - if (shrinkDict.found("concaveAngle")) - { - concaveAngle = readScalar(shrinkDict.lookup("concaveAngle")); - } - scalar concaveCos = Foam::cos(concaveAngle*mathematicalConstant::pi/180.0); + scalar concaveCos = Foam::cos + ( + layerParams.concaveAngle() + * mathematicalConstant::pi/180.0 + ); Info<< nl << "Merging all faces of a cell" << nl << "---------------------------" << nl << " - which are on the same patch" << nl - << " - which make an angle < " << featureAngle << " degrees" + << " - which make an angle < " << layerParams.featureAngle() + << " degrees" << nl << " (cos:" << minCos << ')' << nl << " - as long as the resulting face doesn't become concave" << " by more than " - << concaveAngle << " degrees (0=straight, 180=fully concave)" << nl + << layerParams.concaveAngle() + << " degrees (0=straight, 180=fully concave)" << nl << endl; label nChanged = mergePatchFacesUndo(minCos, concaveCos, motionDict); @@ -2342,82 +2464,23 @@ void Foam::autoHexMeshDriver::mergePatchFacesUndo } -void Foam::autoHexMeshDriver::addLayers +void Foam::autoLayerDriver::addLayers ( - const dictionary& shrinkDict, + const layerParameters& layerParams, const dictionary& motionDict, const label nAllowableErrors, - motionSmoother& meshMover + motionSmoother& meshMover, + decompositionMethod& decomposer, + fvMeshDistribute& distributor ) { - // Read some more dictionary settings - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - // Min thickness per cell - const scalar relMinThickness(readScalar(shrinkDict.lookup("minThickness"))); - - // Warped faces recoginition - const scalar maxFaceThicknessRatio - ( - readScalar(shrinkDict.lookup("maxFaceThicknessRatio")) - ); - const scalar featureAngle(readScalar(shrinkDict.lookup("featureAngle"))); - - // Feature angle - const scalar minCos = Foam::cos(featureAngle*mathematicalConstant::pi/180.); - - // Number of layers for to grow non-extrusion region by - const label nGrow(readLabel(shrinkDict.lookup("nGrow"))); - - //const label nSmoothDisp(readLabel(shrinkDict.lookup("nSmoothDispl"))); - // Snapping iterations - const label nSnap(readLabel(shrinkDict.lookup("nSnap"))); - - // Mesh termination and medial axis smoothing quantities - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - const scalar minCosLayerTermination = - Foam::cos(0.5*featureAngle*mathematicalConstant::pi/180.); - const scalar expansionRatio - ( - readScalar(shrinkDict.lookup("expansionRatio")) - ); - const scalar finalLayerRatio - ( - readScalar(shrinkDict.lookup("finalLayerRatio")) - ); - const label nBufferCellsNoExtrude - ( - readLabel(shrinkDict.lookup("nBufferCellsNoExtrude")) - ); - const label nSmoothSurfaceNormals - ( - readLabel(shrinkDict.lookup("nSmoothSurfaceNormals")) - ); - const label nSmoothNormals(readLabel(shrinkDict.lookup("nSmoothNormals"))); - const label nSmoothThickness - ( - readLabel(shrinkDict.lookup("nSmoothThickness")) - ); - const scalar maxThicknessToMedialRatio - ( - readScalar(shrinkDict.lookup("maxThicknessToMedialRatio")) - ); - - // Medial axis setup - - const scalar minMedianAxisAngle - ( - readScalar(shrinkDict.lookup("minMedianAxisAngle")) - ); - const scalar minMedianAxisAngleCos = - Foam::cos(minMedianAxisAngle*mathematicalConstant::pi/180.); - - - // Precalculate mesh edge labels for patch edges + fvMesh& mesh = meshRefiner_.mesh(); const indirectPrimitivePatch& pp = meshMover.patch(); const labelList& meshPoints = pp.meshPoints(); + // Precalculate mesh edge labels for patch edges + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + labelList meshEdges(pp.nEdges()); forAll(pp.edges(), edgeI) { @@ -2426,8 +2489,8 @@ void Foam::autoHexMeshDriver::addLayers label v1 = meshPoints[ppEdge[1]]; meshEdges[edgeI] = meshTools::findEdge ( - mesh_.edges(), - mesh_.pointEdges()[v0], + mesh.edges(), + mesh.pointEdges()[v0], v0, v1 ); @@ -2449,8 +2512,9 @@ void Foam::autoHexMeshDriver::addLayers setNumLayers ( - meshMover.adaptPatchIDs(), - pp, + layerParams.numLayers(), // per patch the num layers + meshMover.adaptPatchIDs(), // patches that are being moved + pp, // indirectpatch for all faces moving patchDisp, patchNLayers, @@ -2477,7 +2541,7 @@ void Foam::autoHexMeshDriver::addLayers ( pp, meshEdges, - minCos, + layerParams.featureAngle()*mathematicalConstant::pi/180.0, patchDisp, patchNLayers, @@ -2488,13 +2552,13 @@ void Foam::autoHexMeshDriver::addLayers // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Undistorted edge length - const scalar edge0Len = meshRefinerPtr_().meshCutter().level0EdgeLength(); - const labelList& cellLevel = meshRefinerPtr_().meshCutter().cellLevel(); + const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength(); + const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel(); handleWarpedFaces ( pp, - maxFaceThicknessRatio, + layerParams.maxFaceThicknessRatio(), edge0Len, cellLevel, @@ -2517,7 +2581,7 @@ void Foam::autoHexMeshDriver::addLayers // Grow out region of non-extrusion - for (label i = 0; i < nGrow; i++) + for (label i = 0; i < layerParams.nGrow(); i++) { growNoExtrusion ( @@ -2528,21 +2592,24 @@ void Foam::autoHexMeshDriver::addLayers ); } - // Determine point-wise layer thickness + // Determine (wanted) point-wise layer thickness and expansion ratio scalarField thickness(pp.nPoints()); scalarField minThickness(pp.nPoints()); + scalarField expansionRatio(pp.nPoints()); calculateLayerThickness ( - expansionRatio, - finalLayerRatio, - relMinThickness, pp, + meshMover.adaptPatchIDs(), + layerParams.expansionRatio(), + layerParams.finalLayerRatio(), + layerParams.minThickness(), cellLevel, patchNLayers, edge0Len, thickness, - minThickness + minThickness, + expansionRatio ); // Calculate wall to medial axis distance for smoothing displacement @@ -2553,8 +2620,8 @@ void Foam::autoHexMeshDriver::addLayers IOobject ( "pointMedialDist", - mesh_.time().timeName(), - mesh_, + mesh.time().timeName(), + mesh, IOobject::NO_READ, IOobject::NO_WRITE, false @@ -2568,8 +2635,8 @@ void Foam::autoHexMeshDriver::addLayers IOobject ( "dispVec", - mesh_.time().timeName(), - mesh_, + mesh.time().timeName(), + mesh, IOobject::NO_READ, IOobject::NO_WRITE, false @@ -2583,8 +2650,8 @@ void Foam::autoHexMeshDriver::addLayers IOobject ( "medialRatio", - mesh_.time().timeName(), - mesh_, + mesh.time().timeName(), + mesh, IOobject::NO_READ, IOobject::NO_WRITE, false @@ -2602,9 +2669,9 @@ void Foam::autoHexMeshDriver::addLayers medialAxisSmoothingInfo ( meshMover, - nSmoothNormals, - nSmoothSurfaceNormals, - minMedianAxisAngleCos, + layerParams.nSmoothNormals(), + layerParams.nSmoothSurfaceNormals(), + layerParams.minMedianAxisAngleCos(), dispVec, medialRatio, @@ -2614,10 +2681,10 @@ void Foam::autoHexMeshDriver::addLayers // Saved old points - pointField oldPoints(mesh_.points()); + pointField oldPoints(mesh.points()); // Last set of topology changes. (changing mesh clears out polyTopoChange) - polyTopoChange savedMeshMod(mesh_.boundaryMesh().size()); + polyTopoChange savedMeshMod(mesh.boundaryMesh().size()); boolList flaggedCells; boolList flaggedFaces; @@ -2657,8 +2724,8 @@ void Foam::autoHexMeshDriver::addLayers // debug, // meshMover, // -patchDisp, // Shrink in opposite direction of addedPoints - // nSmoothDisp, - // nSnap + // layerParams.nSmoothDisp(), + // layerParams.nSnap() //); // Medial axis based shrinking @@ -2666,11 +2733,11 @@ void Foam::autoHexMeshDriver::addLayers ( meshMover, - nSmoothThickness, - maxThicknessToMedialRatio, + layerParams.nSmoothThickness(), + layerParams.maxThicknessToMedialRatio(), nAllowableErrors, - nSnap, - minCosLayerTermination, + layerParams.nSnap(), + layerParams.layerTerminationCos(), thickness, minThickness, @@ -2690,7 +2757,7 @@ void Foam::autoHexMeshDriver::addLayers // Truncate displacements that are too small (this will do internal // ones, coupled ones have already been truncated by syncPatch) - faceSet dummySet(mesh_, "wrongPatchFaces", 0); + faceSet dummySet(mesh, "wrongPatchFaces", 0); truncateDisplacement ( meshMover, @@ -2703,27 +2770,27 @@ void Foam::autoHexMeshDriver::addLayers // Dump to .obj file for debugging. - if (debug_) + if (debug) { dumpDisplacement ( - mesh_.time().path()/"layer", + mesh.time().path()/"layer", pp, patchDisp, extrudeStatus ); - const_cast<Time&>(mesh_.time())++; - Info<< "Writing shrunk mesh to " << mesh_.time().timeName() << endl; - mesh_.write(); + const_cast<Time&>(mesh.time())++; + Info<< "Writing shrunk mesh to " << mesh.time().timeName() << endl; + mesh.write(); } // Mesh topo change engine - polyTopoChange meshMod(mesh_); + polyTopoChange meshMod(mesh); // Grow layer of cells on to patch. Handles zero sized displacement. - addPatchCellLayer addLayer(mesh_); + addPatchCellLayer addLayer(mesh); // Determine per point/per face number of layers to extrude. Also // handles the slow termination of layers when going switching layers @@ -2735,7 +2802,7 @@ void Foam::autoHexMeshDriver::addLayers meshMover, patchNLayers, extrudeStatus, - nBufferCellsNoExtrude, + layerParams.nBufferCellsNoExtrude(), nPatchPointLayers, nPatchFaceLayers ); @@ -2747,7 +2814,7 @@ void Foam::autoHexMeshDriver::addLayers { if (patchNLayers[i] > 0) { - if (expansionRatio == 1.0) + if (expansionRatio[i] == 1.0) { firstDisp[i] = patchDisp[i]/nPatchPointLayers[i]; } @@ -2755,15 +2822,15 @@ void Foam::autoHexMeshDriver::addLayers { label nLay = nPatchPointLayers[i]; scalar h = - pow(expansionRatio,nLay - 1) - * (mag(patchDisp[i])*(1.0 - expansionRatio)) - / (1.0 - pow(expansionRatio, nLay)); + pow(expansionRatio[i], nLay - 1) + * (mag(patchDisp[i])*(1.0 - expansionRatio[i])) + / (1.0 - pow(expansionRatio[i], nLay)); firstDisp[i] = h/mag(patchDisp[i])*patchDisp[i]; } } } - scalar invExpansionRatio = 1.0 / expansionRatio; + scalarField invExpansionRatio = 1.0 / expansionRatio; // Add topo regardless of whether extrudeStatus is extruderemove. // Not add layer if patchDisp is zero. @@ -2777,9 +2844,9 @@ void Foam::autoHexMeshDriver::addLayers meshMod ); - if (debug_) + if (debug) { - const_cast<Time&>(mesh_.time())++; + const_cast<Time&>(mesh.time())++; } // Store mesh changes for if mesh is correct. @@ -2796,13 +2863,13 @@ void Foam::autoHexMeshDriver::addLayers IOobject ( //mesh.name()+"_layer", - mesh_.name(), - static_cast<polyMesh&>(mesh_).instance(), - mesh_.db(), - static_cast<polyMesh&>(mesh_).readOpt(), - static_cast<polyMesh&>(mesh_).writeOpt() + mesh.name(), + static_cast<polyMesh&>(mesh).instance(), + mesh.db(), + static_cast<polyMesh&>(mesh).readOpt(), + static_cast<polyMesh&>(mesh).writeOpt() ), // io params from original mesh but new name - mesh_, // original mesh + mesh, // original mesh true // parallel sync ); fvMesh& newMesh = newMeshPtr(); @@ -2830,9 +2897,9 @@ void Foam::autoHexMeshDriver::addLayers ); - if (debug_) + if (debug) { - Info<< "Writing layer mesh to " << mesh_.time().timeName() << endl; + Info<< "Writing layer mesh to " << mesh.time().timeName() << endl; newMesh.write(); cellSet addedCellSet ( @@ -2843,8 +2910,7 @@ void Foam::autoHexMeshDriver::addLayers Info<< "Writing " << returnReduce(addedCellSet.size(), sumOp<label>()) << " added cells to cellSet " - << addedCellSet.objectPath() - << endl; + << addedCellSet.name() << endl; addedCellSet.write(); faceSet layerFacesSet @@ -2856,8 +2922,7 @@ void Foam::autoHexMeshDriver::addLayers Info<< "Writing " << returnReduce(layerFacesSet.size(), sumOp<label>()) << " faces inside added layer to faceSet " - << layerFacesSet.objectPath() - << endl; + << layerFacesSet.name() << endl; layerFacesSet.write(); } @@ -2895,18 +2960,18 @@ void Foam::autoHexMeshDriver::addLayers // current mesh. // Apply the stored topo changes to the current mesh. - autoPtr<mapPolyMesh> map = savedMeshMod.changeMesh(mesh_, false); + autoPtr<mapPolyMesh> map = savedMeshMod.changeMesh(mesh, false); // Update fields - mesh_.updateMesh(map); + mesh.updateMesh(map); // Move mesh (since morphing does not do this) if (map().hasMotionPoints()) { - mesh_.movePoints(map().preMotionPoints()); + mesh.movePoints(map().preMotionPoints()); } - meshRefinerPtr_().updateMesh(map, labelList(0)); + meshRefiner_.updateMesh(map, labelList(0)); // Do final balancing @@ -2914,8 +2979,24 @@ void Foam::autoHexMeshDriver::addLayers if (Pstream::parRun()) { + Info<< nl + << "Doing final balancing" << nl + << "---------------------" << nl + << endl; + + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + // Balance. No restriction on face zones and baffles. - autoPtr<mapDistributePolyMesh> map = balance(false, false); + autoPtr<mapDistributePolyMesh> map = meshRefiner_.balance + ( + false, + false, + decomposer, + distributor + ); // Re-distribute flag of layer faces and cells map().distributeCellData(flaggedCells); @@ -2926,23 +3007,122 @@ void Foam::autoHexMeshDriver::addLayers // Write mesh // ~~~~~~~~~~ - //writeMesh("Layer mesh"); - cellSet addedCellSet(mesh_, "addedCells", findIndices(flaggedCells, true)); + cellSet addedCellSet(mesh, "addedCells", findIndices(flaggedCells, true)); Info<< "Writing " << returnReduce(addedCellSet.size(), sumOp<label>()) << " added cells to cellSet " - << addedCellSet.objectPath() - << endl; + << addedCellSet.name() << endl; addedCellSet.write(); - faceSet layerFacesSet(mesh_, "layerFaces", findIndices(flaggedFaces, true)); + faceSet layerFacesSet(mesh, "layerFaces", findIndices(flaggedFaces, true)); Info<< "Writing " << returnReduce(layerFacesSet.size(), sumOp<label>()) << " faces inside added layer to faceSet " - << layerFacesSet.objectPath() - << endl; + << layerFacesSet.name() << endl; layerFacesSet.write(); } +void Foam::autoLayerDriver::doLayers +( + const dictionary& shrinkDict, + const dictionary& motionDict, + const layerParameters& layerParams, + decompositionMethod& decomposer, + fvMeshDistribute& distributor +) +{ + fvMesh& mesh = meshRefiner_.mesh(); + + Info<< nl + << "Shrinking and layer addition phase" << nl + << "----------------------------------" << nl + << endl; + + const_cast<Time&>(mesh.time())++; + + Info<< "Using mesh parameters " << motionDict << nl << endl; + + // Merge coplanar boundary faces + mergePatchFacesUndo(layerParams, motionDict); + + // Per patch the number of layers (0 if no layer) + const labelList& numLayers = layerParams.numLayers(); + + // Patches that need to get a layer + DynamicList<label> patchIDs(numLayers.size()); + label nFacesWithLayers = 0; + forAll(numLayers, patchI) + { + if (numLayers[patchI] > 0) + { + patchIDs.append(patchI); + nFacesWithLayers += mesh.boundaryMesh()[patchI].size(); + } + } + patchIDs.shrink(); + + if (returnReduce(nFacesWithLayers, sumOp<label>()) == 0) + { + Info<< nl << "No layers to generate ..." << endl; + } + else + { + autoPtr<indirectPrimitivePatch> ppPtr + ( + meshRefinement::makePatch + ( + mesh, + patchIDs + ) + ); + indirectPrimitivePatch& pp = ppPtr(); + + // Construct iterative mesh mover. + Info<< "Constructing mesh displacer ..." << endl; + + { + pointMesh pMesh(mesh); + + motionSmoother meshMover + ( + mesh, + pp, + patchIDs, + meshRefinement::makeDisplacementField(pMesh, patchIDs), + motionDict + ); + + // Check that outside of mesh is not multiply connected. + checkMeshManifold(); + + // Check initial mesh + Info<< "Checking initial mesh ..." << endl; + labelHashSet wrongFaces(mesh.nFaces()/100); + motionSmoother::checkMesh(false, mesh, motionDict, wrongFaces); + const label nInitErrors = returnReduce + ( + wrongFaces.size(), + sumOp<label>() + ); + + Info<< "Detected " << nInitErrors << " illegal faces" + << " (concave, zero area or negative cell pyramid volume)" + << endl; + + // Do all topo changes + addLayers + ( + layerParams, + motionDict, + nInitErrors, + meshMover, + decomposer, + distributor + ); + } + } +} + + // ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.H new file mode 100644 index 0000000000000000000000000000000000000000..af768a64aa42ad05d67d63a46c12a8605594282f --- /dev/null +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.H @@ -0,0 +1,562 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::autoLayerDriver + +Description + All to do with adding layers + +SourceFiles + autoLayerDriver.C + +\*---------------------------------------------------------------------------*/ + +#ifndef autoLayerDriver_H +#define autoLayerDriver_H + +#include "meshRefinement.H" +#include "wallPoint.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration of classes +class removePoints; +class pointSet; +class motionSmoother; +class addPatchCellLayer; +class pointData; +class wallPoint; +class faceSet; +class layerParameters; + +/*---------------------------------------------------------------------------*\ + Class autoLayerDriver Declaration +\*---------------------------------------------------------------------------*/ + +class autoLayerDriver +{ + // Static data members + + //- Extrusion controls + enum extrudeMode + { + NOEXTRUDE, /*!< Do not extrude. No layers added. */ + EXTRUDE, /*!< Extrude */ + EXTRUDEREMOVE /*!< Extrude but afterwards remove added */ + /*!< faces locally */ + }; + + + // Private classes + + //- Combine operator class to combine normal with other normal. + class nomalsCombine + { + public: + + void operator()(vector& x, const vector& y) const + { + if (y != wallPoint::greatPoint) + { + if (x == wallPoint::greatPoint) + { + x = y; + } + else + { + x *= (x&y); + } + } + } + }; + + + // Private data + + //- Mesh+surface + meshRefinement& meshRefiner_; + + //- From surface region to patch + const labelList globalToPatch_; + + + + // Private Member Functions + + + // Face merging + + //- Merge patch faces. Undo until no checkMesh errors. + label mergePatchFacesUndo + ( + const scalar minCos, + const scalar concaveCos, + const dictionary& + ); + + //- Remove points. + autoPtr<mapPolyMesh> doRemovePoints + ( + removePoints& pointRemover, + const boolList& pointCanBeDeleted + ); + + //- Restore faces (which contain removed points) + autoPtr<mapPolyMesh> doRestorePoints + ( + removePoints& pointRemover, + const labelList& facesToRestore + ); + + //- Return candidateFaces that are also in set. + labelList collectFaces + ( + const labelList& candidateFaces, + const labelHashSet& set + ) const; + + //- Pick up faces of cells of faces in set. + labelList growFaceCellFace(const labelHashSet&) const; + + //- Remove points not used by any face or points used by only + // two faces where the edges are in line + label mergeEdgesUndo(const scalar minCos, const dictionary&); + + + // Layers + + //- For debugging: Dump displacement to .obj files + static void dumpDisplacement + ( + const fileName&, + const indirectPrimitivePatch&, + const vectorField&, + const List<extrudeMode>& + ); + + //- Check that primitivePatch is not multiply connected. + // Collect non-manifold points in pointSet. + static void checkManifold + ( + const indirectPrimitivePatch&, + pointSet& nonManifoldPoints + ); + + //- Check that mesh outside is not multiply connected. + void checkMeshManifold() const; + + + // Static extrusion setup + + //- Unset extrusion on point. Returns true if anything unset. + static bool unmarkExtrusion + ( + const label patchPointI, + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ); + + //- Unset extrusion on face. Returns true if anything unset. + static bool unmarkExtrusion + ( + const face& localFace, + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ); + + //- No extrusion at non-manifold points. + void handleNonManifolds + ( + const indirectPrimitivePatch& pp, + const labelList& meshEdges, + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ) const; + + //- No extrusion on feature edges. Assumes non-manifold + // edges already handled. + void handleFeatureAngle + ( + const indirectPrimitivePatch& pp, + const labelList& meshEdges, + const scalar minCos, + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ) const; + + //- No extrusion on warped faces + void handleWarpedFaces + ( + const indirectPrimitivePatch& pp, + const scalar faceRatio, + const scalar edge0Len, + const labelList& cellLevel, + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ) const; + + //- Determine the number of layers per point from the number of + // layers per surface. + void setNumLayers + ( + const labelList& patchToNLayers, + const labelList& patchIDs, + const indirectPrimitivePatch& pp, + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ) const; + + //- Grow no-extrusion layer. + static void growNoExtrusion + ( + const indirectPrimitivePatch& pp, + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ); + + //- Calculate pointwise wanted and minimum thickness. + // thickness: wanted thickness + // minthickness: when to give up and not extrude + // Gets per patch parameters and determine pp pointwise + // parameters. + void calculateLayerThickness + ( + const indirectPrimitivePatch& pp, + const labelList& patchIDs, + const scalarField& patchExpansionRatio, + const scalarField& patchFinalLayerRatio, + const scalarField& patchRelMinThickness, + const labelList& cellLevel, + const labelList& patchNLayers, + const scalar edge0Len, + + scalarField& thickness, + scalarField& minThickness, + scalarField& expansionRatio + ) const; + + + // Extrusion execution + + //- Synchronize displacement among coupled patches. + void syncPatchDisplacement + ( + const motionSmoother& meshMover, + const scalarField& minThickness, + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ) const; + + //- Get nearest point on surface to snap to + void getPatchDisplacement + ( + const motionSmoother& meshMover, + const scalarField& thickness, + const scalarField& minThickness, + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ) const; + + //- Truncates displacement + // - for all patchFaces in the faceset displacement gets set + // to zero + // - all displacement < minThickness gets set to zero + label truncateDisplacement + ( + const motionSmoother& meshMover, + const scalarField& minThickness, + const faceSet& illegalPatchFaces, + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ) const; + + //- Setup layer information (at points and faces) to + // modify mesh topology in + // regions where layer mesh terminates. Guarantees an + // optional slow decreasing of the number of layers. + // Returns the number of layers per face and per point + // to go into the actual layer addition engine. + void setupLayerInfoTruncation + ( + const motionSmoother& meshMover, + const labelList& patchNLayers, + const List<extrudeMode>& extrudeStatus, + const label nBufferCellsNoExtrude, + labelList& nPatchPointLayers, + labelList& nPatchFaceLayers + ) const; + + //- Does any of the cells use a face from faces? + static bool cellsUseFace + ( + const polyMesh& mesh, + const labelList& cellLabels, + const labelHashSet& faces + ); + + //- Checks the newly added cells and locally unmarks points + // so they will not get extruded next time round. Returns + // global number of unmarked points (0 if all was fine) + static label checkAndUnmark + ( + const addPatchCellLayer& addLayer, + const dictionary& motionDict, + const indirectPrimitivePatch& pp, + const fvMesh&, + + pointField& patchDisp, + labelList& patchNLayers, + List<extrudeMode>& extrudeStatus + ); + + //- Count global number of extruded faces + static label countExtrusion + ( + const indirectPrimitivePatch& pp, + const List<extrudeMode>& extrudeStatus + ); + + //- Collect layer faces and layer cells into bools + // for ease of handling + static void getLayerCellsFaces + ( + const polyMesh&, + const addPatchCellLayer&, + boolList&, + boolList& + ); + + // Mesh shrinking (to create space for layers) + + //- Average field (over all subset of mesh points) by + // summing contribution from edges. Global parallel since only + // does master edges for coupled edges. + template<class Type> + static void averageNeighbours + ( + const polyMesh& mesh, + const PackedList<1>& isMasterEdge, + const labelList& meshEdges, + const labelList& meshPoints, + const edgeList& edges, + const scalarField& invSumWeight, + const Field<Type>& data, + Field<Type>& average + ); + + //- Calculate inverse sum of edge weights (currently always 1.0) + void sumWeights + ( + const PackedList<1>& isMasterEdge, + const labelList& meshEdges, + const labelList& meshPoints, + const edgeList& edges, + scalarField& invSumWeight + ) const; + + //- Smooth scalar field on patch + void smoothField + ( + const motionSmoother& meshMover, + const PackedList<1>& isMasterEdge, + const labelList& meshEdges, + const scalarField& fieldMin, + const label& nSmoothDisp, + scalarField& field + ) const; + + //- Smooth normals on patch. + void smoothPatchNormals + ( + const motionSmoother& meshMover, + const PackedList<1>& isMasterEdge, + const labelList& meshEdges, + const label nSmoothDisp, + pointField& normals + ) const; + + //- Smooth normals in interior. + void smoothNormals + ( + const label nSmoothDisp, + const PackedList<1>& isMasterEdge, + const labelList& fixedPoints, + pointVectorField& normals + ) const; + + bool isMaxEdge + ( + const List<pointData>&, + const label edgeI, + const scalar minCos + ) const; + + //- Stop layer growth where mesh wraps around edge with a + // large feature angle + void handleFeatureAngleLayerTerminations + ( + const indirectPrimitivePatch& pp, + const scalar minCos, + List<extrudeMode>& extrudeStatus, + pointField& patchDisp, + labelList& patchNLayers, + label& nPointCounter + ) const; + + //- Find isolated islands (points, edges and faces and + // layer terminations) + // in the layer mesh and stop any layer growth at these points. + void findIsolatedRegions + ( + const indirectPrimitivePatch& pp, + const PackedList<1>& isMasterEdge, + const labelList& meshEdges, + const scalar minCosLayerTermination, + scalarField& field, + List<extrudeMode>& extrudeStatus, + pointField& patchDisp, + labelList& patchNLayers + ) const; + + // Calculate medial axis fields + void medialAxisSmoothingInfo + ( + const motionSmoother& meshMover, + const label nSmoothNormals, + const label nSmoothSurfaceNormals, + const scalar minMedianAxisAngleCos, + + pointVectorField& dispVec, + pointScalarField& medialRatio, + pointScalarField& medialDist + ) const; + + //- Main routine to shrink mesh + void shrinkMeshMedialDistance + ( + motionSmoother& meshMover, + const label nSmoothThickness, + const scalar maxThicknessToMedialRatio, + const label nAllowableErrors, + const label nSnap, + const scalar minCosLayerTermination, + + const scalarField& layerThickness, + const scalarField& minThickness, + + const pointVectorField& dispVec, + const pointScalarField& medialRatio, + const pointScalarField& medialDist, + + List<extrudeMode>& extrudeStatus, + pointField& patchDisp, + labelList& patchNLayers + ) const; + + + + //- Disallow default bitwise copy construct + autoLayerDriver(const autoLayerDriver&); + + //- Disallow default bitwise assignment + void operator=(const autoLayerDriver&); + + +public: + + //- Runtime type information + ClassName("autoLayerDriver"); + + // Constructors + + //- Construct from components + autoLayerDriver + ( + meshRefinement& meshRefiner, + const labelList& globalToPatch + ); + + + // Member Functions + + //- Merge patch faces on same cell. + void mergePatchFacesUndo + ( + const layerParameters& layerParams, + const dictionary& motionDict + ); + + //- Add cell layers + void addLayers + ( + const layerParameters& layerParams, + const dictionary& motionDict, + const label nAllowableErrors, + motionSmoother& meshMover, + decompositionMethod& decomposer, + fvMeshDistribute& distributor + ); + + //- Add layers according to the dictionary settings + void doLayers + ( + const dictionary& shrinkDict, + const dictionary& motionDict, + const layerParameters& layerParams, + decompositionMethod& decomposer, + fvMeshDistribute& distributor + ); + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository +# include "autoLayerDriverTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverShrink.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverShrink.C similarity index 93% rename from src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverShrink.C rename to src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverShrink.C index 0c66073e84c422135bcdb5aa82a2b6314641d61b..8c41371ddc2ef07f5a9613baebf765d91632cf8e 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverShrink.C +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverShrink.C @@ -27,7 +27,7 @@ Description \*----------------------------------------------------------------------------*/ -#include "autoHexMeshDriver.H" +#include "autoLayerDriver.H" #include "fvMesh.H" #include "Time.H" #include "pointFields.H" @@ -41,7 +41,7 @@ Description // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // Calculate inverse sum of edge weights (currently always 1.0) -void Foam::autoHexMeshDriver::sumWeights +void Foam::autoLayerDriver::sumWeights ( const PackedList<1>& isMasterEdge, const labelList& meshEdges, @@ -67,7 +67,7 @@ void Foam::autoHexMeshDriver::sumWeights syncTools::syncPointList ( - mesh_, + meshRefiner_.mesh(), meshPoints, invSumWeight, plusEqOp<scalar>(), @@ -88,7 +88,7 @@ void Foam::autoHexMeshDriver::sumWeights // Smooth field on moving patch -void Foam::autoHexMeshDriver::smoothField +void Foam::autoLayerDriver::smoothField ( const motionSmoother& meshMover, const PackedList<1>& isMasterEdge, @@ -120,6 +120,7 @@ void Foam::autoHexMeshDriver::smoothField scalarField average(pp.nPoints()); averageNeighbours ( + meshMover.mesh(), isMasterEdge, meshEdges, meshPoints, @@ -159,7 +160,7 @@ void Foam::autoHexMeshDriver::smoothField // Smooth normals on moving patch. -void Foam::autoHexMeshDriver::smoothPatchNormals +void Foam::autoLayerDriver::smoothPatchNormals ( const motionSmoother& meshMover, const PackedList<1>& isMasterEdge, @@ -192,6 +193,7 @@ void Foam::autoHexMeshDriver::smoothPatchNormals vectorField average(pp.nPoints()); averageNeighbours ( + meshMover.mesh(), isMasterEdge, meshEdges, meshPoints, @@ -223,7 +225,7 @@ void Foam::autoHexMeshDriver::smoothPatchNormals // Smooth normals in interior. -void Foam::autoHexMeshDriver::smoothNormals +void Foam::autoLayerDriver::smoothNormals ( const label nSmoothDisp, const PackedList<1>& isMasterEdge, @@ -234,10 +236,11 @@ void Foam::autoHexMeshDriver::smoothNormals // Get smoothly varying internal normals field. Info<< "shrinkMeshDistance : Smoothing normals ..." << endl; - const edgeList& edges = mesh_.edges(); + const fvMesh& mesh = meshRefiner_.mesh(); + const edgeList& edges = mesh.edges(); // Points that do not change. - PackedList<1> isFixedPoint(mesh_.nPoints(), 0); + PackedList<1> isFixedPoint(mesh.nPoints(), 0); // Internal points that are fixed forAll(fixedPoints, i) @@ -247,12 +250,12 @@ void Foam::autoHexMeshDriver::smoothNormals } // Correspondence between local edges/points and mesh edges/points - const labelList meshEdges(identity(mesh_.nEdges())); - const labelList meshPoints(identity(mesh_.nPoints())); + const labelList meshEdges(identity(mesh.nEdges())); + const labelList meshPoints(identity(mesh.nPoints())); // Calculate inverse sum of weights - scalarField invSumWeight(mesh_.nPoints(), 0); + scalarField invSumWeight(mesh.nPoints(), 0); sumWeights ( isMasterEdge, @@ -266,9 +269,10 @@ void Foam::autoHexMeshDriver::smoothNormals for (label iter = 0; iter < nSmoothDisp; iter++) { - vectorField average(mesh_.nPoints()); + vectorField average(mesh.nPoints()); averageNeighbours ( + mesh, isMasterEdge, meshEdges, meshPoints, @@ -305,18 +309,19 @@ void Foam::autoHexMeshDriver::smoothNormals // Tries and find a medial axis point. Done by comparing vectors to nearest // wall point for both vertices of edge. -bool Foam::autoHexMeshDriver::isMaxEdge +bool Foam::autoLayerDriver::isMaxEdge ( const List<pointData>& pointWallDist, const label edgeI, const scalar minCos ) const { - const pointField& points = mesh_.points(); + const fvMesh& mesh = meshRefiner_.mesh(); + const pointField& points = mesh.points(); // Do not mark edges with one side on moving wall. - const edge& e = mesh_.edges()[edgeI]; + const edge& e = mesh.edges()[edgeI]; vector v0(points[e[0]] - pointWallDist[e[0]].origin()); scalar magV0(mag(v0)); @@ -351,7 +356,7 @@ bool Foam::autoHexMeshDriver::isMaxEdge // Stop layer growth where mesh wraps around edge with a // large feature angle -void Foam::autoHexMeshDriver::handleFeatureAngleLayerTerminations +void Foam::autoLayerDriver::handleFeatureAngleLayerTerminations ( const indirectPrimitivePatch& pp, const scalar minCos, @@ -444,7 +449,7 @@ void Foam::autoHexMeshDriver::handleFeatureAngleLayerTerminations // Find isolated islands (points, edges and faces and layer terminations) // in the layer mesh and stop any layer growth at these points. -void Foam::autoHexMeshDriver::findIsolatedRegions +void Foam::autoLayerDriver::findIsolatedRegions ( const indirectPrimitivePatch& pp, const PackedList<1>& isMasterEdge, @@ -456,6 +461,8 @@ void Foam::autoHexMeshDriver::findIsolatedRegions labelList& patchNLayers ) const { + const fvMesh& mesh = meshRefiner_.mesh(); + Info<< "shrinkMeshDistance : Removing isolated regions ..." << endl; // Keep count of number of points unextruded @@ -514,7 +521,7 @@ void Foam::autoHexMeshDriver::findIsolatedRegions syncTools::syncPointList ( - mesh_, + mesh, pp.meshPoints(), keptPoints, orEqOp<bool>(), @@ -582,7 +589,7 @@ void Foam::autoHexMeshDriver::findIsolatedRegions syncTools::syncPointList ( - mesh_, + mesh, pp.meshPoints(), isolatedPoint, plusEqOp<label>(), @@ -650,7 +657,7 @@ void Foam::autoHexMeshDriver::findIsolatedRegions // medialDist : distance to medial axis // medialRatio : ratio of medial distance to wall distance. // (1 at wall, 0 at medial axis) -void Foam::autoHexMeshDriver::medialAxisSmoothingInfo +void Foam::autoLayerDriver::medialAxisSmoothingInfo ( const motionSmoother& meshMover, const label nSmoothNormals, @@ -666,7 +673,8 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo Info<< "medialAxisSmoothingInfo :" << " Calculate distance to Medial Axis ..." << endl; - const pointField& points = mesh_.points(); + const polyMesh& mesh = meshMover.mesh(); + const pointField& points = mesh.points(); const pointMesh& pMesh = meshMover.pMesh(); const indirectPrimitivePatch& pp = meshMover.patch(); @@ -677,7 +685,7 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo // ~~~~~~~~~~~~~~~~~~~~~~~ // Precalulate master edge (only relevant for shared edges) - PackedList<1> isMasterEdge(syncTools::getMasterEdges(mesh_)); + PackedList<1> isMasterEdge(syncTools::getMasterEdges(mesh)); // Precalculate meshEdge per pp edge labelList meshEdges(pp.nEdges()); @@ -689,8 +697,8 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo label v1 = pp.meshPoints()[e[1]]; meshEdges[patchEdgeI] = meshTools::findEdge ( - mesh_.edges(), - mesh_.pointEdges()[v0], + mesh.edges(), + mesh.pointEdges()[v0], v0, v1 ); @@ -717,7 +725,7 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo syncTools::syncPointList ( - mesh_, + mesh, meshPoints, pointNormals, plusEqOp<vector>(), @@ -727,7 +735,7 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo syncTools::syncPointList ( - mesh_, + mesh, meshPoints, nPointFaces, plusEqOp<label>(), @@ -756,7 +764,7 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Distance to wall - List<pointData> pointWallDist(mesh_.nPoints()); + List<pointData> pointWallDist(mesh.nPoints()); // 1. Calculate distance to points where displacement is specified. @@ -777,7 +785,7 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo } // Do all calculations - List<pointData> edgeWallDist(mesh_.nEdges()); + List<pointData> edgeWallDist(mesh.nEdges()); PointEdgeWave<pointData> wallDistCalc ( pMesh, @@ -785,15 +793,15 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo wallInfo, pointWallDist, edgeWallDist, - mesh_.nPoints() // max iterations + mesh.nPoints() // max iterations ); } // 2. Find points with max distance and transport information back to // wall. { - List<pointData> pointMedialDist(mesh_.nPoints()); - List<pointData> edgeMedialDist(mesh_.nEdges()); + List<pointData> pointMedialDist(mesh.nPoints()); + List<pointData> edgeMedialDist(mesh.nEdges()); // Seed point data. DynamicList<pointData> maxInfo(meshPoints.size()); @@ -801,7 +809,7 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo // 1. Medial axis points - const edgeList& edges = mesh_.edges(); + const edgeList& edges = mesh.edges(); forAll(edges, edgeI) { @@ -836,7 +844,7 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo // 2. Seed non-adapt patches - const polyBoundaryMesh& patches = mesh_.boundaryMesh(); + const polyBoundaryMesh& patches = mesh.boundaryMesh(); labelHashSet adaptPatches(meshMover.adaptPatchIDs()); @@ -890,7 +898,7 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo pointMedialDist, edgeMedialDist, - mesh_.nPoints() // max iterations + mesh.nPoints() // max iterations ); // Extract medial axis distance as pointScalarField @@ -925,7 +933,7 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo } } - if (debug_) + if (debug) { Info<< "medialAxisSmoothingInfo :" << " Writing:" << nl @@ -943,7 +951,7 @@ void Foam::autoHexMeshDriver::medialAxisSmoothingInfo } -void Foam::autoHexMeshDriver::shrinkMeshMedialDistance +void Foam::autoLayerDriver::shrinkMeshMedialDistance ( motionSmoother& meshMover, const label nSmoothThickness, @@ -973,7 +981,7 @@ void Foam::autoHexMeshDriver::shrinkMeshMedialDistance const labelList& meshPoints = pp.meshPoints(); // Precalulate master edge (only relevant for shared edges) - PackedList<1> isMasterEdge(syncTools::getMasterEdges(mesh_)); + PackedList<1> isMasterEdge(syncTools::getMasterEdges(mesh)); // Precalculate meshEdge per pp edge labelList meshEdges(pp.nEdges()); @@ -985,8 +993,8 @@ void Foam::autoHexMeshDriver::shrinkMeshMedialDistance label v1 = pp.meshPoints()[e[1]]; meshEdges[patchEdgeI] = meshTools::findEdge ( - mesh_.edges(), - mesh_.pointEdges()[v0], + mesh.edges(), + mesh.pointEdges()[v0], v0, v1 ); diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverTemplates.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverTemplates.C similarity index 95% rename from src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverTemplates.C rename to src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverTemplates.C index 31807f0dee77b8e43cd5d9e70684391adcf566b3..7284b4a355bb7f2cf17a53f25594504aa5f2d1c4 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverTemplates.C +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverTemplates.C @@ -24,14 +24,15 @@ License \*---------------------------------------------------------------------------*/ -#include "autoHexMeshDriver.H" +#include "autoLayerDriver.H" #include "syncTools.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // template<class Type> -void Foam::autoHexMeshDriver::averageNeighbours +void Foam::autoLayerDriver::averageNeighbours ( + const polyMesh& mesh, const PackedList<1>& isMasterEdge, const labelList& meshEdges, const labelList& meshPoints, @@ -39,7 +40,7 @@ void Foam::autoHexMeshDriver::averageNeighbours const scalarField& invSumWeight, const Field<Type>& data, Field<Type>& average -) const +) { average = pTraits<Type>::zero; @@ -60,7 +61,7 @@ void Foam::autoHexMeshDriver::averageNeighbours syncTools::syncPointList ( - mesh_, + mesh, meshPoints, average, plusEqOp<Type>(), diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C new file mode 100644 index 0000000000000000000000000000000000000000..218087f7748435f5638052e36addf1914d20cd8d --- /dev/null +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C @@ -0,0 +1,776 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*----------------------------------------------------------------------------*/ + +#include "autoRefineDriver.H" +#include "fvMesh.H" +#include "Time.H" +#include "boundBox.H" +#include "mapDistributePolyMesh.H" +#include "cellSet.H" +#include "syncTools.H" +#include "refinementParameters.H" +#include "featureEdgeMesh.H" +#include "refinementSurfaces.H" +#include "shellSurfaces.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(autoRefineDriver, 0); + +} // End namespace Foam + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +// Read explicit feature edges +Foam::label Foam::autoRefineDriver::readFeatureEdges +( + const PtrList<dictionary>& featDicts, + PtrList<featureEdgeMesh>& featureMeshes, + labelList& featureLevels +) const +{ + Info<< "Reading external feature lines." << endl; + + const fvMesh& mesh = meshRefiner_.mesh(); + + featureMeshes.setSize(featDicts.size()); + featureLevels.setSize(featDicts.size()); + + forAll(featDicts, i) + { + const dictionary& dict = featDicts[i]; + + fileName featFileName(dict.lookup("file")); + + featureMeshes.set + ( + i, + new featureEdgeMesh + ( + IOobject + ( + featFileName, // name + mesh.time().constant(), // directory + "triSurface", // instance + mesh.db(), // registry + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ) + ) + ); + + featureMeshes[i].mergePoints(meshRefiner_.mergeDistance()); + featureLevels[i] = readLabel(dict.lookup("level")); + + Info<< "Refinement level " << featureLevels[i] + << " for all cells crossed by feature " << featFileName + << " (" << featureMeshes[i].points().size() << " points, " + << featureMeshes[i].edges().size() << ")." << endl; + } + + Info<< "Read feature lines in = " + << mesh.time().cpuTimeIncrement() << " s" << nl << endl; + + return featureMeshes.size(); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +// Construct from components +Foam::autoRefineDriver::autoRefineDriver +( + meshRefinement& meshRefiner, + decompositionMethod& decomposer, + fvMeshDistribute& distributor, + const labelList& globalToPatch +) +: + meshRefiner_(meshRefiner), + decomposer_(decomposer), + distributor_(distributor), + globalToPatch_(globalToPatch) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::label Foam::autoRefineDriver::featureEdgeRefine +( + const refinementParameters& refineParams, + const PtrList<dictionary>& featDicts, + const label maxIter, + const label minRefine +) +{ + const fvMesh& mesh = meshRefiner_.mesh(); + + // Read explicit feature edges + PtrList<featureEdgeMesh> featureMeshes; + // Per feature the refinement level + labelList featureLevels; + readFeatureEdges(featDicts, featureMeshes, featureLevels); + + + label iter = 0; + + if (featureMeshes.size() > 0 && maxIter > 0) + { + for (; iter < maxIter; iter++) + { + Info<< nl + << "Feature refinement iteration " << iter << nl + << "------------------------------" << nl + << endl; + + labelList candidateCells + ( + meshRefiner_.refineCandidates + ( + refineParams.keepPoints()[0], // For now only use one. + refineParams.curvature(), + + featureMeshes, + featureLevels, + + true, // featureRefinement + false, // internalRefinement + false, // surfaceRefinement + false, // curvatureRefinement + refineParams.maxGlobalCells(), + refineParams.maxLocalCells() + ) + ); + labelList cellsToRefine + ( + meshRefiner_.meshCutter().consistentRefinement + ( + candidateCells, + true + ) + ); + Info<< "Determined cells to refine in = " + << mesh.time().cpuTimeIncrement() << " s" << endl; + + + + label nCellsToRefine = cellsToRefine.size(); + reduce(nCellsToRefine, sumOp<label>()); + + Info<< "Selected for feature refinement : " << nCellsToRefine + << " cells (out of " << mesh.globalData().nTotalCells() + << ')' << endl; + + if (nCellsToRefine <= minRefine) + { + Info<< "Stopping refining since too few cells selected." + << nl << endl; + break; + } + + + if (debug > 0) + { + const_cast<Time&>(mesh.time())++; + } + + meshRefiner_.refineAndBalance + ( + "feature refinement iteration " + name(iter), + decomposer_, + distributor_, + cellsToRefine + ); + } + } + return iter; +} + + +Foam::label Foam::autoRefineDriver::surfaceOnlyRefine +( + const refinementParameters& refineParams, + const label maxIter +) +{ + const fvMesh& mesh = meshRefiner_.mesh(); + + // Determine the maximum refinement level over all surfaces. This + // determines the minumum number of surface refinement iterations. + label overallMaxLevel = max(meshRefiner_.surfaces().maxLevel()); + + label iter; + for (iter = 0; iter < maxIter; iter++) + { + Info<< nl + << "Surface refinement iteration " << iter << nl + << "------------------------------" << nl + << endl; + + + // Determine cells to refine + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + // Only look at surface intersections (minLevel and surface curvature), + // do not do internal refinement (refinementShells) + + labelList candidateCells + ( + meshRefiner_.refineCandidates + ( + refineParams.keepPoints()[0], + refineParams.curvature(), + + PtrList<featureEdgeMesh>(0), // dummy featureMeshes; + labelList(0), // dummy featureLevels; + + false, // featureRefinement + false, // internalRefinement + true, // surfaceRefinement + true, // curvatureRefinement + refineParams.maxGlobalCells(), + refineParams.maxLocalCells() + ) + ); + labelList cellsToRefine + ( + meshRefiner_.meshCutter().consistentRefinement + ( + candidateCells, + true + ) + ); + Info<< "Determined cells to refine in = " + << mesh.time().cpuTimeIncrement() << " s" << endl; + + + label nCellsToRefine = cellsToRefine.size(); + reduce(nCellsToRefine, sumOp<label>()); + + Info<< "Selected for refinement : " << nCellsToRefine + << " cells (out of " << mesh.globalData().nTotalCells() + << ')' << endl; + + // Stop when no cells to refine or have done minimum nessecary + // iterations and not enough cells to refine. + if + ( + nCellsToRefine == 0 + || ( + iter >= overallMaxLevel + && nCellsToRefine <= refineParams.minRefineCells() + ) + ) + { + Info<< "Stopping refining since too few cells selected." + << nl << endl; + break; + } + + + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + + meshRefiner_.refineAndBalance + ( + "surface refinement iteration " + name(iter), + decomposer_, + distributor_, + cellsToRefine + ); + } + return iter; +} + + +void Foam::autoRefineDriver::removeInsideCells +( + const refinementParameters& refineParams, + const label nBufferLayers +) +{ + Info<< nl + << "Removing mesh beyond surface intersections" << nl + << "------------------------------------------" << nl + << endl; + + const fvMesh& mesh = meshRefiner_.mesh(); + + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + + meshRefiner_.splitMesh + ( + nBufferLayers, // nBufferLayers + globalToPatch_, + refineParams.keepPoints()[0] + ); + + if (debug) + { + Pout<< "Writing subsetted mesh to time " + << mesh.time().timeName() << '.' << endl; + meshRefiner_.write(debug, mesh.time().path()/mesh.time().timeName()); + Pout<< "Dumped mesh in = " + << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl; + } +} + + +Foam::label Foam::autoRefineDriver::shellRefine +( + const refinementParameters& refineParams, + const label maxIter +) +{ + const fvMesh& mesh = meshRefiner_.mesh(); + + // Mark current boundary faces with 0. Have meshRefiner maintain them. + meshRefiner_.userFaceData().setSize(1); + + // mark list to remove any refined faces + meshRefiner_.userFaceData()[0].first() = meshRefinement::REMOVE; + meshRefiner_.userFaceData()[0].second() = createWithValues<labelList> + ( + mesh.nFaces(), + -1, + meshRefiner_.intersectedFaces(), + 0 + ); + + // Determine the maximum refinement level over all volume refinement + // regions. This determines the minumum number of shell refinement + // iterations. + label overallMaxShellLevel = meshRefiner_.shells().maxLevel(); + + label iter; + for (iter = 0; iter < maxIter; iter++) + { + Info<< nl + << "Shell refinement iteration " << iter << nl + << "----------------------------" << nl + << endl; + + labelList candidateCells + ( + meshRefiner_.refineCandidates + ( + refineParams.keepPoints()[0], + refineParams.curvature(), + + PtrList<featureEdgeMesh>(0), // dummy featureMeshes; + labelList(0), // dummy featureLevels; + + false, // featureRefinement + true, // internalRefinement + false, // surfaceRefinement + false, // curvatureRefinement + refineParams.maxGlobalCells(), + refineParams.maxLocalCells() + ) + ); + + if (debug) + { + Pout<< "Dumping " << candidateCells.size() + << " cells to cellSet candidateCellsFromShells." << endl; + + cellSet(mesh, "candidateCellsFromShells", candidateCells).write(); + } + + // Problem choosing starting faces for bufferlayers (bFaces) + // - we can't use the current intersected boundary faces + // (intersectedFaces) since this grows indefinitely + // - if we use 0 faces we don't satisfy bufferLayers from the + // surface. + // - possibly we want to have bFaces only the initial set of faces + // and maintain the list while doing the refinement. + labelList bFaces + ( + findIndices(meshRefiner_.userFaceData()[0].second(), 0) + ); + + //Info<< "Collected boundary faces : " + // << returnReduce(bFaces.size(), sumOp<label>()) << endl; + + labelList cellsToRefine; + + if (refineParams.nBufferLayers() <= 2) + { + cellsToRefine = meshRefiner_.meshCutter().consistentSlowRefinement + ( + refineParams.nBufferLayers(), + candidateCells, // cells to refine + bFaces, // faces for nBufferLayers + 1, // point difference + meshRefiner_.intersectedPoints() // points to check + ); + } + else + { + cellsToRefine = meshRefiner_.meshCutter().consistentSlowRefinement2 + ( + refineParams.nBufferLayers(), + candidateCells, // cells to refine + bFaces // faces for nBufferLayers + ); + } + + Info<< "Determined cells to refine in = " + << mesh.time().cpuTimeIncrement() << " s" << endl; + + + label nCellsToRefine = cellsToRefine.size(); + reduce(nCellsToRefine, sumOp<label>()); + + Info<< "Selected for internal refinement : " << nCellsToRefine + << " cells (out of " << mesh.globalData().nTotalCells() + << ')' << endl; + + // Stop when no cells to refine or have done minimum nessecary + // iterations and not enough cells to refine. + if + ( + nCellsToRefine == 0 + || ( + iter >= overallMaxShellLevel + && nCellsToRefine <= refineParams.minRefineCells() + ) + ) + { + Info<< "Stopping refining since too few cells selected." + << nl << endl; + break; + } + + + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + + meshRefiner_.refineAndBalance + ( + "shell refinement iteration " + name(iter), + decomposer_, + distributor_, + cellsToRefine + ); + } + meshRefiner_.userFaceData().clear(); + + return iter; +} + + +void Foam::autoRefineDriver::baffleAndSplitMesh +( + const refinementParameters& refineParams, + const bool handleSnapProblems +) +{ + Info<< nl + << "Splitting mesh at surface intersections" << nl + << "---------------------------------------" << nl + << endl; + + const fvMesh& mesh = meshRefiner_.mesh(); + + // Introduce baffles at surface intersections. Note: + // meshRefiment::surfaceIndex() will + // be like boundary face from now on so not coupled anymore. + meshRefiner_.baffleAndSplitMesh + ( + handleSnapProblems, + !handleSnapProblems, // merge free standing baffles? + const_cast<Time&>(mesh.time()), + globalToPatch_, + refineParams.keepPoints()[0] + ); +} + + +void Foam::autoRefineDriver::zonify +( + const refinementParameters& refineParams +) +{ + // Mesh is at its finest. Do zoning + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // This puts all faces with intersection across a zoneable surface + // into that surface's faceZone. All cells inside faceZone get given the + // same cellZone. + + if (meshRefiner_.surfaces().getNamedSurfaces().size() > 0) + { + Info<< nl + << "Introducing zones for interfaces" << nl + << "--------------------------------" << nl + << endl; + + const fvMesh& mesh = meshRefiner_.mesh(); + + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + + meshRefiner_.zonify(refineParams.keepPoints()[0]); + + if (debug) + { + Pout<< "Writing zoned mesh to time " + << mesh.time().timeName() << '.' << endl; + meshRefiner_.write + ( + debug, + mesh.time().path()/mesh.time().timeName() + ); + } + + // Check that all faces are synced + meshRefinement::checkCoupledFaceZones(mesh); + } +} + + +void Foam::autoRefineDriver::splitAndMergeBaffles +( + const refinementParameters& refineParams, + const bool handleSnapProblems +) +{ + Info<< nl + << "Handling cells with snap problems" << nl + << "---------------------------------" << nl + << endl; + + const fvMesh& mesh = meshRefiner_.mesh(); + + // Introduce baffles and split mesh + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + + meshRefiner_.baffleAndSplitMesh + ( + handleSnapProblems, + false, // merge free standing baffles? + const_cast<Time&>(mesh.time()), + globalToPatch_, + refineParams.keepPoints()[0] + ); + + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + + // Duplicate points on baffles that are on more than one cell + // region. This will help snapping pull them to separate surfaces. + meshRefiner_.dupNonManifoldPoints(); + + + // Merge all baffles that are still remaining after duplicating points. + List<labelPair> couples + ( + meshRefiner_.getDuplicateFaces // get all baffles + ( + identity(mesh.nFaces()-mesh.nInternalFaces()) + + mesh.nInternalFaces() + ) + ); + + label nCouples = returnReduce(couples.size(), sumOp<label>()); + + Info<< "Detected unsplittable baffles : " + << nCouples << endl; + + if (nCouples > 0) + { + // Actually merge baffles. Note: not exactly parallellized. Should + // convert baffle faces into processor faces if they resulted + // from them. + meshRefiner_.mergeBaffles(couples); + + if (debug) + { + // Debug:test all is still synced across proc patches + meshRefiner_.checkData(); + } + Info<< "Merged free-standing baffles in = " + << mesh.time().cpuTimeIncrement() << " s." << endl; + } + + if (debug) + { + Pout<< "Writing handleProblemCells mesh to time " + << mesh.time().timeName() << '.' << endl; + meshRefiner_.write(debug, mesh.time().path()/mesh.time().timeName()); + } +} + + +void Foam::autoRefineDriver::mergePatchFaces +( + const refinementParameters& refineParams +) +{ + const fvMesh& mesh = meshRefiner_.mesh(); + + Info<< nl + << "Merge refined boundary faces" << nl + << "----------------------------" << nl + << endl; + + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + + meshRefiner_.mergePatchFaces + ( + Foam::cos(45*mathematicalConstant::pi/180.0), + Foam::cos(45*mathematicalConstant::pi/180.0), + meshRefinement::addedPatches(globalToPatch_) + ); + + if (debug) + { + meshRefiner_.checkData(); + } + + meshRefiner_.mergeEdges(Foam::cos(45*mathematicalConstant::pi/180.0)); + + if (debug) + { + meshRefiner_.checkData(); + } +} + + +void Foam::autoRefineDriver::doRefine +( + const dictionary& refineDict, + const refinementParameters& refineParams, + const bool prepareForSnapping +) +{ + Info<< nl + << "Refinement phase" << nl + << "----------------" << nl + << endl; + + const fvMesh& mesh = meshRefiner_.mesh(); + + const_cast<Time&>(mesh.time())++; + + + // Check that all the keep points are inside the mesh. + refineParams.findCells(mesh); + + PtrList<dictionary> featDicts(refineDict.lookup("features")); + + // Refine around feature edges + featureEdgeRefine + ( + refineParams, + featDicts, + 100, // maxIter + 0 // min cells to refine + ); + + // Refine based on surface + surfaceOnlyRefine + ( + refineParams, + 100 // maxIter + ); + + // Remove cells (a certain distance) beyond surface intersections + removeInsideCells + ( + refineParams, + 1 // nBufferLayers + ); + + // Internal mesh refinement + shellRefine + ( + refineParams, + 100 // maxIter + ); + + // Introduce baffles at surface intersections + baffleAndSplitMesh(refineParams, prepareForSnapping); + + // Mesh is at its finest. Do optional zoning. + zonify(refineParams); + + // Pull baffles apart + splitAndMergeBaffles(refineParams, prepareForSnapping); + + // Do something about cells with refined faces on the boundary + if (prepareForSnapping) + { + mergePatchFaces(refineParams); + } + + + if (Pstream::parRun()) + { + Info<< nl + << "Doing final balancing" << nl + << "---------------------" << nl + << endl; + + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + + // Do final balancing. Keep zoned faces on one processor. + meshRefiner_.balance + ( + true, + false, + decomposer_, + distributor_ + ); + } +} + + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H new file mode 100644 index 0000000000000000000000000000000000000000..8aa33855def83c7c8cade6f4fa9abbaf202b0ba5 --- /dev/null +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H @@ -0,0 +1,179 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::autoRefineDriver + +Description + +SourceFiles + autoRefineDriver.C + +\*---------------------------------------------------------------------------*/ + +#ifndef autoRefineDriver_H +#define autoRefineDriver_H + +#include "meshRefinement.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration of classes +class featureEdgeMesh; +class refinementParameters; + + +/*---------------------------------------------------------------------------*\ + Class autoRefineDriver Declaration +\*---------------------------------------------------------------------------*/ + +class autoRefineDriver +{ + // Private data + + //- Mesh+surface + meshRefinement& meshRefiner_; + + //- Reference to decomposition method + decompositionMethod& decomposer_; + + //- Reference to mesh distribution engine + fvMeshDistribute& distributor_; + + //- From surface region to patch + const labelList globalToPatch_; + + + // Private Member Functions + + //- Read explicit feature edges + label readFeatureEdges + ( + const PtrList<dictionary>& featDicts, + PtrList<featureEdgeMesh>& featureMeshes, + labelList& featureLevel + ) const; + + //- Refine all cells pierced by explicit feature edges + label featureEdgeRefine + ( + const refinementParameters& refineParams, + const PtrList<dictionary>& featDicts, + const label maxIter, + const label minRefine + ); + + //- Refine all cells interacting with the surface + label surfaceOnlyRefine + ( + const refinementParameters& refineParams, + const label maxIter + ); + + //- Remove all cells within intersected region + void removeInsideCells + ( + const refinementParameters& refineParams, + const label nBufferLayers + ); + + //- Remove all cells inside/outside shell + label shellRefine + ( + const refinementParameters& refineParams, + const label maxIter + ); + + //- Add baffles and remove unreachable cells + void baffleAndSplitMesh + ( + const refinementParameters& refineParams, + const bool handleSnapProblems + ); + + //- Add zones + void zonify(const refinementParameters& refineParams); + + void splitAndMergeBaffles + ( + const refinementParameters& refineParams, + const bool handleSnapProblems + ); + + //- Merge refined boundary faces (from exposing coarser cell) + void mergePatchFaces + ( + const refinementParameters& refineParams + ); + + + //- Disallow default bitwise copy construct + autoRefineDriver(const autoRefineDriver&); + + //- Disallow default bitwise assignment + void operator=(const autoRefineDriver&); + + +public: + + //- Runtime type information + ClassName("autoRefineDriver"); + + + // Constructors + + //- Construct from components + autoRefineDriver + ( + meshRefinement& meshRefiner, + decompositionMethod& decomposer, + fvMeshDistribute& distributor, + const labelList& globalToPatch + ); + + + // Member Functions + + //- Do all the refinement + void doRefine + ( + const dictionary& refineDict, + const refinementParameters& refineParams, + const bool prepareForSnapping + ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverSnap.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoSnapDriver.C similarity index 70% rename from src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverSnap.C rename to src/autoMesh/autoHexMesh/autoHexMeshDriver/autoSnapDriver.C index d4c72ea4dadfef698cf8ab40debe7e6b2dbed864..85b4f9d5d7adf8826d627ac54690747b16aec5c6 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverSnap.C +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoSnapDriver.C @@ -27,7 +27,12 @@ Description \*----------------------------------------------------------------------------*/ -#include "autoHexMeshDriver.H" +#include "autoSnapDriver.H" +#include "Time.H" +#include "pointFields.H" +#include "motionSmoother.H" +#include "polyTopoChange.H" +#include "OFstream.H" #include "syncTools.H" #include "fvMesh.H" #include "Time.H" @@ -37,16 +42,29 @@ Description #include "pointEdgePoint.H" #include "PointEdgeWave.H" #include "mergePoints.H" +#include "snapParameters.H" +#include "refinementSurfaces.H" + + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(autoSnapDriver, 0); + +} // End namespace Foam + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -void Foam::autoHexMeshDriver::getZonedSurfaces +void Foam::autoSnapDriver::getZonedSurfaces ( labelList& zonedSurfaces, labelList& unzonedSurfaces ) const { // Surfaces with zone information - const wordList& faceZoneNames = surfaces().faceZoneNames(); + const wordList& faceZoneNames = meshRefiner_.surfaces().faceZoneNames(); zonedSurfaces.setSize(faceZoneNames.size()); label zonedI = 0; @@ -70,15 +88,18 @@ void Foam::autoHexMeshDriver::getZonedSurfaces // Get faces to repatch. Returns map from face to patch. -Foam::Map<Foam::label> Foam::autoHexMeshDriver::getZoneBafflePatches +Foam::Map<Foam::label> Foam::autoSnapDriver::getZoneBafflePatches ( const bool allowBoundary ) const { - Map<label> bafflePatch(mesh_.nFaces()/1000); + const fvMesh& mesh = meshRefiner_.mesh(); + const refinementSurfaces& surfaces = meshRefiner_.surfaces(); + + Map<label> bafflePatch(mesh.nFaces()/1000); - const wordList& faceZoneNames = surfaces().faceZoneNames(); - const faceZoneMesh& fZones = mesh_.faceZones(); + const wordList& faceZoneNames = surfaces.faceZoneNames(); + const faceZoneMesh& fZones = mesh.faceZones(); forAll(faceZoneNames, surfI) { @@ -92,13 +113,12 @@ Foam::Map<Foam::label> Foam::autoHexMeshDriver::getZoneBafflePatches //// Get patch allocated for zone //label patchI = surfaceToCyclicPatch_[surfI]; // Get patch of (first region) of surface - label patchI = globalToPatch_[surfaces().globalRegion(surfI, 0)]; + label patchI = globalToPatch_[surfaces.globalRegion(surfI, 0)]; Info<< "For surface " - << surfaces()[surfI].IOobject::name() - //<< surfaces().names()[surfI] + << surfaces.names()[surfI] << " found faceZone " << fZone.name() - << " and patch " << mesh_.boundaryMesh()[patchI].name() + << " and patch " << mesh.boundaryMesh()[patchI].name() << endl; @@ -106,7 +126,7 @@ Foam::Map<Foam::label> Foam::autoHexMeshDriver::getZoneBafflePatches { label faceI = fZone[i]; - if (allowBoundary || mesh_.isInternalFace(faceI)) + if (allowBoundary || mesh.isInternalFace(faceI)) { if (!bafflePatch.insert(faceI, patchI)) { @@ -116,11 +136,11 @@ Foam::Map<Foam::label> Foam::autoHexMeshDriver::getZoneBafflePatches { FatalErrorIn("getZoneBafflePatches(const bool)") << "Face " << faceI - << " fc:" << mesh_.faceCentres()[faceI] + << " fc:" << mesh.faceCentres()[faceI] << " is in faceZone " - << mesh_.boundaryMesh()[oldPatchI].name() + << mesh.boundaryMesh()[oldPatchI].name() << " and in faceZone " - << mesh_.boundaryMesh()[patchI].name() + << mesh.boundaryMesh()[patchI].name() << abort(FatalError); } } @@ -134,7 +154,7 @@ Foam::Map<Foam::label> Foam::autoHexMeshDriver::getZoneBafflePatches // Calculate geometrically collocated points, Requires PackedList to be // sizes and initalised! -Foam::label Foam::autoHexMeshDriver::getCollocatedPoints +Foam::label Foam::autoSnapDriver::getCollocatedPoints ( const scalar tol, const pointField& points, @@ -196,7 +216,7 @@ Foam::label Foam::autoHexMeshDriver::getCollocatedPoints // Calculate displacement as average of patch points. -Foam::pointField Foam::autoHexMeshDriver::smoothPatchDisplacement +Foam::pointField Foam::autoSnapDriver::smoothPatchDisplacement ( const motionSmoother& meshMover ) const @@ -483,7 +503,7 @@ Foam::pointField Foam::autoHexMeshDriver::smoothPatchDisplacement } -Foam::tmp<Foam::scalarField> Foam::autoHexMeshDriver::edgePatchDist +Foam::tmp<Foam::scalarField> Foam::autoSnapDriver::edgePatchDist ( const pointMesh& pMesh, const indirectPrimitivePatch& pp @@ -565,7 +585,7 @@ Foam::tmp<Foam::scalarField> Foam::autoHexMeshDriver::edgePatchDist } -void Foam::autoHexMeshDriver::dumpMove +void Foam::autoSnapDriver::dumpMove ( const fileName& fName, const pointField& meshPts, @@ -596,7 +616,7 @@ void Foam::autoHexMeshDriver::dumpMove // Check whether all displacement vectors point outwards of patch. Return true // if so. -bool Foam::autoHexMeshDriver::outwardsDisplacement +bool Foam::autoSnapDriver::outwardsDisplacement ( const indirectPrimitivePatch& pp, const vectorField& patchDisp @@ -637,9 +657,22 @@ bool Foam::autoHexMeshDriver::outwardsDisplacement } +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::autoSnapDriver::autoSnapDriver +( + meshRefinement& meshRefiner, + const labelList& globalToPatch +) +: + meshRefiner_(meshRefiner), + globalToPatch_(globalToPatch) +{} + + // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::createZoneBaffles +Foam::autoPtr<Foam::mapPolyMesh> Foam::autoSnapDriver::createZoneBaffles ( List<labelPair>& baffles ) @@ -653,6 +686,8 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::createZoneBaffles // No need to sync; all processors will have all same zonedSurfaces. if (zonedSurfaces.size() > 0) { + fvMesh& mesh = meshRefiner_.mesh(); + // Split internal faces on interface surfaces Info<< "Converting zoned faces into baffles ..." << endl; @@ -664,14 +699,14 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::createZoneBaffles if (nZoneFaces > 0) { // Convert into labelLists - labelList ownPatch(mesh_.nFaces(), -1); + labelList ownPatch(mesh.nFaces(), -1); forAllConstIter(Map<label>, faceToPatch, iter) { ownPatch[iter.key()] = iter(); } // Create baffles. both sides same patch. - map = meshRefinerPtr_().createBaffles(ownPatch, ownPatch); + map = meshRefiner_.createBaffles(ownPatch, ownPatch); // Get pairs of faces created. // Just loop over faceMap and store baffle if we encounter a slave @@ -702,29 +737,29 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::createZoneBaffles if (baffleI != faceToPatch.size()) { - FatalErrorIn("autoHexMeshDriver::createZoneBaffles(..)") + FatalErrorIn("autoSnapDriver::createZoneBaffles(..)") << "Had " << faceToPatch.size() << " patches to create " << " but encountered " << baffleI << " slave faces originating from patcheable faces." << abort(FatalError); } - if (debug_) + if (debug) { - const_cast<Time&>(mesh_.time())++; - Pout<< "Writing baffled mesh to time " << mesh_.time().timeName() - << endl; - mesh_.write(); + const_cast<Time&>(mesh.time())++; + Pout<< "Writing baffled mesh to time " + << mesh.time().timeName() << endl; + mesh.write(); } } Info<< "Created " << nZoneFaces << " baffles in = " - << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl; + << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl; } return map; } -Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::mergeZoneBaffles +Foam::autoPtr<Foam::mapPolyMesh> Foam::autoSnapDriver::mergeZoneBaffles ( const List<labelPair>& baffles ) @@ -743,29 +778,27 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::mergeZoneBaffles Info<< "Converting " << nBaffles << " baffles back into zoned faces ..." << endl; - map = meshRefinerPtr_().mergeBaffles(baffles); + map = meshRefiner_.mergeBaffles(baffles); Info<< "Converted baffles in = " - << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl; + << meshRefiner_.mesh().time().cpuTimeIncrement() + << " s\n" << nl << endl; } return map; } -Foam::scalarField Foam::autoHexMeshDriver::calcSnapDistance +Foam::scalarField Foam::autoSnapDriver::calcSnapDistance ( - const dictionary& snapDict, + const snapParameters& snapParams, const indirectPrimitivePatch& pp ) const { - // When to snap - scalar snapTol(readScalar(snapDict.lookup("snapTol"))); - - const edgeList& edges = pp.edges(); const labelListList& pointEdges = pp.pointEdges(); const pointField& localPoints = pp.localPoints(); + const fvMesh& mesh = meshRefiner_.mesh(); scalarField maxEdgeLen(localPoints.size(), -GREAT); @@ -785,7 +818,7 @@ Foam::scalarField Foam::autoHexMeshDriver::calcSnapDistance syncTools::syncPointList ( - mesh_, + mesh, pp.meshPoints(), maxEdgeLen, maxEqOp<scalar>(), // combine op @@ -793,57 +826,61 @@ Foam::scalarField Foam::autoHexMeshDriver::calcSnapDistance false // no separation ); - return snapTol*maxEdgeLen; + return snapParams.snapTol()*maxEdgeLen; } -// Invert globalToPatch_ to get the patches related to surfaces. -Foam::labelList Foam::autoHexMeshDriver::getSurfacePatches() const -{ - // Set of patches originating from surface - labelHashSet surfacePatchSet(surfaces().size()); - - forAll(globalToPatch_, i) - { - if (globalToPatch_[i] != -1) - { - surfacePatchSet.insert(globalToPatch_[i]); - } - } - - DynamicList<label> surfacePatches(surfacePatchSet.size()); - - for (label patchI = 0; patchI < mesh_.boundaryMesh().size(); patchI++) - { - if (surfacePatchSet.found(patchI)) - { - surfacePatches.append(patchI); - } - } - return surfacePatches.shrink(); -} - - -void Foam::autoHexMeshDriver::preSmoothPatch +//// Invert globalToPatch_ to get the patches related to surfaces. +//Foam::labelList Foam::autoSnapDriver::getSurfacePatches() const +//{ +// // Set of patches originating from surface +// labelHashSet surfacePatchSet(globalToPatch_.size()); +// +// forAll(globalToPatch_, i) +// { +// if (globalToPatch_[i] != -1) +// { +// surfacePatchSet.insert(globalToPatch_[i]); +// } +// } +// +// const fvMesh& mesh = meshRefiner_.mesh(); +// +// DynamicList<label> surfacePatches(surfacePatchSet.size()); +// +// for (label patchI = 0; patchI < mesh.boundaryMesh().size(); patchI++) +// { +// if (surfacePatchSet.found(patchI)) +// { +// surfacePatches.append(patchI); +// } +// } +// return surfacePatches.shrink(); +//} + + +void Foam::autoSnapDriver::preSmoothPatch ( - const dictionary& snapDict, + const snapParameters& snapParams, const label nInitErrors, const List<labelPair>& baffles, motionSmoother& meshMover ) const { - // Smoothing iterations - label nSmoothPatch(readLabel(snapDict.lookup("nSmoothPatch"))); - // Snapping iterations - label nSnap(readLabel(snapDict.lookup("nSnap"))); + const fvMesh& mesh = meshRefiner_.mesh(); labelList checkFaces; Info<< "Smoothing patch points ..." << endl; - for (label smoothIter = 0; smoothIter < nSmoothPatch; smoothIter++) + for + ( + label smoothIter = 0; + smoothIter < snapParams.nSmoothPatch(); + smoothIter++ + ) { Info<< "Smoothing iteration " << smoothIter << endl; - checkFaces.setSize(mesh_.nFaces()); + checkFaces.setSize(mesh.nFaces()); forAll(checkFaces, faceI) { checkFaces[faceI] = faceI; @@ -857,11 +894,11 @@ void Foam::autoHexMeshDriver::preSmoothPatch scalar oldErrorReduction = -1; - for (label snapIter = 0; snapIter < 2*nSnap; snapIter++) + for (label snapIter = 0; snapIter < 2*snapParams.nSnap(); snapIter++) { Info<< nl << "Scaling iteration " << snapIter << endl; - if (snapIter == nSnap) + if (snapIter == snapParams.nSnap()) { Info<< "Displacement scaling for error reduction set to 0." << endl; @@ -888,20 +925,72 @@ void Foam::autoHexMeshDriver::preSmoothPatch // The current mesh is the starting mesh to smooth from. meshMover.correct(); - if (debug_) + if (debug) { - const_cast<Time&>(mesh_.time())++; - Pout<< "Writing patch smoothed mesh to time " << mesh_.time().timeName() + const_cast<Time&>(mesh.time())++; + Pout<< "Writing patch smoothed mesh to time " << mesh.time().timeName() << endl; - mesh_.write(); + mesh.write(); } Info<< "Patch points smoothed in = " - << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl; + << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl; +} + + +// Get (pp-local) indices of points that are both on zone and on patched surface +Foam::labelList Foam::autoSnapDriver::getZoneSurfacePoints +( + const indirectPrimitivePatch& pp, + const word& zoneName +) const +{ + const fvMesh& mesh = meshRefiner_.mesh(); + + label zoneI = mesh.faceZones().findZoneID(zoneName); + + if (zoneI == -1) + { + FatalErrorIn + ( + "autoSnapDriver::getZoneSurfacePoints" + "(const indirectPrimitivePatch&, const word&)" + ) << "Cannot find zone " << zoneName + << exit(FatalError); + } + + const faceZone& fZone = mesh.faceZones()[zoneI]; + + + // Could use PrimitivePatch & localFaces to extract points but might just + // as well do it ourselves. + + boolList pointOnZone(pp.nPoints(), false); + + forAll(fZone, i) + { + const face& f = mesh.faces()[fZone[i]]; + + forAll(f, fp) + { + label meshPointI = f[fp]; + + Map<label>::const_iterator iter = + pp.meshPointMap().find(meshPointI); + + if (iter != pp.meshPointMap().end()) + { + label pointI = iter(); + pointOnZone[pointI] = true; + } + } + } + + return findIndices(pointOnZone, true); } -Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface +Foam::vectorField Foam::autoSnapDriver::calcNearestSurface ( const scalarField& snapDist, motionSmoother& meshMover @@ -912,6 +1001,8 @@ Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface const indirectPrimitivePatch& pp = meshMover.patch(); const pointField& localPoints = pp.localPoints(); + const refinementSurfaces& surfaces = meshRefiner_.surfaces(); + const fvMesh& mesh = meshRefiner_.mesh(); // Divide surfaces into zoned and unzoned labelList zonedSurfaces; @@ -925,38 +1016,45 @@ Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface // 1. All points to non-interface surfaces // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - forAll(localPoints, pointI) { - pointIndexHit pHit; - - label surfI = surfaces().findNearest + List<pointIndexHit> hitInfo; + labelList hitSurface; + surfaces.findNearest ( unzonedSurfaces, - localPoints[pointI], - sqr(4*snapDist[pointI]), // sqr of attract distance - pHit + localPoints, + sqr(4*snapDist), // sqr of attract distance + hitSurface, + hitInfo ); - if (surfI != -1) + forAll(hitInfo, pointI) { - patchDisp[pointI] = pHit.hitPoint() - localPoints[pointI]; + if (hitInfo[pointI].hit()) + { + patchDisp[pointI] = + hitInfo[pointI].hitPoint() + - localPoints[pointI]; + } + //else + //{ + // WarningIn("autoSnapDriver::calcNearestSurface(..)") + // << "For point:" << pointI + // << " coordinate:" << localPoints[pointI] + // << " did not find any surface within:" + // << 4*snapDist[pointI] + // << " meter." << endl; + //} } - //else - //{ - // WarningIn("autoHexMeshDriver::calcNearestSurface(..)") - // << "For point:" << pointI - // << " coordinate:" << localPoints[pointI] - // << " did not find any surface within:" << 4*snapDist[pointI] - // << " meter." << endl; - //} } + // 2. All points on zones to their respective surface // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Surfaces with zone information - const wordList& faceZoneNames = surfaces().faceZoneNames(); + const wordList& faceZoneNames = surfaces.faceZoneNames(); forAll(zonedSurfaces, i) { @@ -964,50 +1062,50 @@ Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface const labelList surfacesToTest(1, zoneSurfI); - label zoneI = mesh_.faceZones().findZoneID(faceZoneNames[zoneSurfI]); - - const faceZone& fZone = mesh_.faceZones()[zoneI]; + // Get indices of points both on faceZone and on pp. + labelList zonePointIndices + ( + getZoneSurfacePoints + ( + pp, + faceZoneNames[zoneSurfI] + ) + ); - forAll(fZone, i) + pointField zonePoints(zonePointIndices.size()); + forAll(zonePointIndices, i) { - const face& f = mesh_.faces()[fZone[i]]; - - forAll(f, fp) - { - label meshPointI = f[fp]; - - Map<label>::const_iterator iter = - pp.meshPointMap().find(meshPointI); - - if (iter != pp.meshPointMap().end()) - { - label pointI = iter(); - - pointIndexHit pHit; + zonePoints[i] = localPoints[zonePointIndices[i]]; + } - label surfI = surfaces().findNearest - ( - surfacesToTest, - localPoints[pointI], - sqr(4*snapDist[pointI]), // sqr of attract distance - pHit - ); + // Find nearest for points both on faceZone and pp. + List<pointIndexHit> hitInfo; + labelList hitSurface; + surfaces.findNearest + ( + labelList(1, zoneSurfI), + zonePoints, + sqr(4*snapDist), + hitSurface, + hitInfo + ); - if (surfI != -1) - { - patchDisp[pointI] = - pHit.hitPoint() - localPoints[pointI]; - } - else - { - WarningIn("autoHexMeshDriver::calcNearestSurface(..)") - << "For point:" << pointI - << " coordinate:" << localPoints[pointI] - << " did not find any surface within:" - << 4*snapDist[pointI] - << " meter." << endl; - } - } + forAll(hitInfo, pointI) + { + if (hitInfo[pointI].hit()) + { + patchDisp[pointI] = + hitInfo[pointI].hitPoint() + - localPoints[pointI]; + } + else + { + WarningIn("autoSnapDriver::calcNearestSurface(..)") + << "For point:" << pointI + << " coordinate:" << localPoints[pointI] + << " did not find any surface within:" + << 4*snapDist[pointI] + << " meter." << endl; } } } @@ -1023,7 +1121,7 @@ Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface } Info<< "Calculated surface displacement in = " - << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl; + << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl; // Limit amount of movement. @@ -1045,7 +1143,7 @@ Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface // will not do condition 2 on all. Sync explicitly. syncTools::syncPointList ( - mesh_, + mesh, pp.meshPoints(), patchDisp, minMagEqOp(), // combine op @@ -1062,11 +1160,11 @@ Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface // pointVectorField. meshMover.setDisplacement(patchDisp); - if (debug_) + if (debug) { dumpMove ( - mesh_.time().path()/"patchDisplacement.obj", + mesh.time().path()/"patchDisplacement.obj", pp.localPoints(), pp.localPoints() + patchDisp ); @@ -1076,29 +1174,27 @@ Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface } -void Foam::autoHexMeshDriver::smoothDisplacement +void Foam::autoSnapDriver::smoothDisplacement ( - const dictionary& snapDict, + const snapParameters& snapParams, motionSmoother& meshMover ) const { + const fvMesh& mesh = meshRefiner_.mesh(); const pointMesh& pMesh = meshMover.pMesh(); const indirectPrimitivePatch& pp = meshMover.patch(); Info<< "Smoothing displacement ..." << endl; - // Smoothing iterations - label nSmoothDisp(readLabel(snapDict.lookup("nSmoothDispl"))); - // Set edge diffusivity as inverse of distance to patch scalarField edgeGamma(1.0/(edgePatchDist(pMesh, pp) + SMALL)); - //scalarField edgeGamma(mesh_.nEdges(), 1.0); + //scalarField edgeGamma(mesh.nEdges(), 1.0); //scalarField edgeGamma(wallGamma(mesh, pp, 10, 1)); // Get displacement field pointVectorField& disp = meshMover.displacement(); - for (label iter = 0; iter < nSmoothDisp; iter++) + for (label iter = 0; iter < snapParams.nSmoothDispl(); iter++) { if ((iter % 10) == 0) { @@ -1109,14 +1205,14 @@ void Foam::autoHexMeshDriver::smoothDisplacement meshMover.smooth(oldDisp, edgeGamma, false, disp); } Info<< "Displacement smoothed in = " - << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl; + << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl; - if (debug_) + if (debug) { - const_cast<Time&>(mesh_.time())++; - Pout<< "Writing smoothed mesh to time " << mesh_.time().timeName() + const_cast<Time&>(mesh.time())++; + Pout<< "Writing smoothed mesh to time " << mesh.time().timeName() << endl; - mesh_.write(); + mesh.write(); Pout<< "Writing displacement field ..." << endl; disp.write(); @@ -1130,7 +1226,7 @@ void Foam::autoHexMeshDriver::smoothDisplacement ); dumpMove ( - mesh_.time().path()/"actualPatchDisplacement.obj", + mesh.time().path()/"actualPatchDisplacement.obj", pp.localPoints(), pp.localPoints() + actualPatchDisp ); @@ -1138,30 +1234,28 @@ void Foam::autoHexMeshDriver::smoothDisplacement } -void Foam::autoHexMeshDriver::scaleMesh +void Foam::autoSnapDriver::scaleMesh ( - const dictionary& snapDict, + const snapParameters& snapParams, const label nInitErrors, const List<labelPair>& baffles, motionSmoother& meshMover ) { - // Snapping iterations - label nSnap(readLabel(snapDict.lookup("nSnap"))); - + const fvMesh& mesh = meshRefiner_.mesh(); // Relax displacement until correct mesh // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - labelList checkFaces(identity(mesh_.nFaces())); + labelList checkFaces(identity(mesh.nFaces())); scalar oldErrorReduction = -1; Info<< "Moving mesh ..." << endl; - for (label iter = 0; iter < 2*nSnap; iter++) + for (label iter = 0; iter < 2*snapParams.nSnap(); iter++) { Info<< nl << "Iteration " << iter << endl; - if (iter == nSnap) + if (iter == snapParams.nSnap()) { Info<< "Displacement scaling for error reduction set to 0." << endl; oldErrorReduction = meshMover.setErrorReduction(0.0); @@ -1173,12 +1267,12 @@ void Foam::autoHexMeshDriver::scaleMesh break; } - if (debug_) + if (debug) { - const_cast<Time&>(mesh_.time())++; - Pout<< "Writing scaled mesh to time " << mesh_.time().timeName() + const_cast<Time&>(mesh.time())++; + Pout<< "Writing scaled mesh to time " << mesh.time().timeName() << endl; - mesh_.write(); + mesh.write(); Pout<< "Writing displacement field ..." << endl; meshMover.displacement().write(); @@ -1192,7 +1286,99 @@ void Foam::autoHexMeshDriver::scaleMesh meshMover.setErrorReduction(oldErrorReduction); } Info<< "Moved mesh in = " - << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl; + << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl; +} + + +void Foam::autoSnapDriver::doSnap +( + const dictionary& snapDict, + const dictionary& motionDict, + const snapParameters& snapParams +) +{ + fvMesh& mesh = meshRefiner_.mesh(); + + Info<< nl + << "Morphing phase" << nl + << "--------------" << nl + << endl; + + const_cast<Time&>(mesh.time())++; + + // Get the labels of added patches. + labelList adaptPatchIDs(meshRefinement::addedPatches(globalToPatch_)); + + // Create baffles (pairs of faces that share the same points) + // Baffles stored as owner and neighbour face that have been created. + List<labelPair> baffles; + createZoneBaffles(baffles); + + { + autoPtr<indirectPrimitivePatch> ppPtr + ( + meshRefinement::makePatch + ( + mesh, + adaptPatchIDs + ) + ); + indirectPrimitivePatch& pp = ppPtr(); + + // Distance to attact to nearest feature on surface + const scalarField snapDist(calcSnapDistance(snapParams, pp)); + + + // Construct iterative mesh mover. + Info<< "Constructing mesh displacer ..." << endl; + Info<< "Using mesh parameters " << motionDict << nl << endl; + + pointMesh pMesh(mesh); + + motionSmoother meshMover + ( + mesh, + pp, + adaptPatchIDs, + meshRefinement::makeDisplacementField(pMesh, adaptPatchIDs), + motionDict + ); + + + // Check initial mesh + Info<< "Checking initial mesh ..." << endl; + labelHashSet wrongFaces(mesh.nFaces()/100); + motionSmoother::checkMesh(false, mesh, motionDict, wrongFaces); + const label nInitErrors = returnReduce + ( + wrongFaces.size(), + sumOp<label>() + ); + + Info<< "Detected " << nInitErrors << " illegal faces" + << " (concave, zero area or negative cell pyramid volume)" + << endl; + + + Info<< "Checked initial mesh in = " + << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl; + + // Pre-smooth patch vertices (so before determining nearest) + preSmoothPatch(snapParams, nInitErrors, baffles, meshMover); + + // Calculate displacement at every patch point. Insert into + // meshMover. + calcNearestSurface(snapDist, meshMover); + + // Get smoothly varying internal displacement field. + smoothDisplacement(snapParams, meshMover); + + // Apply internal displacement to mesh. + scaleMesh(snapParams, nInitErrors, baffles, meshMover); + } + + // Merge any introduced baffles. + mergeZoneBaffles(baffles); } diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoSnapDriver.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoSnapDriver.H new file mode 100644 index 0000000000000000000000000000000000000000..82cf448b98ae6b506fea1bf81bc16f2bd17e5dd7 --- /dev/null +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoSnapDriver.H @@ -0,0 +1,236 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::autoSnapDriver + +Description + All to do with snapping to surface + +SourceFiles + autoSnapDriver.C + +\*---------------------------------------------------------------------------*/ + +#ifndef autoSnapDriver_H +#define autoSnapDriver_H + +#include "meshRefinement.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration of classes +class motionSmoother; +class snapParameters; + +/*---------------------------------------------------------------------------*\ + Class autoSnapDriver Declaration +\*---------------------------------------------------------------------------*/ + +class autoSnapDriver +{ + // Private classes + + //- Combine operator class for equalizing displacements. + class minMagEqOp + { + public: + + void operator()(vector& x, const vector& y) const + { + if (magSqr(y) < magSqr(x)) + { + x = y; + } + } + }; + + + // Private data + + //- Mesh+surface + meshRefinement& meshRefiner_; + + //- From surface region to patch + const labelList globalToPatch_; + + + // Private Member Functions + + + // Snapping + + //- Split surfaces into non-zoned and zones ones + void getZonedSurfaces(labelList&, labelList&) const; + + //- Get faces to repatch. Returns map from face to patch. + Map<label> getZoneBafflePatches(const bool allowBoundary) const; + + //- Calculates (geometric) shared points + static label getCollocatedPoints + ( + const scalar tol, + const pointField&, + PackedList<1>& + ); + + //- Calculate displacement per patch point to smooth out patch. + // Quite complicated in determining which points to move where. + pointField smoothPatchDisplacement(const motionSmoother&) const; + + //- Check that face zones are synced + void checkCoupledFaceZones() const; + + //- Per edge distance to patch + static tmp<scalarField> edgePatchDist + ( + const pointMesh&, + const indirectPrimitivePatch& + ); + + //- Write displacement as .obj file. + static void dumpMove + ( + const fileName&, + const pointField&, + const pointField& + ); + + //- Check displacement is outwards pointing + static bool outwardsDisplacement + ( + const indirectPrimitivePatch&, + const vectorField& + ); + + + //- Disallow default bitwise copy construct + autoSnapDriver(const autoSnapDriver&); + + //- Disallow default bitwise assignment + void operator=(const autoSnapDriver&); + + +public: + + //- Runtime type information + ClassName("autoSnapDriver"); + + + // Constructors + + //- Construct from components + autoSnapDriver + ( + meshRefinement& meshRefiner, + const labelList& globalToPatch + ); + + + // Member Functions + + // Snapping + + //- Create baffles for faces straddling zoned surfaces. Return + // baffles. + autoPtr<mapPolyMesh> createZoneBaffles(List<labelPair>&); + + //- Merge baffles. + autoPtr<mapPolyMesh> mergeZoneBaffles(const List<labelPair>&); + + //- Calculate edge length per patch point. + scalarField calcSnapDistance + ( + const snapParameters& snapParams, + const indirectPrimitivePatch& + ) const; + + ////- Get patches generated for surfaces. + //labelList getSurfacePatches() const; + + //- Smooth the mesh (patch and internal) to increase visibility + // of surface points (on castellated mesh) w.r.t. surface. + void preSmoothPatch + ( + const snapParameters& snapParams, + const label nInitErrors, + const List<labelPair>& baffles, + motionSmoother& + ) const; + + //- Get points both on patch and facezone. + labelList getZoneSurfacePoints + ( + const indirectPrimitivePatch&, + const word& zoneName + ) const; + + //- Per patch point calculate point on nearest surface. Set as + // boundary conditions of motionSmoother displacement field. Return + // displacement of patch points. + vectorField calcNearestSurface + ( + const scalarField& snapDist, + motionSmoother& meshMover + ) const; + + //- Smooth the displacement field to the internal. + void smoothDisplacement + ( + const snapParameters& snapParams, + motionSmoother& + ) const; + + //- Do the hard work: move the mesh according to displacement, + // locally relax the displacement. + void scaleMesh + ( + const snapParameters& snapParams, + const label nInitErrors, + const List<labelPair>& baffles, + motionSmoother& + ); + + void doSnap + ( + const dictionary& snapDict, + const dictionary& motionDict, + const snapParameters& snapParams + ); + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C new file mode 100644 index 0000000000000000000000000000000000000000..a2fd5ca976afe7c1891bdaf20e8b5b5dfdaed26d --- /dev/null +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C @@ -0,0 +1,327 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "layerParameters.H" +#include "polyBoundaryMesh.H" +#include "mathematicalConstants.H" +#include "refinementSurfaces.H" +#include "searchableSurfaces.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +const Foam::scalar Foam::layerParameters::defaultConcaveAngle = 90; + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +// Read the number of layers from dictionary. Per patch 0 or the number +// of layers. +Foam::labelList Foam::layerParameters::readNumLayers +( + const PtrList<dictionary>& surfaceDicts, + const refinementSurfaces& refineSurfaces, + const labelList& globalToPatch, + const polyBoundaryMesh& boundaryMesh +) +{ + // Per surface the number of layers + labelList globalSurfLayers(surfaceDicts.size()); + // Per surface, per region the number of layers + List<Map<label> > regionSurfLayers(surfaceDicts.size()); + + const labelList& surfaceIndices = refineSurfaces.surfaces(); + + forAll(surfaceDicts, surfI) + { + const dictionary& dict = surfaceDicts[surfI]; + + globalSurfLayers[surfI] = readLabel(dict.lookup("surfaceLayers")); + + if (dict.found("regions")) + { + // Per-region layer information + + PtrList<dictionary> regionDicts(dict.lookup("regions")); + + const wordList& regionNames = + refineSurfaces.geometry()[surfaceIndices[surfI]].regions(); + + forAll(regionDicts, dictI) + { + const dictionary& regionDict = regionDicts[dictI]; + + const word regionName(regionDict.lookup("name")); + + label regionI = findIndex(regionNames, regionName); + + label nLayers = readLabel(regionDict.lookup("surfaceLayers")); + + Info<< " region " << regionName << ':'<< nl + << " surface layers:" << nLayers << nl; + + regionSurfLayers[surfI].insert(regionI, nLayers); + } + } + } + + + // Transfer per surface/region information into patchwise region info + + labelList nLayers(boundaryMesh.size(), 0); + + forAll(surfaceIndices, surfI) + { + const wordList& regionNames = + refineSurfaces.geometry()[surfaceIndices[surfI]].regions(); + + forAll(regionNames, regionI) + { + const word& regionName = regionNames[regionI]; + + label global = refineSurfaces.globalRegion(surfI, regionI); + + label patchI = globalToPatch[global]; + + // Initialise to surface-wise layers + nLayers[patchI] = globalSurfLayers[surfI]; + + // Override with region specific data if available + Map<label>::const_iterator iter = + regionSurfLayers[surfI].find(regionI); + + if (iter != regionSurfLayers[surfI].end()) + { + nLayers[patchI] = iter(); + } + + // Check + if (nLayers[patchI] < 0) + { + FatalErrorIn + ( + "layerParameters::readNumLayers(..)" + ) << "Illegal number of layers " << nLayers[patchI] + << " for surface " + << refineSurfaces.names()[surfI] + << " region " << regionName << endl + << exit(FatalError); + } + } + } + return nLayers; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +// Construct from dictionary +Foam::layerParameters::layerParameters +( + const PtrList<dictionary>& surfaceDicts, + const refinementSurfaces& refineSurfaces, + const labelList& globalToPatch, + const dictionary& dict, + const polyBoundaryMesh& boundaryMesh +) +: + numLayers_ + ( + readNumLayers + ( + surfaceDicts, + refineSurfaces, + globalToPatch, + boundaryMesh + ) + ), + expansionRatio_ + ( + numLayers_.size(), + readScalar(dict.lookup("expansionRatio")) + ), + finalLayerRatio_ + ( + numLayers_.size(), + readScalar(dict.lookup("finalLayerRatio")) + ), + minThickness_ + ( + numLayers_.size(), + readScalar(dict.lookup("minThickness")) + ), + featureAngle_(readScalar(dict.lookup("featureAngle"))), + concaveAngle_ + ( + dict.found("concaveAngle") + ? readScalar(dict.lookup("concaveAngle")) + : defaultConcaveAngle + ), + nGrow_(readLabel(dict.lookup("nGrow"))), + nSmoothSurfaceNormals_ + ( + readLabel(dict.lookup("nSmoothSurfaceNormals")) + ), + nSmoothNormals_(readLabel(dict.lookup("nSmoothNormals"))), + nSmoothThickness_(readLabel(dict.lookup("nSmoothThickness"))), + maxFaceThicknessRatio_ + ( + readScalar(dict.lookup("maxFaceThicknessRatio")) + ), + layerTerminationCos_ + ( + Foam::cos + ( + 0.5 + * featureAngle_ + * mathematicalConstant::pi/180. + ) + ), + maxThicknessToMedialRatio_ + ( + readScalar(dict.lookup("maxThicknessToMedialRatio")) + ), + minMedianAxisAngleCos_ + ( + Foam::cos(readScalar(dict.lookup("minMedianAxisAngle"))) + * mathematicalConstant::pi/180. + ), + nBufferCellsNoExtrude_ + ( + readLabel(dict.lookup("nBufferCellsNoExtrude")) + ), + nSnap_(readLabel(dict.lookup("nSnap"))) +{} + + +// Construct from dictionary +Foam::layerParameters::layerParameters +( + const dictionary& dict, + const polyBoundaryMesh& boundaryMesh +) +: + numLayers_(boundaryMesh.size(), 0), + expansionRatio_ + ( + boundaryMesh.size(), + readScalar(dict.lookup("expansionRatio")) + ), + finalLayerRatio_ + ( + boundaryMesh.size(), + readScalar(dict.lookup("finalLayerRatio")) + ), + minThickness_ + ( + boundaryMesh.size(), + readScalar(dict.lookup("minThickness")) + ), + featureAngle_(readScalar(dict.lookup("featureAngle"))), + concaveAngle_ + ( + dict.found("concaveAngle") + ? readScalar(dict.lookup("concaveAngle")) + : defaultConcaveAngle + ), + nGrow_(readLabel(dict.lookup("nGrow"))), + nSmoothSurfaceNormals_ + ( + readLabel(dict.lookup("nSmoothSurfaceNormals")) + ), + nSmoothNormals_(readLabel(dict.lookup("nSmoothNormals"))), + nSmoothThickness_(readLabel(dict.lookup("nSmoothThickness"))), + maxFaceThicknessRatio_ + ( + readScalar(dict.lookup("maxFaceThicknessRatio")) + ), + layerTerminationCos_ + ( + Foam::cos + ( + 0.5 + * featureAngle_ + * mathematicalConstant::pi/180. + ) + ), + maxThicknessToMedialRatio_ + ( + readScalar(dict.lookup("maxThicknessToMedialRatio")) + ), + minMedianAxisAngleCos_ + ( + Foam::cos(readScalar(dict.lookup("minMedianAxisAngle"))) + * mathematicalConstant::pi/180. + ), + nBufferCellsNoExtrude_ + ( + readLabel(dict.lookup("nBufferCellsNoExtrude")) + ), + nSnap_(readLabel(dict.lookup("nRelaxIter"))) +{ + const dictionary& layersDict = dict.subDict("layers"); + + forAllConstIter(dictionary, layersDict, iter) + { + const word& key = iter().keyword(); + + if (layersDict.isDict(key)) + { + label patchI = boundaryMesh.findPatchID(key); + + if (patchI == -1) + { + FatalErrorIn + ( + "layerParameters::layerParameters" + "(const dictionary&, const polyBoundaryMesh&)" + ) << "Specified illegal patch " << key + << " in layer dictionary." << endl + << "Valid patch names are " << boundaryMesh.names() + << exit(FatalError); + } + + const dictionary& layerDict = layersDict.subDict(key); + + numLayers_[patchI] = + readLabel(layerDict.lookup("nSurfaceLayers")); + + //- Patch-wise layer parameters disabled for now. Just remove + // settings in initialiser list and uncomment below. + //expansionRatio_[patchI] = + // readScalar(layerDict.lookup("expansionRatio")); + //finalLayerRatio_[patchI] = + // readScalar(layerDict.lookup("finalLayerRatio")); + //minThickness_[patchI] = + // readScalar(layerDict.lookup("minThickness")); + } + } +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.H new file mode 100644 index 0000000000000000000000000000000000000000..2e391328e16bc8a59774c9e16f1fdc4881b93bb7 --- /dev/null +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.H @@ -0,0 +1,263 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::layerParameters + +Description + Simple container to keep together layer specific information. + +SourceFiles + layerParameters.C + +\*---------------------------------------------------------------------------*/ + +#ifndef layerParameters_H +#define layerParameters_H + +#include "dictionary.H" +#include "scalarField.H" +#include "labelList.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Class forward declarations +class polyBoundaryMesh; +class refinementSurfaces; + +/*---------------------------------------------------------------------------*\ + Class layerParameters Declaration +\*---------------------------------------------------------------------------*/ + +class layerParameters +{ + // Static data members + + //- Default angle for faces to be convcave + static const scalar defaultConcaveAngle; + + + // Private data + + // Per patch (not region!) information + + //- How many layers to add. + labelList numLayers_; + + scalarField expansionRatio_; + + //- Wanted thickness of final added cell layer. If multiple layers + // is the thickness of the layer furthest away from the wall. + // Relative to undistorted size of cell outside layer. + scalarField finalLayerRatio_; + + //- Minimum thickness of cell layer. If for any reason layer + // cannot be above minThickness do not add layer. + // Relative to undistorted size of cell outside layer. + scalarField minThickness_; + + + scalar featureAngle_; + + scalar concaveAngle_; + + label nGrow_; + + label nSmoothSurfaceNormals_; + + label nSmoothNormals_; + + label nSmoothThickness_; + + scalar maxFaceThicknessRatio_; + + scalar layerTerminationCos_; + + scalar maxThicknessToMedialRatio_; + + scalar minMedianAxisAngleCos_; + + label nBufferCellsNoExtrude_; + + label nSnap_; + + + // Private Member Functions + + //- Extract patch-wise number of layers + static labelList readNumLayers + ( + const PtrList<dictionary>& surfaceDicts, + const refinementSurfaces& refineSurfaces, + const labelList& globalToPatch, + const polyBoundaryMesh& boundaryMesh + ); + + //- Disallow default bitwise copy construct + layerParameters(const layerParameters&); + + //- Disallow default bitwise assignment + void operator=(const layerParameters&); + + +public: + + // Constructors + + //- Construct from dictionary - old syntax + layerParameters + ( + const PtrList<dictionary>& surfaceDicts, + const refinementSurfaces& refineSurfaces, + const labelList& globalToPatch, + const dictionary& dict, + const polyBoundaryMesh& boundaryMesh + ); + + //- Construct from dictionary - new syntax + layerParameters(const dictionary& dict, const polyBoundaryMesh&); + + + // Member Functions + + // Access + + // Per patch information + + //- How many layers to add. + const labelList& numLayers() const + { + return numLayers_; + } + + // Expansion factor for layer mesh + const scalarField& expansionRatio() const + { + return expansionRatio_; + } + + //- Wanted thickness of final added cell layer. If multiple + // layers + // is the thickness of the layer furthest away from the wall. + // Relative to undistorted size of cell outside layer. + const scalarField& finalLayerRatio() const + { + return finalLayerRatio_; + } + + //- Minimum thickness of cell layer. If for any reason layer + // cannot be above minThickness do not add layer. + // Relative to undistorted size of cell outside layer. + const scalarField& minThickness() const + { + return minThickness_; + } + + + scalar featureAngle() const + { + return featureAngle_; + } + + scalar concaveAngle() const + { + return concaveAngle_; + } + + //- If points get not extruded do nGrow layers of connected faces + // that are not grown. Is used to not do layers at all close to + // features. + label nGrow() const + { + return nGrow_; + } + + // Number of smoothing iterations of surface normals + label nSmoothSurfaceNormals() const + { + return nSmoothSurfaceNormals_; + } + + // Number of smoothing iterations of interior mesh movement + // direction + label nSmoothNormals() const + { + return nSmoothNormals_; + } + + // Smooth layer thickness over surface patches + label nSmoothThickness() const + { + return nSmoothThickness_; + } + + // Stop layer growth on highly warped cells + scalar maxFaceThicknessRatio() const + { + return maxFaceThicknessRatio_; + } + + scalar layerTerminationCos() const + { + return layerTerminationCos_; + } + + // Reduce layer growth where ratio thickness to medial + // distance is large + scalar maxThicknessToMedialRatio() const + { + return maxThicknessToMedialRatio_; + } + + // Angle used to pick up medial axis points + scalar minMedianAxisAngleCos() const + { + return minMedianAxisAngleCos_; + } + + // Create buffer region for new layer terminations + label nBufferCellsNoExtrude() const + { + return nBufferCellsNoExtrude_; + } + + label nSnap() const + { + return nSnap_; + } +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.C new file mode 100644 index 0000000000000000000000000000000000000000..7912279e017eefb0d30f3a56af5a7526d112abf3 --- /dev/null +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.C @@ -0,0 +1,123 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "refinementParameters.H" +#include "mathematicalConstants.H" +#include "polyMesh.H" +#include "globalIndex.H" + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +// Construct from dictionary +Foam::refinementParameters::refinementParameters +( + const dictionary& dict, + const label dummy +) +: + maxGlobalCells_(readLabel(dict.lookup("cellLimit"))), + maxLocalCells_(readLabel(dict.lookup("procCellLimit"))), + minRefineCells_(readLabel(dict.lookup("minimumRefine"))), + curvature_(readScalar(dict.lookup("curvature"))), + nBufferLayers_(readLabel(dict.lookup("nBufferLayers"))), + keepPoints_(dict.lookup("keepPoints")) +{} + + +Foam::refinementParameters::refinementParameters(const dictionary& dict) +: + maxGlobalCells_(readLabel(dict.lookup("maxGlobalCells"))), + maxLocalCells_(readLabel(dict.lookup("maxLocalCells"))), + minRefineCells_(readLabel(dict.lookup("minRefinementCells"))), + nBufferLayers_(readLabel(dict.lookup("nCellsBetweenLevels"))), + keepPoints_(pointField(1, dict.lookup("locationInMesh"))) +{ + scalar featAngle(readScalar(dict.lookup("resolveFeatureAngle"))); + + if (featAngle < 0 || featAngle > 180) + { + curvature_ = -GREAT; + } + else + { + curvature_ = Foam::cos(featAngle*mathematicalConstant::pi/180.0); + } +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::labelList Foam::refinementParameters::findCells(const polyMesh& mesh) + const +{ + // Global calculation engine + globalIndex globalCells(mesh.nCells()); + + // Cell label per point + labelList cellLabels(keepPoints_.size()); + + forAll(keepPoints_, i) + { + const point& keepPoint = keepPoints_[i]; + + label localCellI = mesh.findCell(keepPoint); + + label globalCellI = -1; + + if (localCellI != -1) + { + Pout<< "Found point " << keepPoint << " in cell " << localCellI + << " on processor " << Pstream::myProcNo() << endl; + globalCellI = globalCells.toGlobal(localCellI); + } + + reduce(globalCellI, maxOp<label>()); + + if (globalCellI == -1) + { + FatalErrorIn + ( + "refinementParameters::findCells(const polyMesh&) const" + ) << "Point " << keepPoint + << " is not inside the mesh or on a face or edge." << nl + << "Bounding box of the mesh:" << mesh.bounds() + << exit(FatalError); + } + + if (globalCells.isLocal(globalCellI)) + { + cellLabels[i] = localCellI; + } + else + { + cellLabels[i] = -1; + } + } + return cellLabels; +} + + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.H new file mode 100644 index 0000000000000000000000000000000000000000..25b97af0346fa6afb41d8e90297502a69493232d --- /dev/null +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.H @@ -0,0 +1,154 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::refinementParameters + +Description + Simple container to keep together refinement specific information. + +SourceFiles + refinementParameters.C + +\*---------------------------------------------------------------------------*/ + +#ifndef refinementParameters_H +#define refinementParameters_H + +#include "dictionary.H" +#include "pointField.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Class forward declarations +class polyMesh; + +/*---------------------------------------------------------------------------*\ + Class refinementParameters Declaration +\*---------------------------------------------------------------------------*/ + +class refinementParameters +{ + // Private data + + //- Total number of cells + const label maxGlobalCells_; + + //- Per processor max number of cells + const label maxLocalCells_; + + //- When to stop refining + const label minRefineCells_; + + //- Curvature + scalar curvature_; + + //- Number of layers between different refinement levels + const label nBufferLayers_; + + //- Areas to keep + const pointField keepPoints_; + + + // Private Member Functions + + //- Disallow default bitwise copy construct + refinementParameters(const refinementParameters&); + + //- Disallow default bitwise assignment + void operator=(const refinementParameters&); + + +public: + + // Constructors + + //- Construct from dictionary - old syntax + refinementParameters(const dictionary& dict, const label dummy); + + //- Construct from dictionary - new syntax + refinementParameters(const dictionary& dict); + + + // Member Functions + + // Access + + //- Total number of cells + label maxGlobalCells() const + { + return maxGlobalCells_; + } + + //- Per processor max number of cells + label maxLocalCells() const + { + return maxLocalCells_; + } + + //- When to stop refining + label minRefineCells() const + { + return minRefineCells_; + } + + //- Curvature + scalar curvature() const + { + return curvature_; + } + + //- Number of layers between different refinement levels + label nBufferLayers() const + { + return nBufferLayers_; + } + + //- Areas to keep + const pointField& keepPoints() const + { + return keepPoints_; + } + + + // Other + + //- Checks that cells are in mesh. Returns cells they are in. + labelList findCells(const polyMesh&) const; + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.C new file mode 100644 index 0000000000000000000000000000000000000000..253826c38fddfdb52c106951353469ee46f21c3c --- /dev/null +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.C @@ -0,0 +1,54 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "snapParameters.H" + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +// Construct from dictionary +Foam::snapParameters::snapParameters(const dictionary& dict, const label dummy) +: + nSmoothPatch_(readLabel(dict.lookup("nSmoothPatch"))), + snapTol_(readScalar(dict.lookup("snapTol"))), + nSmoothDispl_(readLabel(dict.lookup("nSmoothDispl"))), + nSnap_(readLabel(dict.lookup("nSnap"))) +{} + + +// Construct from dictionary +Foam::snapParameters::snapParameters(const dictionary& dict) +: + nSmoothPatch_(readLabel(dict.lookup("nSmoothPatch"))), + snapTol_(readScalar(dict.lookup("tolerance"))), + nSmoothDispl_(readLabel(dict.lookup("nSolveIter"))), + nSnap_(readLabel(dict.lookup("nRelaxIter"))) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.H new file mode 100644 index 0000000000000000000000000000000000000000..2a173578b0c5e336e8fe888d2b63c35b8346287c --- /dev/null +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.H @@ -0,0 +1,129 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::snapParameters + +Description + Simple container to keep together snap specific information. + +SourceFiles + snapParameters.C + +\*---------------------------------------------------------------------------*/ + +#ifndef snapParameters_H +#define snapParameters_H + +#include "dictionary.H" +#include "scalar.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Class forward declarations + +/*---------------------------------------------------------------------------*\ + Class snapParameters Declaration +\*---------------------------------------------------------------------------*/ + +class snapParameters +{ + // Private data + + const label nSmoothPatch_; + + const scalar snapTol_; + + const label nSmoothDispl_; + + const label nSnap_; + + + // Private Member Functions + + //- Disallow default bitwise copy construct + snapParameters(const snapParameters&); + + //- Disallow default bitwise assignment + void operator=(const snapParameters&); + + +public: + + // Constructors + + //- Construct from dictionary - old syntax + snapParameters(const dictionary& dict, const label dummy); + + //- Construct from dictionary - new syntax + snapParameters(const dictionary& dict); + + + // Member Functions + + // Access + + //- Number of patch smoothing iterations before finding + // correspondence to surface + label nSmoothPatch() const + { + return nSmoothPatch_; + } + + //- Relative distance for points to be attracted by surface + // feature point + // or edge. True distance is this factor times local + // maximum edge length. + scalar snapTol() const + { + return snapTol_; + } + + //- Number of mesh displacement smoothing iterations. + label nSmoothDispl() const + { + return nSmoothDispl_; + } + + //- Maximum number of snapping relaxation iterations. Should stop + // before upon reaching a correct mesh. + label nSnap() const + { + return nSnap_; + } +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C index 8b9869ad57f0b28b9cf0a8a7df5ce2940ead8d73..4fe3005766f4f224c2fd219d7f27451d6a4fa290 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C @@ -24,9 +24,7 @@ License \*----------------------------------------------------------------------------*/ -#include "Pstream.H" #include "meshRefinement.H" - #include "volMesh.H" #include "volFields.H" #include "surfaceMesh.H" @@ -34,7 +32,6 @@ License #include "Time.H" #include "refinementHistory.H" #include "refinementSurfaces.H" -#include "cellSet.H" #include "decompositionMethod.H" #include "regionSplit.H" #include "fvMeshDistribute.H" @@ -50,8 +47,9 @@ License #include "globalPointPatchFields.H" #include "calculatedPointPatchFields.H" #include "processorPointPatch.H" -#include "featureEdgeMesh.H" #include "globalIndex.H" +#include "meshTools.H" +#include "OFstream.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -117,90 +115,6 @@ void Foam::meshRefinement::calcNeighbourData } -//void Foam::meshRefinement::calcCanonicalBoundaryData -//( -// labelList& leftLevel, -// pointField& leftCc, -// labelList& rightLevel, -// pointField& rightCc -//) const -//{ -// const labelList& cellLevel = meshCutter_.cellLevel(); -// const pointField& cellCentres = mesh_.cellCentres(); -// const polyBoundaryMesh& patches = mesh_.boundaryMesh(); -// -// // Get boundary face centre and level. Coupled aware. -// calcNeighbourData(rightLevel, rightCc); -// -// // Get owner face centre and level. Canonical sort for coupled faces. -// forAll(patches, patchI) -// { -// const polyPatch& pp = patches[patchI]; -// -// const unallocLabelList& faceCells = pp.faceCells(); -// const vectorField::subField faceCentres = pp.faceCentres(); -// -// if (isA<processorPolyPatch>(pp)) -// { -// const processorPolyPatch& procPp = -// refCast<const processorPolyPatch>(patches[patchI]); -// -// label bFaceI = pp.start()-mesh_.nInternalFaces(); -// forAll(faceCells, i) -// { -// leftLevel[bFaceI] = cellLevel[faceCells[i]]; -// leftCc[bFaceI] = cellCentres[faceCells[i]]; -// bFaceI++; -// } -// -// // Swap if on neighbour so both sides have same values -// if (!procPp.owner()) -// { -// forAll(leftLevel, i) -// { -// Swap(leftLevel[i], rightLevel[i]); -// Swap(leftCc[i], rightCc[i]); -// } -// } -// } -// else if (isA<cyclicPolyPatch>(pp)) -// { -// const processorPolyPatch& cycPp = -// refCast<const processorPolyPatch>(patches[patchI]); -// -// label bFaceI = pp.start()-mesh_.nInternalFaces(); -// forAll(faceCells, i) -// { -// leftLevel[bFaceI] = cellLevel[faceCells[i]]; -// leftCc[bFaceI] = cellCentres[faceCells[i]]; -// bFaceI++; -// } -// -// // First half has data in normal order: owner in leftLevel,leftCc -// // and coupled data in rightLevel, rightCc. Second half has it -// // swapped: -// bFaceI = pp.start()+cycPp.size()/2-mesh_.nInternalFaces(); -// for (label i = 0; i < cycPp.size()/2; i++) -// { -// Swap(leftLevel[bFaceI], rightLevel[bFaceI]); -// Swap(leftCc[bFaceI], rightCc[bFaceI]); -// bFaceI++; -// } -// } -// else -// { -// label bFaceI = pp.start()-mesh_.nInternalFaces(); -// forAll(faceCells, i) -// { -// leftLevel[bFaceI] = cellLevel[faceCells[i]]; -// leftCc[bFaceI] = cellCentres[faceCells[i]]; -// bFaceI++; -// } -// } -// } -//} - - // Find intersections of edges (given by their two endpoints) with surfaces. // Returns first intersection if there are more than one. void Foam::meshRefinement::updateIntersections(const labelList& changedFaces) @@ -220,33 +134,46 @@ void Foam::meshRefinement::updateIntersections(const labelList& changedFaces) pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces()); calcNeighbourData(neiLevel, neiCc); + // Collect segments we want to test for + pointField start(changedFaces.size()); + pointField end(changedFaces.size()); + forAll(changedFaces, i) { label faceI = changedFaces[i]; label own = mesh_.faceOwner()[faceI]; - pointIndexHit surfaceHitInfo; - + start[i] = cellCentres[own]; if (mesh_.isInternalFace(faceI)) { - surfaceIndex_[faceI] = surfaces_.findAnyIntersection - ( - cellCentres[own], - cellCentres[mesh_.faceNeighbour()[faceI]], - surfaceHitInfo - ); + end[i] = cellCentres[mesh_.faceNeighbour()[faceI]]; } else { - surfaceIndex_[faceI] = surfaces_.findAnyIntersection - ( - cellCentres[own], - neiCc[faceI-mesh_.nInternalFaces()], - surfaceHitInfo - ); + end[i] = neiCc[faceI-mesh_.nInternalFaces()]; } } + // Do tests in one go + labelList surfaceHit; + { + labelList surfaceLevel; + surfaces_.findHigherIntersection + ( + start, + end, + labelList(start.size(), -1), // accept any intersection + surfaceHit, + surfaceLevel + ); + } + + // Keep just surface hit + forAll(surfaceHit, i) + { + surfaceIndex_[changedFaces[i]] = surfaceHit[i]; + } + // Make sure both sides have same information. This should be // case in general since same vectors but just to make sure. syncTools::syncFaceList(mesh_, surfaceIndex_, maxEqOp<label>(), false); @@ -297,7 +224,7 @@ void Foam::meshRefinement::checkData() // Compare testSyncBoundaryFaceList ( - tol_, + mergeDistance_, "testing faceCentres : ", boundaryFc, neiBoundaryFc @@ -305,67 +232,72 @@ void Foam::meshRefinement::checkData() } // Check meshRefinement { - for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++) - { - label own = mesh_.faceOwner()[faceI]; - label nei = mesh_.faceNeighbour()[faceI]; - const point& ownCc = mesh_.cellCentres()[own]; - const point& neiCc = mesh_.cellCentres()[nei]; - - pointIndexHit surfaceHitInfo; - label surfI = surfaces_.findAnyIntersection - ( - ownCc, - neiCc, - surfaceHitInfo - ); - - if (surfI != surfaceIndex_[faceI]) - { - WarningIn("meshRefinement::checkData()") - << "Internal face:" << faceI - << " fc:" << mesh_.faceCentres()[faceI] - << " cached surfaceIndex_:" << surfaceIndex_[faceI] - << " current:" << surfI - << " ownCc:" << ownCc << " neiCc:" << neiCc - << endl; - } - } - // Get boundary face centre and level. Coupled aware. labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces()); pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces()); calcNeighbourData(neiLevel, neiCc); - for - ( - label faceI = mesh_.nInternalFaces(); - faceI < mesh_.nFaces(); - faceI++ - ) + // Collect segments we want to test for + pointField start(mesh_.nFaces()); + pointField end(mesh_.nFaces()); + + forAll(start, faceI) { - label own = mesh_.faceOwner()[faceI]; - const point& ownCc = mesh_.cellCentres()[own]; + start[faceI] = mesh_.cellCentres()[mesh_.faceOwner()[faceI]]; - pointIndexHit surfaceHitInfo; - label surfI = surfaces_.findAnyIntersection + if (mesh_.isInternalFace(faceI)) + { + end[faceI] = mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]]; + } + else + { + end[faceI] = neiCc[faceI-mesh_.nInternalFaces()]; + } + } + + // Do tests in one go + labelList surfaceHit; + { + labelList surfaceLevel; + surfaces_.findHigherIntersection ( - ownCc, - neiCc[faceI-mesh_.nInternalFaces()], - surfaceHitInfo + start, + end, + labelList(start.size(), -1), // accept any intersection + surfaceHit, + surfaceLevel ); + } - if (surfI != surfaceIndex_[faceI]) + // Check + forAll(surfaceHit, faceI) + { + if (surfaceHit[faceI] != surfaceIndex_[faceI]) { - WarningIn("meshRefinement::checkData()") - << "Boundary face:" << faceI - << " patch:" << mesh_.boundaryMesh().whichPatch(faceI) - << " fc:" << mesh_.faceCentres()[faceI] - << " cached surfaceIndex_:" << surfaceIndex_[faceI] - << " current:" << surfI - << " ownCc:" << ownCc - << " neiCc:" << neiCc[faceI-mesh_.nInternalFaces()] - << endl; + if (mesh_.isInternalFace(faceI)) + { + WarningIn("meshRefinement::checkData()") + << "Internal face:" << faceI + << " fc:" << mesh_.faceCentres()[faceI] + << " cached surfaceIndex_:" << surfaceIndex_[faceI] + << " current:" << surfaceHit[faceI] + << " ownCc:" + << mesh_.cellCentres()[mesh_.faceOwner()[faceI]] + << " neiCc:" + << mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]] + << endl; + } + else + { + WarningIn("meshRefinement::checkData()") + << "Boundary face:" << faceI + << " fc:" << mesh_.faceCentres()[faceI] + << " cached surfaceIndex_:" << surfaceIndex_[faceI] + << " current:" << surfaceHit[faceI] + << " ownCc:" + << mesh_.cellCentres()[mesh_.faceOwner()[faceI]] + << endl; + } } } } @@ -492,283 +424,6 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::doRemoveCells } -// Get which are inside any closed surface. Note that all closed surfaces -// will have already been oriented to have keepPoint outside. -Foam::labelList Foam::meshRefinement::getInsideCells -( - const word& postfix -) const -{ - const pointField& points = mesh_.points(); - - // This test can be done in various ways. The ultimate is the intersection - // of any edge of the mesh with any surface and intersection of any edge - // of any surface of the mesh with any mesh face. - // For now: - // - none of the edges of a cell intersects any surface - // - any point of the cell is inside. - - - // Is point inside any closed surface? - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - PackedList<1> pointIsInside; - label nPointInside = surfaces_.markInsidePoints - ( - points, - pointIsInside - ); - - if (debug) - { - Pout<< "getInsideCells : Points internal to closed surfaces :" - << " local:" << nPointInside - << " global:" << returnReduce(nPointInside, sumOp<label>()) - << endl; - } - - - // Find cells with all points inside closed surface - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - PackedList<1> cellIsInside(mesh_.nCells(), 1u); - label nCellInside = mesh_.nCells(); - - // Unmark cells with any point outside - forAll(points, pointI) - { - if (pointIsInside.get(pointI) == 0u) - { - // Outside point. Unmark cells. - const labelList& pCells = mesh_.pointCells()[pointI]; - - forAll(pCells, i) - { - label cellI = pCells[i]; - - if (cellIsInside.get(cellI) == 1u) - { - cellIsInside.set(cellI, 0u); - nCellInside--; - } - } - } - } - - label totNCellInside = nCellInside; - reduce(totNCellInside, sumOp<label>()); - if (debug) - { - Pout<< "getInsideCells : Cells using inside points only :" - << " local:" << nCellInside << " global:" << totNCellInside - << endl; - } - - // Filter any cells with cc-cc edge intersection - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - const cellList& cells = mesh_.cells(); - - cellSet insidePoints(mesh_, "insidePoints_"+postfix, mesh_.nCells()/100); - cellSet insidePointsButCut - ( - mesh_, - "insidePointsButCut_"+postfix, - mesh_.nCells()/100 - ); - - forAll(cells, cellI) - { - if (cellIsInside.get(cellI) == 1u) - { - insidePoints.insert(cellI); - - const cell& cFaces = cells[cellI]; - - forAll(cFaces, i) - { - if (surfaceIndex_[cFaces[i]] != -1) - { - cellIsInside.set(cellI, 0u); - nCellInside--; - - insidePointsButCut.insert(cellI); - - break; - } - } - } - } - - if (debug) - { - Pout<< "getInsideCells : cells with all points inside : " - << insidePoints.objectPath() << endl; - insidePoints.write(); - Pout<< "getInsideCells : cells with all points inside" - << " but intersecting (cc) surface : " - << insidePointsButCut.objectPath() << endl; - insidePointsButCut.write(); - } - - totNCellInside = nCellInside; - reduce(totNCellInside, sumOp<label>()); - if (debug) - { - Pout<< "getInsideCells : After filtering cc-cc intersections :" - << " local:" << nCellInside << " global:" << totNCellInside - << endl; - } - - - // Filter cells with any normal edge intersection - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - cellSet insidePointsButEdge - ( - mesh_, - "insidePointsButEdge_"+postfix, - mesh_.nCells()/100 - ); - - const labelListList& edgeCells = mesh_.edgeCells(); - - forAll(edgeCells, edgeI) - { - const labelList& eCells = edgeCells[edgeI]; - - // Does edge use any inside cells? Prefilter since edge intersection - // test expensive. - bool edgeHasInsideCells = false; - - forAll(eCells, i) - { - if (cellIsInside.get(eCells[i]) == 1u) - { - edgeHasInsideCells = true; - break; - } - } - - if (edgeHasInsideCells) - { - const edge& e = mesh_.edges()[edgeI]; - - // Find any pierces of surface by mesh edge. - pointIndexHit hit; - label surfI = surfaces().findHigherIntersection - ( - points[e[0]], - points[e[1]], - -1, // minimum level. - hit - ); - - if (surfI != -1) - { - // This edge intersects some surface. Unmark all cells - // using this edge. - - forAll(eCells, i) - { - if (cellIsInside.get(eCells[i]) == 1u) - { - cellIsInside.set(eCells[i], 0u); - nCellInside--; - - insidePointsButEdge.insert(eCells[i]); - } - } - } - } - } - - if (debug) - { - Pout<< "getInsideCells : cells with all points inside" - << " but intersecting (edges) surface : " - << insidePointsButEdge.objectPath() << endl; - insidePointsButEdge.write(); - } - - totNCellInside = nCellInside; - reduce(totNCellInside, sumOp<label>()); - if (debug) - { - Pout<< "getInsideCells : After filtering edge interesections :" - << " local:" << nCellInside << " global:" << totNCellInside - << endl; - } - - - // Collect cells - // ~~~~~~~~~~~~~ - - DynamicList<label> cellsToRemove(nCellInside); - - forAll(cellIsInside, cellI) - { - if (cellIsInside.get(cellI) == 1u) - { - cellsToRemove.append(cellI); - } - } - return cellsToRemove.shrink(); -} - - -// Do all to remove inside cells -Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::removeInsideCells -( - const string& msg, - const label exposedPatchI -) -{ - labelList insideCells - ( - getInsideCells - ( - string::validate<word>(msg) - ) - ); - - Info<< "Removing inside cells : " - << returnReduce(insideCells.size(), sumOp<label>()) - << '.' << endl; - - removeCells cellRemover(mesh_); - - labelList exposedFaces(cellRemover.getExposedFaces(insideCells)); - - // Debug check - forAll(exposedFaces, i) - { - label faceI = exposedFaces[i]; - - if (surfaceIndex_[faceI] != -1) - { - FatalErrorIn - ( - "removeInsideCells" - "(const label, const string&, const label)" - ) << "Face:" << faceI - << " fc:" << mesh_.faceCentres()[faceI] - << " is actually cutting the surface and should never have been" - << " included in the cells to remove." - << abort(FatalError); - } - } - - return doRemoveCells - ( - insideCells, - exposedFaces, - labelList(exposedFaces.size(), exposedPatchI), - cellRemover - ); -} - - // Determine for multi-processor regions the lowest numbered cell on the lowest // numbered processor. void Foam::meshRefinement::getRegionMaster @@ -834,13 +489,15 @@ void Foam::meshRefinement::getRegionMaster Foam::meshRefinement::meshRefinement ( fvMesh& mesh, - const scalar tol, - const refinementSurfaces& surfaces + const scalar mergeDistance, + const refinementSurfaces& surfaces, + const shellSurfaces& shells ) : mesh_(mesh), - tol_(tol), + mergeDistance_(mergeDistance), surfaces_(surfaces), + shells_(shells), meshCutter_ ( mesh, @@ -926,109 +583,6 @@ Foam::label Foam::meshRefinement::countHits() const } -//// Determine distribution to keep baffles together -//Foam::labelList Foam::meshRefinement::decomposePreserveBaffles -//( -// decompositionMethod& decomposer -//) const -//{ -// // Find duplicate faces -// labelList duplicateFace -// ( -// localPointRegion::findDuplicateFaces -// ( -// mesh_, -// identity(mesh_.nFaces()-mesh_.nInternalFaces()) -// + mesh_.nInternalFaces() -// ) -// ); -// -// -// // Agglomerate cells on both sides of duplicate face pair -// -// const pointField& cellCentres = mesh_.cellCentres(); -// const labelList& faceOwner = mesh_.faceOwner(); -// -// labelList toAgglom(mesh_.nCells(), -1); -// pointField agglomCellCentres(mesh_.nCells()); -// labelList nAgglomCellCentres(mesh_.nCells(), 0); -// -// label agglomI = 0; -// -// // Do all baffle cells -// forAll(duplicateFace, i) -// { -// if (duplicateFace[i] != -1) -// { -// label own = faceOwner[i+mesh_.nInternalFaces()]; -// label otherOwn = -// faceOwner[duplicateFace[i]+mesh_.nInternalFaces()]; -// -// if (toAgglom[own] == -1 && toAgglom[otherOwn] == -1) -// { -// // Allocate new agglomeration -// agglomCellCentres[agglomI] = -// cellCentres[own] -// + cellCentres[otherOwn]; -// nAgglomCellCentres[agglomI] = 2; -// toAgglom[own] = agglomI; -// toAgglom[otherOwn] = agglomI; -// agglomI++; -// } -// else if (toAgglom[own] != -1) -// { -// // Owner already part of agglomeration. Add otherOwn to it. -// label destAgglom = toAgglom[own]; -// agglomCellCentres[destAgglom] += cellCentres[otherOwn]; -// nAgglomCellCentres[destAgglom]++; -// toAgglom[otherOwn] = destAgglom; -// } -// else if (toAgglom[otherOwn] != -1) -// { -// // otherOwn already part of agglomeration. Add own to it. -// label destAgglom = toAgglom[otherOwn]; -// agglomCellCentres[destAgglom] += cellCentres[own]; -// nAgglomCellCentres[destAgglom]++; -// toAgglom[own] = destAgglom; -// } -// } -// } -// -// // Do all other cells -// forAll(toAgglom, cellI) -// { -// if (toAgglom[cellI] == -1) -// { -// agglomCellCentres[agglomI] = cellCentres[cellI]; -// nAgglomCellCentres[agglomI] = 1; -// toAgglom[cellI] = agglomI; -// agglomI++; -// } -// } -// -// // Average -// agglomCellCentres.setSize(agglomI); -// -// forAll(agglomCellCentres, i) -// { -// agglomCellCentres[i] /= nAgglomCellCentres[i]; -// } -// -// // Decompose based on agglomerated cell centres -// labelList agglomDistribution(decomposer.decompose(agglomCellCentres)); -// -// // Rework back into decomposition for original mesh_ -// labelList distribution(mesh_.nCells()); -// -// forAll(toAgglom, cellI) -// { -// distribution[cellI] = agglomDistribution[toAgglom[cellI]]; -// } -// -// return distribution; -//} - - // Determine distribution to move connected regions onto one processor. Foam::labelList Foam::meshRefinement::decomposeCombineRegions ( @@ -1164,6 +718,141 @@ Foam::labelList Foam::meshRefinement::decomposeCombineRegions } +Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance +( + const bool keepZoneFaces, + const bool keepBaffles, + decompositionMethod& decomposer, + fvMeshDistribute& distributor +) +{ + autoPtr<mapDistributePolyMesh> map; + + if (Pstream::parRun()) + { + //Info<< nl + // << "Doing final balancing" << nl + // << "---------------------" << nl + // << endl; + // + //if (debug_) + //{ + // const_cast<Time&>(mesh_.time())++; + //} + + // Wanted distribution + labelList distribution; + + if (keepZoneFaces || keepBaffles) + { + // Faces where owner and neighbour are not 'connected' so can + // go to different processors. + boolList blockedFace(mesh_.nFaces(), true); + // Pairs of baffles + List<labelPair> couples; + + if (keepZoneFaces) + { + label nNamed = surfaces().getNamedSurfaces().size(); + + Info<< "Found " << nNamed << " surfaces with faceZones." + << " Applying special decomposition to keep those together." + << endl; + + // Determine decomposition to keep/move surface zones + // on one processor. The reason is that snapping will make these + // into baffles, move and convert them back so if they were + // proc boundaries after baffling&moving the points might be no + // longer snychronised so recoupling will fail. To prevent this + // keep owner&neighbour of such a surface zone on the same + // processor. + + const wordList& fzNames = surfaces().faceZoneNames(); + const faceZoneMesh& fZones = mesh_.faceZones(); + + // Get faces whose owner and neighbour should stay together, + // i.e. they are not 'blocked'. + + label nZoned = 0; + + forAll(fzNames, surfI) + { + if (fzNames[surfI].size() > 0) + { + // Get zone + label zoneI = fZones.findZoneID(fzNames[surfI]); + + const faceZone& fZone = fZones[zoneI]; + + forAll(fZone, i) + { + if (blockedFace[fZone[i]]) + { + blockedFace[fZone[i]] = false; + nZoned++; + } + } + } + } + Info<< "Found " << returnReduce(nZoned, sumOp<label>()) + << " zoned faces to keep together." + << endl; + } + + if (keepBaffles) + { + // Get boundary baffles that need to stay together. + couples = getDuplicateFaces // all baffles + ( + identity(mesh_.nFaces()-mesh_.nInternalFaces()) + +mesh_.nInternalFaces() + ); + + Info<< "Found " << returnReduce(couples.size(), sumOp<label>()) + << " baffles to keep together." + << endl; + } + + distribution = decomposeCombineRegions + ( + blockedFace, + couples, + decomposer + ); + + labelList nProcCells(distributor.countCells(distribution)); + Pstream::listCombineGather(nProcCells, plusEqOp<label>()); + Pstream::listCombineScatter(nProcCells); + + Info<< "Calculated decomposition:" << endl; + forAll(nProcCells, procI) + { + Info<< " " << procI << '\t' << nProcCells[procI] << endl; + } + Info<< endl; + } + else + { + // Normal decomposition + distribution = decomposer.decompose(mesh_.cellCentres()); + } + + if (debug) + { + Pout<< "Wanted distribution:" + << distributor.countCells(distribution) + << endl; + } + // Do actual sending/receiving of mesh + map = distributor.distribute(distribution); + + // Update numbering of meshRefiner + distribute(map); + } + return map; +} + + // Helper function to get intersected faces Foam::labelList Foam::meshRefinement::intersectedFaces() const { @@ -1213,9 +902,8 @@ Foam::labelList Foam::meshRefinement::intersectedPoints forAll(f, fp) { - if (isBoundaryPoint.get(f[fp]) == 0u) + if (isBoundaryPoint.set(f[fp], 1u)) { - isBoundaryPoint.set(f[fp], 1u); nBoundaryPoints++; } } @@ -1239,9 +927,7 @@ Foam::labelList Foam::meshRefinement::intersectedPoints // // forAll(f, fp) // { - // if (isBoundaryPoint.get(f[fp]) == 0u) - // { - // isBoundaryPoint.set(f[fp], 1u); + // if (isBoundaryPoint.set(f[fp], 1u)) // nBoundaryPoints++; // } // } @@ -1390,6 +1076,101 @@ Foam::tmp<Foam::pointVectorField> Foam::meshRefinement::makeDisplacementField } +void Foam::meshRefinement::checkCoupledFaceZones(const polyMesh& mesh) +{ + const faceZoneMesh& fZones = mesh.faceZones(); + + // Check any zones are present anywhere and in same order + + { + List<wordList> zoneNames(Pstream::nProcs()); + zoneNames[Pstream::myProcNo()] = fZones.names(); + Pstream::gatherList(zoneNames); + Pstream::scatterList(zoneNames); + // All have same data now. Check. + forAll(zoneNames, procI) + { + if (procI != Pstream::myProcNo()) + { + if (zoneNames[procI] != zoneNames[Pstream::myProcNo()]) + { + FatalErrorIn + ( + "meshRefinement::checkCoupledFaceZones(const polyMesh&)" + ) << "faceZones are not synchronised on processors." << nl + << "Processor " << procI << " has faceZones " + << zoneNames[procI] << nl + << "Processor " << Pstream::myProcNo() + << " has faceZones " + << zoneNames[Pstream::myProcNo()] << nl + << exit(FatalError); + } + } + } + } + + // Check that coupled faces are present on both sides. + + labelList faceToZone(mesh.nFaces()-mesh.nInternalFaces(), -1); + + forAll(fZones, zoneI) + { + const faceZone& fZone = fZones[zoneI]; + + forAll(fZone, i) + { + label bFaceI = fZone[i]-mesh.nInternalFaces(); + + if (bFaceI >= 0) + { + if (faceToZone[bFaceI] == -1) + { + faceToZone[bFaceI] = zoneI; + } + else if (faceToZone[bFaceI] == zoneI) + { + FatalErrorIn + ( + "meshRefinement::checkCoupledFaceZones(const polyMesh&)" + ) << "Face " << fZone[i] << " in zone " + << fZone.name() + << " is twice in zone!" + << abort(FatalError); + } + else + { + FatalErrorIn + ( + "meshRefinement::checkCoupledFaceZones(const polyMesh&)" + ) << "Face " << fZone[i] << " in zone " + << fZone.name() + << " is also in zone " + << fZones[faceToZone[bFaceI]].name() + << abort(FatalError); + } + } + } + } + + labelList neiFaceToZone(faceToZone); + syncTools::swapBoundaryFaceList(mesh, neiFaceToZone, false); + + forAll(faceToZone, i) + { + if (faceToZone[i] != neiFaceToZone[i]) + { + FatalErrorIn + ( + "meshRefinement::checkCoupledFaceZones(const polyMesh&)" + ) << "Face " << mesh.nInternalFaces()+i + << " is in zone " << faceToZone[i] + << ", its coupled face is in zone " << neiFaceToZone[i] + << abort(FatalError); + } + } +} + + // Adds patch if not yet there. Returns patchID. Foam::label Foam::meshRefinement::addPatch ( @@ -1910,53 +1691,56 @@ void Foam::meshRefinement::dumpIntersections(const fileName& prefix) const << " Writing cellcentre-cellcentre intersections to file " << str.name() << endl; - // Internal faces - for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++) - { - if (surfaceIndex_[faceI] != -1) - { - const point& ownCc = cellCentres[mesh_.faceOwner()[faceI]]; - const point& neiCc = cellCentres[mesh_.faceNeighbour()[faceI]]; - - // Re-intersect to get position - pointIndexHit surfaceHitInfo; - surfaces_.findAnyIntersection(ownCc, neiCc, surfaceHitInfo); - - meshTools::writeOBJ(str, ownCc); - vertI++; - meshTools::writeOBJ(str, surfaceHitInfo.hitPoint()); - vertI++; - meshTools::writeOBJ(str, neiCc); - vertI++; - str << "l " << vertI-2 << ' ' << vertI-1 << nl - << "l " << vertI-1 << ' ' << vertI << nl; - } - } - // Boundary faces + // Redo all intersections + // ~~~~~~~~~~~~~~~~~~~~~~ // Get boundary face centre and level. Coupled aware. labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces()); pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces()); calcNeighbourData(neiLevel, neiCc); - forAll(neiCc, i) + labelList intersectionFaces(intersectedFaces()); + + // Collect segments we want to test for + pointField start(intersectionFaces.size()); + pointField end(intersectionFaces.size()); + + forAll(intersectionFaces, i) { - label faceI = i + mesh_.nInternalFaces(); + label faceI = intersectionFaces[i]; + start[i] = cellCentres[mesh_.faceOwner()[faceI]]; - if (surfaceIndex_[faceI] != -1) + if (mesh_.isInternalFace(faceI)) { - const point& ownCc = cellCentres[mesh_.faceOwner()[faceI]]; + end[i] = cellCentres[mesh_.faceNeighbour()[faceI]]; + } + else + { + end[i] = neiCc[faceI-mesh_.nInternalFaces()]; + } + } - // Re-intersect to get position - pointIndexHit surfaceHitInfo; - surfaces_.findAnyIntersection(ownCc, neiCc[i], surfaceHitInfo); + // Do tests in one go + labelList surfaceHit; + List<pointIndexHit> surfaceHitInfo; + surfaces_.findAnyIntersection + ( + start, + end, + surfaceHit, + surfaceHitInfo + ); - meshTools::writeOBJ(str, ownCc); + forAll(intersectionFaces, i) + { + if (surfaceHit[i] != -1) + { + meshTools::writeOBJ(str, start[i]); vertI++; - meshTools::writeOBJ(str, surfaceHitInfo.hitPoint()); + meshTools::writeOBJ(str, surfaceHitInfo[i].hitPoint()); vertI++; - meshTools::writeOBJ(str, neiCc[i]); + meshTools::writeOBJ(str, end[i]); vertI++; str << "l " << vertI-2 << ' ' << vertI-1 << nl << "l " << vertI-1 << ' ' << vertI << nl; @@ -1996,13 +1780,4 @@ void Foam::meshRefinement::write } -// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * // - - // ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H index 78fed5349306a3f57daf6a6fe10d17f4c84cbc30..d27eaae413946987954c4a168144fe67b1d64849 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H @@ -30,7 +30,7 @@ Description (static) surfaces. Maintains - - per face any intersections of this edge with any of the surfaces + - per face any intersections of the cc-cc segment with any of the surfaces SourceFiles meshRefinement.C @@ -62,6 +62,7 @@ class fvMesh; class mapDistributePolyMesh; class decompositionMethod; class refinementSurfaces; +class shellSurfaces; class removeCells; class featureEdgeMesh; class fvMeshDistribute; @@ -93,7 +94,7 @@ public: { MASTERONLY = 1, /*!< maintain master only */ KEEPALL = 2, /*!< have slaves (upon refinement) from master */ - REMOVE = 4 /*!< set value to -1 any face that has been refined */ + REMOVE = 4 /*!< set value to -1 any face that was refined */ }; @@ -105,10 +106,14 @@ private: fvMesh& mesh_; //- tolerance used for sorting coordinates (used in 'less' routine) - const scalar tol_; + const scalar mergeDistance_; + //- All surface-intersection interaction const refinementSurfaces& surfaces_; + //- All shell-refinement interaction + const shellSurfaces& shells_; + //- refinement engine hexRef8 meshCutter_; @@ -229,14 +234,18 @@ private: //- Mark cells for refinement-shells based refinement. label markInternalRefinement ( - const PtrList<searchableSurface>&, - const labelList& shellLevels, - const boolList& shellRefineInside, const label nAllowRefine, labelList& refineCell, label& nRefine ) const; + //- Collect faces that are intersected and whose neighbours aren't + // yet marked for refinement. + labelList getRefineCandidateFaces + ( + const labelList& refineCell + ) const; + //- Mark cells for surface intersection based refinement. label markSurfaceRefinement ( @@ -252,17 +261,13 @@ private: // regions. bool checkCurvature ( - const labelList& globalToPatch, const scalar curvature, - const bool markDifferingRegions, const label nAllowRefine, - const label newSurfI, - const label newTriI, + const label surfaceLevel, + const vector& surfaceNormal, const label cellI, - - label& maxCellSurfI, - label& maxCellTriI, - + label& cellMaxLevel, + vector& cellMaxNormal, labelList& refineCell, label& nRefine ) const; @@ -273,9 +278,7 @@ private: // (markDifferingRegions) label markSurfaceCurvatureRefinement ( - const labelList& globalToPatch, const scalar curvature, - const bool markDifferingRegions, const label nAllowRefine, const labelList& neiLevel, const pointField& neiCc, @@ -380,8 +383,9 @@ public: meshRefinement ( fvMesh& mesh, - const scalar tol, - const refinementSurfaces& + const scalar mergeDistance, + const refinementSurfaces&, + const shellSurfaces& ); @@ -399,12 +403,23 @@ public: return mesh_; } + scalar mergeDistance() const + { + return mergeDistance_; + } + //- reference to surface search engines const refinementSurfaces& surfaces() const { return surfaces_; } + //- reference to refinement shells (regions) + const shellSurfaces& shells() const + { + return shells_; + } + //- reference to meshcutting engine const hexRef8& meshCutter() const { @@ -454,6 +469,18 @@ public: decompositionMethod& ) const; + //- Redecompose according to cell count + // keepZoneFaces : find all faceZones from zoned surfaces and keep + // owner and neighbour together + // keepBaffles : find all baffles and keep them together + autoPtr<mapDistributePolyMesh> balance + ( + const bool keepZoneFaces, + const bool keepBaffles, + decompositionMethod& decomposer, + fvMeshDistribute& distributor + ); + //- Get faces with intersection. labelList intersectedFaces() const; @@ -482,22 +509,21 @@ public: const labelList& adaptPatchIDs ); + //- Helper function: check that face zones are synced + static void checkCoupledFaceZones(const polyMesh&); + + // Refinement //- Calculate list of cells to refine. labelList refineCandidates ( const point& keepPoint, - const labelList& globalToPatch, const scalar curvature, const PtrList<featureEdgeMesh>& featureMeshes, const labelList& featureLevels, - const PtrList<searchableSurface>&, - const labelList& shellLevels, - const boolList& shellRefineInside, - const bool featureRefinement, const bool internalRefinement, const bool surfaceRefinement, @@ -626,7 +652,7 @@ public: template<class T> void testSyncBoundaryFaceList ( - const scalar tol, + const scalar mergeDistance, const string&, const UList<T>&, const UList<T>& diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C index 17eaaeaa275cce90b0802adcef1712f934a4c154..a92f61a78adbf93d7cdaf3079069c006fe5e9ca8 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C @@ -249,7 +249,7 @@ void Foam::meshRefinement::getBafflePatches if (debug) { Pout<< "getBafflePatches : Not baffling surface " - << surfaces_[surfI].searchableSurface::name() << endl; + << surfaces_.names()[surfI] << endl; } } else @@ -264,69 +264,95 @@ void Foam::meshRefinement::getBafflePatches neiPatch.setSize(mesh_.nFaces()); neiPatch = -1; - forAll(surfaceIndex_, faceI) + + // Collect candidate faces + // ~~~~~~~~~~~~~~~~~~~~~~~ + + labelList testFaces(intersectedFaces()); + + // Collect segments + // ~~~~~~~~~~~~~~~~ + + pointField start(testFaces.size()); + pointField end(testFaces.size()); + + forAll(testFaces, i) { - if (surfaceIndex_[faceI] != -1) - { - // Edge between owner and neighbour of face pierces a surface. - // Do closer inspection to find nearest intersection on both sides. + label faceI = testFaces[i]; - label own = mesh_.faceOwner()[faceI]; + label own = mesh_.faceOwner()[faceI]; - // Cc of neighbouring cell - point end - ( - mesh_.isInternalFace(faceI) - ? cellCentres[mesh_.faceNeighbour()[faceI]] - : neiCc[faceI-mesh_.nInternalFaces()] - ); + if (mesh_.isInternalFace(faceI)) + { + start[i] = cellCentres[own]; + end[i] = cellCentres[mesh_.faceNeighbour()[faceI]]; + } + else + { + start[i] = cellCentres[own]; + end[i] = neiCc[faceI-mesh_.nInternalFaces()]; + } + } - label surface1, surface2; - pointIndexHit hit1, hit2; - surfaces_.findNearestIntersection - ( - surfacesToBaffle, - cellCentres[own], - end, - surface1, - hit1, - surface2, - hit2 - ); + // Do test for intersections + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + labelList surface1; + List<pointIndexHit> hit1; + labelList region1; + labelList surface2; + List<pointIndexHit> hit2; + labelList region2; + surfaces_.findNearestIntersection + ( + surfacesToBaffle, + start, + end, - if (hit1.hit() && hit2.hit()) - { - if (str.valid()) - { - meshTools::writeOBJ(str(), cellCentres[own]); - vertI++; - meshTools::writeOBJ(str(), hit1.rawPoint()); - vertI++; - meshTools::writeOBJ(str(), hit2.rawPoint()); - vertI++; - meshTools::writeOBJ(str(), end); - vertI++; - str()<< "l " << vertI-3 << ' ' << vertI-2 << nl; - str()<< "l " << vertI-2 << ' ' << vertI-1 << nl; - str()<< "l " << vertI-1 << ' ' << vertI << nl; - } + surface1, + hit1, + region1, + surface2, + hit2, + region2 + ); - // Pick up the patches - ownPatch[faceI] = globalToPatch - [ - surfaces_.triangleRegion(surface1, hit1.index()) - ]; - neiPatch[faceI] = globalToPatch - [ - surfaces_.triangleRegion(surface2, hit2.index()) - ]; + forAll(testFaces, i) + { + label faceI = testFaces[i]; - if (ownPatch[faceI] == -1 || neiPatch[faceI] == -1) - { - FatalErrorIn("getBafflePatches()") << abort(FatalError); - } + if (hit1[i].hit() && hit2[i].hit()) + { + if (str.valid()) + { + meshTools::writeOBJ(str(), start[i]); + vertI++; + meshTools::writeOBJ(str(), hit1[i].rawPoint()); + vertI++; + meshTools::writeOBJ(str(), hit2[i].rawPoint()); + vertI++; + meshTools::writeOBJ(str(), end[i]); + vertI++; + str()<< "l " << vertI-3 << ' ' << vertI-2 << nl; + str()<< "l " << vertI-2 << ' ' << vertI-1 << nl; + str()<< "l " << vertI-1 << ' ' << vertI << nl; + } + + // Pick up the patches + ownPatch[faceI] = globalToPatch + [ + surfaces_.globalRegion(surface1[i], region1[i]) + ]; + neiPatch[faceI] = globalToPatch + [ + surfaces_.globalRegion(surface2[i], region2[i]) + ]; + + if (ownPatch[faceI] == -1 || neiPatch[faceI] == -1) + { + FatalErrorIn("getBafflePatches(..)") + << "problem." << abort(FatalError); } } } @@ -1203,15 +1229,20 @@ void Foam::meshRefinement::findCellZoneGeometric const labelList& faceOwner = mesh_.faceOwner(); const labelList& faceNeighbour = mesh_.faceNeighbour(); - forAll(cellToZone, cellI) + // Check if cell centre is inside + labelList insideSurfaces; + surfaces_.findInside + ( + closedNamedSurfaces, + cellCentres, + insideSurfaces + ); + + forAll(insideSurfaces, cellI) { if (cellToZone[cellI] == -2) { - label surfI = surfaces_.insideZone - ( - closedNamedSurfaces, - cellCentres[cellI] - ); + label surfI = insideSurfaces[cellI]; if (surfI != -1) { @@ -1223,6 +1254,32 @@ void Foam::meshRefinement::findCellZoneGeometric // Some cells with cell centres close to surface might have // had been put into wrong surface. Recheck with perturbed cell centre. + + + // 1. Collect points + + // Count points to test. + label nCandidates = 0; + forAll(namedSurfaceIndex, faceI) + { + label surfI = namedSurfaceIndex[faceI]; + + if (surfI != -1) + { + if (mesh_.isInternalFace(faceI)) + { + nCandidates += 2; + } + else + { + nCandidates += 1; + } + } + } + + // Collect points. + pointField candidatePoints(nCandidates); + nCandidates = 0; forAll(namedSurfaceIndex, faceI) { label surfI = namedSurfaceIndex[faceI]; @@ -1236,55 +1293,65 @@ void Foam::meshRefinement::findCellZoneGeometric { label nei = faceNeighbour[faceI]; const point& neiCc = cellCentres[nei]; - + // Perturbed cc const vector d = 1E-4*(neiCc - ownCc); + candidatePoints[nCandidates++] = ownCc-d; + candidatePoints[nCandidates++] = neiCc+d; + } + else + { + const point& neiFc = mesh_.faceCentres()[faceI]; + // Perturbed cc + const vector d = 1E-4*(neiFc - ownCc); + candidatePoints[nCandidates++] = ownCc-d; + } + } + } - // Test perturbed owner - { - label ownSurfI = surfaces_.insideZone - ( - closedNamedSurfaces, - ownCc-d - ); - if (ownSurfI != -1) - { - cellToZone[own] = surfaceToCellZone[ownSurfI]; - } + // 2. Test points for inside + + surfaces_.findInside + ( + closedNamedSurfaces, + candidatePoints, + insideSurfaces + ); + + + // 3. Update zone information + + nCandidates = 0; + forAll(namedSurfaceIndex, faceI) + { + label surfI = namedSurfaceIndex[faceI]; + + if (surfI != -1) + { + label own = faceOwner[faceI]; + + if (mesh_.isInternalFace(faceI)) + { + label ownSurfI = insideSurfaces[nCandidates++]; + if (ownSurfI != -1) + { + cellToZone[own] = surfaceToCellZone[ownSurfI]; } - // Test perturbed neighbour + label neiSurfI = insideSurfaces[nCandidates++]; + if (neiSurfI != -1) { - label neiSurfI = surfaces_.insideZone - ( - closedNamedSurfaces, - neiCc+d - ); + label nei = faceNeighbour[faceI]; - if (neiSurfI != -1) - { - cellToZone[nei] = surfaceToCellZone[neiSurfI]; - } + cellToZone[nei] = surfaceToCellZone[neiSurfI]; } } else { - const point& neiCc = mesh_.faceCentres()[faceI]; - - const vector d = 1E-4*(neiCc - ownCc); - - // Test perturbed owner + label ownSurfI = insideSurfaces[nCandidates++]; + if (ownSurfI != -1) { - label ownSurfI = surfaces_.insideZone - ( - closedNamedSurfaces, - ownCc-d - ); - - if (ownSurfI != -1) - { - cellToZone[own] = surfaceToCellZone[ownSurfI]; - } + cellToZone[own] = surfaceToCellZone[ownSurfI]; } } } @@ -1771,7 +1838,11 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMesh const labelList& faceNeighbour = mesh_.faceNeighbour(); // Patch for exposed faces for lack of anything sensible. - const label defaultPatch = globalToPatch[0]; + label defaultPatch = 0; + if (globalToPatch.size() > 0) + { + defaultPatch = globalToPatch[0]; + } for (label i = 0; i < nBufferLayers; i++) { @@ -2291,7 +2362,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify isNamedSurface[surfI] = true; - Info<< "Surface : " << surfaces_[surfI].searchableSurface::name() << nl + Info<< "Surface : " << surfaces_.names()[surfI] << nl << " faceZone : " << faceZoneNames[surfI] << nl << " cellZone : " << cellZoneNames[surfI] << endl; } @@ -2329,7 +2400,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify if (debug) { - Pout<< "Faces on " << surfaces_[surfI].searchableSurface::name() + Pout<< "Faces on " << surfaces_.names()[surfI] << " will go into faceZone " << zoneI << endl; } surfaceToFaceZone[surfI] = zoneI; @@ -2387,8 +2458,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify if (debug) { - Pout<< "Cells inside " - << surfaces_[surfI].searchableSurface::name() + Pout<< "Cells inside " << surfaces_.names()[surfI] << " will go into cellZone " << zoneI << endl; } surfaceToCellZone[surfI] = zoneI; @@ -2444,78 +2514,83 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify // Note: for all internal faces? internal + coupled? // Since zonify is run after baffling the surfaceIndex_ on baffles is // not synchronised across both baffle faces. Fortunately we don't - // do zonify baffle faces anyway. - forAll(surfaceIndex_, faceI) + // do zonify baffle faces anyway (they are normal boundary faces). + + // Collect candidate faces + // ~~~~~~~~~~~~~~~~~~~~~~~ + + labelList testFaces(intersectedFaces()); + + // Collect segments + // ~~~~~~~~~~~~~~~~ + + pointField start(testFaces.size()); + pointField end(testFaces.size()); + + forAll(testFaces, i) { - label surfI = surfaceIndex_[faceI]; + label faceI = testFaces[i]; - if - ( - surfI != -1 - && ( - mesh_.isInternalFace(faceI) - || patches[patches.whichPatch(faceI)].coupled() - ) - ) + label own = mesh_.faceOwner()[faceI]; + + if (mesh_.isInternalFace(faceI)) { - if (isNamedSurface[surfI]) - { - namedSurfaceIndex[faceI] = surfI; - nSurfFaces[surfI]++; - } - else - { - // Test more accurately for whether intersection is at - // zoneable surface + start[i] = cellCentres[own]; + end[i] = cellCentres[mesh_.faceNeighbour()[faceI]]; + } + else + { + start[i] = cellCentres[own]; + end[i] = neiCc[faceI-mesh_.nInternalFaces()]; + } + } - label surface1, surface2; - pointIndexHit hit1, hit2; - if (mesh_.isInternalFace(faceI)) - { - surfaces_.findNearestIntersection - ( - namedSurfaces, - cellCentres[faceOwner[faceI]], - cellCentres[faceNeighbour[faceI]], - - surface1, - hit1, - surface2, - hit2 - ); - } - else - { - surfaces_.findNearestIntersection - ( - namedSurfaces, - cellCentres[faceOwner[faceI]], - neiCc[faceI-mesh_.nInternalFaces()], - - surface1, - hit1, - surface2, - hit2 - ); - } + // Do test for intersections + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + // Note that we intersect all intersected faces again. Could reuse + // the information already in surfaceIndex_. - if (hit1.hit()) - { - // If both hit should probably choose nearest. For - // later. - namedSurfaceIndex[faceI] = surface1; - nSurfFaces[surface1]++; - } - else if (hit2.hit()) - { - namedSurfaceIndex[faceI] = surface2; - nSurfFaces[surface2]++; - } - } + labelList surface1; + labelList surface2; + { + List<pointIndexHit> hit1; + labelList region1; + List<pointIndexHit> hit2; + labelList region2; + surfaces_.findNearestIntersection + ( + namedSurfaces, + start, + end, + + surface1, + hit1, + region1, + surface2, + hit2, + region2 + ); + } + + forAll(testFaces, i) + { + label faceI = testFaces[i]; + + if (surface1[i] != -1) + { + // If both hit should probably choose nearest. For later. + namedSurfaceIndex[faceI] = surface1[i]; + nSurfFaces[surface1[i]]++; + } + else if (surface2[i] != -1) + { + namedSurfaceIndex[faceI] = surface2[i]; + nSurfFaces[surface2[i]]++; } } + // surfaceIndex migh have different surfaces on both sides if // there happen to be a (obviously thin) surface with different // regions between the cell centres. If one is on a named surface @@ -2534,7 +2609,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify forAll(nSurfFaces, surfI) { Pout<< "Surface:" - << surfaces_[surfI].searchableSurface::name() + << surfaces_.names()[surfI] << " nZoneFaces:" << nSurfFaces[surfI] << nl; } Pout<< endl; @@ -2591,7 +2666,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify ( mesh_.faces()[faceI], // modified face faceI, // label of face - faceOwner[faceI], // owner + faceOwner[faceI], // owner -1, // neighbour false, // face flip patchI, // patch for face @@ -2609,20 +2684,8 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify // Put the cells into the correct zone // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - labelList closedNamedSurfaces(namedSurfaces.size()); - label nClosed = 0; - - forAll(namedSurfaces, i) - { - label surfI = namedSurfaces[i]; - - if (surfaces_.closed()[surfI]) - { - closedNamedSurfaces[nClosed++] = surfI; - } - } - closedNamedSurfaces.setSize(nClosed); - + // Closed surfaces with cellZone specified. + labelList closedNamedSurfaces(surfaces_.getClosedNamedSurfaces()); // Zone per cell: // -2 : unset @@ -2704,13 +2767,4 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify } -// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * // - - // ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementMerge.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementMerge.C index 14c3304979b41030960405291825a04bdcfe79c4..d8ddb69bcece7841e39e71751245cc21efd5d5ee 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementMerge.C +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementMerge.C @@ -30,15 +30,9 @@ License #include "removePoints.H" -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - - // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - - // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // Merge faces that are in-line. @@ -244,13 +238,4 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::mergeEdges } -// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * // - - // ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C index bc65921bf5aa74179e90972f61eba7c71b831228..9a5f6cf63379293e884c8c74fa59fa48b981c203 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C @@ -29,6 +29,7 @@ License #include "syncTools.H" #include "Time.H" #include "refinementSurfaces.H" +#include "shellSurfaces.H" #include "faceSet.H" #include "decompositionMethod.H" #include "fvMeshDistribute.H" @@ -37,9 +38,6 @@ License #include "featureEdgeMesh.H" #include "Cloud.H" -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - - // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // Get faces (on the new mesh) that have in some way been affected by the @@ -369,7 +367,7 @@ Foam::label Foam::meshRefinement::markFeatureRefinement { label edgeI = pEdges[i]; - if (featureEdgeVisited[featI].get(edgeI) == 0) + if (featureEdgeVisited[featI].set(edgeI, 1u)) { // Unvisited edge. Make the particle go to the other point // on the edge. @@ -377,7 +375,6 @@ Foam::label Foam::meshRefinement::markFeatureRefinement const edge& e = featureMesh.edges()[edgeI]; label otherPointI = e.otherVertex(pointI); - featureEdgeVisited[featI].set(edgeI, 1u); tp.end() = featureMesh.points()[otherPointI]; tp.j() = otherPointI; keepParticle = true; @@ -438,6 +435,15 @@ Foam::label Foam::meshRefinement::markFeatureRefinement } } + if + ( + returnReduce(nRefine, sumOp<label>()) + > returnReduce(nAllowRefine, sumOp<label>()) + ) + { + Info<< "Reached refinement limit." << endl; + } + return returnReduce(nRefine-oldNRefine, sumOp<label>()); } @@ -445,9 +451,6 @@ Foam::label Foam::meshRefinement::markFeatureRefinement // Mark cells for non-surface intersection based refinement. Foam::label Foam::meshRefinement::markInternalRefinement ( - const PtrList<searchableSurface>& shells, - const labelList& shellLevels, - const boolList& shellRefineInside, const label nAllowRefine, labelList& refineCell, @@ -457,94 +460,113 @@ Foam::label Foam::meshRefinement::markInternalRefinement const labelList& cellLevel = meshCutter_.cellLevel(); const pointField& cellCentres = mesh_.cellCentres(); - label oldNRefine = nRefine; - // Number of cells marked for refinement per shell. - labelList nCellsPerShell(shells.size(), 0); + // Collect cells to test + pointField testCc(cellLevel.size()-nRefine); + labelList testLevels(cellLevel.size()-nRefine); + label testI = 0; forAll(cellLevel, cellI) { if (refineCell[cellI] == -1) { - // Cell not marked for refinement. Check if inside any shell - // with higher refinement level than cell currently has. + testCc[testI] = cellCentres[cellI]; + testLevels[testI] = cellLevel[cellI]; + testI++; + } + } - bool reachedLimit = false; + // Do test to see whether cells is inside/outside shell with higher level + labelList maxLevel; + shells_.findHigherLevel(testCc, testLevels, maxLevel); - forAll(shells, shellI) + // Mark for refinement. Note that we didn't store the original cellID so + // now just reloop in same order. + testI = 0; + forAll(cellLevel, cellI) + { + if (refineCell[cellI] == -1) + { + if (maxLevel[testI] > testLevels[testI]) { - // Cached inside-outside from tree - searchableSurface::volumeType t = - shells[shellI].getVolumeType(cellCentres[cellI]); - - //// Uncached inside-outside from treeData - //label t = shells[shellI].shapes().getVolumeType - // ( - // shells[shellI], - // cellCentres[cellI] - // ); - - // Which side of shell is to be refined - searchableSurface::volumeType refSide = + bool reachedLimit = !markForRefine ( - shellRefineInside[shellI] - ? searchableSurface::INSIDE - : searchableSurface::OUTSIDE + maxLevel[testI], // mark with any positive value + nAllowRefine, + refineCell[cellI], + nRefine ); - if (t == refSide && cellLevel[cellI] < shellLevels[shellI]) + if (reachedLimit) { - // Cell is inside shell with higher refinement level. Mark - // for refinement. - - reachedLimit = !markForRefine - ( - labelMax, - nAllowRefine, - refineCell[cellI], - nRefine - ); - - if (reachedLimit) - { - if (debug) - { - Pout<< "Stopped refining internal cells" - << " since reaching my cell limit of " - << mesh_.nCells()+7*nRefine << endl; - } - break; - } - else + if (debug) { - // Cell successfully marked for refinement - nCellsPerShell[shellI]++; + Pout<< "Stopped refining internal cells" + << " since reaching my cell limit of " + << mesh_.nCells()+7*nRefine << endl; } + break; } } - - if (reachedLimit) - { - break; - } + testI++; } } - Pstream::listCombineGather(nCellsPerShell, plusEqOp<label>()); - Pstream::listCombineScatter(nCellsPerShell); - - Info<< "Marked for refinement per shell :" << endl; - forAll(nCellsPerShell, shellI) + if + ( + returnReduce(nRefine, sumOp<label>()) + > returnReduce(nAllowRefine, sumOp<label>()) + ) { - Info<< " shell:" << shellI << " nCells:" << nCellsPerShell[shellI] - << nl; + Info<< "Reached refinement limit." << endl; } return returnReduce(nRefine-oldNRefine, sumOp<label>()); } +// Collect faces that are intersected and whose neighbours aren't yet marked +// for refinement. +Foam::labelList Foam::meshRefinement::getRefineCandidateFaces +( + const labelList& refineCell +) const +{ + labelList testFaces(mesh_.nCells()); + + label nTest = 0; + + forAll(surfaceIndex_, faceI) + { + if (surfaceIndex_[faceI] != -1) + { + label own = mesh_.faceOwner()[faceI]; + + if (mesh_.isInternalFace(faceI)) + { + label nei = mesh_.faceNeighbour()[faceI]; + + if (refineCell[own] == -1 || refineCell[nei] == -1) + { + testFaces[nTest++] = faceI; + } + } + else + { + if (refineCell[own] == -1) + { + testFaces[nTest++] = faceI; + } + } + } + } + testFaces.setSize(nTest); + + return testFaces; +} + + // Mark cells for surface intersection based refinement. Foam::label Foam::meshRefinement::markSurfaceRefinement ( @@ -564,156 +586,149 @@ Foam::label Foam::meshRefinement::markSurfaceRefinement // Use cached surfaceIndex_ to detect if any intersection. If so // re-intersect to determine level wanted. - label faceI; - for (faceI = 0; faceI < surfaceIndex_.size(); faceI++) + // Collect candidate faces + // ~~~~~~~~~~~~~~~~~~~~~~~ + + labelList testFaces(getRefineCandidateFaces(refineCell)); + + // Collect segments + // ~~~~~~~~~~~~~~~~ + + pointField start(testFaces.size()); + pointField end(testFaces.size()); + labelList minLevel(testFaces.size()); + + forAll(testFaces, i) { - if (surfaceIndex_[faceI] != -1) + label faceI = testFaces[i]; + + label own = mesh_.faceOwner()[faceI]; + + if (mesh_.isInternalFace(faceI)) { - label own = mesh_.faceOwner()[faceI]; + label nei = mesh_.faceNeighbour()[faceI]; - if (mesh_.isInternalFace(faceI)) - { - label nei = mesh_.faceNeighbour()[faceI]; + start[i] = cellCentres[own]; + end[i] = cellCentres[nei]; + minLevel[i] = min(cellLevel[own], cellLevel[nei]); + } + else + { + label bFaceI = faceI - mesh_.nInternalFaces(); - // Test if not both sides already marked for refinement. - if (refineCell[own] == -1 || refineCell[nei] == -1) - { - pointIndexHit hit; - label surfI = surfaces_.findHigherIntersection - ( - cellCentres[own], - cellCentres[nei], - min(cellLevel[own], cellLevel[nei]), - hit - ); + start[i] = cellCentres[own]; + end[i] = neiCc[bFaceI]; + minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]); + } + } - if (surfI != -1) - { - // Found intersection with surface with higher wanted - // refinement. Mark cell for refining. - // Note: could do optimization here and only refine the - // side of the face the intersection actually goes - // through. - // This would require us though to find all - // intersections - // first instead of now only the first higher one. Also - // would need the exact intersection of face with cc-cc - // connection? - - label surfaceMinLevel = - surfaces_.minLevelField(surfI)[hit.index()]; - - if (surfaceMinLevel > cellLevel[own]) - { - // Owner needs refining - if - ( - !markForRefine - ( - surfI, - nAllowRefine, - refineCell[own], - nRefine - ) - ) - { - break; - } - } - if (surfaceMinLevel > cellLevel[nei]) - { - // Neighbour needs refining - if - ( - !markForRefine - ( - surfI, - nAllowRefine, - refineCell[nei], - nRefine - ) - ) - { - break; - } - } - } - } - } - else if (refineCell[own] == -1) - { - // boundary face with unmarked owner + // Do test for higher intersections + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + labelList surfaceHit; + labelList surfaceMinLevel; + surfaces_.findHigherIntersection + ( + start, + end, + minLevel, + + surfaceHit, + surfaceMinLevel + ); + + + // Mark cells for refinement + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + + forAll(testFaces, i) + { + label faceI = testFaces[i]; + + label surfI = surfaceHit[i]; - label bFaceI = faceI - mesh_.nInternalFaces(); + if (surfI != -1) + { + // Found intersection with surface with higher wanted + // refinement. Check if the level field on that surface + // specifies an even higher level. Note:this is weird. Should + // do the check with the surfaceMinLevel whilst intersecting the + // surfaces? + + label own = mesh_.faceOwner()[faceI]; - pointIndexHit hit; - label surfI = surfaces_.findHigherIntersection + if (surfaceMinLevel[i] > cellLevel[own]) + { + // Owner needs refining + if ( - cellCentres[own], - neiCc[bFaceI], - min(cellLevel[own], neiLevel[bFaceI]), - hit - ); + !markForRefine + ( + surfI, + nAllowRefine, + refineCell[own], + nRefine + ) + ) + { + break; + } + } - if (surfI != -1) + if (mesh_.isInternalFace(faceI)) + { + label nei = mesh_.faceNeighbour()[faceI]; + if (surfaceMinLevel[i] > cellLevel[nei]) { - // Make sure it is my side that wants refinement. - label surfaceMinLevel = - surfaces_.minLevelField(surfI)[hit.index()]; - - if (surfaceMinLevel > cellLevel[own]) - { - if + // Neighbour needs refining + if + ( + !markForRefine ( - !markForRefine - ( - surfI, - nAllowRefine, - refineCell[own], - nRefine - ) + surfI, + nAllowRefine, + refineCell[nei], + nRefine ) - { - break; - } + ) + { + break; } } } } } - if (faceI < surfaceIndex_.size()) + if + ( + returnReduce(nRefine, sumOp<label>()) + > returnReduce(nAllowRefine, sumOp<label>()) + ) { - if (debug) - { - Pout<< "Stopped refining since reaching my cell limit of " - << mesh_.nCells()+7*nRefine << endl; - } + Info<< "Reached refinement limit." << endl; } return returnReduce(nRefine-oldNRefine, sumOp<label>()); } -// Given intersection of (face of) cell by newSurfI, newTriI, check whether -// it needs to be refined. Updates maxCellSurf, maxCellTri and -// refineCell,nRefine if it decides to refine the cell. Returns false -// if the nRefine limit has been reached, true otherwise. +// Checks if multiple intersections of a cell (by a surface with a higher +// max than the cell level) and if so if the normals at these intersections +// make a large angle. +// Returns false if the nRefine limit has been reached, true otherwise. bool Foam::meshRefinement::checkCurvature ( - const labelList& globalToPatch, const scalar curvature, - const bool markDifferingRegions, const label nAllowRefine, - const label newSurfI, - const label newTriI, + const label surfaceLevel, // current intersection max level + const vector& surfaceNormal,// current intersection normal const label cellI, - label& maxCellSurfI, - label& maxCellTriI, + label& cellMaxLevel, // cached max surface level for this cell + vector& cellMaxNormal, // cached surface normal for this cell labelList& refineCell, label& nRefine @@ -721,59 +736,35 @@ bool Foam::meshRefinement::checkCurvature { const labelList& cellLevel = meshCutter_.cellLevel(); - if (maxCellSurfI == -1) - { - // First visit of cell. Store - maxCellSurfI = newSurfI; - maxCellTriI = newTriI; - } - else + // Test if surface applicable + if (surfaceLevel > cellLevel[cellI]) { - // Second or more visit. - label cellRegion = surfaces_.triangleRegion(maxCellSurfI, maxCellTriI); - label newRegion = surfaces_.triangleRegion(newSurfI, newTriI); - - // Update max - label maxLevel = surfaces_.maxLevel()[cellRegion]; - - if (surfaces_.maxLevel()[newRegion] > maxLevel) + if (cellMaxLevel == -1) { - maxCellSurfI = newSurfI; - maxCellTriI = newTriI; - maxLevel = surfaces_.maxLevel()[newRegion]; + // First visit of cell. Store + cellMaxLevel = surfaceLevel; + cellMaxNormal = surfaceNormal; } - - - // Check if cell is candidate for refinement - if (cellLevel[cellI] < maxLevel) + else { - // Test 1: different regions - if (markDifferingRegions && cellRegion != newRegion) + // Second or more visit. Check curvature. + if ((cellMaxNormal & surfaceNormal) < curvature) { return markForRefine ( - globalToPatch[newRegion], // mark with non-neg number. + surfaceLevel, // mark with any non-neg number. nAllowRefine, refineCell[cellI], nRefine ); } - // Test 2: different normals - const vector& cellN = - surfaces_[maxCellSurfI].faceNormals()[maxCellTriI]; - const vector& newN = - surfaces_[newSurfI].faceNormals()[newTriI]; - - if ((cellN & newN) < curvature) + // Set normal to that of highest surface. Not really necessary + // over here but we reuse cellMax info when doing coupled faces. + if (surfaceLevel > cellMaxLevel) { - return markForRefine - ( - globalToPatch[newRegion], // mark with non-neg number. - nAllowRefine, - refineCell[cellI], - nRefine - ); + cellMaxLevel = surfaceLevel; + cellMaxNormal = surfaceNormal; } } } @@ -786,9 +777,7 @@ bool Foam::meshRefinement::checkCurvature // Mark cells for surface curvature based refinement. Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement ( - const labelList& globalToPatch, const scalar curvature, - const bool markDifferingRegions, const label nAllowRefine, const labelList& neiLevel, const pointField& neiCc, @@ -802,107 +791,117 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement label oldNRefine = nRefine; - // 1. Any cell on more than one surface gets refined (if its current level - // is <= max of the surface max level) - - // 2. Any cell on only one surface with a neighbour on a different surface - // gets refined (if its current level etc.) + // 1. local test: any cell on more than one surface gets refined + // (if its current level is < max of the surface max level) + // 2. 'global' test: any cell on only one surface with a neighbour + // on a different surface gets refined (if its current level etc.) - // Index of surface with the max maxLevel and the actual triangle - // on the surface. We store these and not e.g. global region so we can get - // at: - // - global region - // - global patch - // - face normal - labelList cellMaxSurface(mesh_.nCells(), -1); - labelList cellMaxTriangle(mesh_.nCells(), -1); + // Collect candidate faces (i.e. intersecting any surface and + // owner/neighbour not yet refined. + labelList testFaces(getRefineCandidateFaces(refineCell)); - // 1. + // Collect segments + pointField start(testFaces.size()); + pointField end(testFaces.size()); + labelList minLevel(testFaces.size()); - forAll(surfaceIndex_, faceI) + forAll(testFaces, i) { - if (surfaceIndex_[faceI] != -1) + label faceI = testFaces[i]; + + label own = mesh_.faceOwner()[faceI]; + + if (mesh_.isInternalFace(faceI)) { - label own = mesh_.faceOwner()[faceI]; + label nei = mesh_.faceNeighbour()[faceI]; - // There is an intersection. Do more accurate test to get all - // intersections - labelList surfaceIndices; - List<pointIndexHit> hits; + start[i] = cellCentres[own]; + end[i] = cellCentres[nei]; + minLevel[i] = min(cellLevel[own], cellLevel[nei]); + } + else + { + label bFaceI = faceI - mesh_.nInternalFaces(); - if (mesh_.isInternalFace(faceI)) - { - label nei = mesh_.faceNeighbour()[faceI]; + start[i] = cellCentres[own]; + end[i] = neiCc[bFaceI]; + minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]); + } + } - surfaces_.findAllIntersections - ( - cellCentres[own], - cellCentres[nei], - surfaceIndices, - hits - ); - } - else - { - label bFaceI = faceI - mesh_.nInternalFaces(); + // Test for all intersections (with surfaces of higher max level than + // minLevel) and cache per cell the max surface level and the local normal + // on that surface. + labelList cellMaxLevel(mesh_.nCells(), -1); + vectorField cellMaxNormal(mesh_.nCells()); - surfaces_.findAllIntersections - ( - cellCentres[own], - neiCc[bFaceI], - surfaceIndices, - hits - ); - } + { + // Per segment the normals of the surfaces + List<vectorList> surfaceNormal; + // Per segment the list of levels of the surfaces + labelListList surfaceLevel; + surfaces_.findAllHigherIntersections + ( + start, + end, + minLevel, // max level of surface has to be bigger + // than min level of neighbouring cells + surfaceNormal, + surfaceLevel + ); + // Clear out unnecessary data + start.clear(); + end.clear(); + minLevel.clear(); - // See if intersection adds any new information to the owner or - // neighbour cell. + // Extract per cell information on the surface with the highest max + forAll(testFaces, i) + { + label faceI = testFaces[i]; + label own = mesh_.faceOwner()[faceI]; - forAll(surfaceIndices, i) - { - label surfI = surfaceIndices[i]; - label triI = hits[i].index(); + const vectorList& fNormals = surfaceNormal[i]; + const labelList& fLevels = surfaceLevel[i]; + forAll(fLevels, hitI) + { checkCurvature ( - globalToPatch, curvature, - markDifferingRegions, nAllowRefine, - surfI, - triI, + fLevels[hitI], + fNormals[hitI], own, - - cellMaxSurface[own], - cellMaxTriangle[own], + cellMaxLevel[own], + cellMaxNormal[own], refineCell, nRefine ); + } - if (mesh_.isInternalFace(faceI)) - { - label nei = mesh_.faceNeighbour()[faceI]; + if (mesh_.isInternalFace(faceI)) + { + label nei = mesh_.faceNeighbour()[faceI]; + forAll(fLevels, hitI) + { checkCurvature ( - globalToPatch, curvature, - markDifferingRegions, nAllowRefine, - surfI, - triI, + fLevels[hitI], + fNormals[hitI], nei, - - cellMaxSurface[nei], - cellMaxTriangle[nei], + cellMaxLevel[nei], + cellMaxNormal[nei], refineCell, nRefine @@ -910,93 +909,46 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement } } } - - if (nRefine > nAllowRefine) - { - if (debug) - { - Pout<< "Stopped refining since reaching my cell limit of " - << mesh_.nCells()+7*nRefine << endl; - } - break; - } } // 2. Find out a measure of surface curvature and region edges. // Send over surface region and surface normal to neighbour cell. - // global region - labelList ownRegion(mesh_.nFaces(), -1); - labelList neiRegion(mesh_.nFaces(), -1); - // local normal at hit - vectorField ownNormal(mesh_.nFaces(), vector::zero); - vectorField neiNormal(mesh_.nFaces(), vector::zero); - - // Internal faces - for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++) - { - label own = mesh_.faceOwner()[faceI]; - - if (cellMaxSurface[own] != -1) - { - label surfI = cellMaxSurface[own]; - label triI = cellMaxTriangle[own]; - - ownRegion[faceI] = surfaces_.triangleRegion(surfI, triI); - ownNormal[faceI] = surfaces_[surfI].faceNormals()[triI]; - } - - label nei = mesh_.faceNeighbour()[faceI]; + labelList neiBndMaxLevel(mesh_.nFaces()-mesh_.nInternalFaces()); + vectorField neiBndMaxNormal(mesh_.nFaces()-mesh_.nInternalFaces()); - if (cellMaxSurface[nei] != -1) - { - label surfI = cellMaxSurface[nei]; - label triI = cellMaxTriangle[nei]; - - neiRegion[faceI] = surfaces_.triangleRegion(surfI, triI); - neiNormal[faceI] = surfaces_[surfI].faceNormals()[triI]; - } - } - // Boundary faces for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++) { + label bFaceI = faceI-mesh_.nInternalFaces(); label own = mesh_.faceOwner()[faceI]; - if (cellMaxSurface[own] != -1) - { - label surfI = cellMaxSurface[own]; - label triI = cellMaxTriangle[own]; - - ownRegion[faceI] = surfaces_.triangleRegion(surfI, triI); - ownNormal[faceI] = surfaces_[surfI].faceNormals()[triI]; - - neiRegion[faceI] = ownRegion[faceI]; - neiNormal[faceI] = ownNormal[faceI]; - } + neiBndMaxLevel[bFaceI] = cellMaxLevel[own]; + neiBndMaxNormal[bFaceI] = cellMaxNormal[own]; } + syncTools::swapBoundaryFaceList(mesh_, neiBndMaxLevel, false); + syncTools::swapBoundaryFaceList(mesh_, neiBndMaxNormal, false); - syncTools::swapFaceList(mesh_, neiRegion, false); - syncTools::swapFaceList(mesh_, neiNormal, false); + // Loop over all faces. Could only be checkFaces.. except if they're coupled - for (label faceI = 0; faceI < mesh_.nFaces(); faceI++) + // Internal faces + for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++) { - if (ownRegion[faceI] != -1 && neiRegion[faceI] != -1) + label own = mesh_.faceOwner()[faceI]; + label nei = mesh_.faceNeighbour()[faceI]; + + if (cellMaxLevel[own] != -1 && cellMaxLevel[nei] != -1) { - if - ( - (markDifferingRegions && (ownRegion[faceI] != neiRegion[faceI])) - || ((ownNormal[faceI] & neiNormal[faceI]) < curvature) - ) + // Have valid data on both sides. Check curvature. + if ((cellMaxNormal[own] & cellMaxNormal[nei]) < curvature) { - label own = mesh_.faceOwner()[faceI]; - - if (cellLevel[own] < surfaces_.maxLevel()[ownRegion[faceI]]) + // See which side to refine + if (cellLevel[own] < cellMaxLevel[own]) { if ( !markForRefine ( - globalToPatch[ownRegion[faceI]], + cellMaxLevel[own], nAllowRefine, refineCell[own], nRefine @@ -1011,46 +963,77 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement } break; } - } - if (mesh_.isInternalFace(faceI)) + if (cellLevel[nei] < cellMaxLevel[nei]) { - label nei = mesh_.faceNeighbour()[faceI]; - - if (cellLevel[nei] < surfaces_.maxLevel()[neiRegion[faceI]]) - { - if + if + ( + !markForRefine ( - !markForRefine - ( - globalToPatch[neiRegion[faceI]], - nAllowRefine, - - refineCell[nei], - nRefine - ) + cellMaxLevel[nei], + nAllowRefine, + refineCell[nei], + nRefine ) + ) + { + if (debug) { - if (debug) - { - Pout<< "Stopped refining since reaching my cell" - << " limit of " << mesh_.nCells()+7*nRefine - << endl; - } - break; + Pout<< "Stopped refining since reaching my cell" + << " limit of " << mesh_.nCells()+7*nRefine + << endl; } + break; } } } } } + // Boundary faces + for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++) + { + label own = mesh_.faceOwner()[faceI]; + label bFaceI = faceI - mesh_.nInternalFaces(); + if (cellLevel[own] < cellMaxLevel[own] && neiBndMaxLevel[bFaceI] != -1) + { + // Have valid data on both sides. Check curvature. + if ((cellMaxNormal[own] & neiBndMaxNormal[bFaceI]) < curvature) + { + if + ( + !markForRefine + ( + cellMaxLevel[own], + nAllowRefine, + refineCell[own], + nRefine + ) + ) + { + if (debug) + { + Pout<< "Stopped refining since reaching my cell" + << " limit of " << mesh_.nCells()+7*nRefine + << endl; + } + break; + } + } + } + } - return returnReduce(nRefine-oldNRefine, sumOp<label>()); - label totNRefined = returnReduce(totNRefined, sumOp<label>()); + if + ( + returnReduce(nRefine, sumOp<label>()) + > returnReduce(nAllowRefine, sumOp<label>()) + ) + { + Info<< "Reached refinement limit." << endl; + } - return totNRefined; + return returnReduce(nRefine-oldNRefine, sumOp<label>()); } @@ -1064,16 +1047,11 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement Foam::labelList Foam::meshRefinement::refineCandidates ( const point& keepPoint, - const labelList& globalToPatch, const scalar curvature, const PtrList<featureEdgeMesh>& featureMeshes, const labelList& featureLevels, - const PtrList<searchableSurface>& shells, - const labelList& shellLevels, - const boolList& shellRefineInside, - const bool featureRefinement, const bool internalRefinement, const bool surfaceRefinement, @@ -1086,7 +1064,12 @@ Foam::labelList Foam::meshRefinement::refineCandidates labelList cellsToRefine; - if (totNCells < maxGlobalCells) + if (totNCells >= maxGlobalCells) + { + Info<< "No cells marked for refinement since reached limit " + << maxGlobalCells << '.' << endl; + } + else { // Every cell I refine adds 7 cells. Estimate the number of cells // I am allowed to refine. @@ -1151,9 +1134,6 @@ Foam::labelList Foam::meshRefinement::refineCandidates { label nShell = markInternalRefinement ( - shells, - shellLevels, - shellRefineInside, nAllowRefine, refineCell, @@ -1184,13 +1164,11 @@ Foam::labelList Foam::meshRefinement::refineCandidates // Refinement based on curvature of surface // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - if (curvatureRefinement) + if (curvatureRefinement && (curvature >= -1 && curvature <= 1)) { label nCurv = markSurfaceCurvatureRefinement ( - globalToPatch, curvature, - false, // do not refine at multiple regions nAllowRefine, neiLevel, neiCc, @@ -1287,28 +1265,6 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> printMeshInfo(debug, "After refinement " + msg); - //// Remove cells which are inside closed surfaces - //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // - //if (findIndex(surfaces.closed(), true) != -1) - //{ - // Info<< "Removing cells fully inside closed surfaces." - // << endl; - // removeInsideCells - // ( - // msg, // refinement iteration for statistics only - // exposedFacesPatch // patch to use for exposed internal faces - // ); - // Info<< "Removed inside cells in = " - // << mesh_.time().cpuTimeIncrement() << " s" << endl; - // if (debug) - // { - // // test all is still synced across proc patches - // checkData(); - // } - //} - - // Load balancing // ~~~~~~~~~~~~~~ diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C index 83816314a7cdc674876b41d03f47239bd831b171..ce09e597e2480c80f1583778639ff7899aac5b57 100644 --- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C +++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C @@ -27,25 +27,17 @@ License #include "refinementSurfaces.H" #include "orientedSurface.H" #include "Time.H" -#include "searchableSurface.H" +#include "searchableSurfaces.H" +#include "shellSurfaces.H" +#include "triSurfaceMesh.H" +#include "labelPair.H" +#include "searchableSurfacesQueries.H" + // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -Foam::fileNameList Foam::refinementSurfaces::extractFileNames -( - const PtrList<dictionary>& surfaceDicts -) -{ - fileNameList surfaceFileNames(surfaceDicts.size()); - - forAll(surfaceDicts, i) - { - surfaceFileNames[i] = fileName(surfaceDicts[i].lookup("file")); - } - return surfaceFileNames; -} +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // @@ -53,13 +45,13 @@ Foam::fileNameList Foam::refinementSurfaces::extractFileNames // Construct from components Foam::refinementSurfaces::refinementSurfaces ( - const IOobject& io, + const searchableSurfaces& allGeometry, const PtrList<dictionary>& surfaceDicts ) : - triSurfaceMeshes(io, extractFileNames(surfaceDicts)), + allGeometry_(allGeometry), + surfaces_(surfaceDicts.size()), names_(surfaceDicts.size()), - closed_(surfaceDicts.size(), true), faceZoneNames_(surfaceDicts.size()), cellZoneNames_(surfaceDicts.size()), zoneInside_(surfaceDicts.size()), @@ -67,29 +59,25 @@ Foam::refinementSurfaces::refinementSurfaces { labelList globalMinLevel(surfaceDicts.size(), 0); labelList globalMaxLevel(surfaceDicts.size(), 0); - List<HashTable<label> > regionMinLevel(surfaceDicts.size()); - List<HashTable<label> > regionMaxLevel(surfaceDicts.size()); + List<Map<label> > regionMinLevel(surfaceDicts.size()); + List<Map<label> > regionMaxLevel(surfaceDicts.size()); - labelList globalSurfLayers(surfaceDicts.size()); - List<HashTable<label> > regionSurfLayers(surfaceDicts.size()); - - wordList globalPatchType(surfaceDicts.size()); - List<HashTable<word> > regionPatchType(surfaceDicts.size()); - List<HashTable<word> > regionPatchName(surfaceDicts.size()); + //wordList globalPatchType(surfaceDicts.size()); + //List<HashTable<word> > regionPatchType(surfaceDicts.size()); + //List<HashTable<word> > regionPatchName(surfaceDicts.size()); forAll(surfaceDicts, surfI) { const dictionary& dict = surfaceDicts[surfI]; - names_[surfI] = word(dict.lookup("name")); + dict.lookup("name") >> names_[surfI]; + + surfaces_[surfI] = allGeometry_.findSurfaceID(names_[surfI]); // Global refinement level globalMinLevel[surfI] = readLabel(dict.lookup("minRefinementLevel")); globalMaxLevel[surfI] = readLabel(dict.lookup("maxRefinementLevel")); - // Global number of layers - globalSurfLayers[surfI] = readLabel(dict.lookup("surfaceLayers")); - // Global zone names per surface if (dict.found("faceZone")) { @@ -98,50 +86,62 @@ Foam::refinementSurfaces::refinementSurfaces dict.lookup("zoneInside") >> zoneInside_[surfI]; } - // Global patch name per surface - if (dict.found("patchType")) - { - dict.lookup("patchType") >> globalPatchType[surfI]; - } + //// Global patch name per surface + //if (dict.found("patchType")) + //{ + // dict.lookup("patchType") >> globalPatchType[surfI]; + //} if (dict.found("regions")) { PtrList<dictionary> regionDicts(dict.lookup("regions")); + const wordList& regionNames = + allGeometry_[surfaces_[surfI]].regions(); + forAll(regionDicts, dictI) { const dictionary& regionDict = regionDicts[dictI]; const word regionName(regionDict.lookup("name")); - label min = readLabel(regionDict.lookup("minRefinementLevel")); - label max = readLabel(regionDict.lookup("maxRefinementLevel")); - regionMinLevel[surfI].insert(regionName, min); - regionMaxLevel[surfI].insert(regionName, max); + label regionI = findIndex(regionNames, regionName); - label nLayers = readLabel(regionDict.lookup("surfaceLayers")); - regionSurfLayers[surfI].insert(regionName, nLayers); - - if (regionDict.found("patchType")) + if (regionI == -1) { - regionPatchType[surfI].insert + FatalErrorIn ( - regionName, - regionDict.lookup("patchType") - ); - regionPatchName[surfI].insert + "refinementSurfaces::refinementSurfaces" + "(const IOobject&, const PtrList<dictionary>&)" + ) << "No region called " << regionName << " on surface " + << allGeometry_[surfaces_[surfI]].name() << endl + << "Valid regions are " << regionNames + << exit(FatalError); + } + + + label min = readLabel(regionDict.lookup("minRefinementLevel")); + label max = readLabel(regionDict.lookup("maxRefinementLevel")); + + bool hasInserted = regionMinLevel[surfI].insert(regionI, min); + if (!hasInserted) + { + FatalErrorIn ( - regionName, - regionDict.lookup("patchName") - ); + "refinementSurfaces::refinementSurfaces" + "(const IOobject&, const PtrList<dictionary>&)" + ) << "Duplicate region name " << regionName + << " on surface " << names_[surfI] + << exit(FatalError); } + regionMaxLevel[surfI].insert(regionI, max); } } } - // Check for duplicate surface or region names + // Check for duplicate surface names { HashTable<label> surfaceNames(names_.size()); @@ -158,57 +158,173 @@ Foam::refinementSurfaces::refinementSurfaces << surfaceNames[names_[surfI]] << exit(FatalError); } + } + } + + // Calculate local to global region offset + label nRegions = 0; + + forAll(surfaceDicts, surfI) + { + regionOffset_[surfI] = nRegions; + + nRegions += allGeometry_[surfaces_[surfI]].regions().size(); + } + + // Rework surface specific information into information per global region + minLevel_.setSize(nRegions); + minLevel_ = 0; + maxLevel_.setSize(nRegions); + maxLevel_ = 0; + //patchName_.setSize(nRegions); + //patchType_.setSize(nRegions); + + forAll(surfaceDicts, surfI) + { + label nRegions = allGeometry_[surfaces_[surfI]].regions().size(); + + // Initialise to global (i.e. per surface) + for (label i = 0; i < nRegions; i++) + { + minLevel_[regionOffset_[surfI] + i] = globalMinLevel[surfI]; + maxLevel_[regionOffset_[surfI] + i] = globalMaxLevel[surfI]; + } - // Check for duplicate region names - const geometricSurfacePatchList& patches = - operator[](surfI).patches(); + // Overwrite with region specific information + forAllConstIter(Map<label>, regionMinLevel[surfI], iter) + { + label globalRegionI = regionOffset_[surfI] + iter.key(); - HashTable<label> regionNames(patches.size()); - forAll(patches, i) + minLevel_[globalRegionI] = iter(); + maxLevel_[globalRegionI] = regionMaxLevel[surfI][iter.key()]; + + // Check validity + if + ( + minLevel_[globalRegionI] < 0 + || maxLevel_[globalRegionI] < minLevel_[globalRegionI] + ) { - if (!regionNames.insert(patches[i].name(), i)) - { - FatalErrorIn - ( - "refinementSurfaces::refinementSurfaces" - "(const IOobject&, const PtrList<dictionary>&)" - ) << "Duplicate region name " << patches[i].name() - << " on surface " << names_[surfI] << endl - << "Previous occurrence of region at index " - << regionNames[patches[i].name()] - << exit(FatalError); - } + FatalErrorIn + ( + "refinementSurfaces::refinementSurfaces" + "(const IOobject&, const PtrList<dictionary>&)" + ) << "Illegal level or layer specification for surface " + << names_[surfI] + << " : minLevel:" << minLevel_[globalRegionI] + << " maxLevel:" << maxLevel_[globalRegionI] + << exit(FatalError); } } + + //// Optional patch names and patch types + //forAllConstIter(HashTable<word>, regionPatchName[surfI], iter) + //{ + // label regionI = findIndex(regionNames, iter.key()); + // label globalRegionI = regionOffset_[surfI] + regionI; + // + // patchName_[globalRegionI] = iter(); + // patchType_[globalRegionI] = regionPatchType[surfI][iter.key()]; + //} } +} + +Foam::refinementSurfaces::refinementSurfaces +( + const searchableSurfaces& allGeometry, + const dictionary& surfacesDict +) +: + allGeometry_(allGeometry), + surfaces_(surfacesDict.size()), + names_(surfacesDict.size()), + faceZoneNames_(surfacesDict.size()), + cellZoneNames_(surfacesDict.size()), + zoneInside_(surfacesDict.size()), + regionOffset_(surfacesDict.size()) +{ + labelList globalMinLevel(surfacesDict.size(), 0); + labelList globalMaxLevel(surfacesDict.size(), 0); + List<Map<label> > regionMinLevel(surfacesDict.size()); + List<Map<label> > regionMaxLevel(surfacesDict.size()); - // Calculate closedness - forAll(closed_, surfI) + label surfI = 0; + forAllConstIter(dictionary, surfacesDict, iter) { - const triSurface& s = operator[](surfI); + names_[surfI] = iter().keyword(); + + surfaces_[surfI] = allGeometry_.findSurfaceID(names_[surfI]); - const labelListList& edgeFaces = s.edgeFaces(); + if (surfaces_[surfI] == -1) + { + FatalErrorIn + ( + "refinementSurfaces::refinementSurfaces" + "(const searchableSurfaces&, const dictionary>&" + ) << "No surface called " << iter().keyword() << endl + << "Valid surfaces are " << allGeometry_.names() + << exit(FatalError); + } + const dictionary& dict = surfacesDict.subDict(iter().keyword()); + + const labelPair refLevel(dict.lookup("level")); + globalMinLevel[surfI] = refLevel[0]; + globalMaxLevel[surfI] = refLevel[1]; + + // Global zone names per surface + if (dict.found("faceZone")) + { + dict.lookup("faceZone") >> faceZoneNames_[surfI]; + dict.lookup("cellZone") >> cellZoneNames_[surfI]; + dict.lookup("zoneInside") >> zoneInside_[surfI]; + } - forAll(edgeFaces, edgeI) + if (dict.found("regions")) { - if (edgeFaces[edgeI].size() != 2) + const dictionary& regionsDict = dict.subDict("regions"); + const wordList& regionNames = + allGeometry_[surfaces_[surfI]].regions(); + + forAllConstIter(dictionary, regionsDict, iter) { - closed_[surfI] = false; - break; + const word& key = iter().keyword(); + + if (regionsDict.isDict(key)) + { + // Get the dictionary for region iter.keyword() + const dictionary& regionDict = regionsDict.subDict(key); + + label regionI = findIndex(regionNames, key); + if (regionI == -1) + { + FatalErrorIn + ( + "refinementSurfaces::refinementSurfaces" + "(const searchableSurfaces&, const dictionary>&" + ) << "No region called " << key << " on surface " + << allGeometry_[surfaces_[surfI]].name() << endl + << "Valid regions are " << regionNames + << exit(FatalError); + } + + const labelPair refLevel(regionDict.lookup("level")); + + regionMinLevel[surfI].insert(regionI, refLevel[0]); + regionMaxLevel[surfI].insert(regionI, refLevel[1]); + } } } + surfI++; } - // Calculate local to global region offset label nRegions = 0; - forAll(surfaceDicts, surfI) + forAll(surfacesDict, surfI) { regionOffset_[surfI] = nRegions; - - nRegions += operator[](surfI).patches().size(); + nRegions += allGeometry_[surfaces_[surfI]].regions().size(); } // Rework surface specific information into information per global region @@ -216,92 +332,52 @@ Foam::refinementSurfaces::refinementSurfaces minLevel_ = 0; maxLevel_.setSize(nRegions); maxLevel_ = 0; - numLayers_.setSize(nRegions); - numLayers_ = 0; - patchName_.setSize(nRegions); - patchType_.setSize(nRegions); - forAll(surfaceDicts, surfI) + + forAll(globalMinLevel, surfI) { - const geometricSurfacePatchList& regions = operator[](surfI).patches(); + label nRegions = allGeometry_[surfaces_[surfI]].regions().size(); // Initialise to global (i.e. per surface) - forAll(regions, i) + for (label i = 0; i < nRegions; i++) { minLevel_[regionOffset_[surfI] + i] = globalMinLevel[surfI]; maxLevel_[regionOffset_[surfI] + i] = globalMaxLevel[surfI]; - numLayers_[regionOffset_[surfI] + i] = globalSurfLayers[surfI]; - patchType_[regionOffset_[surfI] + i] = globalPatchType[surfI]; - } - - // Get the region names - wordList regionNames(regions.size()); - forAll(regions, regionI) - { - regionNames[regionI] = regions[regionI].name(); } // Overwrite with region specific information - forAllConstIter(HashTable<label>, regionMinLevel[surfI], iter) + forAllConstIter(Map<label>, regionMinLevel[surfI], iter) { - // Find the local region number. - label regionI = findIndex(regionNames, iter.key()); - - if (regionI == -1) - { - FatalErrorIn - ( - "refinementSurfaces::refinementSurfaces" - "(const IOobject&, const PtrList<dictionary>&)" - ) << "Cannot find region " << iter.key() - << " in surface " << names_[surfI] - << " which has regions " << regionNames - << abort(FatalError); - } - - label globalRegionI = regionOffset_[surfI] + regionI; + label globalRegionI = regionOffset_[surfI] + iter.key(); minLevel_[globalRegionI] = iter(); maxLevel_[globalRegionI] = regionMaxLevel[surfI][iter.key()]; - numLayers_[globalRegionI] = regionSurfLayers[surfI][iter.key()]; // Check validity if ( minLevel_[globalRegionI] < 0 || maxLevel_[globalRegionI] < minLevel_[globalRegionI] - || numLayers_[globalRegionI] < 0 ) { FatalErrorIn ( "refinementSurfaces::refinementSurfaces" - "(const IOobject&, const PtrList<dictionary>&)" + "(const searchableSurfaces&, const dictionary>&" ) << "Illegal level or layer specification for surface " << names_[surfI] << " : minLevel:" << minLevel_[globalRegionI] << " maxLevel:" << maxLevel_[globalRegionI] - << " numLayers:" << numLayers_[globalRegionI] << exit(FatalError); } } - - // Optional patch names and patch types - forAllConstIter(HashTable<word>, regionPatchName[surfI], iter) - { - label regionI = findIndex(regionNames, iter.key()); - label globalRegionI = regionOffset_[surfI] + regionI; - - patchName_[globalRegionI] = iter(); - patchType_[globalRegionI] = regionPatchType[surfI][iter.key()]; - } } } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -//- Get indices of named surfaces (surfaces with cellZoneNam) +// Get indices of named surfaces (surfaces with cellZoneName) Foam::labelList Foam::refinementSurfaces::getNamedSurfaces() const { labelList namedSurfaces(cellZoneNames_.size()); @@ -320,16 +396,26 @@ Foam::labelList Foam::refinementSurfaces::getNamedSurfaces() const } -bool Foam::refinementSurfaces::isSurfaceClosed(const triSurface& s) +// Get indices of closed named surfaces +Foam::labelList Foam::refinementSurfaces::getClosedNamedSurfaces() const { - if (s.nEdges() == s.nInternalEdges()) - { - return true; - } - else + labelList named(getNamedSurfaces()); + + labelList closed(named.size()); + label closedI = 0; + + forAll(named, i) { - return false; + label surfI = named[i]; + + if (allGeometry_[surfaces_[surfI]].hasVolumeType()) + { + closed[closedI++] = surfI; + } } + closed.setSize(closedI); + + return closed; } @@ -373,238 +459,475 @@ Foam::labelList Foam::refinementSurfaces::countRegions(const triSurface& s) } -// Find intersections of edge. Return -1 or first surface with higher minLevel -// number. -Foam::label Foam::refinementSurfaces::findHigherIntersection +// Precalculate the refinement level for every element of the searchable +// surface. This is currently hardcoded for triSurfaceMesh only. +void Foam::refinementSurfaces::setMinLevelFields ( - const point& start, - const point& end, - const label currentLevel, // current cell refinement level - - pointIndexHit& hit -) const + const shellSurfaces& shells +) { - forAll(*this, surfI) + minLevelFields_.setSize(surfaces_.size()); + + forAll(surfaces_, surfI) { - hit = operator[](surfI).findLineAny(start, end); + const searchableSurface& geom = allGeometry_[surfaces_[surfI]]; - if (hit.hit()) + if (isA<triSurfaceMesh>(geom)) { - if (currentLevel == -1) + const triSurfaceMesh& triMesh = refCast<const triSurfaceMesh>(geom); + + minLevelFields_.set + ( + surfI, + new triSurfaceLabelField + ( + IOobject + ( + triMesh.searchableSurface::name(), + triMesh.objectRegistry::time().constant(),// directory + "triSurface", // instance + triMesh, + IOobject::NO_READ, + IOobject::AUTO_WRITE, + false + ), + triMesh, + dimless + ) + ); + triSurfaceLabelField& minLevelField = minLevelFields_[surfI]; + + const triSurface& s = static_cast<const triSurface&>(triMesh); + + // Initialise fields to region wise minLevel + forAll(s, triI) { - // Return any. - return surfI; + minLevelField[triI] = minLevel(surfI, s[triI].region()); } - else + + // Find out if triangle inside shell with higher level + pointField fc(s.size()); + forAll(s, triI) { - //const triSurface& s = trees()[surfI].shapes().surface(); - //label region = globalRegion(surfI, s[hit.index()].region()); - //if (minLevel_[region] > currentLevel) - if (minLevelFields_[surfI][hit.index()] > currentLevel) - { - return surfI; - } + fc[triI] = s[triI].centre(s.points()); + } + // What level does shell want to refine fc to? + labelList shellLevel; + shells.findHigherLevel(fc, minLevelField, shellLevel); + + forAll(minLevelField, triI) + { + minLevelField[triI] = max + ( + minLevelField[triI], + shellLevel[triI] + ); } } } - - hit.setMiss(); - - return -1; } -// Find intersection with max of edge. Return -1 or the surface -// with the highest maxLevel above currentLevel -Foam::label Foam::refinementSurfaces::findHighestIntersection +// Find intersections of edge. Return -1 or first surface with higher minLevel +// number. +void Foam::refinementSurfaces::findHigherIntersection ( - const point& start, - const point& end, - const label currentLevel, // current cell refinement level + const pointField& start, + const pointField& end, + const labelList& currentLevel, // current cell refinement level - pointIndexHit& maxHit + labelList& surfaces, + labelList& surfaceLevel ) const { - // surface with highest maxlevel - label maxSurface = -1; - // maxLevel of maxSurface - label maxLevel = currentLevel; + surfaces.setSize(start.size()); + surfaces = -1; + surfaceLevel.setSize(start.size()); + surfaceLevel = -1; + + if (surfaces_.size() == 0) + { + return; + } + + // Work arrays + labelList hitMap(identity(start.size())); + pointField p0(start); + pointField p1(end); + List<pointIndexHit> hitInfo(start.size()); - forAll(*this, surfI) + + forAll(surfaces_, surfI) { - pointIndexHit hit = operator[](surfI).findLineAny(start, end); + allGeometry_[surfaces_[surfI]].findLineAny(p0, p1, hitInfo); - if (hit.hit()) + // Copy all hits into arguments, continue with misses + label newI = 0; + forAll(hitInfo, hitI) { - const triSurface& s = operator[](surfI); + // Get the minLevel for the point + label minLocalLevel = -1; + + if (hitInfo[hitI].hit()) + { + // Check if minLevelField for this surface. + if + ( + minLevelFields_.set(surfI) + && minLevelFields_[surfI].size() > 0 + ) + { + minLocalLevel = + minLevelFields_[surfI][hitInfo[hitI].index()]; + } + else + { + // Use the min level for the surface instead. Assume + // single region 0. + minLocalLevel = minLevel(surfI, 0); + } + } - label region = globalRegion(surfI, s[hit.index()].region()); + label pointI = hitMap[hitI]; - if (maxLevel_[region] > maxLevel) + if (minLocalLevel > currentLevel[pointI]) + { + surfaces[pointI] = surfI; + surfaceLevel[pointI] = minLocalLevel; + } + else { - maxSurface = surfI; - maxLevel = maxLevel_[region]; - maxHit = hit; + if (hitI != newI) + { + hitMap[newI] = hitMap[hitI]; + p0[newI] = p0[hitI]; + p1[newI] = p1[hitI]; + } + newI++; } } - } - if (maxSurface == -1) - { - // maxLevel unchanged. No interesting surface hit. - maxHit.setMiss(); - } + // All done? Note that this decision should be synchronised + if (newI == 0) + { + break; + } - return maxSurface; + // Trim and continue + hitMap.setSize(newI); + p0.setSize(newI); + p1.setSize(newI); + hitInfo.setSize(newI); + } } -Foam::label Foam::refinementSurfaces::insideZone +void Foam::refinementSurfaces::findAllHigherIntersections ( - const labelList& surfaces, - const point& pt + const pointField& start, + const pointField& end, + const labelList& currentLevel, // current cell refinement level + + List<vectorList>& surfaceNormal, + labelListList& surfaceLevel ) const { - forAll(surfaces, i) + surfaceLevel.setSize(start.size()); + surfaceNormal.setSize(start.size()); + + if (surfaces_.size() == 0) { - label surfI = surfaces[i]; + return; + } + + // Work arrays + List<List<pointIndexHit> > hitInfo; + labelList pRegions; + vectorField pNormals; + + forAll(surfaces_, surfI) + { + allGeometry_[surfaces_[surfI]].findLineAll(start, end, hitInfo); - if (closed_[surfI]) + forAll(hitInfo, pointI) { - const triSurfaceMesh& s = operator[](surfI); + const List<pointIndexHit>& pHits = hitInfo[pointI]; + allGeometry_[surfaces_[surfI]].getRegion(pHits, pRegions); + allGeometry_[surfaces_[surfI]].getNormal(pHits, pNormals); - triSurfaceMesh::volumeType t = s.getVolumeType(pt); + // Extract those hits that are on higher levelled surfaces. + // Note: should move extraction of region, normal outside of loop + // below for if getRegion/getNormal have high overhead. - if - ( - (t == triSurfaceMesh::INSIDE && zoneInside_[surfI]) - || (t == triSurfaceMesh::OUTSIDE && !zoneInside_[surfI]) - ) + forAll(pHits, pHitI) { - return surfI; + label region = globalRegion(surfI, pRegions[pHitI]); + + if (maxLevel_[region] > currentLevel[pointI]) + { + // Append to pointI info + label sz = surfaceNormal[pointI].size(); + surfaceNormal[pointI].setSize(sz+1); + surfaceNormal[pointI][sz] = pNormals[pHitI]; + + surfaceLevel[pointI].setSize(sz+1); + surfaceLevel[pointI][sz] = maxLevel_[region]; + } } } } - return -1; } -Foam::label Foam::refinementSurfaces::markInsidePoints +void Foam::refinementSurfaces::findNearestIntersection ( - const pointField& points, - PackedList<1>& isInside + const labelList& surfacesToTest, + const pointField& start, + const pointField& end, + + labelList& surface1, + List<pointIndexHit>& hit1, + labelList& region1, + labelList& surface2, + List<pointIndexHit>& hit2, + labelList& region2 ) const { - isInside.setSize(points.size()); - isInside = 0u; + // 1. intersection from start to end + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + // Initialize arguments + surface1.setSize(start.size()); + surface1 = -1; + hit1.setSize(start.size()); + region1.setSize(start.size()); + + // Current end of segment to test. + pointField nearest(end); + // Work array + List<pointIndexHit> nearestInfo(start.size()); + labelList region; + + forAll(surfacesToTest, testI) + { + label surfI = surfacesToTest[testI]; - label nPointInside = 0; + // See if any intersection between start and current nearest + allGeometry_[surfaces_[surfI]].findLine + ( + start, + nearest, + nearestInfo + ); + allGeometry_[surfaces_[surfI]].getRegion + ( + nearestInfo, + region + ); - forAll(points, pointI) - { - forAll(*this, surfI) + forAll(nearestInfo, pointI) { - if (closed()[surfI]) + if (nearestInfo[pointI].hit()) { - const triSurfaceMesh& s = operator[](surfI); - - triSurfaceMesh::volumeType t = s.getVolumeType(points[pointI]); - - if (t == triSurfaceMesh::INSIDE) - { - isInside.set(pointI, 1u); - nPointInside++; - break; - } + hit1[pointI] = nearestInfo[pointI]; + surface1[pointI] = surfI; + region1[pointI] = region[pointI]; + nearest[pointI] = hit1[pointI].hitPoint(); } } } - return nPointInside; -} + // 2. intersection from end to last intersection + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -void Foam::refinementSurfaces::setMinLevelFields -( - const PtrList<searchableSurface>& shells, - const labelList& shellLevels, - const boolList& shellRefineInside -) -{ - typedef Foam::DimensionedField<label, triSurfaceGeoMesh> - triSurfaceLabelField; + // Find the nearest intersection from end to start. Note that we initialize + // to the first intersection (if any). + surface2 = surface1; + hit2 = hit1; + region2 = region1; - minLevelFields_.setSize(size()); + // Set current end of segment to test. + forAll(nearest, pointI) + { + if (hit1[pointI].hit()) + { + nearest[pointI] = hit1[pointI].hitPoint(); + } + else + { + // Disable testing by setting to end. + nearest[pointI] = end[pointI]; + } + } - forAll(*this, surfI) + forAll(surfacesToTest, testI) { - const triSurfaceMesh& surfMesh = operator[](surfI); + label surfI = surfacesToTest[testI]; - minLevelFields_.set + // See if any intersection between end and current nearest + allGeometry_[surfaces_[surfI]].findLine ( - surfI, - new triSurfaceLabelField - ( - IOobject - ( - surfMesh.IOobject::name(), - surfMesh.time().constant(), // directory - "triSurface", // instance - surfMesh, - IOobject::NO_READ, - IOobject::AUTO_WRITE, - false - ), - surfMesh, - dimless - ) + end, + nearest, + nearestInfo + ); + allGeometry_[surfaces_[surfI]].getRegion + ( + nearestInfo, + region ); + + forAll(nearestInfo, pointI) + { + if (nearestInfo[pointI].hit()) + { + hit2[pointI] = nearestInfo[pointI]; + surface2[pointI] = surfI; + region2[pointI] = region[pointI]; + nearest[pointI] = hit2[pointI].hitPoint(); + } + } } +} - // Initialise fields to region wise minLevel - forAll(*this, surfI) - { - const triSurface& s = operator[](surfI); - triSurfaceLabelField& minLevelField = minLevelFields_[surfI]; +void Foam::refinementSurfaces::findAnyIntersection +( + const pointField& start, + const pointField& end, + + labelList& hitSurface, + List<pointIndexHit>& hitInfo +) const +{ + searchableSurfacesQueries::findAnyIntersection + ( + allGeometry_, + surfaces_, + start, + end, + hitSurface, + hitInfo + ); +} + - forAll(s, i) +void Foam::refinementSurfaces::findNearest +( + const labelList& surfacesToTest, + const pointField& samples, + const scalarField& nearestDistSqr, + labelList& hitSurface, + List<pointIndexHit>& hitInfo +) const +{ + labelList geometries(IndirectList<label>(surfaces_, surfacesToTest)); + + // Do the tests. Note that findNearest returns index in geometries. + searchableSurfacesQueries::findNearest + ( + allGeometry_, + geometries, + samples, + nearestDistSqr, + hitSurface, + hitInfo + ); + + // Rework the hitSurface to be surface (i.e. index into surfaces_) + forAll(hitSurface, pointI) + { + if (hitSurface[pointI] != -1) { - minLevelField[i] = minLevel_[globalRegion(surfI, s[i].region())]; + hitSurface[pointI] = surfacesToTest[hitSurface[pointI]]; } } +} + - // Adapt for triangles inside shells - forAll(*this, surfI) +//// Find intersection with max of edge. Return -1 or the surface +//// with the highest maxLevel above currentLevel +//Foam::label Foam::refinementSurfaces::findHighestIntersection +//( +// const point& start, +// const point& end, +// const label currentLevel, // current cell refinement level +// +// pointIndexHit& maxHit +//) const +//{ +// // surface with highest maxlevel +// label maxSurface = -1; +// // maxLevel of maxSurface +// label maxLevel = currentLevel; +// +// forAll(*this, surfI) +// { +// pointIndexHit hit = operator[](surfI).findLineAny(start, end); +// +// if (hit.hit()) +// { +// const triSurface& s = operator[](surfI); +// +// label region = globalRegion(surfI, s[hit.index()].region()); +// +// if (maxLevel_[region] > maxLevel) +// { +// maxSurface = surfI; +// maxLevel = maxLevel_[region]; +// maxHit = hit; +// } +// } +// } +// +// if (maxSurface == -1) +// { +// // maxLevel unchanged. No interesting surface hit. +// maxHit.setMiss(); +// } +// +// return maxSurface; +//} + + +void Foam::refinementSurfaces::findInside +( + const labelList& testSurfaces, + const pointField& pt, + labelList& insideSurfaces +) const +{ + insideSurfaces.setSize(pt.size()); + insideSurfaces = -1; + + forAll(testSurfaces, i) { - const triSurface& s = operator[](surfI); - triSurfaceLabelField& minLevelField = minLevelFields_[surfI]; + label surfI = testSurfaces[i]; - forAll(s, i) + if (allGeometry_[surfaces_[surfI]].hasVolumeType()) { - point fc = s[i].centre(s.points()); + List<searchableSurface::volumeType> volType; + allGeometry_[surfaces_[surfI]].getVolumeType(pt, volType); - forAll(shells, shellI) + forAll(volType, pointI) { - // Which side of shell is to be refined - searchableSurface::volumeType refSide = - ( - shellRefineInside[shellI] - ? searchableSurface::INSIDE - : searchableSurface::OUTSIDE - ); - - // Find whether point is inside or outside shell - searchableSurface::volumeType t = - shells[shellI].getVolumeType(fc); - - if (t == refSide) + if (insideSurfaces[pointI] == -1) { - minLevelField[i] = max + if ( - minLevelField[i], - shellLevels[shellI] - ); + ( + volType[pointI] == triSurfaceMesh::INSIDE + && zoneInside_[surfI] + ) + || ( + volType[pointI] == triSurfaceMesh::OUTSIDE + && !zoneInside_[surfI] + ) + ) + { + insideSurfaces[pointI] = surfI; + } } } } diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H index dc5bd0adfb6122f66f61830575c5aedf6c2c8d25..edb613d966f11b8b62ab55de4c83765b9ab55bd9 100644 --- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H +++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H @@ -26,8 +26,8 @@ Class Foam::refinementSurfaces Description - Container for triSurfaces used for surface-driven refinement. - These contain all the data about the level of refinement needed per + Container for data on surfaces used for surface-driven refinement. + Contains all the data about the level of refinement needed per surface. SourceFiles @@ -38,34 +38,38 @@ SourceFiles #ifndef refinementSurfaces_H #define refinementSurfaces_H -#include "triSurfaceMeshes.H" #include "PackedList.H" #include "triSurfaceGeoMesh.H" #include "triSurfaceFields.H" +#include "vectorList.H" +#include "pointIndexHit.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { -class searchableSurface; +class searchableSurfaces; +class shellSurfaces; +class triSurfaceMesh; /*---------------------------------------------------------------------------*\ Class refinementSurfaces Declaration \*---------------------------------------------------------------------------*/ class refinementSurfaces -: - public triSurfaceMeshes { // Private data + //- Reference to all geometry. + const searchableSurfaces& allGeometry_; + + //- Indices of surfaces that are refinement ones + labelList surfaces_; + //- Surface name (word) wordList names_; - //- Per surface whether is closed - boolList closed_; - //- Per 'interface' surface : name of faceZone to put faces into wordList faceZoneNames_; @@ -86,24 +90,12 @@ class refinementSurfaces //- From global region number to refinement level labelList maxLevel_; - //- From global region number to added layers - labelList numLayers_; - - //- From global region number to patch name - wordList patchName_; - - //- From global region number to patch name - wordList patchType_; - - //- Per surface refinement level adapted for shells. PtrList<triSurfaceLabelField> minLevelFields_; // Private Member Functions - static fileNameList extractFileNames(const PtrList<dictionary>&); - //- Disallow default bitwise copy construct refinementSurfaces(const refinementSurfaces&); @@ -115,28 +107,39 @@ public: // Constructors - //- Construct from directory (io.instance()) and dictionaries + //- Construct from surfaces and dictionaries refinementSurfaces ( - const IOobject& io, + const searchableSurfaces& allGeometry, const PtrList<dictionary>& ); + //- Construct from surfaces and dictionary + refinementSurfaces + ( + const searchableSurfaces& allGeometry, + const dictionary& + ); + // Member Functions // Access - //- Names of surfaces - const wordList& names() const + const searchableSurfaces& geometry() const { - return names_; + return allGeometry_; } - //- Per surface whether is closed - const boolList& closed() const + const labelList& surfaces() const { - return closed_; + return surfaces_; + } + + //- Names of surfaces + const wordList& names() const + { + return names_; } //- Per 'interface' surface : name of faceZone to put faces into @@ -151,15 +154,11 @@ public: return cellZoneNames_; } - //- Per 'interface' surface : if closed: zonify cells inside surface - const boolList& zoneInside() const - { - return zoneInside_; - } - //- Get indices of named surfaces (surfaces with cellZoneName) labelList getNamedSurfaces() const; + //- Get indices of closed named surfaces + labelList getClosedNamedSurfaces() const; //- From local region number to global region number const labelList& regionOffset() const @@ -179,24 +178,6 @@ public: return maxLevel_; } - //- From global region number to added layers - const labelList& numLayers() const - { - return numLayers_; - } - - //- From global region number to patch name. Patchnames can be empty - const wordList& patchName() const - { - return patchName_; - } - - //- From global region number to patch name - const wordList& patchType() const - { - return patchType_; - } - // Helper @@ -206,14 +187,6 @@ public: return regionOffset_[surfI]+regionI; } - //- From triangle on surface to global region - label triangleRegion(const label surfI, const label triI) const - { - const triSurface& s = operator[](surfI); - - return globalRegion(surfI, s[triI].region()); - } - //- Min level for surface and region on surface label minLevel(const label surfI, const label regionI) const { @@ -231,23 +204,12 @@ public: return minLevel_.size(); } - //- Minlevel updated for refinement shells - const triSurfaceLabelField& minLevelField(const label surfI) const - { - return minLevelFields_[surfI]; - } - //- Calculate minLevelFields void setMinLevelFields ( - const PtrList<searchableSurface>& shells, - const labelList& shellLevels, - const boolList& shellRefineInside + const shellSurfaces& shells ); - //- Helper: is surface closed? - static bool isSurfaceClosed(const triSurface&); - //- Helper: orient (closed only) surfaces so keepPoint is outside. static void orientSurface ( @@ -263,36 +225,71 @@ public: //- Find intersection of edge. Return -1 or first surface // with higher (than currentLevel) minlevel. - // Return surface number and hit info. - label findHigherIntersection + // Return surface number and level. + void findHigherIntersection ( - const point& start, - const point& end, - const label currentLevel, // current cell refinement level - pointIndexHit& + const pointField& start, + const pointField& end, + const labelList& currentLevel, // current cell refinement level + + labelList& surfaces, + labelList& surfaceLevel ) const; - //- Find intersection with max level. Return -1 or the surface - // with the highest maxLevel above currentLevel - label findHighestIntersection + //- Find all intersections of edge. Unsorted order. + void findAllHigherIntersections ( - const point& start, - const point& end, - const label currentLevel, // current cell refinement level - pointIndexHit& + const pointField& start, + const pointField& end, + const labelList& currentLevel, // current cell refinement level + + List<vectorList>& surfaceNormal, + labelListList& surfaceLevel ) const; - //- Detect if a point is 'inside' (depending on zoneInside flag) a - // zoneable surface. Returns -1 if not, returns first surface it - // is. - label insideZone(const labelList& surfaces, const point& pt) const; + //- Find intersection nearest to the endpoints. surface1,2 are + // not indices into surfacesToTest but refinement surface indices. + void findNearestIntersection + ( + const labelList& surfacesToTest, + const pointField& start, + const pointField& end, + + labelList& surface1, + List<pointIndexHit>& hit1, + labelList& region1, + labelList& surface2, + List<pointIndexHit>& hit2, + labelList& region2 + ) const; + //- Used for debugging only: find intersection of edge. + void findAnyIntersection + ( + const pointField& start, + const pointField& end, + labelList& surfaces, + List<pointIndexHit>& + ) const; - //- Mark for all points whether it is inside any closed surface - // Return number of inside points. - label markInsidePoints(const pointField&, PackedList<1>& isInside) - const; + //- Find nearest point on surfaces. + void findNearest + ( + const labelList& surfacesToTest, + const pointField& samples, + const scalarField& nearestDistSqr, + labelList& surfaces, + List<pointIndexHit>& + ) const; + //- Detect if a point is 'inside' (closed) surfaces. + // Returns -1 if not, returns first surface it is. + void findInside + ( + const labelList& surfacesToTest, + const pointField& pt, + labelList& insideSurfaces + ) const; }; diff --git a/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.C b/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.C new file mode 100644 index 0000000000000000000000000000000000000000..fe64ea81c3d86d8f57b661ac0b24c4d694d76696 --- /dev/null +++ b/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.C @@ -0,0 +1,465 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "searchableSurface.H" +#include "shellSurfaces.H" +#include "boundBox.H" +#include "triSurfaceMesh.H" +#include "refinementSurfaces.H" +#include "searchableSurfaces.H" +#include "pointIndexHit.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + + +namespace Foam +{ + +template<> +const char* +NamedEnum<shellSurfaces::refineMode, 3>:: +names[] = +{ + "inside", + "outside", + "distance" +}; + +const NamedEnum<shellSurfaces::refineMode, 3> shellSurfaces::refineModeNames_; + +} // End namespace Foam + + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::shellSurfaces::setAndCheckLevels +( + const scalar shellI, + const List<Tuple2<scalar, label> >& distLevels +) +{ + if (modes_[shellI] != DISTANCE && distLevels.size() != 1) + { + FatalErrorIn + ( + "shellSurfaces::shellSurfaces" + "(const searchableSurfaces&, const dictionary&)" + ) << "For refinement mode " + << refineModeNames_[modes_[shellI]] + << " specify only one distance+level." + << " (its distance gets discarded)" + << exit(FatalError); + } + // Extract information into separate distance and level + distances_[shellI].setSize(distLevels.size()); + levels_[shellI].setSize(distLevels.size()); + + forAll(distLevels, j) + { + distances_[shellI][j] = distLevels[j].first(); + levels_[shellI][j] = distLevels[j].second(); + + // Check in incremental order + if (j > 0) + { + if + ( + (distances_[shellI][j] <= distances_[shellI][j-1]) + || (levels_[shellI][j] > levels_[shellI][j-1]) + ) + { + FatalErrorIn + ( + "shellSurfaces::shellSurfaces" + "(const searchableSurfaces&, const dictionary&)" + ) << "For refinement mode " + << refineModeNames_[modes_[shellI]] + << " : Refinement should be specified in order" + << " of increasing distance" + << " (and decreasing refinement level)." << endl + << "Distance:" << distances_[shellI][j] + << " refinementLevel:" << levels_[shellI][j] + << exit(FatalError); + } + } + } + + const searchableSurface& shell = allGeometry_[shells_[shellI]]; + + if (modes_[shellI] == DISTANCE) + { + Info<< "Refinement level according to distance to " + << shell.name() << endl; + forAll(levels_[shellI], j) + { + Info<< " level " << levels_[shellI][j] + << " for all cells within " << distances_[shellI][j] + << " meter." << endl; + } + } + else + { + if (!allGeometry_[shells_[shellI]].hasVolumeType()) + { + FatalErrorIn + ( + "shellSurfaces::shellSurfaces" + "(const searchableSurfaces&" + ", const PtrList<dictionary>&)" + ) << "Shell " << shell.name() + << " does not support testing for " + << refineModeNames_[modes_[shellI]] << endl + << "Probably it is not closed." + << exit(FatalError); + } + + if (modes_[shellI] == INSIDE) + { + Info<< "Refinement level " << levels_[shellI][0] + << " for all cells inside " << shell.name() << endl; + } + else + { + Info<< "Refinement level " << levels_[shellI][0] + << " for all cells outside " << shell.name() << endl; + } + } +} + + +// Specifically orient triSurfaces using a calculated point outside. +// Done since quite often triSurfaces not of consistent orientation which +// is (currently) necessary for sideness calculation +void Foam::shellSurfaces::orient() +{ + // Determine outside point. + boundBox overallBb + ( + point(GREAT, GREAT, GREAT), + point(-GREAT, -GREAT, -GREAT) + ); + + bool hasSurface = false; + + forAll(shells_, shellI) + { + const searchableSurface& s = allGeometry_[shells_[shellI]]; + + if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s)) + { + const triSurfaceMesh& shell = refCast<const triSurfaceMesh>(s); + + if (shell.triSurface::size() > 0) + { + const pointField& points = shell.points(); + + hasSurface = true; + + boundBox shellBb(points[0], points[0]); + // Assume surface is compact! + for (label i = 0; i < points.size(); i++) + { + const point& pt = points[i]; + shellBb.min() = min(shellBb.min(), pt); + shellBb.max() = max(shellBb.max(), pt); + } + + overallBb.min() = min(overallBb.min(), shellBb.min()); + overallBb.max() = max(overallBb.max(), shellBb.max()); + } + } + } + + if (hasSurface) + { + const point outsidePt(2*overallBb.max() - overallBb.min()); + + //Info<< "Using point " << outsidePt << " to orient shells" << endl; + + forAll(shells_, shellI) + { + const searchableSurface& s = allGeometry_[shells_[shellI]]; + + if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s)) + { + triSurfaceMesh& shell = const_cast<triSurfaceMesh&> + ( + refCast<const triSurfaceMesh>(s) + ); + + refinementSurfaces::orientSurface(outsidePt, shell); + } + } + } +} + + +// Find maximum level of a shell. +void Foam::shellSurfaces::findHigherLevel +( + const pointField& pt, + const label shellI, + labelList& maxLevel +) const +{ + const labelList& levels = levels_[shellI]; + + if (modes_[shellI] == DISTANCE) + { + // Distance mode. + + const scalarField& distances = distances_[shellI]; + + // Collect all those points that have a current maxLevel less than + // (any of) the shell. Also collect the furthest distance allowable + // to any shell with a higher level. + + pointField candidates(pt.size()); + labelList candidateMap(pt.size()); + scalarField candidateDistSqr(pt.size()); + label candidateI = 0; + + forAll(maxLevel, pointI) + { + forAllReverse(levels, levelI) + { + if (levels[levelI] > maxLevel[pointI]) + { + candidates[candidateI] = pt[pointI]; + candidateMap[candidateI] = pointI; + candidateDistSqr[candidateI] = sqr(distances[levelI]); + candidateI++; + break; + } + } + } + candidates.setSize(candidateI); + candidateMap.setSize(candidateI); + candidateDistSqr.setSize(candidateI); + + // Do the expensive nearest test only for the candidate points. + List<pointIndexHit> nearInfo; + allGeometry_[shells_[shellI]].findNearest + ( + candidates, + candidateDistSqr, + nearInfo + ); + + // Update maxLevel + forAll(nearInfo, candidateI) + { + if (nearInfo[candidateI].hit()) + { + // Check which level it actually is in. + label minDistI = findLower + ( + distances, + mag(nearInfo[candidateI].hitPoint()-candidates[candidateI]) + ); + + label pointI = candidateMap[candidateI]; + + // pt is inbetween shell[minDistI] and shell[minDistI+1] + maxLevel[pointI] = levels[minDistI+1]; + } + } + } + else + { + // Inside/outside mode + + // Collect all those points that have a current maxLevel less than the + // shell. + + pointField candidates(pt.size()); + labelList candidateMap(pt.size()); + label candidateI = 0; + + forAll(maxLevel, pointI) + { + if (levels[0] > maxLevel[pointI]) + { + candidates[candidateI] = pt[pointI]; + candidateMap[candidateI] = pointI; + candidateI++; + } + } + candidates.setSize(candidateI); + candidateMap.setSize(candidateI); + + // Do the expensive nearest test only for the candidate points. + List<searchableSurface::volumeType> volType; + allGeometry_[shells_[shellI]].getVolumeType(candidates, volType); + + forAll(volType, i) + { + label pointI = candidateMap[i]; + + if + ( + ( + modes_[shellI] == INSIDE + && volType[i] == searchableSurface::INSIDE + ) + || ( + modes_[shellI] == OUTSIDE + && volType[i] == searchableSurface::OUTSIDE + ) + ) + { + maxLevel[pointI] = levels[0]; + } + } + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::shellSurfaces::shellSurfaces +( + const searchableSurfaces& allGeometry, + const PtrList<dictionary>& shellDicts +) +: + allGeometry_(allGeometry) +{ + shells_.setSize(shellDicts.size()); + modes_.setSize(shellDicts.size()); + distances_.setSize(shellDicts.size()); + levels_.setSize(shellDicts.size()); + + forAll(shellDicts, shellI) + { + const dictionary& dict = shellDicts[shellI]; + const word name = dict.lookup("name"); + const word type = dict.lookup("type"); + + shells_[shellI] = allGeometry_.findSurfaceID(name); + + if (shells_[shellI] == -1) + { + FatalErrorIn + ( + "shellSurfaces::shellSurfaces" + "(const searchableSurfaces&, const PtrList<dictionary>&)" + ) << "No surface called " << name << endl + << "Valid surfaces are " << allGeometry_.names() + << exit(FatalError); + } + + modes_[shellI] = refineModeNames_.read(dict.lookup("refineMode")); + + // Read pairs of distance+level + setAndCheckLevels(shellI, dict.lookup("levels")); + } + + // Orient shell surfaces before any searching is done. Note that this + // only needs to be done for inside or outside. Orienting surfaces + // constructs lots of addressing which we want to avoid. + orient(); +} + + +Foam::shellSurfaces::shellSurfaces +( + const searchableSurfaces& allGeometry, + const dictionary& shellsDict +) +: + allGeometry_(allGeometry) +{ + shells_.setSize(shellsDict.size()); + modes_.setSize(shellsDict.size()); + distances_.setSize(shellsDict.size()); + levels_.setSize(shellsDict.size()); + + label shellI = 0; + forAllConstIter(dictionary, shellsDict, iter) + { + shells_[shellI] = allGeometry_.findSurfaceID(iter().keyword()); + + if (shells_[shellI] == -1) + { + FatalErrorIn + ( + "shellSurfaces::shellSurfaces" + "(const searchableSurfaces&, const dictionary>&" + ) << "No surface called " << iter().keyword() << endl + << "Valid surfaces are " << allGeometry_.names() + << exit(FatalError); + } + const dictionary& dict = shellsDict.subDict(iter().keyword()); + + modes_[shellI] = refineModeNames_.read(dict.lookup("mode")); + + // Read pairs of distance+level + setAndCheckLevels(shellI, dict.lookup("levels")); + + shellI++; + } + + // Orient shell surfaces before any searching is done. Note that this + // only needs to be done for inside or outside. Orienting surfaces + // constructs lots of addressing which we want to avoid. + orient(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +// Highest shell level +Foam::label Foam::shellSurfaces::maxLevel() const +{ + label overallMax = 0; + forAll(levels_, shellI) + { + overallMax = max(overallMax, max(levels_[shellI])); + } + return overallMax; +} + + +void Foam::shellSurfaces::findHigherLevel +( + const pointField& pt, + const labelList& ptLevel, + labelList& maxLevel +) const +{ + // Maximum level of any shell. Start off with level of point. + maxLevel = ptLevel; + + forAll(shells_, shellI) + { + findHigherLevel(pt, shellI, maxLevel); + } +} + + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.H b/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.H new file mode 100644 index 0000000000000000000000000000000000000000..b996e98e8972f76544c73d032babc2a73ffd5778 --- /dev/null +++ b/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.H @@ -0,0 +1,182 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + shellSurfaces + +Description + Encapsulates queries for volume refinement ('refine all cells within + shell'). + +SourceFiles + shellSurfaces.C + +\*---------------------------------------------------------------------------*/ + +#ifndef shellSurfaces_H +#define shellSurfaces_H + +#include "searchableSurface.H" +#include "Tuple2.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +class searchableSurfaces; + +/*---------------------------------------------------------------------------*\ + Class shellSurfaces Declaration +\*---------------------------------------------------------------------------*/ + +class shellSurfaces +{ +public: + + // Public data types + + //- Volume refinement controls + enum refineMode + { + INSIDE, // Refine all inside shell + OUTSIDE, // ,, outside + DISTANCE // Refine based on distance to shell + }; + + +private: + + // Private data + + //- Reference to all geometry. + const searchableSurfaces& allGeometry_; + + //- Indices of surfaces that are shells + labelList shells_; + + //- Per shell whether to refine inside or outside + List<refineMode> modes_; + + //- Per shell the list of ranges + List<scalarField> distances_; + + //- Per shell per distance the refinement level + labelListList levels_; + + + // Private data + + //- refineMode names + static const NamedEnum<refineMode, 3> refineModeNames_; + + + // Private Member Functions + + //- Helper function for initialisation. + void setAndCheckLevels + ( + const scalar shellI, + const List<Tuple2<scalar, label> >& + ); + + void orient(); + + void findHigherLevel + ( + const pointField& pt, + const label shellI, + labelList& maxLevel + ) const; + +public: + + // Constructors + + //- Construct from components + shellSurfaces + ( + const searchableSurfaces& allGeometry, + const labelList& shells, + const List<refineMode>& modes, + const List<scalarField>& distances, + const labelListList& levels + ); + + //- Construct from geometry and dictionaries + shellSurfaces + ( + const searchableSurfaces& allGeometry, + const PtrList<dictionary>& shellDicts + ); + + //- Construct from geometry and dictionary + shellSurfaces + ( + const searchableSurfaces& allGeometry, + const dictionary& shellsDict + ); + + + // Member Functions + + // Access + + //const List<scalarField>& distances() const + //{ + // return distances_; + //} + // + ////- Per shell per distance the refinement level + //const labelListList& levels() const + //{ + // return levels_; + //} + + + // Query + + //- Highest shell level + label maxLevel() const; + + //- Find shell level higher than ptLevel + void findHigherLevel + ( + const pointField& pt, + const labelList& ptLevel, + labelList& maxLevel + ) const; + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C b/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C index 508143aaf9729a6ccd63648325f06bacc16fa353..cebb6597c217c15bdcdf5a9780e7dfe365b5f787 100644 --- a/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C +++ b/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C @@ -256,7 +256,7 @@ Foam::Ostream& Foam::operator<< const ExactParticle<ParticleType>& p ) { - return operator<<(os, static_cast<Particle<ParticleType> >(p)); + return operator<<(os, static_cast<const Particle<ParticleType>&>(p)); } diff --git a/src/dynamicMesh/fvMeshDistribute/fvMeshDistribute.H b/src/dynamicMesh/fvMeshDistribute/fvMeshDistribute.H index d764c3fa6f2e996b42023eaff80023488ea79194..2db82c8eed8954d395b596580688cf3402c36362 100644 --- a/src/dynamicMesh/fvMeshDistribute/fvMeshDistribute.H +++ b/src/dynamicMesh/fvMeshDistribute/fvMeshDistribute.H @@ -361,7 +361,7 @@ public: // Member Functions - //- Helper funntion: count cells per processor in wanted distribution + //- Helper function: count cells per processor in wanted distribution static labelList countCells(const labelList&); //- Send cells to neighbours according to distribution diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C index c1c0e4f316edb9801cf722a14e11417bb5afade5..0742fd44b50fd83ec1c3f03b563e08c17a6f0e6e 100644 --- a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C +++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C @@ -553,7 +553,7 @@ Foam::labelListList Foam::addPatchCellLayer::addedCells() const void Foam::addPatchCellLayer::setRefinement ( - const scalar expansionRatio, + const scalarField& expansionRatio, const indirectPrimitivePatch& pp, const labelList& nFaceLayers, const labelList& nPointLayers, @@ -885,7 +885,7 @@ void Foam::addPatchCellLayer::setRefinement addedPoints_[patchPointI][i] = addedVertI; - disp *= expansionRatio; + disp *= expansionRatio[patchPointI]; } } } diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H index 0e47acb7eaeec67dbdec4334e19b0cc337db57b8..0b5caaba86f8d2b84c6f1605809ecb5925937d0b 100644 --- a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H +++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H @@ -305,7 +305,7 @@ public: // (instead of e.g. from patch faces) void setRefinement ( - const scalar expansionRatio, + const scalarField& expansionRatio, const indirectPrimitivePatch& pp, const labelList& nFaceLayers, const labelList& nPointLayers, @@ -325,7 +325,7 @@ public: { setRefinement ( - 1.0, // expansion ration + scalarField(pp.nPoints(), 1.0), // expansion ration pp, labelList(pp.size(), nLayers), labelList(pp.nPoints(), nLayers), diff --git a/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.C b/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.C index cfedeb6112f868b5a1ef5075bdc1ac4726b50eee..7b035e0e4ad69290d4b0923d6d4cc6f0e9016202 100644 --- a/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.C +++ b/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.C @@ -62,7 +62,6 @@ surfaceSlipDisplacementPointPatchVectorField ) : pointPatchVectorField(p, iF), - surfaceNames_(), projectMode_(NEAREST), projectDir_(vector::zero), wedgePlane_(-1) @@ -78,7 +77,7 @@ surfaceSlipDisplacementPointPatchVectorField ) : pointPatchVectorField(p, iF, dict), - surfaceNames_(dict.lookup("projectSurfaces")), + surfacesDict_(dict.subDict("geometry")), projectMode_(followModeNames_.read(dict.lookup("followMode"))), projectDir_(dict.lookup("projectDirection")), wedgePlane_(readLabel(dict.lookup("wedgePlane"))), @@ -96,7 +95,7 @@ surfaceSlipDisplacementPointPatchVectorField ) : pointPatchVectorField(p, iF), - surfaceNames_(ppf.surfaceNames()), + surfacesDict_(ppf.surfacesDict()), projectMode_(ppf.projectMode()), projectDir_(ppf.projectDir()), wedgePlane_(ppf.wedgePlane()), @@ -111,7 +110,7 @@ surfaceSlipDisplacementPointPatchVectorField ) : pointPatchVectorField(ppf), - surfaceNames_(ppf.surfaceNames()), + surfacesDict_(ppf.surfacesDict()), projectMode_(ppf.projectMode()), projectDir_(ppf.projectDir()), wedgePlane_(ppf.wedgePlane()), @@ -127,7 +126,7 @@ surfaceSlipDisplacementPointPatchVectorField ) : pointPatchVectorField(ppf, iF), - surfaceNames_(ppf.surfaceNames()), + surfacesDict_(ppf.surfacesDict()), projectMode_(ppf.projectMode()), projectDir_(ppf.projectDir()), wedgePlane_(ppf.wedgePlane()), @@ -137,14 +136,14 @@ surfaceSlipDisplacementPointPatchVectorField // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -const triSurfaceMeshes& surfaceSlipDisplacementPointPatchVectorField:: +const searchableSurfaces& surfaceSlipDisplacementPointPatchVectorField:: surfaces() const { if (!surfacesPtr_.valid()) { surfacesPtr_.reset ( - new triSurfaceMeshes + new searchableSurfaces ( IOobject ( @@ -155,7 +154,7 @@ surfaces() const IOobject::MUST_READ, IOobject::NO_WRITE ), - surfaceNames_ + surfacesDict_ ) ); } @@ -215,128 +214,180 @@ void surfaceSlipDisplacementPointPatchVectorField::evaluate ); const pointField& points0 = motionSolver.points0(); - forAll(localPoints, i) + +//XXXXXX + + + pointField start(meshPoints.size()); + forAll(start, i) + { + start[i] = points0[meshPoints[i]] + displacement[i]; + } + + if (projectMode_ == NEAREST) + { + List<pointIndexHit> nearest; + labelList hitSurfaces; + surfaces().findNearest + ( + start, + scalarField(start.size(), sqr(projectLen)), + hitSurfaces, + nearest + ); + + forAll(nearest, i) + { + if (zonePtr && (zonePtr->whichPoint(meshPoints[i]) >= 0)) + { + // Fixed point. Reset to point0 location. + displacement[i] = points0[meshPoints[i]] - localPoints[i]; + } + else if (nearest[i].hit()) + { + displacement[i] = + nearest[i].hitPoint() + - points0[meshPoints[i]]; + } + else + { + Pout<< " point:" << meshPoints[i] + << " coord:" << localPoints[i] + << " did not find any surface within " << projectLen + << endl; + } + } + } + else { - if (zonePtr && (zonePtr->whichPoint(meshPoints[i]) >= 0)) + // Do tests on all points. Combine later on. + + // 1. Check if already on surface + List<pointIndexHit> nearest; { - // Fixed point. Reset to point0 location. + labelList nearestSurface; + surfaces().findNearest + ( + start, + scalarField(start.size(), sqr(SMALL)), + nearestSurface, + nearest + ); + } - //Pout<< " Fixed point:" << meshPoints[i] - // << " coord:" << localPoints[i] - // << " should be at:" << points0[meshPoints[i]] - // << endl; - displacement[i] = points0[meshPoints[i]] - localPoints[i]; + // 2. intersection. (combined later on with information from nearest + // above) + vectorField projectVecs(start.size(), projectVec); + + if (projectMode_ == POINTNORMAL) + { + projectVecs = projectLen*patch().pointNormals(); } - else + + // Knock out any wedge component + scalarField offset(start.size(), 0.0); + if (wedgePlane_ >= 0 && wedgePlane_ <= vector::nComponents) { - point start(points0[meshPoints[i]] + displacement[i]); + forAll(offset, i) + { + offset[i] = start[i][wedgePlane_]; + start[i][wedgePlane_] = 0; + projectVecs[i][wedgePlane_] = 0; + } + } - scalar offset = 0; - pointIndexHit intersection; + List<pointIndexHit> rightHit; + { + labelList rightSurf; + surfaces().findAnyIntersection + ( + start, + start+projectVecs, + rightSurf, + rightHit + ); + } + + List<pointIndexHit> leftHit; + { + labelList leftSurf; + surfaces().findAnyIntersection + ( + start, + start-projectVecs, + leftSurf, + leftHit + ); + } - if (projectMode_ == NEAREST) + // 3. Choose either -fixed, nearest, right, left. + forAll(displacement, i) + { + if (zonePtr && (zonePtr->whichPoint(meshPoints[i]) >= 0)) { - surfaces().findNearest(start, sqr(projectLen), intersection); + // Fixed point. Reset to point0 location. + displacement[i] = points0[meshPoints[i]] - localPoints[i]; + } + else if (nearest[i].hit()) + { + // Found nearest. + displacement[i] = + nearest[i].hitPoint() + - points0[meshPoints[i]]; } else { - // Check if already on surface - surfaces().findNearest(start, sqr(SMALL), intersection); + pointIndexHit interPt; - if (!intersection.hit()) + if (rightHit[i].hit()) { - // No nearest found. Do intersection - - if (projectMode_ == POINTNORMAL) + if (leftHit[i].hit()) { - projectVec = projectLen*patch().pointNormals()[i]; - } - - // Knock out any wedge component - if (wedgePlane_ >= 0 && wedgePlane_ <= vector::nComponents) - { - offset = start[wedgePlane_]; - start[wedgePlane_] = 0; - projectVec[wedgePlane_] = 0; - } - - label rightSurf0, rightSurf1; - pointIndexHit rightHit0, rightHit1; - surfaces().findNearestIntersection - ( - start, - start+projectVec, - rightSurf0, - rightHit0, - rightSurf1, - rightHit1 - ); - - // Do intersection - label leftSurf0, leftSurf1; - pointIndexHit leftHit0, leftHit1; - surfaces().findNearestIntersection - ( - start, - start-projectVec, - leftSurf0, - leftHit0, - leftSurf1, - leftHit1 - ); - - if (rightHit0.hit()) - { - if (leftHit0.hit()) + if + ( + magSqr(rightHit[i].hitPoint()-start[i]) + < magSqr(leftHit[i].hitPoint()-start[i]) + ) { - if - ( - magSqr(rightHit0.hitPoint()-start) - < magSqr(leftHit0.hitPoint()-start) - ) - { - intersection = rightHit0; - } - else - { - intersection = leftHit0; - } + interPt = rightHit[i]; } else { - intersection = rightHit0; + interPt = leftHit[i]; } } else { - if (leftHit0.hit()) - { - intersection = leftHit0; - } + interPt = rightHit[i]; + } + } + else + { + if (leftHit[i].hit()) + { + interPt = leftHit[i]; } } - } - - // Update *this from intersection point - if (intersection.hit()) - { - point interPt = intersection.hitPoint(); - if (wedgePlane_ >= 0 && wedgePlane_ <= vector::nComponents) + if (interPt.hit()) { - interPt[wedgePlane_] += offset; + if (wedgePlane_ >= 0 && wedgePlane_ <= vector::nComponents) + { + interPt.rawPoint()[wedgePlane_] += offset[i]; + } + displacement[i] = interPt.rawPoint()-points0[meshPoints[i]]; + } + else + { + Pout<< " point:" << meshPoints[i] + << " coord:" << localPoints[i] + << " did not find any intersection between ray from " + << start[i]-projectVecs[i] + << " to " << start[i]+projectVecs[i] + << endl; } - displacement[i] = interPt-points0[meshPoints[i]]; } - else - { - Pout<< " point:" << meshPoints[i] - << " coord:" << localPoints[i] - << " did not find any intersection between ray from " - << start-projectVec << " to " << start+projectVec - << endl; - } } } @@ -353,7 +404,7 @@ void surfaceSlipDisplacementPointPatchVectorField::evaluate void surfaceSlipDisplacementPointPatchVectorField::write(Ostream& os) const { pointPatchVectorField::write(os); - os.writeKeyword("projectSurfaces") << surfaceNames_ + os.writeKeyword("geometry") << surfacesDict_ << token::END_STATEMENT << nl; os.writeKeyword("followMode") << followModeNames_[projectMode_] << token::END_STATEMENT << nl; diff --git a/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.H b/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.H index b164795cac52a02f3db8c341967609bf99e5f8bc..5b8fca9409d0b0f06c81d1a0639e0c281a8cf5b3 100644 --- a/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.H +++ b/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.H @@ -52,7 +52,7 @@ SourceFiles #define surfaceSlipDisplacementPointPatchVectorField_H #include "pointPatchFields.H" -#include "triSurfaceMeshes.H" +#include "searchableSurfaces.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -87,7 +87,7 @@ private: static const NamedEnum<followMode, 3> followModeNames_; //- names of surfaces - const fileNameList surfaceNames_; + const dictionary surfacesDict_; //- How to follow/project onto surface const followMode projectMode_; @@ -102,7 +102,7 @@ private: const word frozenPointsZone_; //- Demand driven: surface to follow - mutable autoPtr<triSurfaceMeshes> surfacesPtr_; + mutable autoPtr<searchableSurfaces> surfacesPtr_; // Private Member Functions @@ -187,13 +187,13 @@ public: // Member Functions //- Surfaces to follow - const fileNameList& surfaceNames() const + const dictionary& surfacesDict() const { - return surfaceNames_; + return surfacesDict_; } //- Surface to follow. Demand loads surfaceNames. - const triSurfaceMeshes& surfaces() const; + const searchableSurfaces& surfaces() const; //- Mode of projection/following followMode projectMode() const diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files index 3a3d2aff830ff305ddb6e6057dc244bcfa7e93f6..90f9de250e298142d18b889e8be63a8bf86dac96 100644 --- a/src/meshTools/Make/files +++ b/src/meshTools/Make/files @@ -53,6 +53,14 @@ indexedOctree/treeDataFace.C indexedOctree/treeDataPoint.C indexedOctree/treeDataTriSurface.C +searchableSurface = searchableSurface +$(searchableSurface)/searchableBox.C +$(searchableSurface)/searchableSphere.C +$(searchableSurface)/searchableSurface.C +$(searchableSurface)/searchableSurfaces.C +$(searchableSurface)/searchableSurfacesQueries.C +$(searchableSurface)/triSurfaceMesh.C + topoSets = sets/topoSets $(topoSets)/cellSet.C $(topoSets)/topoSet.C @@ -117,20 +125,10 @@ $(intersectedSurface)/intersectedSurface.C $(intersectedSurface)/edgeSurface.C triSurface/triSurfaceSearch/triSurfaceSearch.C - triSurface/octreeData/octreeDataTriSurface.C triSurface/octreeData/octreeDataTriSurfaceTreeLeaf.C - triSurface/triangleFuncs/triangleFuncs.C - -triSurface/searchableSurface/searchableSurface.C -triSurface/searchableSurface/triSurfaceMesh.C -triSurface/searchableSurface/searchableBox.C - triSurface/surfaceFeatures/surfaceFeatures.C - -triSurface/triSurfaceMeshes/triSurfaceMeshes.C - triSurface/triSurfaceTools/triSurfaceTools.C triSurface/triSurfaceTools/geompack/geompack.C diff --git a/src/meshTools/searchableSurface/searchableBox.C b/src/meshTools/searchableSurface/searchableBox.C new file mode 100644 index 0000000000000000000000000000000000000000..cb664b57575d901a583587b92fa69a1072b4f169 --- /dev/null +++ b/src/meshTools/searchableSurface/searchableBox.C @@ -0,0 +1,541 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "searchableBox.H" +#include "addToRunTimeSelectionTable.H" +#include "SortableList.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(searchableBox, 0); +addToRunTimeSelectionTable(searchableSurface, searchableBox, dict); + +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::searchableBox::projectOntoCoordPlane +( + const direction dir, + const point& planePt, + pointIndexHit& info +) const +{ + // Set point + info.rawPoint()[dir] = planePt[dir]; + // Set face + if (planePt[dir] == min()[dir]) + { + info.setIndex(dir*2); + } + else if (planePt[dir] == max()[dir]) + { + info.setIndex(dir*2+1); + } + else + { + FatalErrorIn("searchableBox::projectOntoCoordPlane(..)") + << "Point on plane " << planePt + << " is not on coordinate " << min()[dir] + << " nor " << max()[dir] << abort(FatalError); + } +} + + +// Returns miss or hit with face (0..5) and region(always 0) +Foam::pointIndexHit Foam::searchableBox::findNearest +( + const point& bbMid, + const point& sample, + const scalar nearestDistSqr +) const +{ + // Point can be inside or outside. For every component direction can be + // left of min, right of max or inbetween. + // - outside points: project first one x plane (either min().x() + // or max().x()), then onto y plane and finally z. You should be left + // with intersection point + // - inside point: find nearest side (compare to mid point). Project onto + // that. + + // The face is set to the last projected face. + + + // Outside point projected onto cube. Assume faces 0..5. + pointIndexHit info(true, sample, -1); + bool outside = false; + + // (for internal points) per direction what nearest cube side is + point near; + + for (direction dir = 0; dir < vector::nComponents; dir++) + { + if (info.rawPoint()[dir] < min()[dir]) + { + projectOntoCoordPlane(dir, min(), info); + outside = true; + } + else if (info.rawPoint()[dir] > max()[dir]) + { + projectOntoCoordPlane(dir, max(), info); + outside = true; + } + else if (info.rawPoint()[dir] > bbMid[dir]) + { + near[dir] = max()[dir]; + } + else + { + near[dir] = min()[dir]; + } + } + + + // For outside points the info will be correct now. Handle inside points + // using the three near distances. Project onto the nearest plane. + if (!outside) + { + vector dist(cmptMag(info.rawPoint() - near)); + + if (dist.x() < dist.y()) + { + if (dist.x() < dist.z()) + { + // Project onto x plane + projectOntoCoordPlane(vector::X, near, info); + } + else + { + projectOntoCoordPlane(vector::Z, near, info); + } + } + else + { + if (dist.y() < dist.z()) + { + projectOntoCoordPlane(vector::Y, near, info); + } + else + { + projectOntoCoordPlane(vector::Z, near, info); + } + } + } + + + // Check if outside. Optimisation: could do some checks on distance already + // on components above + if (magSqr(info.rawPoint() - sample) > nearestDistSqr) + { + info.setMiss(); + info.setIndex(-1); + } + + return info; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::searchableBox::searchableBox +( + const IOobject& io, + const treeBoundBox& bb +) +: + searchableSurface(io), + treeBoundBox(bb) +{} + + +Foam::searchableBox::searchableBox +( + const IOobject& io, + const dictionary& dict +) +: + searchableSurface(io), + treeBoundBox(dict.lookup("min"), dict.lookup("max")) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::searchableBox::~searchableBox() +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +const Foam::wordList& Foam::searchableBox::regions() const +{ + if (regions_.size() == 0) + { + regions_.setSize(1); + regions_[0] = "region0"; + } + return regions_; +} + + +Foam::pointIndexHit Foam::searchableBox::findNearest +( + const point& sample, + const scalar nearestDistSqr +) const +{ + return findNearest(mid(), sample, nearestDistSqr); +} + + +Foam::pointIndexHit Foam::searchableBox::findNearestOnEdge +( + const point& sample, + const scalar nearestDistSqr +) const +{ + const point bbMid(mid()); + + // Outside point projected onto cube. Assume faces 0..5. + pointIndexHit info(true, sample, -1); + bool outside = false; + + // (for internal points) per direction what nearest cube side is + point near; + + for (direction dir = 0; dir < vector::nComponents; dir++) + { + if (info.rawPoint()[dir] < min()[dir]) + { + projectOntoCoordPlane(dir, min(), info); + outside = true; + } + else if (info.rawPoint()[dir] > max()[dir]) + { + projectOntoCoordPlane(dir, max(), info); + outside = true; + } + else if (info.rawPoint()[dir] > bbMid[dir]) + { + near[dir] = max()[dir]; + } + else + { + near[dir] = min()[dir]; + } + } + + + // For outside points the info will be correct now. Handle inside points + // using the three near distances. Project onto the nearest two planes. + if (!outside) + { + // Get the per-component distance to nearest wall + vector dist(cmptMag(info.rawPoint() - near)); + + SortableList<scalar> sortedDist(3); + sortedDist[0] = dist[0]; + sortedDist[1] = dist[1]; + sortedDist[2] = dist[2]; + sortedDist.sort(); + + // Project onto nearest + projectOntoCoordPlane(sortedDist.indices()[0], near, info); + // Project onto second nearest + projectOntoCoordPlane(sortedDist.indices()[1], near, info); + } + + + // Check if outside. Optimisation: could do some checks on distance already + // on components above + if (magSqr(info.rawPoint() - sample) > nearestDistSqr) + { + info.setMiss(); + info.setIndex(-1); + } + + return info; +} + + +Foam::pointIndexHit Foam::searchableBox::findNearest +( + const linePointRef& ln, + treeBoundBox& tightest, + point& linePoint +) const +{ + notImplemented + ( + "searchableBox::findNearest" + "(const linePointRef&, treeBoundBox&, point&)" + ); + return pointIndexHit(); +} + + +Foam::pointIndexHit Foam::searchableBox::findLine +( + const point& start, + const point& end +) const +{ + pointIndexHit info(false, start, -1); + + bool foundInter; + + if (posBits(start) == 0) + { + if (posBits(end) == 0) + { + // Both start and end inside. + foundInter = false; + } + else + { + // end is outside. Clip to bounding box. + foundInter = intersects(end, start, info.rawPoint()); + } + } + else + { + // start is outside. Clip to bounding box. + foundInter = intersects(start, end, info.rawPoint()); + } + + + // Classify point + if (foundInter) + { + info.setHit(); + + for (direction dir = 0; dir < vector::nComponents; dir++) + { + if (info.rawPoint()[dir] == min()[dir]) + { + info.setIndex(2*dir); + break; + } + else if (info.rawPoint()[dir] == max()[dir]) + { + info.setIndex(2*dir+1); + break; + } + } + + if (info.index() == -1) + { + FatalErrorIn("searchableBox::findLine(const point&, const point&)") + << "point " << info.rawPoint() + << " on segment " << start << end + << " should be on face of " << *this + << " but it isn't." << abort(FatalError); + } + } + + return info; +} + + +Foam::pointIndexHit Foam::searchableBox::findLineAny +( + const point& start, + const point& end +) const +{ + return findLine(start, end); +} + + +void Foam::searchableBox::findNearest +( + const pointField& samples, + const scalarField& nearestDistSqr, + List<pointIndexHit>& info +) const +{ + info.setSize(samples.size()); + + const point bbMid(mid()); + + forAll(samples, i) + { + info[i] = findNearest(bbMid, samples[i], nearestDistSqr[i]); + } +} + + +void Foam::searchableBox::findLine +( + const pointField& start, + const pointField& end, + List<pointIndexHit>& info +) const +{ + info.setSize(start.size()); + + forAll(start, i) + { + info[i] = findLine(start[i], end[i]); + } +} + + +void Foam::searchableBox::findLineAny +( + const pointField& start, + const pointField& end, + List<pointIndexHit>& info +) const +{ + info.setSize(start.size()); + + forAll(start, i) + { + info[i] = findLineAny(start[i], end[i]); + } +} + + +void Foam::searchableBox::findLineAll +( + const pointField& start, + const pointField& end, + List<List<pointIndexHit> >& info +) const +{ + info.setSize(start.size()); + + // Work array + DynamicList<pointIndexHit, 1, 1> hits; + + // Tolerances + const vectorField dirVec(end-start); + const scalarField magSqrDirVec(magSqr(dirVec)); + const vectorField smallVec + ( + Foam::sqrt(SMALL)*dirVec + + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL) + ); + + forAll(start, pointI) + { + hits.clear(); + + // Current starting point of ray. + point pt = start[pointI]; + + while (true) + { + // See if any intersection between pt and end + pointIndexHit inter = findLine(pt, end[pointI]); + + if (!inter.hit()) + { + break; + } + hits.append(inter); + + pt = inter.hitPoint() + smallVec[pointI]; + + if (((pt-start[pointI])&dirVec[pointI]) > magSqrDirVec[pointI]) + { + // Adding smallVec has taken us beyond end + break; + } + } + + hits.shrink(); + info[pointI].transfer(hits); + hits.clear(); + } +} + + +void Foam::searchableBox::getRegion +( + const List<pointIndexHit>& info, + labelList& region +) const +{ + region.setSize(info.size()); + region = 0; +} + + +void Foam::searchableBox::getNormal +( + const List<pointIndexHit>& info, + vectorField& normal +) const +{ + normal.setSize(info.size()); + normal = vector::zero; + + forAll(info, i) + { + if (info[i].hit()) + { + normal[i] = treeBoundBox::faceNormals[info[i].index()]; + } + else + { + // Set to what? + } + } +} + + +void Foam::searchableBox::getVolumeType +( + const pointField& points, + List<volumeType>& volType +) const +{ + volType.setSize(points.size()); + volType = INSIDE; + + forAll(points, pointI) + { + const point& pt = points[pointI]; + + for (direction dir = 0; dir < vector::nComponents; dir++) + { + if (pt[dir] < min()[dir] || pt[dir] > max()[dir]) + { + volType[pointI] = OUTSIDE; + break; + } + } + } +} + + +// ************************************************************************* // diff --git a/src/meshTools/searchableSurface/searchableBox.H b/src/meshTools/searchableSurface/searchableBox.H new file mode 100644 index 0000000000000000000000000000000000000000..1c51311511b0840fd27bc81d1d67e26f6bfc67e9 --- /dev/null +++ b/src/meshTools/searchableSurface/searchableBox.H @@ -0,0 +1,249 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::searchableBox + +Description + Searching on bounding box + +SourceFiles + searchableBox.C + +\*---------------------------------------------------------------------------*/ + +#ifndef searchableBox_H +#define searchableBox_H + +#include "searchableSurface.H" +#include "treeBoundBox.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration of classes + +/*---------------------------------------------------------------------------*\ + Class searchableBox Declaration +\*---------------------------------------------------------------------------*/ + +class searchableBox +: + public searchableSurface, + public treeBoundBox +{ +private: + + // Private Member Data + + mutable wordList regions_; + + + // Private Member Functions + + //- Project onto component dir of planePt and update index() (=face) + void projectOntoCoordPlane + ( + const direction dir, + const point& planePt, + pointIndexHit& info + ) const; + + //- Returns miss or hit with face (0..5) + pointIndexHit findNearest + ( + const point& bbMid, + const point& sample, + const scalar nearestDistSqr + ) const; + + + //- Disallow default bitwise copy construct + searchableBox(const searchableBox&); + + //- Disallow default bitwise assignment + void operator=(const searchableBox&); + + +public: + + //- Runtime type information + TypeName("searchableBox"); + + + // Constructors + + //- Construct from components + searchableBox(const IOobject& io, const treeBoundBox& bb); + + //- Construct from dictionary (used by searchableSurface) + searchableBox + ( + const IOobject& io, + const dictionary& dict + ); + + // Destructor + + virtual ~searchableBox(); + + + // Member Functions + + virtual const wordList& regions() const; + + //- Whether supports volume type below + virtual bool hasVolumeType() const + { + return true; + } + + + // Single point queries. + + //- Calculate nearest point on surface. Returns + // - bool : any point found nearer than nearestDistSqr + // - label: relevant index in surface (=face 0..5) + // - point: actual nearest point found + pointIndexHit findNearest + ( + const point& sample, + const scalar nearestDistSqr + ) const; + + //- Calculate nearest point on edge. Returns + // - bool : any point found nearer than nearestDistSqr + // - label: relevant index in surface(=?) + // - point: actual nearest point found + pointIndexHit findNearestOnEdge + ( + const point& sample, + const scalar nearestDistSqr + ) const; + + //- Find nearest to segment. Returns + // - bool : any point found? + // - label: relevant index in shapes (=face 0..5) + // - point: actual nearest point found + // sets: + // - tightest : bounding box + // - linePoint : corresponding nearest point on line + pointIndexHit findNearest + ( + const linePointRef& ln, + treeBoundBox& tightest, + point& linePoint + ) const; + + //- Find nearest intersection of line between start and end. + pointIndexHit findLine + ( + const point& start, + const point& end + ) const; + + //- Find any intersection of line between start and end. + pointIndexHit findLineAny + ( + const point& start, + const point& end + ) const; + + + // Multiple point queries. + + virtual void findNearest + ( + const pointField& sample, + const scalarField& nearestDistSqr, + List<pointIndexHit>& + ) const; + + virtual void findLine + ( + const pointField& start, + const pointField& end, + List<pointIndexHit>& + ) const; + + virtual void findLineAny + ( + const pointField& start, + const pointField& end, + List<pointIndexHit>& + ) const; + + //- Get all intersections in order from start to end. + virtual void findLineAll + ( + const pointField& start, + const pointField& end, + List<List<pointIndexHit> >& + ) const; + + //- From a set of points and indices get the region + virtual void getRegion + ( + const List<pointIndexHit>&, + labelList& region + ) const; + + //- From a set of points and indices get the normal + virtual void getNormal + ( + const List<pointIndexHit>&, + vectorField& normal + ) const; + + //- Determine type (inside/outside/mixed) for point. unknown if + // cannot be determined (e.g. non-manifold surface) + virtual void getVolumeType + ( + const pointField&, + List<volumeType>& + ) const; + + + // regIOobject implementation + + bool writeData(Ostream&) const + { + notImplemented("searchableBox::writeData(Ostream&) const"); + return false; + } + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/meshTools/searchableSurface/searchableSphere.C b/src/meshTools/searchableSurface/searchableSphere.C new file mode 100644 index 0000000000000000000000000000000000000000..039be46749d05d74d07824334faf587672464df9 --- /dev/null +++ b/src/meshTools/searchableSurface/searchableSphere.C @@ -0,0 +1,328 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "searchableSphere.H" +#include "addToRunTimeSelectionTable.H" +#include "SortableList.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(searchableSphere, 0); +addToRunTimeSelectionTable(searchableSurface, searchableSphere, dict); + +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::pointIndexHit Foam::searchableSphere::findNearest +( + const point& sample, + const scalar nearestDistSqr +) const +{ + pointIndexHit info(false, sample, -1); + + const vector n(sample-centre_); + scalar magN = mag(n); + + if (nearestDistSqr > sqr(magN-radius_)) + { + info.rawPoint() = centre_ + n/magN*radius_; + info.setHit(); + info.setIndex(0); + } + + return info; +} + + +// From Graphics Gems - intersection of sphere with ray +void Foam::searchableSphere::findLineAll +( + const point& start, + const point& end, + pointIndexHit& near, + pointIndexHit& far +) const +{ + near.setMiss(); + far.setMiss(); + + vector dir(end-start); + scalar magSqrDir = magSqr(dir); + + if (magSqrDir > ROOTVSMALL) + { + const vector toCentre(centre_-start); + scalar magSqrToCentre = magSqr(toCentre); + + dir /= Foam::sqrt(magSqrDir); + + scalar v = (toCentre & dir); + + scalar disc = sqr(radius_) - (magSqrToCentre - sqr(v)); + + if (disc >= 0) + { + scalar d = Foam::sqrt(disc); + + scalar nearParam = v-d; + + if (nearParam >= 0 && sqr(nearParam) <= magSqrDir) + { + near.setHit(); + near.setPoint(start + nearParam*dir); + near.setIndex(0); + } + + scalar farParam = v+d; + + if (farParam >= 0 && sqr(farParam) <= magSqrDir) + { + far.setHit(); + far.setPoint(start + farParam*dir); + far.setIndex(0); + } + } + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::searchableSphere::searchableSphere +( + const IOobject& io, + const point& centre, + const scalar radius +) +: + searchableSurface(io), + centre_(centre), + radius_(radius) +{} + + +Foam::searchableSphere::searchableSphere +( + const IOobject& io, + const dictionary& dict +) +: + searchableSurface(io), + centre_(dict.lookup("centre")), + radius_(readScalar(dict.lookup("radius"))) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::searchableSphere::~searchableSphere() +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +const Foam::wordList& Foam::searchableSphere::regions() const +{ + if (regions_.size() == 0) + { + regions_.setSize(1); + regions_[0] = "region0"; + } + return regions_; +} + + + +void Foam::searchableSphere::findNearest +( + const pointField& samples, + const scalarField& nearestDistSqr, + List<pointIndexHit>& info +) const +{ + info.setSize(samples.size()); + + forAll(samples, i) + { + info[i] = findNearest(samples[i], nearestDistSqr[i]); + } +} + + +void Foam::searchableSphere::findLine +( + const pointField& start, + const pointField& end, + List<pointIndexHit>& info +) const +{ + info.setSize(start.size()); + + pointIndexHit b; + + forAll(start, i) + { + // Pick nearest intersection. If none intersected take second one. + findLineAll(start[i], end[i], info[i], b); + if (!info[i].hit() && b.hit()) + { + info[i] = b; + } + } +} + + +void Foam::searchableSphere::findLineAny +( + const pointField& start, + const pointField& end, + List<pointIndexHit>& info +) const +{ + info.setSize(start.size()); + + pointIndexHit b; + + forAll(start, i) + { + // Discard far intersection + findLineAll(start[i], end[i], info[i], b); + if (!info[i].hit() && b.hit()) + { + info[i] = b; + } + } +} + + +void Foam::searchableSphere::findLineAll +( + const pointField& start, + const pointField& end, + List<List<pointIndexHit> >& info +) const +{ + info.setSize(start.size()); + + pointIndexHit near, far; + + forAll(start, i) + { + findLineAll(start[i], end[i], near, far); + + if (near.hit()) + { + if (far.hit()) + { + info[i].setSize(2); + info[i][0] = near; + info[i][1] = far; + } + else + { + info[i].setSize(1); + info[i][0] = near; + } + } + else + { + if (far.hit()) + { + info[i].setSize(1); + info[i][0] = far; + } + } + } +} + + +void Foam::searchableSphere::getRegion +( + const List<pointIndexHit>& info, + labelList& region +) const +{ + region.setSize(info.size()); + region = 0; +} + + +void Foam::searchableSphere::getNormal +( + const List<pointIndexHit>& info, + vectorField& normal +) const +{ + normal.setSize(info.size()); + normal = vector::zero; + + forAll(info, i) + { + if (info[i].hit()) + { + normal[i] = info[i].hitPoint() - centre_; + normal[i] /= mag(normal[i]); + } + else + { + // Set to what? + } + } +} + + +void Foam::searchableSphere::getVolumeType +( + const pointField& points, + List<volumeType>& volType +) const +{ + volType.setSize(points.size()); + volType = INSIDE; + + forAll(points, pointI) + { + const point& pt = points[pointI]; + + if (magSqr(pt - centre_) <= sqr(radius_)) + { + volType[pointI] = INSIDE; + } + else + { + volType[pointI] = OUTSIDE; + } + } +} + + +// ************************************************************************* // diff --git a/src/meshTools/searchableSurface/searchableSphere.H b/src/meshTools/searchableSurface/searchableSphere.H new file mode 100644 index 0000000000000000000000000000000000000000..61b114de4e46c93aa36b975b9764ef9ea9634770 --- /dev/null +++ b/src/meshTools/searchableSurface/searchableSphere.H @@ -0,0 +1,204 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::searchableSphere + +Description + Searching on sphere + +SourceFiles + searchableSphere.C + +\*---------------------------------------------------------------------------*/ + +#ifndef searchableSphere_H +#define searchableSphere_H + +#include "searchableSurface.H" +#include "treeBoundBox.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration of classes + +/*---------------------------------------------------------------------------*\ + Class searchableSphere Declaration +\*---------------------------------------------------------------------------*/ + +class searchableSphere +: + public searchableSurface +{ +private: + + // Private Member Data + + //- Centre point + const point centre_; + + //- Radius squared + const scalar radius_; + + //- Names of regions + mutable wordList regions_; + + + // Private Member Functions + + //- Find nearest point on sphere. + pointIndexHit findNearest + ( + const point& sample, + const scalar nearestDistSqr + ) const; + + //- Find intersection with sphere + void findLineAll + ( + const point& start, + const point& end, + pointIndexHit& near, + pointIndexHit& far + ) const; + + + //- Disallow default bitwise copy construct + searchableSphere(const searchableSphere&); + + //- Disallow default bitwise assignment + void operator=(const searchableSphere&); + + +public: + + //- Runtime type information + TypeName("searchableSphere"); + + + // Constructors + + //- Construct from components + searchableSphere(const IOobject& io, const point&, const scalar radius); + + //- Construct from dictionary (used by searchableSurface) + searchableSphere + ( + const IOobject& io, + const dictionary& dict + ); + + // Destructor + + virtual ~searchableSphere(); + + + // Member Functions + + virtual const wordList& regions() const; + + //- Whether supports volume type below + virtual bool hasVolumeType() const + { + return true; + } + + + // Multiple point queries. + + virtual void findNearest + ( + const pointField& sample, + const scalarField& nearestDistSqr, + List<pointIndexHit>& + ) const; + + virtual void findLine + ( + const pointField& start, + const pointField& end, + List<pointIndexHit>& + ) const; + + virtual void findLineAny + ( + const pointField& start, + const pointField& end, + List<pointIndexHit>& + ) const; + + //- Get all intersections in order from start to end. + virtual void findLineAll + ( + const pointField& start, + const pointField& end, + List<List<pointIndexHit> >& + ) const; + + //- From a set of points and indices get the region + virtual void getRegion + ( + const List<pointIndexHit>&, + labelList& region + ) const; + + //- From a set of points and indices get the normal + virtual void getNormal + ( + const List<pointIndexHit>&, + vectorField& normal + ) const; + + //- Determine type (inside/outside/mixed) for point. unknown if + // cannot be determined (e.g. non-manifold surface) + virtual void getVolumeType + ( + const pointField&, + List<volumeType>& + ) const; + + + // regIOobject implementation + + bool writeData(Ostream&) const + { + notImplemented("searchableSphere::writeData(Ostream&) const"); + return false; + } + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/meshTools/triSurface/searchableSurface/searchableSurface.C b/src/meshTools/searchableSurface/searchableSurface.C similarity index 67% rename from src/meshTools/triSurface/searchableSurface/searchableSurface.C rename to src/meshTools/searchableSurface/searchableSurface.C index 11996e75341d3cdae108fb2bd57b65089e90f287..4eba2d573bc892c444ddb7f4b2482bb885511a50 100644 --- a/src/meshTools/triSurface/searchableSurface/searchableSurface.C +++ b/src/meshTools/searchableSurface/searchableSurface.C @@ -34,15 +34,13 @@ namespace Foam defineTypeNameAndDebug(searchableSurface, 0); defineRunTimeSelectionTable(searchableSurface, dict); -//defineRunTimeSelectionTable(searchableSurface, istream); // Construct named object from dictionary autoPtr<searchableSurface> searchableSurface::New ( const word& searchableSurfaceType, - const word& name, - const objectRegistry& obj, + const IOobject& io, const dictionary& dict ) { @@ -55,7 +53,7 @@ autoPtr<searchableSurface> searchableSurface::New FatalErrorIn ( "searchableSurface::New(const word&, const word&" - ", const objectRegistry&, const dictionary&)" + ", const IOobject&, const dictionary&)" ) << "Unknown searchableSurface type " << searchableSurfaceType << endl << endl << "Valid searchableSurface types : " << endl @@ -63,44 +61,15 @@ autoPtr<searchableSurface> searchableSurface::New << exit(FatalError); } - return autoPtr<searchableSurface>(cstrIter()(name, obj, dict)); + return autoPtr<searchableSurface>(cstrIter()(io, dict)); } -//// Construct named object from Istream -//autoPtr<searchableSurface> searchableSurface::New -//( -// const word& searchableSurfaceType, -// const objectRegistry& obj, -// Istream& is -//) -//{ -// istreamConstructorTable::iterator cstrIter = -// istreamConstructorTablePtr_ -// ->find(searchableSurfaceType); -// -// if (cstrIter == istreamConstructorTablePtr_->end()) -// { -// FatalErrorIn -// ( -// "searchableSurface::New(const word&, const objectRegistry&" -// ", Istream&)" -// ) << "Unknown searchableSurface type " << searchableSurfaceType -// << endl << endl -// << "Valid searchableSurface types : " << endl -// << istreamConstructorTablePtr_->toc() -// << exit(FatalError); -// } -// -// return autoPtr<searchableSurface>(cstrIter()(obj, is)); -//} - - // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -Foam::searchableSurface::searchableSurface(const word& name) +Foam::searchableSurface::searchableSurface(const IOobject& io) : - name_(name) + regIOobject(io) {} diff --git a/src/meshTools/searchableSurface/searchableSurface.H b/src/meshTools/searchableSurface/searchableSurface.H new file mode 100644 index 0000000000000000000000000000000000000000..f9dc8b12899bb26b52391c23d11085eeb16ca442 --- /dev/null +++ b/src/meshTools/searchableSurface/searchableSurface.H @@ -0,0 +1,322 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::searchableSurface + +Description + Base class of (analytical or triangulated) surface. + Encapsulates all the search routines. WIP. + + Information returned is usually a pointIndexHit: + - bool : was intersection/nearest found? + - point : intersection point or nearest point + - index : unique index on surface (e.g. triangle for triSurfaceMesh) + +SourceFiles + searchableSurface.C + +\*---------------------------------------------------------------------------*/ + +#ifndef searchableSurface_H +#define searchableSurface_H + +#include "pointField.H" +#include "typeInfo.H" +#include "runTimeSelectionTables.H" +#include "pointIndexHit.H" +#include "linePointRef.H" +#include "objectRegistry.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration of classes +class objectRegistry; +class treeBoundBox; + +/*---------------------------------------------------------------------------*\ + Class searchableSurface Declaration +\*---------------------------------------------------------------------------*/ + +class searchableSurface +: + public regIOobject +{ +public: + + // Data types + + //- volume types + enum volumeType + { + UNKNOWN = 0, + MIXED = 1, // not used. only here to maintain consistency with + // indexedOctree volumeType. + INSIDE = 2, + OUTSIDE = 3 + }; + +private: + + // Private data + + const word name_; + + + // Private Member Functions + + //- Disallow default bitwise copy construct + searchableSurface(const searchableSurface&); + + //- Disallow default bitwise assignment + void operator=(const searchableSurface&); + + +public: + + //- Runtime type information + TypeName("searchableSurface"); + + // Declare run-time constructor selection table + + // For the dictionary constructor + declareRunTimeSelectionTable + ( + autoPtr, + searchableSurface, + dict, + ( + const IOobject& io, + const dictionary& dict + ), + (io, dict) + ); + + + //- Class used for the read-construction of + // PtrLists of searchableSurface. + class iNew + { + IOobject& io_; + + public: + + iNew(IOobject& io) + : + io_(io) + {} + + autoPtr<searchableSurface> operator()(Istream& is) const + { + word surfaceType(is); + word readName(is); + dictionary dict(is); + + autoPtr<IOobject> namedIO(io_.clone()); + namedIO().rename(readName); + return searchableSurface::New(surfaceType, namedIO(), dict); + } + }; + + + // Constructors + + searchableSurface(const IOobject& io); + + //- Clone + virtual autoPtr<searchableSurface> clone() const + { + notImplemented("autoPtr<searchableSurface> clone() const"); + return autoPtr<searchableSurface>(NULL); + } + + + // Selectors + + //- Return a reference to the selected searchableSurface + static autoPtr<searchableSurface> New + ( + const word& surfaceType, + const IOobject& io, + const dictionary& dict + ); + + + // Destructor + + virtual ~searchableSurface(); + + + // Member Functions + + + //- Names of regions. + virtual const wordList& regions() const = 0; + + //- Whether supports volume type below. + virtual bool hasVolumeType() const = 0; + + + // Single point queries. + + ////- Calculate nearest point on surface. Returns + //// - bool : any point found nearer than nearestDistSqr + //// - label: relevant index in surface + //// - label: region in surface + //// - point: actual nearest point found + //virtual pointIndexHit findNearest + //( + // const point& sample, + // const scalar nearestDistSqr + //) const = 0; + // + ////- Calculate nearest point on edge. Returns + //// - bool : any point found nearer than nearestDistSqr + //// - label: relevant index in surface + //// - label: region in surface + //// - point: actual nearest point found + //virtual pointIndexHit findNearestOnEdge + //( + // const point& sample, + // const scalar nearestDistSqr + //) const = 0; + // + ////- Find nearest to segment. Returns + //// - bool : any point found? + //// - label: relevant index in shapes + //// - label: region in surface + //// - point: actual nearest point found + //// sets: + //// - tightest : bounding box + //// - linePoint : corresponding nearest point on line + //virtual pointIndexHit findNearest + //( + // const linePointRef& ln, + // treeBoundBox& tightest, + // point& linePoint + //) const = 0; + // + ////- Find nearest intersection of line between start and end. + //virtual pointIndexHit findLine + //( + // const point& start, + // const point& end + //) const = 0; + // + ////- Find any intersection of line between start and end. + //virtual pointIndexHit findLineAny + //( + // const point& start, + // const point& end + //) const = 0; + + + // Multiple point queries. When surface is distributed the index + // should be a global index. Not done yet. + + virtual void findNearest + ( + const pointField& sample, + const scalarField& nearestDistSqr, + List<pointIndexHit>& + ) const = 0; + + //- Find first intersection on segment from start to end. + // Note: searchableSurfacesQueries expects no + // intersection to be found if start==end. Is problem? + virtual void findLine + ( + const pointField& start, + const pointField& end, + List<pointIndexHit>& + ) const = 0; + + //- Return any intersection on segment from start to end. + virtual void findLineAny + ( + const pointField& start, + const pointField& end, + List<pointIndexHit>& + ) const = 0; + + //- Get all intersections in order from start to end. + virtual void findLineAll + ( + const pointField& start, + const pointField& end, + List<List<pointIndexHit> >& + ) const = 0; + + //- From a set of points and indices get the region + virtual void getRegion + ( + const List<pointIndexHit>&, + labelList& region + ) const = 0; + + //- From a set of points and indices get the normal + virtual void getNormal + ( + const List<pointIndexHit>&, + vectorField& normal + ) const = 0; + + //- Determine type (inside/outside) for point. unknown if + // cannot be determined (e.g. non-manifold surface) + virtual void getVolumeType + ( + const pointField&, + List<volumeType>& + ) const = 0; + + + // Other + + ////- Get bounding box. + //const boundBox& bounds() const = 0; + + ////- Set bounding box. + //void setBounds + //( + // const boundBox&, + // autoPtr<mapDistribute>& faceMap, + // autoPtr<mapDistribute>& pointMap + //) = 0; + + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/meshTools/searchableSurface/searchableSurfaces.C b/src/meshTools/searchableSurface/searchableSurfaces.C new file mode 100644 index 0000000000000000000000000000000000000000..9689744fca45e4c8f6ca84a84125b69625803a1a --- /dev/null +++ b/src/meshTools/searchableSurface/searchableSurfaces.C @@ -0,0 +1,355 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*----------------------------------------------------------------------------*/ + +#include "searchableSurfaces.H" +#include "searchableSurfacesQueries.H" +#include "ListOps.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(searchableSurfaces, 0); + +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +// Construct with length. +Foam::searchableSurfaces::searchableSurfaces(const label size) +: + PtrList<searchableSurface>(size), + regionNames_(size), + allSurfaces_(identity(size)) +{} + + +//Foam::searchableSurfaces::searchableSurfaces +//( +// const IOobject& io, +// const PtrList<dictionary>& dicts +//) +//: +// PtrList<searchableSurface>(dicts.size()), +// regionNames_(dicts.size()), +// allSurfaces_(identity(dicts.size())) +//{ +// forAll(dicts, surfI) +// { +// const dictionary& dict = dicts[surfI]; +// +// // Make IOobject with correct name +// autoPtr<IOobject> namedIO(io.clone()); +// namedIO().rename(dict.lookup("name")); +// +// // Create and hook surface +// set +// ( +// surfI, +// searchableSurface::New +// ( +// dict.lookup("type"), +// namedIO(), +// dict +// ) +// ); +// const searchableSurface& s = operator[](surfI); +// +// // Construct default region names by prepending surface name +// // to region name. +// const wordList& localNames = s.regions(); +// +// wordList globalNames(localNames.size()); +// forAll(localNames, regionI) +// { +// globalNames[regionI] = s.name() + '_' + localNames[regionI]; +// } +// +// // See if dictionary provides any global region names. +// if (dict.found("regions")) +// { +// const dictionary& regionsDict = dict.subDict("regions"); +// +// forAllConstIter(dictionary, regionsDict, iter) +// { +// const word& key = iter().keyword(); +// +// if (regionsDict.isDict(key)) +// { +// // Get the dictionary for region iter.key() +// const dictionary& regionDict = regionsDict.subDict(key); +// +// label index = findIndex(localNames, key); +// +// if (index == -1) +// { +// FatalErrorIn +// ( +// "searchableSurfaces::searchableSurfaces" +// "( const IOobject&, const dictionary&)" +// ) << "Unknown region name " << key +// << " for surface " << s.name() << endl +// << "Valid region names are " << localNames +// << exit(FatalError); +// } +// +// globalNames[index] = word(regionDict.lookup("name")); +// } +// } +// } +// +// // Now globalNames contains the names of the regions. +// Info<< "Surface:" << s.name() << " has regions:" +// << endl; +// forAll(globalNames, regionI) +// { +// Info<< " " << globalNames[regionI] << endl; +// } +// +// // Create reverse lookup +// forAll(globalNames, regionI) +// { +// regionNames_.insert +// ( +// globalNames[regionI], +// labelPair(surfI, regionI) +// ); +// } +// } +//} + + +Foam::searchableSurfaces::searchableSurfaces +( + const IOobject& io, + const dictionary& topDict +) +: + PtrList<searchableSurface>(topDict.size()), + names_(topDict.size()), + regionNames_(topDict.size()), + allSurfaces_(identity(topDict.size())) +{ + label surfI = 0; + forAllConstIter(dictionary, topDict, iter) + { + const word& key = iter().keyword(); + + if (!topDict.isDict(key)) + { + FatalErrorIn + ( + "searchableSurfaces::searchableSurfaces" + "( const IOobject&, const dictionary&)" + ) << "Found non-dictionary entry " << iter() + << " in top-level dictionary " << topDict + << exit(FatalError); + } + + const dictionary& dict = topDict.subDict(key); + + names_[surfI] = key; + + if (dict.found("name")) + { + dict.lookup("name") >> names_[surfI]; + } + + + // Make IOobject with correct name + autoPtr<IOobject> namedIO(io.clone()); + // Note: we would like to e.g. register triSurface 'sphere.stl' as + // 'sphere'. Unfortunately + // no support for having object read from different location than + // their object name. Maybe have stlTriSurfaceMesh which appends .stl + // when reading/writing? + namedIO().rename(key); // names_[surfI] + + // Create and hook surface + set + ( + surfI, + searchableSurface::New + ( + dict.lookup("type"), + namedIO(), + dict + ) + ); + const searchableSurface& s = operator[](surfI); + + // Construct default region names by prepending surface name + // to region name. + const wordList& localNames = s.regions(); + + wordList& rNames = regionNames_[surfI]; + rNames.setSize(localNames.size()); + + forAll(localNames, regionI) + { + rNames[regionI] = names_[surfI] + '_' + localNames[regionI]; + } + + // See if dictionary provides any global region names. + if (dict.found("regions")) + { + const dictionary& regionsDict = dict.subDict("regions"); + + forAllConstIter(dictionary, regionsDict, iter) + { + const word& key = iter().keyword(); + + if (regionsDict.isDict(key)) + { + // Get the dictionary for region iter.keyword() + const dictionary& regionDict = regionsDict.subDict(key); + + label index = findIndex(localNames, key); + + if (index == -1) + { + FatalErrorIn + ( + "searchableSurfaces::searchableSurfaces" + "( const IOobject&, const dictionary&)" + ) << "Unknown region name " << key + << " for surface " << s.name() << endl + << "Valid region names are " << localNames + << exit(FatalError); + } + + rNames[index] = word(regionDict.lookup("name")); + } + } + } + + surfI++; + } + + // Trim (not really necessary since we don't allow non-dictionary entries) + PtrList<searchableSurface>::setSize(surfI); + names_.setSize(surfI); + regionNames_.setSize(surfI); + allSurfaces_.setSize(surfI); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::label Foam::searchableSurfaces::findSurfaceID(const word& wantedName) + const +{ + return findIndex(names_, wantedName); +} + + +// Find any intersection +void Foam::searchableSurfaces::findAnyIntersection +( + const pointField& start, + const pointField& end, + labelList& hitSurfaces, + List<pointIndexHit>& hitInfo +) const +{ + searchableSurfacesQueries::findAnyIntersection + ( + *this, + allSurfaces_, + start, + end, + hitSurfaces, + hitInfo + ); +} + + +// Find intersections of edge nearest to both endpoints. +void Foam::searchableSurfaces::findAllIntersections +( + const pointField& start, + const pointField& end, + labelListList& hitSurfaces, + List<List<pointIndexHit> >& hitInfo +) const +{ + searchableSurfacesQueries::findAllIntersections + ( + *this, + allSurfaces_, + start, + end, + hitSurfaces, + hitInfo + ); +} + + +// Find nearest. Return -1 or nearest point +void Foam::searchableSurfaces::findNearest +( + const pointField& samples, + const scalarField& nearestDistSqr, + labelList& nearestSurfaces, + List<pointIndexHit>& nearestInfo +) const +{ + return searchableSurfacesQueries::findNearest + ( + *this, + allSurfaces_, + samples, + nearestDistSqr, + nearestSurfaces, + nearestInfo + ); +} + + +//- Calculate point which is on a set of surfaces. +Foam::pointIndexHit Foam::searchableSurfaces::facesIntersection +( + const scalar initDistSqr, + const scalar convergenceDistSqr, + const point& start +) const +{ + return searchableSurfacesQueries::facesIntersection + ( + *this, + allSurfaces_, + initDistSqr, + convergenceDistSqr, + start + ); +} + + +// ************************************************************************* // diff --git a/src/meshTools/searchableSurface/searchableSurfaces.H b/src/meshTools/searchableSurface/searchableSurfaces.H new file mode 100644 index 0000000000000000000000000000000000000000..4e6c1bc2edfbc27c468e4b2a3331412332e5f037 --- /dev/null +++ b/src/meshTools/searchableSurface/searchableSurfaces.H @@ -0,0 +1,187 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::searchableSurfaces + +Description + Container for searchableSurfaces. + +SourceFiles + searchableSurfaces.C + +\*---------------------------------------------------------------------------*/ + +#ifndef searchableSurfaces_H +#define searchableSurfaces_H + +#include "searchableSurface.H" +#include "labelPair.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration of classes + +/*---------------------------------------------------------------------------*\ + Class searchableSurfaces Declaration +\*---------------------------------------------------------------------------*/ + +class searchableSurfaces +: + public PtrList<searchableSurface> +{ + // Private data + + //- Surface names + wordList names_; + + //- Region names per surface + List<wordList> regionNames_; + + ////- From global region name to surface and region on surface + //HashTable<labelPair> regionNames_; + + //- Indices of all surfaces. Precalculated and stored. + labelList allSurfaces_; + + + //- Disallow default bitwise copy construct + searchableSurfaces(const searchableSurfaces&); + + //- Disallow default bitwise assignment + void operator=(const searchableSurfaces&); + + +public: + + ClassName("searchableSurfaces"); + + // Constructors + + //- Construct with length specified. Fill later. + explicit searchableSurfaces(const label); + + + ////- Construct from list of dictionaries + //searchableSurfaces(const IOobject&, const PtrList<dictionary>&); + + //- Construct from dictionary + searchableSurfaces(const IOobject&, const dictionary&); + + + // Member Functions + + const wordList& names() const + { + return names_; + } + wordList& names() + { + return names_; + } + + const List<wordList>& regionNames() const + { + return regionNames_; + } + List<wordList>& regionNames() + { + return regionNames_; + } + + + ////- If adding surfaces 'by hand' + //HashTable<labelPair>& regionNames() + //{ + // return regionNames_; + //} + ////- Get surface and region for a name + //const labelPair& surfaceRegion(const word& globalRegion) const + //{ + // return regionNames_[globalRegion]; + //} + + //- Find index of surface. Return -1 if not found. + label findSurfaceID(const word& name) const; + + + // Multiple point queries. + + //- Find any intersection. Return hit point information and + // surface number. If multiple surfaces hit the first surface + // is returned, not necessarily the nearest (to start). + void findAnyIntersection + ( + const pointField& start, + const pointField& end, + labelList& surfaces, + List<pointIndexHit>& + ) const; + + //- Find all intersections in order from start to end. Returns for + // every hit the surface and the hit info. + void findAllIntersections + ( + const pointField& start, + const pointField& end, + labelListList& surfaces, + List<List<pointIndexHit> >& surfaceHits + ) const; + + //- Find nearest. Return -1 (and a miss()) or surface and nearest + // point. + void findNearest + ( + const pointField&, + const scalarField& nearestDistSqr, + labelList& surfaces, + List<pointIndexHit>& + ) const; + + + // Single point queries + + //- Calculate point which is on a set of surfaces. + pointIndexHit facesIntersection + ( + const scalar initialDistSqr, + const scalar convergenceDistSqr, + const point& start + ) const; + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/meshTools/searchableSurface/searchableSurfacesQueries.C b/src/meshTools/searchableSurface/searchableSurfacesQueries.C new file mode 100644 index 0000000000000000000000000000000000000000..ed807628199668e30a37c2abdea6822a90c9bd9e --- /dev/null +++ b/src/meshTools/searchableSurface/searchableSurfacesQueries.C @@ -0,0 +1,822 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*----------------------------------------------------------------------------*/ + +#include "searchableSurfacesQueries.H" +#include "SortableList.H" +#include "OFstream.H" +#include "meshTools.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(searchableSurfacesQueries, 0); + +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::pointIndexHit Foam::searchableSurfacesQueries::tempFindNearest +( + const searchableSurface& surf, + const point& pt, + const scalar initDistSqr +) +{ + pointField onePoint(1, pt); + scalarField oneDist(1, initDistSqr); + List<pointIndexHit> oneHit(1); + surf.findNearest(onePoint, oneDist, oneHit); + return oneHit[0]; +} + + +// Calculate sum of distance to surfaces. +Foam::scalar Foam::searchableSurfacesQueries::sumDistSqr +( + const PtrList<searchableSurface>& allSurfaces, + const labelList& surfacesToTest, + const scalar initDistSqr, + const point& pt +) +{ + scalar sum = 0; + + forAll(surfacesToTest, testI) + { + label surfI = surfacesToTest[testI]; + + pointIndexHit hit + ( + tempFindNearest(allSurfaces[surfI], pt, initDistSqr) + ); + + // Note: make it fall over if not hit. + sum += magSqr(hit.hitPoint()-pt); + } + return sum; +} + + +// Reflects the point furthest away around the triangle centre by a factor fac. +// (triangle centre is the average of all points but the ihi. pSum is running +// sum of all points) +Foam::scalar Foam::searchableSurfacesQueries::tryMorphTet +( + const PtrList<searchableSurface>& allSurfaces, + const labelList& surfacesToTest, + const scalar initDistSqr, + List<vector>& p, + List<scalar>& y, + vector& pSum, + const label ihi, + const scalar fac +) +{ + scalar fac1 = (1.0-fac)/vector::nComponents; + scalar fac2 = fac1-fac; + + vector ptry = pSum*fac1-p[ihi]*fac2; + + scalar ytry = sumDistSqr(allSurfaces, surfacesToTest, initDistSqr, ptry); + + if (ytry < y[ihi]) + { + y[ihi] = ytry; + pSum += ptry - p[ihi]; + p[ihi] = ptry; + } + return ytry; +} + + +bool Foam::searchableSurfacesQueries::morphTet +( + const PtrList<searchableSurface>& allSurfaces, + const labelList& surfacesToTest, + const scalar initDistSqr, + const scalar convergenceDistSqr, + const label maxIter, + List<vector>& p, + List<scalar>& y +) +{ + vector pSum = sum(p); + + autoPtr<OFstream> str; + label vertI = 0; + if (debug) + { + wordList names(surfacesToTest.size()); + forAll(surfacesToTest, i) + { + names[i] = allSurfaces[surfacesToTest[i]].name(); + } + Pout<< "searchableSurfacesQueries::morphTet : intersection of " + << names << " starting from points:" << p << endl; + str.reset(new OFstream("track.obj")); + meshTools::writeOBJ(str(), p[0]); + vertI++; + } + + for (label iter = 0; iter < maxIter; iter++) + { + // Get the indices of highest, second-highest and lowest values. + label ihi, inhi, ilo; + { + SortableList<scalar> sortedY(y); + ilo = sortedY.indices()[0]; + ihi = sortedY.indices()[sortedY.size()-1]; + inhi = sortedY.indices()[sortedY.size()-2]; + } + + if (debug) + { + Pout<< "Iteration:" << iter + << " lowest:" << y[ilo] << " highest:" << y[ihi] + << " points:" << p << endl; + + meshTools::writeOBJ(str(), p[ilo]); + vertI++; + str()<< "l " << vertI-1 << ' ' << vertI << nl; + } + + if (y[ihi] < convergenceDistSqr) + { + // Get point on 0th surface. + Swap(p[0], p[ilo]); + Swap(y[0], y[ilo]); + return true; + } + + // Reflection: point furthest away gets reflected. + scalar ytry = tryMorphTet + ( + allSurfaces, + surfacesToTest, + 10*y[ihi], // search box. + p, + y, + pSum, + ihi, + -1.0 + ); + + if (ytry <= y[ilo]) + { + // If in right direction (y lower) expand by two. + ytry = tryMorphTet + ( + allSurfaces, + surfacesToTest, + 10*y[ihi], + p, + y, + pSum, + ihi, + 2.0 + ); + } + else if (ytry >= y[inhi]) + { + // If inside tet try contraction. + + scalar ysave = y[ihi]; + + ytry = tryMorphTet + ( + allSurfaces, + surfacesToTest, + 10*y[ihi], + p, + y, + pSum, + ihi, + 0.5 + ); + + if (ytry >= ysave) + { + // Contract around lowest point. + forAll(p, i) + { + if (i != ilo) + { + p[i] = 0.5*(p[i] + p[ilo]); + y[i] = sumDistSqr + ( + allSurfaces, + surfacesToTest, + y[ihi], + p[i] + ); + } + } + pSum = sum(p); + } + } + } + + if (debug) + { + meshTools::writeOBJ(str(), p[0]); + vertI++; + str()<< "l " << vertI-1 << ' ' << vertI << nl; + } + + // Failure to converge. Return best guess so far. + label ilo = findMin(y); + Swap(p[0], p[ilo]); + Swap(y[0], y[ilo]); + return false; +} + + +//// Get all intersections (in order) for single surface. +//void Foam::searchableSurfacesQueries::findAllIntersections +//( +// const searchableSurface& s, +// const pointField& start, +// const pointField& end, +// const vectorField& smallVec, +// List<List<pointIndexHit> >& surfaceHitInfo +//) +//{ +// surfaceHitInfo.setSize(start.size()); +// +// // Current start point of vector +// pointField p0(start); +// +// List<pointIndexHit> intersectInfo(start.size()); +// +// // For test whether finished doing vector. +// const vectorField dirVec(end-start); +// const scalarField magSqrDirVec(magSqr(dirVec)); +// +// while (true) +// { +// // Find first intersection. Synced. +// s.findLine(p0, end, intersectInfo); +// +// label nHits = 0; +// +// forAll(intersectInfo, i) +// { +// if (intersectInfo[i].hit()) +// { +// nHits++; +// +// label sz = surfaceHitInfo[i].size(); +// surfaceHitInfo[i].setSize(sz+1); +// surfaceHitInfo[i][sz] = intersectInfo[i]; +// +// p0[i] = intersectInfo[i].hitPoint() + smallVec[i]; +// +// // If beyond endpoint set to endpoint so as not to pick up +// // any intersections. Could instead just filter out hits. +// if (((p0[i]-start[i])&dirVec[i]) > magSqrDirVec[i]) +// { +// p0[i] = end[i]; +// } +// } +// else +// { +// // Set to endpoint to stop intersection test. See above. +// p0[i] = end[i]; +// } +// } +// +// // returnReduce(nHits) ? +// if (nHits == 0) +// { +// break; +// } +// } +//} + + +// Given current set of hits (allSurfaces, allInfo) merge in those coming from +// surface surfI. +void Foam::searchableSurfacesQueries::mergeHits +( + const point& start, + const scalar mergeDist, + + const label testI, // index of surface + const List<pointIndexHit>& surfHits, // hits on surface + + labelList& allSurfaces, + List<pointIndexHit>& allInfo, + scalarList& allDistSqr +) +{ + // Precalculate distances + scalarList surfDistSqr(surfHits.size()); + forAll(surfHits, i) + { + surfDistSqr[i] = magSqr(surfHits[i].hitPoint()-start); + } + + forAll(surfDistSqr, i) + { + label index = findLower(allDistSqr, surfDistSqr[i]); + + // Check if equal to lower. + if + ( + index >= 0 + && (mag(allDistSqr[index]-surfDistSqr[i]) < mergeDist) + ) + { + // Same. Do not count. + //Pout<< "point:" << surfHits[i].hitPoint() + // << " considered same as:" << allInfo[index].hitPoint() + // << " within tol:" << mergeDist + // << endl; + } + else + { + // Check if equal to higher + label next = index+1; + if + ( + next < allDistSqr.size() + && (mag(allDistSqr[next]-surfDistSqr[i]) < mergeDist) + ) + { + //Pout<< "point:" << surfHits[i].hitPoint() + // << " considered same as:" << allInfo[next].hitPoint() + // << " within tol:" << mergeDist + // << endl; + } + else + { + // Insert after index + label sz = allSurfaces.size(); + allSurfaces.setSize(sz+1); + allInfo.setSize(allSurfaces.size()); + allDistSqr.setSize(allSurfaces.size()); + // Make space. + for (label j = sz-1; j > index; --j) + { + allSurfaces[j+1] = allSurfaces[j]; + allInfo[j+1] = allInfo[j]; + allDistSqr[j+1] = allDistSqr[j]; + } + // Insert new value + allSurfaces[index+1] = testI; + allInfo[index+1] = surfHits[i]; + allDistSqr[index+1] = surfDistSqr[i]; + } + } + } +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +// Find any intersection +void Foam::searchableSurfacesQueries::findAnyIntersection +( + const PtrList<searchableSurface>& allSurfaces, + const labelList& surfacesToTest, + const pointField& start, + const pointField& end, + labelList& hitSurfaces, + List<pointIndexHit>& hitInfo +) +{ + hitSurfaces.setSize(start.size()); + hitSurfaces = -1; + hitInfo.setSize(start.size()); + + // Work arrays + labelList hitMap(identity(start.size())); + pointField p0(start); + pointField p1(end); + List<pointIndexHit> intersectInfo(start.size()); + + forAll(surfacesToTest, testI) + { + // Do synchronised call to all surfaces. + allSurfaces[surfacesToTest[testI]].findLineAny(p0, p1, intersectInfo); + + // Copy all hits into arguments, continue with misses + label newI = 0; + forAll(intersectInfo, i) + { + if (intersectInfo[i].hit()) + { + hitInfo[hitMap[i]] = intersectInfo[i]; + hitSurfaces[hitMap[i]] = testI; + } + else + { + if (i != newI) + { + hitMap[newI] = hitMap[i]; + p0[newI] = p0[i]; + p1[newI] = p1[i]; + } + newI++; + } + } + + // All done? Note that this decision should be synchronised + if (newI == 0) + { + break; + } + + // Trim and continue + hitMap.setSize(newI); + p0.setSize(newI); + p1.setSize(newI); + intersectInfo.setSize(newI); + } +} + + +void Foam::searchableSurfacesQueries::findAllIntersections +( + const PtrList<searchableSurface>& allSurfaces, + const labelList& surfacesToTest, + const pointField& start, + const pointField& end, + labelListList& hitSurfaces, + List<List<pointIndexHit> >& hitInfo +) +{ + // Note: maybe move the single-surface all intersections test into + // searchable surface? Some of the tolerance issues might be + // lessened. + + // 2. Currently calling searchableSurface::findLine with start==end + // is expected to find no intersection. Problem if it does. + + hitSurfaces.setSize(start.size()); + hitInfo.setSize(start.size()); + + if (surfacesToTest.size() == 0) + { + return; + } + + // Test first surface + allSurfaces[surfacesToTest[0]].findLineAll(start, end, hitInfo); + + // Set hitSurfaces and distance + List<scalarList> hitDistSqr(hitInfo.size()); + forAll(hitInfo, pointI) + { + const List<pointIndexHit>& pHits = hitInfo[pointI]; + + labelList& pSurfaces = hitSurfaces[pointI]; + pSurfaces.setSize(pHits.size()); + pSurfaces = 0; + + scalarList& pDistSqr = hitDistSqr[pointI]; + pDistSqr.setSize(pHits.size()); + forAll(pHits, i) + { + pDistSqr[i] = magSqr(pHits[i].hitPoint() - start[pointI]); + } + } + + + if (surfacesToTest.size() > 1) + { + // Small vector to increment start vector by to find next intersection + // along line. Constant factor added to make sure that start==end still + // ends iteration in findAllIntersections. Also SMALL is just slightly + // too small. + const vectorField smallVec + ( + 1E2*SMALL*(end-start) + + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL) + ); + + // Tolerance used to check whether points are equal. Note: used to + // compare distance^2. Note that we use the maximum possible tolerance + // (reached at intersections close to the end point) + const scalarField mergeDist(2*mag(smallVec)*mag(end-start)); + + // Test the other surfaces and merge (according to distance from start). + for (label testI = 1; testI < surfacesToTest.size(); testI++) + { + List<List<pointIndexHit> > surfHits; + allSurfaces[surfacesToTest[testI]].findLineAll + ( + start, + end, + surfHits + ); + + forAll(surfHits, pointI) + { + mergeHits + ( + start[pointI], // Current segment + mergeDist[pointI], + + testI, // Surface and its hits + surfHits[pointI], + + hitSurfaces[pointI], // Merge into overall hit info + hitInfo[pointI], + hitDistSqr[pointI] + ); + } + } + } +} + + +//// Find intersections of edge nearest to both endpoints. +//void Foam::searchableSurfacesQueries::findNearestIntersection +//( +// const PtrList<searchableSurface>& allSurfaces, +// const labelList& surfacesToTest, +// const pointField& start, +// const pointField& end, +// +// labelList& surface1, +// List<pointIndexHit>& hit1, +// labelList& surface2, +// List<pointIndexHit>& hit2 +//) +//{ +// // 1. intersection from start to end +// // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// // Initialize arguments +// surface1.setSize(start.size()); +// surface1 = -1; +// hit1.setSize(start.size()); +// +// // Current end of segment to test. +// pointField nearest(end); +// // Work array +// List<pointIndexHit> nearestInfo(start.size()); +// +// forAll(surfacesToTest, testI) +// { +// // See if any intersection between start and current nearest +// allSurfaces[surfacesToTest[testI]].findLine +// ( +// start, +// nearest, +// nearestInfo +// ); +// +// forAll(nearestInfo, pointI) +// { +// if (nearestInfo[pointI].hit()) +// { +// hit1[pointI] = nearestInfo[pointI]; +// surface1[pointI] = testI; +// nearest[pointI] = hit1[pointI].hitPoint(); +// } +// } +// } +// +// +// // 2. intersection from end to last intersection +// // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// // Find the nearest intersection from end to start. Note that we +// // initialize to the first intersection (if any). +// surface2 = surface1; +// hit2 = hit1; +// +// // Set current end of segment to test. +// forAll(nearest, pointI) +// { +// if (hit1[pointI].hit()) +// { +// nearest[pointI] = hit1[pointI].hitPoint(); +// } +// else +// { +// // Disable testing by setting to end. +// nearest[pointI] = end[pointI]; +// } +// } +// +// forAll(surfacesToTest, testI) +// { +// // See if any intersection between end and current nearest +// allSurfaces[surfacesToTest[i]].findLine(end, nearest, nearestInfo); +// +// forAll(nearestInfo, pointI) +// { +// if (nearestInfo[pointI].hit()) +// { +// hit2[pointI] = nearestInfo[pointI]; +// surface2[pointI] = testI; +// nearest[pointI] = hit2[pointI].hitPoint(); +// } +// } +// } +//} + + +// Find nearest. Return -1 or nearest point +void Foam::searchableSurfacesQueries::findNearest +( + const PtrList<searchableSurface>& allSurfaces, + const labelList& surfacesToTest, + const pointField& samples, + const scalarField& nearestDistSqr, + labelList& nearestSurfaces, + List<pointIndexHit>& nearestInfo +) +{ + // Initialise + nearestSurfaces.setSize(samples.size()); + nearestSurfaces = -1; + nearestInfo.setSize(samples.size()); + + // Work arrays + scalarField minDistSqr(nearestDistSqr); + List<pointIndexHit> hitInfo(samples.size()); + + forAll(surfacesToTest, testI) + { + allSurfaces[surfacesToTest[testI]].findNearest + ( + samples, + minDistSqr, + hitInfo + ); + + // Update minDistSqr and arguments + forAll(hitInfo, pointI) + { + if (hitInfo[pointI].hit()) + { + minDistSqr[pointI] = magSqr + ( + hitInfo[pointI].hitPoint() + - samples[pointI] + ); + nearestInfo[pointI] = hitInfo[pointI]; + nearestSurfaces[pointI] = testI; + } + } + } +} + + +//- Calculate point which is on a set of surfaces. +Foam::pointIndexHit Foam::searchableSurfacesQueries::facesIntersection +( + const PtrList<searchableSurface>& allSurfaces, + const labelList& surfacesToTest, + const scalar initDistSqr, + const scalar convergenceDistSqr, + const point& start +) +{ + // Get four starting points. Take these as the projection of the + // starting point onto the surfaces and the mid point + List<point> nearest(surfacesToTest.size()+1); + + point sumNearest = vector::zero; + + forAll(surfacesToTest, i) + { + pointIndexHit hit + ( + tempFindNearest(allSurfaces[surfacesToTest[i]], start, initDistSqr) + ); + + if (hit.hit()) + { + nearest[i] = hit.hitPoint(); + sumNearest += nearest[i]; + } + else + { + FatalErrorIn + ( + "searchableSurfacesQueries::facesIntersection" + "(const labelList&, const scalar, const scalar, const point&)" + ) << "Did not find point within distance " + << initDistSqr << " of starting point " << start + << " on surface " + << allSurfaces[surfacesToTest[i]].IOobject::name() + << abort(FatalError); + } + } + + nearest[nearest.size()-1] = sumNearest / surfacesToTest.size(); + + + // Get the sum of distances (initial evaluation) + List<scalar> nearestDist(nearest.size()); + + forAll(nearestDist, i) + { + nearestDist[i] = sumDistSqr + ( + allSurfaces, + surfacesToTest, + initDistSqr, + nearest[i] + ); + } + + + //- Downhill Simplex method + + bool converged = morphTet + ( + allSurfaces, + surfacesToTest, + initDistSqr, + convergenceDistSqr, + 2000, + nearest, + nearestDist + ); + + + pointIndexHit intersection; + + if (converged) + { + // Project nearest onto 0th surface. + intersection = tempFindNearest + ( + allSurfaces[surfacesToTest[0]], + nearest[0], + nearestDist[0] + ); + } + + //if (!intersection.hit()) + //{ + // // Restart + // scalar smallDist = Foam::sqr(convergenceDistSqr); + // nearest[0] = intersection.hitPoint(); + // nearest[1] = nearest[0]; + // nearest[1].x() += smallDist; + // nearest[2] = nearest[0]; + // nearest[2].y() += smallDist; + // nearest[3] = nearest[0]; + // nearest[3].z() += smallDist; + // + // forAll(nearestDist, i) + // { + // nearestDist[i] = sumDistSqr + // ( + // surfacesToTest, + // initDistSqr, + // nearest[i] + // ); + // } + // + // intersection = morphTet + // ( + // allSurfaces, + // surfacesToTest, + // initDistSqr, + // convergenceDistSqr, + // 1000, + // nearest, + // nearestDist + // ); + //} + + return intersection; +} + + + +// ************************************************************************* // diff --git a/src/meshTools/searchableSurface/searchableSurfacesQueries.H b/src/meshTools/searchableSurface/searchableSurfacesQueries.H new file mode 100644 index 0000000000000000000000000000000000000000..599d186baeca4fb7d3899503ec269388e6a08279 --- /dev/null +++ b/src/meshTools/searchableSurface/searchableSurfacesQueries.H @@ -0,0 +1,198 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::searchableSurfacesQueries + +Description + A collection of tools for searchableSurfaces. + +SourceFiles + searchableSurfacesQueries.C + +\*---------------------------------------------------------------------------*/ + +#ifndef searchableSurfacesQueries_H +#define searchableSurfacesQueries_H + +#include "searchableSurface.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration of classes +class plane; + +/*---------------------------------------------------------------------------*\ + Class searchableSurfacesQueries Declaration +\*---------------------------------------------------------------------------*/ + +class searchableSurfacesQueries +{ + // Private data + + // Private Member Functions + + //- Temporary wrapper around findNearest. Used in facesIntersection only + static pointIndexHit tempFindNearest + ( + const searchableSurface&, + const point& pt, + const scalar initDistSqr + ); + + //- Calculate sum of distances to nearest point on surfaces. Is used + // in minimisation to find intersection. Returns sum of (square of) + // distances to the surfaces. + static scalar sumDistSqr + ( + const PtrList<searchableSurface>&, + const labelList& surfacesToTest, + const scalar initialDistSqr, // search box + const point& pt + ); + + //- Takes the tet (points p) and reflects the point with the + // highest value around the centre (pSum). Checks if it gets closer + // and updates p, y if so. + static scalar tryMorphTet + ( + const PtrList<searchableSurface>&, + const labelList& surfacesToTest, + const scalar initialDistSqr, + List<vector>& p, + List<scalar>& y, + vector& pSum, + const label ihi, + const scalar fac + ); + + //- Downhill simplex method: find the point with min cumulative + // distance to all surfaces. Does so by morphing a tet (points p). + // Returns the point on the 0th surface or hit if not reached within + // maxIters iterations. + static bool morphTet + ( + const PtrList<searchableSurface>&, + const labelList& surfacesToTest, + const scalar initialDistSqr, + const scalar convergenceDistSqr, + const label maxIter, + List<vector>& p, + List<scalar>& y + ); + + //static void findAllIntersections + //( + // const searchableSurface& s, + // const pointField& start, + // const pointField& end, + // const vectorField& smallVec, + // List<List<pointIndexHit> >& + //); + + static void mergeHits + ( + const point& start, + const scalar mergeDist, + + const label surfI, + const List<pointIndexHit>& surfHits, + + labelList& allSurfaces, + List<pointIndexHit>& allInfo, + scalarList& allDistSqr + ); + +public: + + // Declare name of the class and its debug switch + ClassName("searchableSurfacesQueries"); + + + // Multiple point queries. + + //- Find any intersection. Return hit point information and + // index in surfacesToTest. If multiple surfaces hit the first + // surface is returned, not necessarily the nearest (to start). + static void findAnyIntersection + ( + const PtrList<searchableSurface>&, + const labelList& surfacesToTest, + const pointField& start, + const pointField& end, + labelList& surfaces, + List<pointIndexHit>& + ); + + //- Find all intersections in order from start to end. Returns for + // every hit the index in surfacesToTest and the hit info. + static void findAllIntersections + ( + const PtrList<searchableSurface>&, + const labelList& surfacesToTest, + const pointField& start, + const pointField& end, + labelListList& surfaces, + List<List<pointIndexHit> >& surfaceHits + ); + + //- Find nearest. Return -1 (and a miss()) or surface and nearest + // point. + static void findNearest + ( + const PtrList<searchableSurface>&, + const labelList& surfacesToTest, + const pointField&, + const scalarField& nearestDistSqr, + labelList& surfaces, + List<pointIndexHit>& + ); + + + // Single point queries + + //- Calculate point which is on a set of surfaces. WIP. + static pointIndexHit facesIntersection + ( + const PtrList<searchableSurface>& allSurfaces, + const labelList& surfacesToTest, + const scalar initDistSqr, + const scalar convergenceDistSqr, + const point& start + ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/meshTools/searchableSurface/triSurfaceMesh.C b/src/meshTools/searchableSurface/triSurfaceMesh.C new file mode 100644 index 0000000000000000000000000000000000000000..9751e3a3eff72fcd7f2d86b13bb964ab13f3ac6e --- /dev/null +++ b/src/meshTools/searchableSurface/triSurfaceMesh.C @@ -0,0 +1,552 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "triSurfaceMesh.H" +#include "Random.H" +#include "addToRunTimeSelectionTable.H" +#include "EdgeMap.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(triSurfaceMesh, 0); +addToRunTimeSelectionTable(searchableSurface, triSurfaceMesh, dict); + +} + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +//- Check file existence +const Foam::fileName& Foam::triSurfaceMesh::checkFile +( + const fileName& fName, + const fileName& objectName +) +{ + if (fName == fileName::null) + { + FatalErrorIn + ( + "triSurfaceMesh::checkFile(const fileName&, const fileName&)" + ) << "Cannot find triSurfaceMesh starting from " + << objectName << exit(FatalError); + } + return fName; +} + + +bool Foam::triSurfaceMesh::isSurfaceClosed() const +{ + // Construct pointFaces. Let's hope surface has compact point + // numbering ... + labelListList pointFaces; + invertManyToMany(points().size(), *this, pointFaces); + + // Loop over all faces surrounding point. Count edges emanating from point. + // Every edge should be used by two faces exactly. + // To prevent doing work twice per edge only look at edges to higher + // point + EdgeMap<label> facesPerEdge(100); + forAll(pointFaces, pointI) + { + const labelList& pFaces = pointFaces[pointI]; + + facesPerEdge.clear(); + forAll(pFaces, i) + { + const labelledTri& f = triSurface::operator[](pFaces[i]); + label fp = findIndex(f, pointI); + + // Forward edge + { + label p1 = f[f.fcIndex(fp)]; + + if (p1 > pointI) + { + const edge e(pointI, p1); + EdgeMap<label>::iterator eFnd = facesPerEdge.find(e); + if (eFnd != facesPerEdge.end()) + { + if (eFnd() == 2) + { + return false; + } + eFnd()++; + } + else + { + facesPerEdge.insert(e, 1); + } + } + } + // Reverse edge + { + label p1 = f[f.rcIndex(fp)]; + + if (p1 > pointI) + { + const edge e(pointI, p1); + EdgeMap<label>::iterator eFnd = facesPerEdge.find(e); + if (eFnd != facesPerEdge.end()) + { + if (eFnd() == 2) + { + return false; + } + eFnd()++; + } + else + { + facesPerEdge.insert(e, 1); + } + } + } + } + + // Check for any edges used only once. + forAllConstIter(EdgeMap<label>, facesPerEdge, iter) + { + if (iter() != 2) + { + return false; + } + } + } + + return true; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io, const triSurface& s) +: + searchableSurface(io), + objectRegistry(io), + triSurface(s), + surfaceClosed_(-1) +{} + + +Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io) +: + searchableSurface(io), + objectRegistry(io), + triSurface + ( + checkFile + ( + searchableSurface::filePath(), + searchableSurface::objectPath() + ) + ), + surfaceClosed_(-1) +{} + + +Foam::triSurfaceMesh::triSurfaceMesh +( + const IOobject& io, + const dictionary& dict +) +: + searchableSurface(io), + objectRegistry(io), + triSurface + ( + checkFile + ( + searchableSurface::filePath(), + searchableSurface::objectPath() + ) + ), + surfaceClosed_(-1) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::triSurfaceMesh::~triSurfaceMesh() +{ + clearOut(); +} + + +void Foam::triSurfaceMesh::clearOut() +{ + tree_.clear(); + edgeTree_.clear(); + triSurface::clearOut(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::triSurfaceMesh::movePoints(const pointField& newPoints) +{ + tree_.clear(); + edgeTree_.clear(); + triSurface::movePoints(newPoints); +} + + +const Foam::indexedOctree<Foam::treeDataTriSurface>& + Foam::triSurfaceMesh::tree() const +{ + if (!tree_.valid()) + { + treeBoundBox bb(points(), meshPoints()); + + // Random number generator. Bit dodgy since not exactly random ;-) + Random rndGen(65431); + + tree_.reset + ( + new indexedOctree<treeDataTriSurface> + ( + treeDataTriSurface(*this), + bb.extend(rndGen, 1E-3), // slightly randomize bb + 10, // maxLevel + 10, // leafsize + 3.0 // duplicity + ) + ); + } + + return tree_(); +} + + +const Foam::indexedOctree<Foam::treeDataEdge>& + Foam::triSurfaceMesh::edgeTree() const +{ + if (!edgeTree_.valid()) + { + treeBoundBox bb(localPoints()); + + // Boundary edges + labelList bEdges + ( + identity + ( + nEdges() + -nInternalEdges() + ) + + nInternalEdges() + ); + + // Random number generator. Bit dodgy since not exactly random ;-) + Random rndGen(65431); + + edgeTree_.reset + ( + new indexedOctree<treeDataEdge> + ( + treeDataEdge + ( + false, // cachebb + edges(), // edges + localPoints(), // points + bEdges // selected edges + ), + bb.extend(rndGen, 1E-3), // slightly randomize bb + 8, // maxLevel + 10, // leafsize + 3.0 // duplicity + ) + ); + } + return edgeTree_(); +} + + +const Foam::wordList& Foam::triSurfaceMesh::regions() const +{ + if (regions_.size() == 0) + { + regions_.setSize(patches().size()); + forAll(regions_, regionI) + { + regions_[regionI] = patches()[regionI].name(); + } + } + return regions_; +} + + +//Foam::pointIndexHit Foam::triSurfaceMesh::findNearest +//( +// const point& sample, +// const scalar nearestDistSqr +//) const +//{ +// return tree().findNearest(sample, nearestDistSqr); +//} +// +// +//Foam::pointIndexHit Foam::triSurfaceMesh::findNearestOnEdge +//( +// const point& sample, +// const scalar nearestDistSqr +//) const +//{ +// return = edgeTree().findNearest(sample, nearestDistSqr); +//} +// +// +//Foam::pointIndexHit Foam::triSurfaceMesh::findNearest +//( +// const linePointRef& ln, +// treeBoundBox& tightest, +// point& linePoint +//) const +//{ +// return tree().findNearest(ln, tightest, linePoint); +//} +// +// +//Foam::pointIndexHit Foam::triSurfaceMesh::findLine +//( +// const point& start, +// const point& end +//) const +//{ +// return tree().findLine(start, end); +//} +// +// +//Foam::pointIndexHit Foam::triSurfaceMesh::findLineAny +//( +// const point& start, +// const point& end +//) const +//{ +// return tree().findLineAny(start, end); +//} + + +// Find out if surface is closed. +bool Foam::triSurfaceMesh::hasVolumeType() const +{ + if (surfaceClosed_ == -1) + { + if (isSurfaceClosed()) + { + surfaceClosed_ = 1; + } + else + { + surfaceClosed_ = 0; + } + } + + return surfaceClosed_ == 1; +} + + +void Foam::triSurfaceMesh::findNearest +( + const pointField& samples, + const scalarField& nearestDistSqr, + List<pointIndexHit>& info +) const +{ + const indexedOctree<treeDataTriSurface>& octree = tree(); + + info.setSize(samples.size()); + + forAll(samples, i) + { + static_cast<pointIndexHit&>(info[i]) = + octree.findNearest(samples[i], nearestDistSqr[i]); + } +} + + +void Foam::triSurfaceMesh::findLine +( + const pointField& start, + const pointField& end, + List<pointIndexHit>& info +) const +{ + const indexedOctree<treeDataTriSurface>& octree = tree(); + + info.setSize(start.size()); + + forAll(start, i) + { + static_cast<pointIndexHit&>(info[i]) = octree.findLine + ( + start[i], + end[i] + ); + } +} + + +void Foam::triSurfaceMesh::findLineAny +( + const pointField& start, + const pointField& end, + List<pointIndexHit>& info +) const +{ + const indexedOctree<treeDataTriSurface>& octree = tree(); + + info.setSize(start.size()); + + forAll(start, i) + { + static_cast<pointIndexHit&>(info[i]) = + octree.findLineAny(start[i], end[i]); + } +} + + +void Foam::triSurfaceMesh::findLineAll +( + const pointField& start, + const pointField& end, + List<List<pointIndexHit> >& info +) const +{ + const indexedOctree<treeDataTriSurface>& octree = tree(); + + info.setSize(start.size()); + + // Work array + DynamicList<pointIndexHit, 1, 1> hits; + + // Tolerances + const vectorField dirVec(end-start); + const scalarField magSqrDirVec(magSqr(dirVec)); + const vectorField smallVec + ( + Foam::sqrt(SMALL)*dirVec + + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL) + ); + + forAll(start, pointI) + { + hits.clear(); + + // Current starting point of ray. + point pt = start[pointI]; + + while (true) + { + // See if any intersection between pt and end + pointIndexHit inter = octree.findLine(pt, end[pointI]); + + if (!inter.hit()) + { + break; + } + hits.append(inter); + + pt = inter.hitPoint() + smallVec[pointI]; + + if (((pt-start[pointI])&dirVec[pointI]) > magSqrDirVec[pointI]) + { + // Adding smallVec has taken us beyond end + break; + } + } + + hits.shrink(); + info[pointI].transfer(hits); + hits.clear(); + } +} + + +void Foam::triSurfaceMesh::getRegion +( + const List<pointIndexHit>& info, + labelList& region +) const +{ + region.setSize(info.size()); + forAll(info, i) + { + if (info[i].hit()) + { + region[i] = triSurface::operator[](info[i].index()).region(); + } + else + { + region[i] = -1; + } + } +} + + +void Foam::triSurfaceMesh::getNormal +( + const List<pointIndexHit>& info, + vectorField& normal +) const +{ + normal.setSize(info.size()); + + forAll(info, i) + { + if (info[i].hit()) + { + normal[i] = faceNormals()[info[i].index()]; + } + else + { + // Set to what? + normal[i] = vector::zero; + } + } +} + + +void Foam::triSurfaceMesh::getVolumeType +( + const pointField& points, + List<volumeType>& volType +) const +{ + volType.setSize(points.size()); + + forAll(points, pointI) + { + const point& pt = points[pointI]; + + // - use cached volume type per each tree node + // - cheat conversion since same values + volType[pointI] = static_cast<volumeType>(tree().getVolumeType(pt)); + } +} + + +// ************************************************************************* // diff --git a/src/meshTools/triSurface/searchableSurface/triSurfaceMesh.H b/src/meshTools/searchableSurface/triSurfaceMesh.H similarity index 65% rename from src/meshTools/triSurface/searchableSurface/triSurfaceMesh.H rename to src/meshTools/searchableSurface/triSurfaceMesh.H index 453b4daa6127456e0077e03568b8688212d6bb3a..8a0709386cd2120eba63e5fd1c15b7fcacc5f93e 100644 --- a/src/meshTools/triSurface/searchableSurface/triSurfaceMesh.H +++ b/src/meshTools/searchableSurface/triSurfaceMesh.H @@ -54,7 +54,7 @@ namespace Foam class triSurfaceMesh : public searchableSurface, - public objectRegistry, + public objectRegistry, // so we can store fields public triSurface { private: @@ -67,6 +67,12 @@ private: //- Search tree for boundary edges. mutable autoPtr<indexedOctree<treeDataEdge> > edgeTree_; + //- Names of regions + mutable wordList regions_; + + //- Is surface closed + mutable label surfaceClosed_; + // Private Member Functions //- Check file existence @@ -76,6 +82,10 @@ private: const fileName& objectName ); + //- Check whether surface is closed without calculating any permanent + // addressing. + bool isSurfaceClosed() const; + //- Disallow default bitwise copy construct triSurfaceMesh(const triSurfaceMesh&); @@ -97,11 +107,10 @@ public: //- Construct read triSurfaceMesh(const IOobject& io); - //- Construct as searchableSurface + //- Construct from dictionary (used by searchableSurface) triSurfaceMesh ( - const word& name, - const objectRegistry& obj, + const IOobject& io, const dictionary& dict ); @@ -128,57 +137,73 @@ public: // searchableSurface implementation - //- Calculate nearest point on surface. Returns - // - bool : any point found nearer than nearestDistSqr - // - label: relevant index in surface - // - point: actual nearest point found - virtual pointIndexHit findNearest + virtual const wordList& regions() const; + + //- Whether supports volume type below. I.e. whether is closed. + virtual bool hasVolumeType() const; + + + // Multiple point queries. + + virtual void findNearest ( - const point& sample, - const scalar nearestDistSqr + const pointField& sample, + const scalarField& nearestDistSqr, + List<pointIndexHit>& ) const; - //- Calculate nearest point on edge. Returns - // - bool : any point found nearer than nearestDistSqr - // - label: relevant index in surface - // - point: actual nearest point found - virtual pointIndexHit findNearestOnEdge + virtual void findLine ( - const point& sample, - const scalar nearestDistSqr + const pointField& start, + const pointField& end, + List<pointIndexHit>& ) const; - //- Find nearest to line. Returns - // - bool : any point found? - // - label: relevant index in shapes - // - point: actual nearest point found - // sets: - // - tightest : bounding box - // - linePoint : corresponding nearest point on line - virtual pointIndexHit findNearest + virtual void findLineAny ( - const linePointRef& ln, - treeBoundBox& tightest, - point& linePoint + const pointField& start, + const pointField& end, + List<pointIndexHit>& ) const; - //- Find nearest intersection of line between start and end. - virtual pointIndexHit findLine + //- Get all intersections in order from start to end. + virtual void findLineAll ( - const point& start, - const point& end + const pointField& start, + const pointField& end, + List<List<pointIndexHit> >& ) const; - //- Find any intersection of line between start and end. - virtual pointIndexHit findLineAny + //- From a set of points and indices get the region + virtual void getRegion ( - const point& start, - const point& end + const List<pointIndexHit>&, + labelList& region + ) const; + + //- From a set of points and indices get the normal + virtual void getNormal + ( + const List<pointIndexHit>&, + vectorField& normal ) const; //- Determine type (inside/outside/mixed) for point. unknown if // cannot be determined (e.g. non-manifold surface) - virtual volumeType getVolumeType(const point&) const; + virtual void getVolumeType + ( + const pointField&, + List<volumeType>& + ) const; + + + // regIOobject implementation + + bool writeData(Ostream&) const + { + notImplemented("triSurfaceMesh::writeData(Ostream&) const"); + return false; + } }; diff --git a/src/meshTools/triSurface/searchableSurface/searchableBox.C b/src/meshTools/triSurface/searchableSurface/searchableBox.C deleted file mode 100644 index 77e48c3a8ee80f863675c3a4bb22e68fcc13dc30..0000000000000000000000000000000000000000 --- a/src/meshTools/triSurface/searchableSurface/searchableBox.C +++ /dev/null @@ -1,247 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. - \\/ M anipulation | -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -\*---------------------------------------------------------------------------*/ - -#include "searchableBox.H" -#include "addToRunTimeSelectionTable.H" - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ - -defineTypeNameAndDebug(searchableBox, 0); -addToRunTimeSelectionTable(searchableSurface, searchableBox, dict); - -} - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -Foam::searchableBox::searchableBox -( - const word& name, - const treeBoundBox& bb -) -: - searchableSurface(name), - treeBoundBox(bb) -{} - - -Foam::searchableBox::searchableBox -( - const word& name, - const objectRegistry& obj, - const dictionary& dict -) -: - searchableSurface(name), - treeBoundBox(dict.lookup("min"), dict.lookup("max")) -{} - - -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::searchableBox::~searchableBox() -{} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -Foam::pointIndexHit Foam::searchableBox::findNearest -( - const point& sample, - const scalar nearestDistSqr -) const -{ - // Point can be inside or outside. For every component direction can be - // left of min, right of max or inbetween. - // - outside points: project first one x plane (either min().x() - // or max().x()), then onto y plane and finally z. You should be left - // with intersection point - // - inside point: find nearest side (compare to mid point). Pick any - // one of three points. - - const point bbMid(mid()); - - // Outside point projected onto cube - point interPt(sample); - bool outside = false; - - // (for internal points) Per direction what nearest cube side is - point near; - - for (direction dir = 0; dir < vector::nComponents; dir++) - { - if (interPt[dir] < min()[dir]) - { - interPt[dir] = min()[dir]; - outside = true; - } - else if (interPt[dir] > max()[dir]) - { - interPt[dir] = max()[dir]; - outside = true; - } - else if (interPt[dir] > bbMid[dir]) - { - near[dir] = max()[dir]; - } - else - { - near[dir] = min()[dir]; - } - } - - - // For outside points the interPt will be correct now. Handle inside points - // using the three near distances. Project onto the nearest plane. - if (!outside) - { - vector dist(cmptMag(interPt - near)); - - if (dist.x() < dist.y()) - { - if (dist.x() < dist.z()) - { - interPt.x() = near.x(); - } - else - { - interPt.z() = near.z(); - } - } - else - { - if (dist.y() < dist.z()) - { - interPt.y() = near.y(); - } - else - { - interPt.z() = near.z(); - } - } - } - - return pointIndexHit(true, interPt, 0); -} - - -Foam::pointIndexHit Foam::searchableBox::findNearestOnEdge -( - const point& sample, - const scalar nearestDistSqr -) const -{ - const point bbMid(mid()); - - point interPt(sample); - - for (direction dir = 0; dir < vector::nComponents; dir++) - { - // Project onto left or right depending on mid - if (interPt[dir] > bbMid[dir]) - { - interPt[dir] = max()[dir]; - } - else - { - interPt[dir] = min()[dir]; - } - } - - return pointIndexHit(true, interPt, 0); -} - - -Foam::pointIndexHit Foam::searchableBox::findNearest -( - const linePointRef& ln, - treeBoundBox& tightest, - point& linePoint -) const -{ - notImplemented - ( - "searchableBox::findNearest" - "(const linePointRef&, treeBoundBox&, point&)" - ); - return pointIndexHit(); -} - - -Foam::pointIndexHit Foam::searchableBox::findLine -( - const point& start, - const point& end -) const -{ - point intPt; - bool foundInter = intersects(start, end, intPt); - - return pointIndexHit(foundInter, intPt, 0); -} - - -Foam::pointIndexHit Foam::searchableBox::findLineAny -( - const point& start, - const point& end -) const -{ - return findLine(start, end); -} - - -Foam::searchableSurface::volumeType Foam::searchableBox::getVolumeType -( - const point& pt -) const -{ - for (direction dir = 0; dir < vector::nComponents; dir++) - { - if (pt[dir] < min()[dir] || pt[dir] > max()[dir]) - { - return OUTSIDE; - } - } - - return INSIDE; -} - - -// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * // - - -// ************************************************************************* // diff --git a/src/meshTools/triSurface/searchableSurface/searchableBox.H b/src/meshTools/triSurface/searchableSurface/searchableBox.H deleted file mode 100644 index 4a347af46a9761629d4c2985392e0043320ce340..0000000000000000000000000000000000000000 --- a/src/meshTools/triSurface/searchableSurface/searchableBox.H +++ /dev/null @@ -1,161 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. - \\/ M anipulation | -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Class - Foam::searchableBox - -Description - Searching on bounding box - -SourceFiles - searchableBox.C - -\*---------------------------------------------------------------------------*/ - -#ifndef searchableBox_H -#define searchableBox_H - -#include "searchableSurface.H" -#include "treeBoundBox.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -// Forward declaration of classes - -/*---------------------------------------------------------------------------*\ - Class searchableBox Declaration -\*---------------------------------------------------------------------------*/ - -class searchableBox -: - public searchableSurface, - public treeBoundBox -{ -private: - - // Private member data - - - // Private Member Functions - - //- Disallow default bitwise copy construct - searchableBox(const searchableBox&); - - //- Disallow default bitwise assignment - void operator=(const searchableBox&); - - -public: - - //- Runtime type information - TypeName("searchableBox"); - - - // Constructors - - //- Construct from components - searchableBox(const word& name, const treeBoundBox& bb); - - searchableBox - ( - const word& name, - const objectRegistry& obj, - const dictionary& dict - ); - - // Destructor - - virtual ~searchableBox(); - - - // Member Functions - - //- Calculate nearest point on surface. Returns - // - bool : any point found nearer than nearestDistSqr - // - label: relevant index in surface - // - point: actual nearest point found - virtual pointIndexHit findNearest - ( - const point& sample, - const scalar nearestDistSqr - ) const; - - //- Calculate nearest point on edge. Returns - // - bool : any point found nearer than nearestDistSqr - // - label: relevant index in surface - // - point: actual nearest point found - virtual pointIndexHit findNearestOnEdge - ( - const point& sample, - const scalar nearestDistSqr - ) const; - - //- Find nearest to line. Returns - // - bool : any point found? - // - label: relevant index in shapes - // - point: actual nearest point found - // sets: - // - tightest : bounding box - // - linePoint : corresponding nearest point on line - virtual pointIndexHit findNearest - ( - const linePointRef& ln, - treeBoundBox& tightest, - point& linePoint - ) const; - - //- Find nearest intersection of line between start and end. - virtual pointIndexHit findLine - ( - const point& start, - const point& end - ) const; - - //- Find any intersection of line between start and end. - virtual pointIndexHit findLineAny - ( - const point& start, - const point& end - ) const; - - //- Determine type (inside/outside/mixed) for point. unknown if - // cannot be determined (e.g. non-manifold surface) - virtual volumeType getVolumeType(const point&) const; - - -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/src/meshTools/triSurface/searchableSurface/searchableSurface.H b/src/meshTools/triSurface/searchableSurface/searchableSurface.H deleted file mode 100644 index 83f7aaf929cd706ce97ae11560f2804c346018bd..0000000000000000000000000000000000000000 --- a/src/meshTools/triSurface/searchableSurface/searchableSurface.H +++ /dev/null @@ -1,257 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. - \\/ M anipulation | -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Class - Foam::searchableSurface - -Description - Base class of (analytical or triangulated) surface. - Encapsulates all the search routines. - -SourceFiles - searchableSurface.C - -\*---------------------------------------------------------------------------*/ - -#ifndef searchableSurface_H -#define searchableSurface_H - -#include "pointField.H" -#include "typeInfo.H" -#include "runTimeSelectionTables.H" -#include "pointIndexHit.H" -#include "linePointRef.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -// Forward declaration of classes -class objectRegistry; -class treeBoundBox; - -/*---------------------------------------------------------------------------*\ - Class searchableSurface Declaration -\*---------------------------------------------------------------------------*/ - -class searchableSurface -{ -public: - - // Data types - - //- volume types - enum volumeType - { - UNKNOWN = 0, - MIXED = 1, - INSIDE = 2, - OUTSIDE = 3 - }; - -private: - - // Private data - - const word name_; - - - // Private Member Functions - - //- Disallow default bitwise copy construct - searchableSurface(const searchableSurface&); - - //- Disallow default bitwise assignment - void operator=(const searchableSurface&); - - -public: - - //- Runtime type information - TypeName("searchableSurface"); - - // Declare run-time constructor selection table - - // For the dictionary constructor - declareRunTimeSelectionTable - ( - autoPtr, - searchableSurface, - dict, - ( - const word& name, - const objectRegistry& obj, - const dictionary& dict - ), - (name, obj, dict) - ); - - //// For the Istream constructor - //declareRunTimeSelectionTable - //( - // autoPtr, - // searchableSurface, - // istream, - // ( - // const objectRegistry& obj, - // Istream& is - // ), - // (obj, is) - //); - - - //- Class used for the read-construction of - // PtrLists of searchableSurface - class iNew - { - const objectRegistry& obj_; - - public: - - iNew(const objectRegistry& obj) - : - obj_(obj) - {} - - autoPtr<searchableSurface> operator()(Istream& is) const - { - word surfaceType(is); - word name(is); - dictionary dict(is); - return searchableSurface::New(surfaceType, name, obj_, dict); - } - }; - - - // Constructors - - searchableSurface(const word& name); - - //- Clone - virtual autoPtr<searchableSurface> clone() const - { - notImplemented("autoPtr<searchableSurface> clone() const"); - return autoPtr<searchableSurface>(NULL); - } - - - // Selectors - - //- Return a reference to the selected searchableSurface - static autoPtr<searchableSurface> New - ( - const word& surfaceType, - const word& name, - const objectRegistry& obj, - const dictionary& dict - ); - - ////- Return a reference to the selected searchableSurface - //static autoPtr<searchableSurface> New - //( - // const word& surfaceType, - // const objectRegistry& obj, - // Istream& is - //); - - - // Destructor - - virtual ~searchableSurface(); - - - // Member Functions - - //- Return name - const word& name() const - { - return name_; - } - - //- Calculate nearest point on surface. Returns - // - bool : any point found nearer than nearestDistSqr - // - label: relevant index in surface - // - point: actual nearest point found - virtual pointIndexHit findNearest - ( - const point& sample, - const scalar nearestDistSqr - ) const = 0; - - //- Calculate nearest point on edge. Returns - // - bool : any point found nearer than nearestDistSqr - // - label: relevant index in surface - // - point: actual nearest point found - virtual pointIndexHit findNearestOnEdge - ( - const point& sample, - const scalar nearestDistSqr - ) const = 0; - - //- Find nearest to segment. Returns - // - bool : any point found? - // - label: relevant index in shapes - // - point: actual nearest point found - // sets: - // - tightest : bounding box - // - linePoint : corresponding nearest point on line - virtual pointIndexHit findNearest - ( - const linePointRef& ln, - treeBoundBox& tightest, - point& linePoint - ) const = 0; - - //- Find nearest intersection of line between start and end. - virtual pointIndexHit findLine - ( - const point& start, - const point& end - ) const = 0; - - //- Find any intersection of line between start and end. - virtual pointIndexHit findLineAny - ( - const point& start, - const point& end - ) const = 0; - - //- Determine type (inside/outside/mixed) for point. unknown if - // cannot be determined (e.g. non-manifold surface) - virtual volumeType getVolumeType(const point&) const = 0; - - -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/src/meshTools/triSurface/searchableSurface/triSurfaceMesh.C b/src/meshTools/triSurface/searchableSurface/triSurfaceMesh.C deleted file mode 100644 index ec17352f99c0b27c3edaad00648b2b8eb290ac41..0000000000000000000000000000000000000000 --- a/src/meshTools/triSurface/searchableSurface/triSurfaceMesh.C +++ /dev/null @@ -1,271 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. - \\/ M anipulation | -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -\*---------------------------------------------------------------------------*/ - -#include "triSurfaceMesh.H" -#include "Random.H" -#include "addToRunTimeSelectionTable.H" - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ - -defineTypeNameAndDebug(triSurfaceMesh, 0); -addToRunTimeSelectionTable(searchableSurface, triSurfaceMesh, dict); - -} - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -//- Check file existence -const Foam::fileName& Foam::triSurfaceMesh::checkFile -( - const fileName& fName, - const fileName& objectName -) -{ - if (fName == fileName::null) - { - FatalErrorIn - ( - "triSurfaceMesh::checkFile(const fileName&, const fileName&)" - ) << "Cannot find triSurfaceMesh starting from " - << objectName << exit(FatalError); - } - return fName; -} - - -const Foam::indexedOctree<Foam::treeDataTriSurface>& - Foam::triSurfaceMesh::tree() const -{ - if (!tree_.valid()) - { - treeBoundBox bb(points(), meshPoints()); - - // Random number generator. Bit dodgy since not exactly random ;-) - Random rndGen(65431); - - tree_.reset - ( - new indexedOctree<treeDataTriSurface> - ( - treeDataTriSurface(*this), - bb.extend(rndGen, 1E-3), // slightly randomize bb - 8, // maxLevel - 10, // leafsize - 3.0 // duplicity - ) - ); - } - - return tree_(); -} - - -const Foam::indexedOctree<Foam::treeDataEdge>& - Foam::triSurfaceMesh::edgeTree() const -{ - if (!edgeTree_.valid()) - { - treeBoundBox bb(localPoints()); - - // Boundary edges - labelList bEdges - ( - identity - ( - nEdges() - -nInternalEdges() - ) - + nInternalEdges() - ); - - // Random number generator. Bit dodgy since not exactly random ;-) - Random rndGen(65431); - - edgeTree_.reset - ( - new indexedOctree<treeDataEdge> - ( - treeDataEdge - ( - false, // cachebb - edges(), // edges - localPoints(), // points - bEdges // selected edges - ), - bb.extend(rndGen, 1E-3), // slightly randomize bb - 8, // maxLevel - 10, // leafsize - 3.0 // duplicity - ) - ); - } - return edgeTree_(); -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -//- Construct from triangles, patches, points. -Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io, const triSurface& s) -: - searchableSurface(io.name()), - objectRegistry(io), - triSurface(s) -{} - - -Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io) -: - searchableSurface(io.name()), - objectRegistry(io), - triSurface(checkFile(filePath(), objectPath())) -{} - - -Foam::triSurfaceMesh::triSurfaceMesh -( - const word& name, - const objectRegistry& obj, - const dictionary& dict -) -: - searchableSurface(name), - objectRegistry - ( - IOobject - ( - name, - "constant", - "triSurface", - obj, - IOobject::MUST_READ, - IOobject::NO_WRITE - ) - ), - triSurface(checkFile(filePath(), objectPath())) -{} - - -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::triSurfaceMesh::~triSurfaceMesh() -{} - - -void Foam::triSurfaceMesh::clearOut() -{ - tree_.clear(); - edgeTree_.clear(); - triSurface::clearOut(); -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -void Foam::triSurfaceMesh::movePoints(const pointField& newPoints) -{ - tree_.clear(); - edgeTree_.clear(); - triSurface::movePoints(newPoints); -} - - -Foam::pointIndexHit Foam::triSurfaceMesh::findNearest -( - const point& sample, - const scalar nearestDistSqr -) const -{ - return tree().findNearest(sample, nearestDistSqr); -} - - -Foam::pointIndexHit Foam::triSurfaceMesh::findNearestOnEdge -( - const point& sample, - const scalar nearestDistSqr -) const -{ - return edgeTree().findNearest(sample, nearestDistSqr); -} - - -Foam::pointIndexHit Foam::triSurfaceMesh::findNearest -( - const linePointRef& ln, - treeBoundBox& tightest, - point& linePoint -) const -{ - return tree().findNearest(ln, tightest, linePoint); -} - - -Foam::pointIndexHit Foam::triSurfaceMesh::findLine -( - const point& start, - const point& end -) const -{ - return tree().findLine(start, end); -} - - -Foam::pointIndexHit Foam::triSurfaceMesh::findLineAny -( - const point& start, - const point& end -) const -{ - return tree().findLineAny(start, end); -} - - -Foam::searchableSurface::volumeType - Foam::triSurfaceMesh::getVolumeType -( - const point& pt -) const -{ - // - use cached volume type per each tree node - // - cheat conversion since same values - return static_cast<volumeType>(tree().getVolumeType(pt)); -} - - -// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * // - - -// ************************************************************************* // diff --git a/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.C b/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.C deleted file mode 100644 index e96c61885437063e78de33697f102120c08673fc..0000000000000000000000000000000000000000 --- a/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.C +++ /dev/null @@ -1,916 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. - \\/ M anipulation | -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -\*----------------------------------------------------------------------------*/ - -#include "triSurfaceMeshes.H" -#include "Random.H" -#include "Time.H" -#include "SortableList.H" -#include "IOmanip.H" -#include "plane.H" -#include "SortableList.H" -#include "triSurfaceTools.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -defineTypeNameAndDebug(triSurfaceMeshes, 0); - -} - - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -// Calculate sum of distance to surfaces. -Foam::scalar Foam::triSurfaceMeshes::sumDistSqr -( - const labelList& surfacesToTest, - const scalar initDistSqr, - const point& pt -) const -{ - scalar sum = 0; - - forAll(surfacesToTest, i) - { - label surfI = surfacesToTest[i]; - - pointIndexHit hit(operator[](surfI).findNearest(pt, initDistSqr)); - - // Note: make it fall over if not hit. - sum += magSqr(hit.hitPoint()-pt); - } - return sum; -} - - -// Reflects the point furthest away around the triangle centre by a factor fac. -// (triangle centre is the average of all points but the ihi. pSum is running -// sum of all points) -Foam::scalar Foam::triSurfaceMeshes::tryMorphTet -( - const labelList& surfacesToTest, - const scalar initDistSqr, - List<vector>& p, - List<scalar>& y, - vector& pSum, - const label ihi, - const scalar fac -) const -{ - scalar fac1 = (1.0-fac)/vector::nComponents; - scalar fac2 = fac1-fac; - - vector ptry = pSum*fac1-p[ihi]*fac2; - - scalar ytry = sumDistSqr(surfacesToTest, initDistSqr, ptry); - - if (ytry < y[ihi]) - { - y[ihi] = ytry; - pSum += ptry - p[ihi]; - p[ihi] = ptry; - } - return ytry; -} - - -bool Foam::triSurfaceMeshes::morphTet -( - const labelList& surfacesToTest, - const scalar initDistSqr, - const scalar convergenceDistSqr, - const label maxIter, - List<vector>& p, - List<scalar>& y -) const -{ - vector pSum = sum(p); - - autoPtr<OFstream> str; - label vertI = 0; - if (debug) - { - Pout<< "triSurfaceMeshes::morphTet : intersection of " - << IndirectList<fileName>(names(), surfacesToTest)() - << " starting from points:" << p << endl; - str.reset(new OFstream("track.obj")); - meshTools::writeOBJ(str(), p[0]); - vertI++; - } - - for (label iter = 0; iter < maxIter; iter++) - { - // Get the indices of highest, second-highest and lowest values. - label ihi, inhi, ilo; - { - SortableList<scalar> sortedY(y); - ilo = sortedY.indices()[0]; - ihi = sortedY.indices()[sortedY.size()-1]; - inhi = sortedY.indices()[sortedY.size()-2]; - } - - if (debug) - { - Pout<< "Iteration:" << iter - << " lowest:" << y[ilo] << " highest:" << y[ihi] - << " points:" << p << endl; - - meshTools::writeOBJ(str(), p[ilo]); - vertI++; - str()<< "l " << vertI-1 << ' ' << vertI << nl; - } - - if (y[ihi] < convergenceDistSqr) - { - // Get point on 0th surface. - Swap(p[0], p[ilo]); - Swap(y[0], y[ilo]); - return true; - } - - // Reflection: point furthest away gets reflected. - scalar ytry = tryMorphTet - ( - surfacesToTest, - 10*y[ihi], // search box. - p, - y, - pSum, - ihi, - -1.0 - ); - - if (ytry <= y[ilo]) - { - // If in right direction (y lower) expand by two. - ytry = tryMorphTet(surfacesToTest, 10*y[ihi], p, y, pSum, ihi, 2.0); - } - else if (ytry >= y[inhi]) - { - // If inside tet try contraction. - - scalar ysave = y[ihi]; - - ytry = tryMorphTet(surfacesToTest, 10*y[ihi], p, y, pSum, ihi, 0.5); - - if (ytry >= ysave) - { - // Contract around lowest point. - forAll(p, i) - { - if (i != ilo) - { - p[i] = 0.5*(p[i] + p[ilo]); - y[i] = sumDistSqr(surfacesToTest, y[ihi], p[i]); - } - } - pSum = sum(p); - } - } - } - - if (debug) - { - meshTools::writeOBJ(str(), p[0]); - vertI++; - str()<< "l " << vertI-1 << ' ' << vertI << nl; - } - - // Failure to converge. Return best guess so far. - label ilo = findMin(y); - Swap(p[0], p[ilo]); - Swap(y[0], y[ilo]); - return false; -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -// Construct from components -Foam::triSurfaceMeshes::triSurfaceMeshes -( - const IOobject& io, - const fileNameList& names -) -: - PtrList<triSurfaceMesh>(names.size()), - allSurfaces_(identity(names.size())) -{ - forAll(names, i) - { - autoPtr<IOobject> surfaceIO = io.clone(); - surfaceIO().rename(names[i]); - - Info<< "Loading surface " << surfaceIO().name() << endl; - - //fileName fullPath = surfaceIO().filePath(); - // - //if (fullPath.size() == 0) - //{ - // FatalErrorIn - // ( - // "triSurfaceMeshes::triSurfaceMeshes" - // "(const IOobject&, const fileNameList&)" - // ) << "Cannot load surface " << surfaceIO().name() - // << " starting from path " << surfaceIO().path() - // << exit(FatalError); - //} - - set(i, new triSurfaceMesh(surfaceIO())); - - if (Pstream::master()) - { - string oldPrefix(Pout.prefix()); - Pout.prefix() += " "; - operator[](i).writeStats(Pout); - Pout.prefix() = oldPrefix; - } - } -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -Foam::fileNameList Foam::triSurfaceMeshes::allNames(const IOobject& io) -{ - return readDir(io.path(), fileName::FILE); -} - - -Foam::fileNameList Foam::triSurfaceMeshes::names() const -{ - fileNameList surfNames(size()); - - forAll(surfNames, surfI) - { - surfNames[surfI] = operator[](surfI).IOobject::name(); - } - return surfNames; -} - - -// Find any intersection -Foam::label Foam::triSurfaceMeshes::findAnyIntersection -( - const labelList& surfaces, - const point& start, - const point& end, - pointIndexHit& hitInfo -) const -{ - forAll(surfaces, i) - { - label surfI = surfaces[i]; - - hitInfo = operator[](surfI).findLineAny(start, end); - - if (hitInfo.hit()) - { - return surfI; - } - } - return -1; -} - - -Foam::label Foam::triSurfaceMeshes::findAnyIntersection -( - const point& start, - const point& end, - pointIndexHit& hitInfo -) const -{ - return findAnyIntersection - ( - allSurfaces_, - start, - end, - hitInfo - ); -} - - -// Find intersections of edge nearest to both endpoints. -void Foam::triSurfaceMeshes::findAllIntersections -( - const labelList& surfaces, - const point& start, - const point& end, - - labelList& surfacesIndex, - List<pointIndexHit>& surfaceHitInfo -) const -{ - DynamicList<label> hitSurfaces(surfaces.size()); - DynamicList<pointIndexHit> hitInfos(surfaces.size()); - DynamicList<scalar> hitDistSqr(surfaces.size()); - - const vector dirVec(end-start); - const scalar magSqrDirVec(magSqr(dirVec)); - const vector smallVec(Foam::sqrt(SMALL)*dirVec); - - forAll(surfaces, i) - { - label surfI = surfaces[i]; - - // Current starting point of ray. - point pt = start; - - while (true) - { - // See if any intersection between pt and end - pointIndexHit inter = operator[](surfI).findLine(pt, end); - - if (!inter.hit()) - { - break; - } - hitSurfaces.append(surfI); - hitInfos.append(inter); - hitDistSqr.append(magSqr(inter.hitPoint() - start)); - - pt = inter.hitPoint() + smallVec; - - if (((pt-start)&dirVec) > magSqrDirVec) - { - // Adding smallVec has taken us beyond end - break; - } - } - } - surfacesIndex.setSize(hitSurfaces.size()); - surfaceHitInfo.setSize(hitSurfaces.size()); - - if (hitSurfaces.size() > 0) - { - // Sort and transfer to arguments - - hitSurfaces.shrink(); - hitInfos.shrink(); - hitDistSqr.shrink(); - - // Sort from start to end. - SortableList<scalar> sortedDist(hitDistSqr); - - forAll(sortedDist.indices(), newPos) - { - label oldPos = sortedDist.indices()[newPos]; - surfacesIndex[newPos] = hitSurfaces[oldPos]; - surfaceHitInfo[newPos] = hitInfos[oldPos]; - } - } -} - - -void Foam::triSurfaceMeshes::findAllIntersections -( - const point& start, - const point& end, - - labelList& surfacesIndex, - List<pointIndexHit>& surfaceHitInfo -) const -{ - findAllIntersections - ( - allSurfaces_, - start, - end, - surfacesIndex, - surfaceHitInfo - ); -} - - -// Find intersections of edge nearest to both endpoints. -void Foam::triSurfaceMeshes::findNearestIntersection -( - const labelList& surfaces, - const point& start, - const point& end, - - label& surface1, - pointIndexHit& hit1, - label& surface2, - pointIndexHit& hit2 -) const -{ - surface1 = -1; - // Initialize to endpoint - hit1 = pointIndexHit(false, end, -1); - - forAll(surfaces, i) - { - label surfI = surfaces[i]; - - if (hit1.rawPoint() == start) - { - break; - } - - // See if any intersection between start and current nearest - pointIndexHit inter = operator[](surfI).findLine - ( - start, - hit1.rawPoint() - ); - - if (inter.hit()) - { - hit1 = inter; - surface1 = surfI; - } - } - - - // Find the nearest intersection from end to start. Note that we initialize - // to the first intersection (if any). - surface2 = surface1; - hit2 = pointIndexHit(hit1); - - if (hit1.hit()) - { - // Test from the end side. - forAll(surfaces, i) - { - label surfI = surfaces[i]; - - if (hit2.rawPoint() == end) - { - break; - } - - // See if any intersection between end and current nearest - pointIndexHit inter = operator[](surfI).findLine - ( - end, - hit2.rawPoint() - ); - - if (inter.hit()) - { - hit2 = inter; - surface2 = surfI; - } - } - } -} - - -void Foam::triSurfaceMeshes::findNearestIntersection -( - const point& start, - const point& end, - - label& surface1, - pointIndexHit& hit1, - label& surface2, - pointIndexHit& hit2 -) const -{ - findNearestIntersection - ( - allSurfaces_, - start, - end, - surface1, - hit1, - surface2, - hit2 - ); -} - - -// Find nearest. Return -1 or nearest point -Foam::label Foam::triSurfaceMeshes::findNearest -( - const labelList& surfaces, - const point& pt, - const scalar nearestDistSqr, - pointIndexHit& nearestHit -) const -{ - // nearest surface - label minSurface = -1; - scalar minDistSqr = Foam::sqr(GREAT); - - forAll(surfaces, i) - { - label surfI = surfaces[i]; - - pointIndexHit hit - ( - operator[](surfI).findNearest(pt, nearestDistSqr) - ); - - if (hit.hit()) - { - scalar distSqr = magSqr(hit.hitPoint()-pt); - - if (distSqr < minDistSqr) - { - minDistSqr = distSqr; - minSurface = surfI; - nearestHit = hit; - } - } - } - - if (minSurface == -1) - { - // maxLevel unchanged. No interesting surface hit. - nearestHit.setMiss(); - } - - return minSurface; -} - - -// Find nearest. Return -1 or nearest point -Foam::label Foam::triSurfaceMeshes::findNearest -( - const point& pt, - const scalar nearestDistSqr, - pointIndexHit& nearestHit -) const -{ - return findNearest - ( - allSurfaces_, - pt, - nearestDistSqr, - nearestHit - ); -} - - -Foam::label Foam::triSurfaceMeshes::findNearestAndClassify -( - const labelList& surfacesToTest, - const point& pt, - const scalar nearestDistSqr, - surfaceLocation& nearest -) const -{ - pointIndexHit nearestInfo; - label surfI = findNearest - ( - surfacesToTest, - pt, - nearestDistSqr, - nearestInfo - ); - - if (surfI != -1) - { - nearest = triSurfaceTools::classify - ( - operator[](surfI), - nearestInfo.index(), // triangle - nearestInfo.rawPoint() // point on edge/inside triangle - ); - } - - return surfI; -} - - -//- Calculate point which is on a set of surfaces. -Foam::surfaceLocation Foam::triSurfaceMeshes::facesIntersectionTrack -( - const labelList& surfacesToTest, - const scalar initialDistSqr, - const scalar convergenceDistSqr, - const point& start -) const -{ - autoPtr<OFstream> str; - label vertI = 0; - - if (debug) - { - str.reset(new OFstream("track.obj")); - } - - surfaceLocation current - ( - pointIndexHit - ( - false, - start, - -1 - ), - triPointRef::NONE, - -1 - ); - - // Dump start point - if (str.valid()) - { - Pout<< "Starting at " << current.info() - << " written as point " << vertI - << endl; - meshTools::writeOBJ(str(), current.rawPoint()); - vertI++; - } - - // Now slide current along all faces until it settles - label iter = 0; - - const label maxIter = 10; - - for (; iter < maxIter; iter++) - { - // - store old position - // - slide it along all faces - // - if it hasn't changed position exit loop - - if (debug) - { - Pout<< endl - << "Iteration " << iter << endl - << "-----------" << endl; - } - - point oldCurrent = current.rawPoint(); - - forAll(surfacesToTest, i) - { - label surfI = surfacesToTest[i]; - - // Project pt onto surf - // ~~~~~~~~~~~~~~~~~~~~ - point copy(current.rawPoint()); // need to work on copy - if - ( - findNearestAndClassify - ( - labelList(1, surfI), - copy, - initialDistSqr, // initialDistSqr - current - ) - == -1 - ) - { - FatalErrorIn("triSurfaceMeshes::facesIntersectionTrack(..)") - << "Did not find a point on surface " << surfI - << " which is within sqrt(" << initialDistSqr - << ") of " << copy - << abort(FatalError); - } - - - if (debug) - { - Pout<< "Nearest onto surface " << surfI - << ' ' << operator[](surfI).IOobject::name() << " : " - << current.info() << " written as point " << vertI - << endl; - } - - // Dump current - if (str.valid()) - { - meshTools::writeOBJ(str(), current.rawPoint()); - vertI++; - str()<< "l " << vertI-1 << ' ' << vertI << nl; - } - - // Find corresponding point on next surface - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - label nextSurfI = surfacesToTest[surfacesToTest.fcIndex(i)]; - - surfaceLocation next; - findNearestAndClassify - ( - labelList(1, nextSurfI), - point(current.rawPoint()), - initialDistSqr, // initialDistSqr - next - ); - - // Since next is on a different surface we cannot compare - // indices (like in snapToEnd) so make sure this does not - // happen. - next.elementType() = triPointRef::NONE; - next.setIndex(-123); - - if (debug) - { - Pout<< "Nearest onto next surface " << nextSurfI - << ' ' << operator[](nextSurfI).IOobject::name() << " : " - << next.info() << endl; - } - - if - ( - magSqr(current.rawPoint() - next.rawPoint()) - > convergenceDistSqr - ) - { - // Track from current to next - // ~~~~~~~~~~~~~~~~~~~~~~~~~~ - //vector n = current.normal(surfaces[surfI]); - - current = triSurfaceTools::trackToEdge - ( - operator[](surfI), - current, - next, - plane(start, current.rawPoint(), next.rawPoint()) - ); - - if (debug) - { - Pout<< "Sliding along surface " - << surfI << ' ' << operator[](surfI).IOobject::name() - << " in direction of " - << nextSurfI << ' ' - << operator[](nextSurfI).IOobject::name() - << " stopped at " << current.info() - << " written as point " << vertI << endl; - } - if (str.valid()) - { - meshTools::writeOBJ(str(), current.rawPoint()); - vertI++; - str()<< "l " << vertI-1 << ' ' << vertI << nl; - } - } - } - - scalar distSqr = magSqr(oldCurrent - current.rawPoint()); - - if (debug) - { - Pout<< "distSqr:" << distSqr - << " convergenceDistSqr:" << convergenceDistSqr << endl; - } - - if (distSqr < convergenceDistSqr) - { - break; - } - } - - if (iter == maxIter) - { - FatalErrorIn("triSurfaceMeshes::facesIntersectionTrack(..)") - << "Did not converge in " << iter - << " iterations to find a point which is on surfaces " - << IndirectList<fileName>(names(), surfacesToTest)() << nl - << "Start point:" << start << nl - << "Current nearest:" << current.info() << nl - << "Please check that your surfaces actually intersect and" - << " that the starting point is close to the intersection point." - << abort(FatalError); - } - - return current; -} - - -//- Calculate point which is on a set of surfaces. -Foam::pointIndexHit Foam::triSurfaceMeshes::facesIntersection -( - const labelList& surfacesToTest, - const scalar initDistSqr, - const scalar convergenceDistSqr, - const point& start -) const -{ - // Get four starting points. Take these as the projection of the - // starting point onto the surfaces and the mid point - List<point> nearest(surfacesToTest.size()+1); - - point sumNearest = vector::zero; - - forAll(surfacesToTest, i) - { - label surfI = surfacesToTest[i]; - - pointIndexHit hit - ( - operator[](surfI).findNearest(start, initDistSqr) - ); - - if (hit.hit()) - { - nearest[i] = hit.hitPoint(); - sumNearest += nearest[i]; - } - else - { - FatalErrorIn - ( - "triSurfaceMeshes::facesIntersection" - "(const labelList&, const scalar, const scalar, const point&)" - ) << "Did not find point within distance " - << initDistSqr << " of starting point " << start - << " on surface " << operator[](surfI).IOobject::name() - << abort(FatalError); - } - } - - nearest[nearest.size()-1] = sumNearest / surfacesToTest.size(); - - - // Get the sum of distances (initial evaluation) - List<scalar> nearestDist(nearest.size()); - - forAll(nearestDist, i) - { - nearestDist[i] = sumDistSqr(surfacesToTest, initDistSqr, nearest[i]); - } - - - //- Downhill Simplex method - - bool converged = morphTet - ( - surfacesToTest, - initDistSqr, - convergenceDistSqr, - 2000, - nearest, - nearestDist - ); - - - pointIndexHit intersection; - - if (converged) - { - // Project nearest onto 0th surface. - intersection = operator[](surfacesToTest[0]).findNearest - ( - nearest[0], - nearestDist[0] - ); - } - - //if (!intersection.hit()) - //{ - // // Restart - // scalar smallDist = Foam::sqr(convergenceDistSqr); - // nearest[0] = intersection.hitPoint(); - // nearest[1] = nearest[0]; - // nearest[1].x() += smallDist; - // nearest[2] = nearest[0]; - // nearest[2].y() += smallDist; - // nearest[3] = nearest[0]; - // nearest[3].z() += smallDist; - // - // forAll(nearestDist, i) - // { - // nearestDist[i] = sumDistSqr - // ( - // surfacesToTest, - // initDistSqr, - // nearest[i] - // ); - // } - // - // intersection = morphTet - // ( - // surfacesToTest, - // initDistSqr, - // convergenceDistSqr, - // 1000, - // nearest, - // nearestDist - // ); - //} - - return intersection; -} - - - -// ************************************************************************* // diff --git a/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.H b/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.H deleted file mode 100644 index 4269dba6a7bb4593adb7bc39d009e7d4fde7a38b..0000000000000000000000000000000000000000 --- a/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.H +++ /dev/null @@ -1,261 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. - \\/ M anipulation | -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Class - Foam::triSurfaceMeshes - -Description - Container for triSurfaces read from files. - -SourceFiles - triSurfaceMeshes.C - -\*---------------------------------------------------------------------------*/ - -#ifndef triSurfaceMeshes_H -#define triSurfaceMeshes_H - -#include "triSurfaceMesh.H" -#include "fileNameList.H" -#include "treeDataTriSurface.H" -#include "indexedOctree.H" -#include "surfaceLocation.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -// Forward declaration of classes -class plane; - -/*---------------------------------------------------------------------------*\ - Class triSurfaceMeshes Declaration -\*---------------------------------------------------------------------------*/ - -class triSurfaceMeshes -: - public PtrList<triSurfaceMesh> -{ - // Private data - - //- Indices of all surfaces. Precalculated and stored. - const labelList allSurfaces_; - - - // Private Member Functions - - //- Calculate sum of distances to nearest point on surfaces. Is used - // in minimisation to find intersection. Returns sum of (square of) - // distances to the surfaces. - scalar sumDistSqr - ( - const labelList& surfacesToTest, - const scalar initialDistSqr, // search box - const point& pt - ) const; - - //- Takes the tet (points p) and reflects the point with the - // highest value around the centre (pSum). Checks if it gets closer - // and updates p, y if so. - scalar tryMorphTet - ( - const labelList& surfacesToTest, - const scalar initialDistSqr, - List<vector>& p, - List<scalar>& y, - vector& pSum, - const label ihi, - const scalar fac - ) const; - - //- Downhill simplex method: find the point with min cumulative - // distance to all surfaces. Does so by morphing a tet (points p). - // Returns the point on the 0th surface or hit if not reached within - // maxIters iterations. - bool morphTet - ( - const labelList& surfacesToTest, - const scalar initialDistSqr, - const scalar convergenceDistSqr, - const label maxIter, - List<vector>& p, - List<scalar>& y - ) const; - - //- Disallow default bitwise copy construct - triSurfaceMeshes(const triSurfaceMeshes&); - - //- Disallow default bitwise assignment - void operator=(const triSurfaceMeshes&); - - -public: - - ClassName("triSurfaceMeshes"); - - // Constructors - - //- Construct from directory (io.instance()) and list of local filenames - triSurfaceMeshes(const IOobject& io, const fileNameList&); - - - // Member Functions - - //- Get all surfaces in directory - static fileNameList allNames(const IOobject&); - - //- Get names of surfaces - fileNameList names() const; - - - //- Find any intersection. Return hit point information and surface - // number - label findAnyIntersection - ( - const labelList& surfacesToTest, - const point& start, - const point& end, - pointIndexHit& - ) const; - - label findAnyIntersection - ( - const point& start, - const point& end, - pointIndexHit& - ) const; - - - //- Find all intersections in order from start to end. Returns for - // every hit the surface and the hit info. - void findAllIntersections - ( - const labelList& surfacesToTest, - const point& start, - const point& end, - labelList& surfaces, - List<pointIndexHit>& surfaceHits - ) const; - - void findAllIntersections - ( - const point& start, - const point& end, - labelList& surfaces, - List<pointIndexHit>& surfaceHits - ) const; - - - //- Find intersections of edge nearest to both endpoints. - void findNearestIntersection - ( - const labelList& surfacesToTest, - const point& start, - const point& end, - - label& surface1, // surface index - pointIndexHit& hit1, // hit point information - label& surface2, - pointIndexHit& hit2 - ) const; - - void findNearestIntersection - ( - const point& start, - const point& end, - - label& surface1, // surface index - pointIndexHit& hit1, // hit point information - label& surface2, - pointIndexHit& hit2 - ) const; - - - //- Find nearest. Return -1 (and a miss()) or surface and nearest point. - label findNearest - ( - const labelList& surfacesToTest, - const point&, - const scalar nearestDistSqr, - pointIndexHit& - ) const; - - label findNearest - ( - const point&, - const scalar nearestDistSqr, - pointIndexHit& - ) const; - - - //- Find nearest point (like findNearest) but also return whether - // point is on edge or on point. Returns -1 if not found - // (within nearestDistSqr) on any of the surfaces. - // Returns surfaceLocation - // - hit : nearest point is inside triangle - // - elementType : none, edge or point - // - index : triI, edgeI or localPointI - label findNearestAndClassify - ( - const labelList& surfacesToTest, - const point& pt, - const scalar nearestDistSqr, - surfaceLocation& nearest - ) const; - - //- Calculate point which is on a set of surfaces. Takes - // - initialDistSqr : search dimensions to find point on surface - // - convergenceDistSqr : when point is converged - // Will bomb out if no stable point reached after certain number - // of iterations. - surfaceLocation facesIntersectionTrack - ( - const labelList& surfacesToTest, - const scalar initialDistSqr, - const scalar convergenceDistSqr, - const point& start - ) const; - - //- Calculate point which is on a set of surfaces. - pointIndexHit facesIntersection - ( - const labelList& surfacesToTest, - const scalar initialDistSqr, - const scalar convergenceDistSqr, - const point& start - ) const; - -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/tutorials/compressibleLesInterFoam/depthCharge3D/Allclean b/tutorials/compressibleLesInterFoam/depthCharge3D/Allclean index 7a7b7f16fe19a6df1c05baa3bb818430d0240cf1..c422ce058e162967e4924ab9cd8404a7ca807133 100755 --- a/tutorials/compressibleLesInterFoam/depthCharge3D/Allclean +++ b/tutorials/compressibleLesInterFoam/depthCharge3D/Allclean @@ -2,4 +2,4 @@ foamCleanTutorials cases rm -rf processor* -rm 0/pd.gz 0/alpha1.gz +rm -rf 0/pd.gz 0/alpha1.gz diff --git a/tutorials/gnemdFoam/Allclean b/tutorials/gnemdFoam/Allclean index 827eacb6ae57fce6c071229216ccde65b3bd8f04..11f901ce8e07f87b4c4e41b1be30311c5ecd5589 100755 --- a/tutorials/gnemdFoam/Allclean +++ b/tutorials/gnemdFoam/Allclean @@ -4,16 +4,13 @@ . $WM_PROJECT_DIR/bin/tools/CleanFunctions cd constrictedChannel - rm -rf 0 > /dev/null 2>&1 - rm Ar-Ar Ar-Ne Ne-Ne > /dev/null 2>&1 - rm constant/idList - + rm -rf 0 + rm -rf Ar-Ar Ar-Ne Ne-Ne + rm -rf constant/idList cleanCase cd .. cd nanoNozzle - rm -rf processor[0-9] > /dev/null 2>&1 - + rm -rf processor[0-9] cleanCase cd .. - diff --git a/tutorials/mdEquilibrationFoam/Allclean b/tutorials/mdEquilibrationFoam/Allclean index 7880b1387e0bea443782452bcd1172445f5432e1..00dd874d7638805cf31b2c56b01b659e0792e1c4 100755 --- a/tutorials/mdEquilibrationFoam/Allclean +++ b/tutorials/mdEquilibrationFoam/Allclean @@ -4,10 +4,8 @@ . $WM_PROJECT_DIR/bin/tools/CleanFunctions cd periodicCube - rm -rf 0 > /dev/null 2>&1 - rm Ar-Ar > /dev/null 2>&1 - rm constant/idList - + rm -rf 0 + rm -rf Ar-Ar + rm -rf constant/idList cleanCase cd .. - diff --git a/tutorials/rhoCentralFoam/Allclean b/tutorials/rhoCentralFoam/Allclean index cbb826cb1d964f21068e9c44b62bdae567243c5b..c783ce638816a8524a36cdb294a5bc8390b786ee 100755 --- a/tutorials/rhoCentralFoam/Allclean +++ b/tutorials/rhoCentralFoam/Allclean @@ -24,7 +24,7 @@ do if [ "$case" = "biconic25-55Run35" ] then - rm $case/constant/polyMesh/boundary + rm -rf $case/constant/polyMesh/boundary wclean $case/datToFoam fi done