486 lines
13 KiB
C
486 lines
13 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | foam-extend: Open Source CFD
|
|
\\ / O peration | Version: 3.2
|
|
\\ / A nd | Web: http://www.foam-extend.org
|
|
\\/ M anipulation | For copyright notice see file Copyright
|
|
-------------------------------------------------------------------------------
|
|
License
|
|
This file is part of foam-extend.
|
|
|
|
foam-extend 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 3 of the License, or (at your
|
|
option) any later version.
|
|
|
|
foam-extend 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 foam-extend. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Application
|
|
snappyHexMesh
|
|
|
|
Description
|
|
Automatic split hex mesher. Refines and snaps to surface.
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#include "argList.H"
|
|
#include "objectRegistry.H"
|
|
#include "foamTime.H"
|
|
#include "fvMesh.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 * meshBb.mag();
|
|
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 " << meshRefiner.timeName() << endl;
|
|
|
|
meshRefiner.write(meshRefinement::MESH|meshRefinement::SCALARLEVELS, "");
|
|
if (debug & meshRefinement::OBJINTERSECTIONS)
|
|
{
|
|
meshRefiner.write
|
|
(
|
|
meshRefinement::OBJINTERSECTIONS,
|
|
mesh.time().path()/meshRefiner.timeName()
|
|
);
|
|
}
|
|
Info<< "Written mesh in = "
|
|
<< mesh.time().cpuTimeIncrement() << " s." << endl;
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
argList::validOptions.insert("overwrite", "");
|
|
# include "setRootCase.H"
|
|
# include "createTime.H"
|
|
runTime.functionObjects().off();
|
|
# include "createMesh.H"
|
|
|
|
Info<< "Read mesh in = "
|
|
<< runTime.cpuTimeIncrement() << " s" << endl;
|
|
|
|
const bool overwrite = args.optionFound("overwrite");
|
|
|
|
|
|
// Check patches and faceZones are synchronised
|
|
mesh.boundaryMesh().checkParallelSync(true);
|
|
meshRefinement::checkCoupledFaceZones(mesh);
|
|
|
|
|
|
// Read decomposePar dictionary
|
|
IOdictionary decomposeDict
|
|
(
|
|
IOobject
|
|
(
|
|
"decomposeParDict",
|
|
runTime.system(),
|
|
mesh,
|
|
IOobject::MUST_READ,
|
|
IOobject::NO_WRITE
|
|
)
|
|
);
|
|
|
|
// Read meshing dictionary
|
|
IOdictionary meshDict
|
|
(
|
|
IOobject
|
|
(
|
|
"snappyHexMeshDict",
|
|
runTime.system(),
|
|
mesh,
|
|
IOobject::MUST_READ,
|
|
IOobject::NO_WRITE
|
|
)
|
|
);
|
|
|
|
// all surface geometry
|
|
const dictionary& geometryDict = meshDict.subDict("geometry");
|
|
|
|
// refinement parameters
|
|
const dictionary& refineDict = meshDict.subDict("castellatedMeshControls");
|
|
|
|
// mesh motion and mesh quality parameters
|
|
const dictionary& motionDict = meshDict.subDict("meshQualityControls");
|
|
|
|
// snap-to-surface parameters
|
|
const dictionary& snapDict = meshDict.subDict("snapControls");
|
|
|
|
// layer addition parameters
|
|
const dictionary& layerDict = meshDict.subDict("addLayersControls");
|
|
|
|
|
|
const scalar mergeDist = getMergeDistance
|
|
(
|
|
mesh,
|
|
readScalar(meshDict.lookup("mergeTolerance"))
|
|
);
|
|
|
|
|
|
|
|
// 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(), // instance
|
|
//mesh.time().findInstance("triSurface", word::null),// instance
|
|
"triSurface", // local
|
|
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;
|
|
|
|
|
|
// Refinement engine
|
|
// ~~~~~~~~~~~~~~~~~
|
|
|
|
Info<< nl
|
|
<< "Determining initial surface intersections" << nl
|
|
<< "-----------------------------------------" << nl
|
|
<< endl;
|
|
|
|
// Main refinement engine
|
|
meshRefinement meshRefiner
|
|
(
|
|
mesh,
|
|
mergeDist, // tolerance used in sorting coordinates
|
|
overwrite, // overwrite mesh files?
|
|
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()/meshRefiner.timeName()
|
|
);
|
|
|
|
|
|
// 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 = meshRefiner.addMeshedPatch
|
|
(
|
|
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);
|
|
}
|
|
|
|
// Mesh distribution engine (uses tolerance to reconstruct meshes)
|
|
fvMeshDistribute distributor(mesh, mergeDist);
|
|
|
|
|
|
|
|
|
|
|
|
// 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)
|
|
{
|
|
cpuTime timer;
|
|
|
|
autoRefineDriver refineDriver
|
|
(
|
|
meshRefiner,
|
|
decomposer,
|
|
distributor,
|
|
globalToPatch
|
|
);
|
|
|
|
// Refinement parameters
|
|
refinementParameters refineParams(refineDict);
|
|
|
|
if (!overwrite)
|
|
{
|
|
const_cast<Time&>(mesh.time())++;
|
|
}
|
|
|
|
refineDriver.doRefine(refineDict, refineParams, wantSnap, motionDict);
|
|
|
|
writeMesh
|
|
(
|
|
"Refined mesh",
|
|
meshRefiner,
|
|
debug
|
|
);
|
|
|
|
Info<< "Mesh refined in = "
|
|
<< timer.cpuTimeIncrement() << " s." << endl;
|
|
}
|
|
|
|
if (wantSnap)
|
|
{
|
|
cpuTime timer;
|
|
|
|
autoSnapDriver snapDriver
|
|
(
|
|
meshRefiner,
|
|
globalToPatch
|
|
);
|
|
|
|
// Snap parameters
|
|
snapParameters snapParams(snapDict);
|
|
|
|
if (!overwrite)
|
|
{
|
|
const_cast<Time&>(mesh.time())++;
|
|
}
|
|
|
|
snapDriver.doSnap(snapDict, motionDict, snapParams);
|
|
|
|
writeMesh
|
|
(
|
|
"Snapped mesh",
|
|
meshRefiner,
|
|
debug
|
|
);
|
|
|
|
Info<< "Mesh snapped in = "
|
|
<< timer.cpuTimeIncrement() << " s." << endl;
|
|
}
|
|
|
|
if (wantLayers)
|
|
{
|
|
cpuTime timer;
|
|
|
|
autoLayerDriver layerDriver(meshRefiner);
|
|
|
|
// Layer addition parameters
|
|
layerParameters layerParams(layerDict, mesh.boundaryMesh());
|
|
|
|
//!!! Temporary hack to get access to maxLocalCells
|
|
bool preBalance;
|
|
{
|
|
refinementParameters refineParams(refineDict);
|
|
|
|
preBalance = returnReduce
|
|
(
|
|
(mesh.nCells() >= refineParams.maxLocalCells()),
|
|
orOp<bool>()
|
|
);
|
|
}
|
|
|
|
|
|
if (!overwrite)
|
|
{
|
|
const_cast<Time&>(mesh.time())++;
|
|
}
|
|
|
|
layerDriver.doLayers
|
|
(
|
|
layerDict,
|
|
motionDict,
|
|
layerParams,
|
|
preBalance,
|
|
decomposer,
|
|
distributor
|
|
);
|
|
|
|
writeMesh
|
|
(
|
|
"Layer mesh",
|
|
meshRefiner,
|
|
debug
|
|
);
|
|
|
|
Info<< "Layers added in = "
|
|
<< timer.cpuTimeIncrement() << " s." << endl;
|
|
}
|
|
|
|
|
|
Info<< "Finished meshing in = "
|
|
<< runTime.elapsedCpuTime() << " s." << endl;
|
|
|
|
Info<< "End\n" << endl;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|