/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | cfMesh: A library for mesh generation
\\ / O peration |
\\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
\\/ M anipulation | Copyright (C) Creative Fields, Ltd.
-------------------------------------------------------------------------------
License
This file is part of cfMesh.
cfMesh 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.
cfMesh 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 cfMesh. If not, see .
Description
\*---------------------------------------------------------------------------*/
#include "cartesian2DMeshGenerator.H"
#include "triSurface2DCheck.H"
#include "polyMeshGen2DEngine.H"
#include "triSurf.H"
#include "triSurfacePatchManipulator.H"
#include "triSurfaceCleanupDuplicateTriangles.H"
#include "demandDrivenData.H"
#include "Time.H"
#include "meshOctreeCreator.H"
#include "cartesianMeshExtractor.H"
#include "meshSurfaceEngine.H"
#include "meshSurfaceMapper2D.H"
#include "meshSurfaceEdgeExtractor2D.H"
#include "meshSurfaceOptimizer.H"
#include "topologicalCleaner.H"
#include "boundaryLayers.H"
#include "refineBoundaryLayers.H"
#include "renameBoundaryPatches.H"
#include "checkMeshDict.H"
#include "checkCellConnectionsOverFaces.H"
#include "checkIrregularSurfaceConnections.H"
#include "checkNonMappableCellConnections.H"
#include "checkBoundaryFacesSharingTwoEdges.H"
#include "triSurfaceMetaData.H"
#include "polyMeshGenGeometryModification.H"
#include "surfaceMeshGeometryModification.H"
//#define DEBUG
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * Private member functions * * * * * * * * * * * * //
void cartesian2DMeshGenerator::createCartesianMesh()
{
//- create polyMesh from octree boxes
cartesianMeshExtractor cme(*octreePtr_, meshDict_, mesh_);
if( meshDict_.found("decomposePolyhedraIntoTetsAndPyrs") )
{
if( readBool(meshDict_.lookup("decomposePolyhedraIntoTetsAndPyrs")) )
cme.decomposeSplitHexes();
}
cme.createMesh();
}
void cartesian2DMeshGenerator::surfacePreparation()
{
//- removes unnecessary cells and morph the boundary
//- such that there is only one boundary face per cell
//- It also checks topology of cells after morphing is performed
bool changed;
do
{
changed = false;
checkIrregularSurfaceConnections checkConnections(mesh_);
if( checkConnections.checkAndFixIrregularConnections() )
changed = true;
if( checkNonMappableCellConnections(mesh_).removeCells() )
changed = true;
if( checkCellConnectionsOverFaces(mesh_).checkCellGroups() )
changed = true;
} while( changed );
checkBoundaryFacesSharingTwoEdges(mesh_).improveTopology();
}
void cartesian2DMeshGenerator::mapMeshToSurface()
{
//- calculate mesh surface
meshSurfaceEngine* msePtr = new meshSurfaceEngine(mesh_);
//- pre-map mesh surface
meshSurfaceMapper2D mapper(*msePtr, *octreePtr_);
mapper.adjustZCoordinates();
mapper.preMapVertices();
//- map mesh surface on the geometry surface
mapper.mapVerticesOntoSurface();
deleteDemandDrivenData(msePtr);
}
void cartesian2DMeshGenerator::extractPatches()
{
meshSurfaceEdgeExtractor2D(mesh_, *octreePtr_).distributeBoundaryFaces();
}
void cartesian2DMeshGenerator::mapEdgesAndCorners()
{
meshSurfaceEdgeExtractor2D(mesh_, *octreePtr_).remapBoundaryPoints();
}
void cartesian2DMeshGenerator::optimiseMeshSurface()
{
meshSurfaceEngine mse(mesh_);
meshSurfaceOptimizer optimizer(mse, *octreePtr_);
optimizer.optimizeSurface2D();
optimizer.untangleSurface2D();
}
void cartesian2DMeshGenerator::generateBoundaryLayers()
{
boundaryLayers bl(mesh_);
bl.activate2DMode();
bl.addLayerForAllPatches();
if( modSurfacePtr_ )
{
polyMeshGenGeometryModification meshMod(mesh_, meshDict_);
//- revert the mesh into the original space
meshMod.revertGeometryModification();
//- delete modified surface mesh
deleteDemandDrivenData(modSurfacePtr_);
//- delete the octree
deleteDemandDrivenData(octreePtr_);
//- contruct a new octree from the input surface
octreePtr_ = new meshOctree(*surfacePtr_, true);
meshOctreeCreator(*octreePtr_).createOctreeWithRefinedBoundary(20);
mapEdgesAndCorners();
optimiseMeshSurface();
}
}
void cartesian2DMeshGenerator::refBoundaryLayers()
{
if( meshDict_.isDict("boundaryLayers") )
{
refineBoundaryLayers refLayers(mesh_);
refineBoundaryLayers::readSettings(meshDict_, refLayers);
refLayers.activate2DMode();
refLayers.refineLayers();
meshSurfaceEngine mse(mesh_);
meshSurfaceOptimizer optimizer(mse, *octreePtr_);
optimizer.untangleSurface2D();
}
}
void cartesian2DMeshGenerator::replaceBoundaries()
{
renameBoundaryPatches rbp(mesh_, meshDict_);
}
void cartesian2DMeshGenerator::renumberMesh()
{
polyMeshGenModifier(mesh_).renumberMesh();
}
void cartesian2DMeshGenerator::generateMesh()
{
try
{
if( controller_.runCurrentStep("templateGeneration") )
{
createCartesianMesh();
}
if( controller_.runCurrentStep("surfaceTopology") )
{
surfacePreparation();
}
if( controller_.runCurrentStep("surfaceProjection") )
{
mapMeshToSurface();
}
if( controller_.runCurrentStep("patchAssignment") )
{
extractPatches();
}
if( controller_.runCurrentStep("edgeExtraction") )
{
mapEdgesAndCorners();
optimiseMeshSurface();
}
if( controller_.runCurrentStep("boundaryLayerGeneration") )
{
generateBoundaryLayers();
}
if( controller_.runCurrentStep("meshOptimisation") )
{
optimiseMeshSurface();
}
if( controller_.runCurrentStep("boundaryLayerRefinement") )
{
refBoundaryLayers();
}
renumberMesh();
replaceBoundaries();
controller_.workflowCompleted();
}
catch(const std::string& message)
{
Info << message << endl;
}
catch(...)
{
WarningIn
(
"void cartesian2DMeshGenerator::generateMesh()"
) << "Meshing process terminated!" << endl;
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
cartesian2DMeshGenerator::cartesian2DMeshGenerator(const Time& time)
:
db_(time),
surfacePtr_(NULL),
modSurfacePtr_(NULL),
meshDict_
(
IOobject
(
"meshDict",
db_.system(),
db_,
IOobject::MUST_READ,
IOobject::NO_WRITE
)
),
octreePtr_(NULL),
mesh_(time),
controller_(mesh_)
{
if( true )
{
checkMeshDict cmd(meshDict_);
}
fileName surfaceFile = meshDict_.lookup("surfaceFile");
if( Pstream::parRun() )
surfaceFile = ".."/surfaceFile;
surfacePtr_ = new triSurf(db_.path()/surfaceFile);
if( true )
{
//- save meta data with the mesh (surface mesh + its topology info)
triSurfaceMetaData sMetaData(*surfacePtr_);
const dictionary& surfMetaDict = sMetaData.metaData();
mesh_.metaData().add("surfaceFile", surfaceFile, true);
mesh_.metaData().add("surfaceMeta", surfMetaDict, true);
triSurface2DCheck surfCheck(*surfacePtr_);
if( !surfCheck.is2DSurface() )
{
surfCheck.createSubsets();
Info << "Writting surface with subsets to file "
<< "badSurfaceWithSubsets.fms" << endl;
surfacePtr_->writeSurface("badSurfaceWithSubsets.fms");
}
}
if( surfacePtr_->featureEdges().size() != 0 )
{
//- get rid of duplicate triangles as they cause strange problems
triSurfaceCleanupDuplicateTriangles(const_cast(*surfacePtr_));
//- create surface patches based on the feature edges
//- and update the meshDict based on the given data
triSurfacePatchManipulator manipulator(*surfacePtr_);
const triSurf* surfaceWithPatches =
manipulator.surfaceWithPatches(&meshDict_);
//- delete the old surface and assign the new one
deleteDemandDrivenData(surfacePtr_);
surfacePtr_ = surfaceWithPatches;
}
if( meshDict_.found("anisotropicSources") )
{
surfaceMeshGeometryModification surfMod(*surfacePtr_, meshDict_);
modSurfacePtr_ = surfMod.modifyGeometry();
octreePtr_ = new meshOctree(*modSurfacePtr_, true);
}
else
{
octreePtr_ = new meshOctree(*surfacePtr_, true);
}
meshOctreeCreator(*octreePtr_, meshDict_).createOctreeBoxes();
generateMesh();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
cartesian2DMeshGenerator::~cartesian2DMeshGenerator()
{
deleteDemandDrivenData(surfacePtr_);
deleteDemandDrivenData(modSurfacePtr_);
deleteDemandDrivenData(octreePtr_);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void cartesian2DMeshGenerator::writeMesh() const
{
mesh_.write();
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //