Add the OpenFOAM source tree

This commit is contained in:
Henry
2014-12-10 22:40:10 +00:00
parent ee487c860d
commit 446e5777f0
13379 changed files with 3983377 additions and 0 deletions

View File

@ -0,0 +1,3 @@
PDRMesh.C
EXE = $(FOAM_APPBIN)/PDRMesh

View File

@ -0,0 +1,10 @@
EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude
EXE_LIBS = \
-lmeshTools \
-ldynamicMesh \
-lfiniteVolume \
-lcompressibleRASModels

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object PDRMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Per faceSet the patch the faces should go into blocked baffles
blockedFaces ((blockedFacesSet blockedFaces));
//- Per faceSet the patch the faces should go into coupled baffles
coupledFaces
{
coupledFacesSet
{
wallPatchName baffleWall;
cyclicMasterPatchName baffleCyclic_half0;
}
}
//- Name of cellSet that holds the cells to fully remove
blockedCells blockedCellsSet;
//- All exposed faces that are not specified in blockedFaces go into
// this patch
defaultPatch outer;
// ************************************************************************* //

View File

@ -0,0 +1,4 @@
autoRefineMesh.C
EXE = $(FOAM_APPBIN)/autoRefineMesh

View File

@ -0,0 +1,11 @@
EXE_INC = \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/triSurface/lnInclude \
-I$(LIB_SRC)/lagrangian/basic/lnInclude
EXE_LIBS = \
-ldynamicMesh \
-lmeshTools \
-ltriSurface \
-llagrangian

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,112 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object autoRefineMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Surface to keep to
surface "plexi.obj";
// What is outside. These points have to be inside a cell (so not on a face!)
outsidePoints ((-0.99001 -0.99001 -0.99001));
//
// Selection of cells to refine
//
// If smallest edge of mesh > maxEdgeLen select all cut cells for refinement.
// If < maxEdgeLen select only those cut cells which are closer than
// curvatureDistance to surface
// and with cos of angle between normals on surface < curvature.
maxEdgeLen 0.1;
curvatureDistance 1.0;
curvature 0.9;
// if > 0: Remove inside cells at every step. Inside is given by number of
// layers separating outside from inside.
// (note that we cannot remove outside
// cells since these contain the outsidePoints)
// Do not use this option if you want mesh to spill through a hole which is
// not visible on the coarsest level but only becomes visible after refinement
nCutLayers 2;
// Refine until smallest edge of mesh < minEdgeLen
minEdgeLen 0.1;
// Or until the number of cells would become more than (stops one level before
// this)
cellLimit 2500000;
//
// Selection of final set
//
// Select based on side of surface. Usually select inside cells and project
// outwards or select outside cells and project inwards.
selectCut false;
selectInside false;
selectOutside true;
// Leave out cell closer than nearDistance to the surface. Usually
// 0.5*minEdgeLen. Set to -1 to disable.
nearDistance -1;
// Some cells on the surface of the selected cells might have all their
// points on the 'outside'. These would get flattened when projecting so
// are either kept and refined (selectHanging) or removed from the set
selectHanging false;
//
// Refinement parameters
//
// Type of coordinate system
coordinateSystem global;
//coordinateSystem patchLocal;
// .. and its coefficients. x,y in this case. (normal = tan1^tan2)
globalCoeffs
{
tan1 (1 0 0);
tan2 (0 1 0);
}
patchLocalCoeffs
{
patch outside; // Normal direction is facenormal of zero'th face of patch
tan1 (1 0 0);
}
// List of directions to refine
directions
(
tan1
tan2
normal
);
// refinement level difference between neighbouring cells. Set to large if
// there is no need for a limit.
splitLevel 2;
// Cut purely geometric (will cut hexes through vertices) or take topology
// into account.
geometricCut false;
// Whether to use hex topology. This will never cut hex through vertices.
useHexTopology yes;
// Write meshes from intermediate steps
writeMesh true;
// ************************************************************************* //

View File

@ -0,0 +1,3 @@
collapseEdges.C
EXE = $(FOAM_APPBIN)/collapseEdges

View File

@ -0,0 +1,9 @@
EXE_INC = \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude
EXE_LIBS = \
-ldynamicMesh \
-lmeshTools \
-lfiniteVolume

View File

@ -0,0 +1,97 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: http://www.openfoam.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
root "";
case "";
instance "";
local "";
class dictionary;
object collapseDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// If on, after collapsing check the quality of the mesh. If bad faces are
// generated then redo the collapsing with stricter filtering.
controlMeshQuality on;
collapseEdgesCoeffs
{
// Edges shorter than this absolute value will be merged
minimumEdgeLength 1e-6;
// The maximum angle between two edges that share a point attached to
// no other edges
maximumMergeAngle 30;
}
collapseFacesCoeffs
{
// The initial face length factor
initialFaceLengthFactor 0.5;
// If the face can't be collapsed to an edge, and it has a span less than
// the target face length multiplied by this coefficient, collapse it
// to a point.
maxCollapseFaceToPointSideLengthCoeff 0.3;
// Allow early collapse of edges to a point
allowEarlyCollapseToPoint on;
// Fraction to premultiply maxCollapseFaceToPointSideLengthCoeff by if
// allowEarlyCollapseToPoint is enabled
allowEarlyCollapseCoeff 0.2;
// Defining how close to the midpoint (M) of the projected
// vertices line a projected vertex (X) can be before making this
// an invalid edge collapse
//
// X---X-g----------------M----X-----------g----X--X
//
// Only allow a collapse if all projected vertices are outwith
// guardFraction (g) of the distance form the face centre to the
// furthest vertex in the considered direction
guardFraction 0.1;
}
controlMeshQualityCoeffs
{
// Name of the dictionary that has the mesh quality coefficients used
// by motionSmoother::checkMesh
#include "meshQualityDict";
// The amount that minimumEdgeLength will be reduced by for each
// edge if that edge's collapse generates a poor quality face
edgeReductionFactor 0.5;
// The amount that initialFaceLengthFactor will be reduced by for each
// face if its collapse generates a poor quality face
faceReductionFactor 0.5;
// Maximum number of smoothing iterations for the reductionFactors
maximumSmoothingIterations 2;
// Maximum number of outer iterations is mesh quality checking is enabled
maximumIterations 10;
// Maximum number of iterations deletion of a point can cause a bad face
// to be constructed before it is forced to not be deleted
maxPointErrorCount 5;
}
// ************************************************************************* //

View File

@ -0,0 +1,247 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Application
collapseEdges
Description
Collapses short edges and combines edges that are in line.
- collapse short edges. Length of edges to collapse provided as argument.
- merge two edges if they are in line. Maximum angle provided as argument.
- remove unused points.
- collapse faces:
- with small areas to a single point
- that have a high aspect ratio (i.e. sliver face) to a single edge
Optionally checks the resulting mesh for bad faces and reduces the desired
face length factor for those faces attached to the bad faces.
When collapsing an edge with one point on the boundary it will leave
the boundary point intact. When both points inside it chooses random. When
both points on boundary random again.
Usage
- collapseEdges [OPTION]
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "timeSelector.H"
#include "polyTopoChange.H"
#include "fvMesh.H"
#include "polyMeshFilter.H"
#include "faceSet.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
timeSelector::addOptions(true, false);
argList::addNote
(
"Collapses small edges to a point.\n"
"Optionally collapse small faces to a point and thin faces to an edge."
);
argList::addBoolOption
(
"collapseFaces",
"Collapse small and sliver faces as well as small edges"
);
argList::addOption
(
"collapseFaceSet",
"faceSet",
"Collapse faces that are in the supplied face set"
);
# include "addOverwriteOption.H"
# include "setRootCase.H"
# include "createTime.H"
runTime.functionObjects().off();
instantList timeDirs = timeSelector::selectIfPresent(runTime, args);
# include "createMesh.H"
const word oldInstance = mesh.pointsInstance();
const bool overwrite = args.optionFound("overwrite");
const bool collapseFaces = args.optionFound("collapseFaces");
const bool collapseFaceSet = args.optionFound("collapseFaceSet");
if (collapseFaces && collapseFaceSet)
{
FatalErrorIn("main(int, char*[])")
<< "Both face zone collapsing and face collapsing have been"
<< "selected. Choose only one of:" << nl
<< " -collapseFaces" << nl
<< " -collapseFaceSet <faceSet>"
<< abort(FatalError);
}
// maintain indirectPatchFaces if it is there (default) or force
// (if collapseFaceSet option provided)
word faceSetName("indirectPatchFaces");
IOobject::readOption readFlag = IOobject::READ_IF_PRESENT;
if (args.optionReadIfPresent("collapseFaceSet", faceSetName))
{
readFlag = IOobject::MUST_READ;
}
labelIOList pointPriority
(
IOobject
(
"pointPriority",
runTime.timeName(),
runTime,
IOobject::READ_IF_PRESENT,
IOobject::AUTO_WRITE
),
labelList(mesh.nPoints(), labelMin)
);
forAll(timeDirs, timeI)
{
runTime.setTime(timeDirs[timeI], timeI);
Info<< "Time = " << runTime.timeName() << endl;
autoPtr<polyMeshFilter> meshFilterPtr;
label nBadFaces = 0;
faceSet indirectPatchFaces
(
mesh,
faceSetName,
readFlag,
IOobject::AUTO_WRITE
);
Info<< "Read faceSet " << indirectPatchFaces.name()
<< " with "
<< returnReduce(indirectPatchFaces.size(), sumOp<label>())
<< " faces" << endl;
{
meshFilterPtr.set(new polyMeshFilter(mesh, pointPriority));
polyMeshFilter& meshFilter = meshFilterPtr();
// newMesh will be empty until it is filtered
const autoPtr<fvMesh>& newMesh = meshFilter.filteredMesh();
// Filter small edges only. This reduces the number of faces so that
// the face filtering is sped up.
nBadFaces = meshFilter.filterEdges(0);
{
polyTopoChange meshMod(newMesh());
meshMod.changeMesh(mesh, false);
polyMeshFilter::copySets(newMesh(), mesh);
}
pointPriority = meshFilter.pointPriority();
}
if (collapseFaceSet)
{
meshFilterPtr.reset(new polyMeshFilter(mesh, pointPriority));
polyMeshFilter& meshFilter = meshFilterPtr();
const autoPtr<fvMesh>& newMesh = meshFilter.filteredMesh();
// Filter faces. Pass in the number of bad faces that are present
// from the previous edge filtering to use as a stopping criterion.
meshFilter.filter(indirectPatchFaces);
{
polyTopoChange meshMod(newMesh);
meshMod.changeMesh(mesh, false);
polyMeshFilter::copySets(newMesh(), mesh);
}
pointPriority = meshFilter.pointPriority();
}
if (collapseFaces)
{
meshFilterPtr.reset(new polyMeshFilter(mesh, pointPriority));
polyMeshFilter& meshFilter = meshFilterPtr();
const autoPtr<fvMesh>& newMesh = meshFilter.filteredMesh();
// Filter faces. Pass in the number of bad faces that are present
// from the previous edge filtering to use as a stopping criterion.
meshFilter.filter(nBadFaces);
{
polyTopoChange meshMod(newMesh);
meshMod.changeMesh(mesh, false);
polyMeshFilter::copySets(newMesh(), mesh);
}
pointPriority = meshFilter.pointPriority();
}
// Write resulting mesh
if (!overwrite)
{
runTime++;
}
else
{
mesh.setInstance(oldInstance);
}
Info<< nl << "Writing collapsed mesh to time "
<< runTime.timeName() << nl << endl;
mesh.write();
pointPriority.write();
}
Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
<< nl << endl;
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,67 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object meshQualityDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Maximum non-orthogonality allowed. Set to 180 to disable.
maxNonOrtho 65;
//- Max skewness allowed. Set to <0 to disable.
maxBoundarySkewness 50;
//- Max skewness allowed. Set to <0 to disable.
maxInternalSkewness 10;
//- Max concaveness allowed. Is angle (in degrees) below which concavity
// is allowed. 0 is straight face, <0 would be convex face.
// Set to 180 to disable.
maxConcave 80;
//- Minimum pyramid volume. Is absolute volume of cell pyramid.
// Set to a sensible fraction of the smallest cell volume expected.
// Set to very negative number (e.g. -1E30) to disable.
minVol 1e-20;
//- Minimum quality of the tet formed by the face-centre
// and variable base point minimum decomposition triangles and
// the cell centre. This has to be a positive number for tracking
// to work. Set to very negative number (e.g. -1E30) to
// disable.
// <0 = inside out tet,
// 0 = flat tet
// 1 = regular tet
minTetQuality 1e-30;
//- Minimum face area. Set to <0 to disable.
minArea -1;
//- Minimum face twist. Set to <-1 to disable. dot product of face normal
//- and face centre triangles normal
minTwist 0.0;
//- minimum normalised cell determinant
//- 1 = hex, <= 0 = folded or flattened illegal cell
minDeterminant 0.001;
//- minFaceWeight (0 -> 0.5)
minFaceWeight 0.02;
//- minVolRatio (0 -> 1)
minVolRatio 0.01;
//must be >0 for Fluent compatibility
minTriangleTwist -1;
// ************************************************************************* //

View File

@ -0,0 +1,4 @@
combinePatchFaces.C
EXE = $(FOAM_APPBIN)/combinePatchFaces

View File

@ -0,0 +1,9 @@
EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
EXE_LIBS = \
-lfiniteVolume \
-ldynamicMesh

View File

@ -0,0 +1,462 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Application
combinePatchFaces
Description
Checks for multiple patch faces on same cell and combines them.
Multiple patch faces can result from e.g. removal of refined
neighbouring cells, leaving 4 exposed faces with same owner.
Rules for merging:
- only boundary faces (since multiple internal faces between two cells
not allowed anyway)
- faces have to have same owner
- faces have to be connected via edge which are not features (so angle
between them < feature angle)
- outside of faces has to be single loop
- outside of face should not be (or just slightly) concave (so angle
between consecutive edges < concaveangle
E.g. to allow all faces on same patch to be merged:
combinePatchFaces 180 -concaveAngle 90
\*---------------------------------------------------------------------------*/
#include "PstreamReduceOps.H"
#include "argList.H"
#include "Time.H"
#include "polyTopoChange.H"
#include "polyModifyFace.H"
#include "polyAddFace.H"
#include "combineFaces.H"
#include "removePoints.H"
#include "polyMesh.H"
#include "mapPolyMesh.H"
#include "unitConversion.H"
#include "motionSmoother.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Merge faces on the same patch (usually from exposing refinement)
// Can undo merges if these cause problems.
label mergePatchFaces
(
const scalar minCos,
const scalar concaveSin,
const autoPtr<IOdictionary>& qualDictPtr,
const Time& runTime,
polyMesh& mesh
)
{
// Patch face merging engine
combineFaces faceCombiner(mesh);
// Get all sets of faces that can be merged
labelListList allFaceSets(faceCombiner.getMergeSets(minCos, concaveSin));
label nFaceSets = returnReduce(allFaceSets.size(), sumOp<label>());
Info<< "Merging " << nFaceSets << " sets of faces." << endl;
if (nFaceSets > 0)
{
// Store the faces of the face sets
List<faceList> allFaceSetsFaces(allFaceSets.size());
forAll(allFaceSets, setI)
{
allFaceSetsFaces[setI] = UIndirectList<face>
(
mesh.faces(),
allFaceSets[setI]
);
}
autoPtr<mapPolyMesh> map;
{
// Topology changes container
polyTopoChange meshMod(mesh);
// Merge all faces of a set into the first face of the set.
faceCombiner.setRefinement(allFaceSets, meshMod);
// Change the mesh (no inflation)
map = meshMod.changeMesh(mesh, false, true);
// Update fields
mesh.updateMesh(map);
// Move mesh (since morphing does not do this)
if (map().hasMotionPoints())
{
mesh.movePoints(map().preMotionPoints());
}
else
{
// Delete mesh volumes. No other way to do this?
mesh.clearOut();
}
}
// Check for errors and undo
// ~~~~~~~~~~~~~~~~~~~~~~~~~
// Faces in error.
labelHashSet errorFaces;
if (qualDictPtr.valid())
{
motionSmoother::checkMesh(false, mesh, qualDictPtr(), errorFaces);
}
else
{
mesh.checkFacePyramids(false, -SMALL, &errorFaces);
}
// Sets where the master is in error
labelHashSet errorSets;
forAll(allFaceSets, setI)
{
label newMasterI = map().reverseFaceMap()[allFaceSets[setI][0]];
if (errorFaces.found(newMasterI))
{
errorSets.insert(setI);
}
}
label nErrorSets = returnReduce(errorSets.size(), sumOp<label>());
Info<< "Detected " << nErrorSets
<< " error faces on boundaries that have been merged."
<< " These will be restored to their original faces."
<< endl;
if (nErrorSets > 0)
{
// Renumber stored faces to new vertex numbering.
forAllConstIter(labelHashSet, errorSets, iter)
{
label setI = iter.key();
faceList& setFaceVerts = allFaceSetsFaces[setI];
forAll(setFaceVerts, i)
{
inplaceRenumber(map().reversePointMap(), setFaceVerts[i]);
// Debug: check that all points are still there.
forAll(setFaceVerts[i], j)
{
label newVertI = setFaceVerts[i][j];
if (newVertI < 0)
{
FatalErrorIn("mergePatchFaces")
<< "In set:" << setI << " old face labels:"
<< allFaceSets[setI] << " new face vertices:"
<< setFaceVerts[i] << " are unmapped vertices!"
<< abort(FatalError);
}
}
}
}
// Topology changes container
polyTopoChange meshMod(mesh);
// Restore faces
forAllConstIter(labelHashSet, errorSets, iter)
{
label setI = iter.key();
const labelList& setFaces = allFaceSets[setI];
const faceList& setFaceVerts = allFaceSetsFaces[setI];
label newMasterI = map().reverseFaceMap()[setFaces[0]];
// Restore. Get face properties.
label own = mesh.faceOwner()[newMasterI];
label zoneID = mesh.faceZones().whichZone(newMasterI);
bool zoneFlip = false;
if (zoneID >= 0)
{
const faceZone& fZone = mesh.faceZones()[zoneID];
zoneFlip = fZone.flipMap()[fZone.whichFace(newMasterI)];
}
label patchID = mesh.boundaryMesh().whichPatch(newMasterI);
Pout<< "Restoring new master face " << newMasterI
<< " to vertices " << setFaceVerts[0] << endl;
// Modify the master face.
meshMod.setAction
(
polyModifyFace
(
setFaceVerts[0], // original face
newMasterI, // label of face
own, // owner
-1, // neighbour
false, // face flip
patchID, // patch for face
false, // remove from zone
zoneID, // zone for face
zoneFlip // face flip in zone
)
);
// Add the previously removed faces
for (label i = 1; i < setFaces.size(); i++)
{
Pout<< "Restoring removed face " << setFaces[i]
<< " with vertices " << setFaceVerts[i] << endl;
meshMod.setAction
(
polyAddFace
(
setFaceVerts[i], // vertices
own, // owner,
-1, // neighbour,
-1, // masterPointID,
-1, // masterEdgeID,
newMasterI, // masterFaceID,
false, // flipFaceFlux,
patchID, // patchID,
zoneID, // zoneID,
zoneFlip // zoneFlip
)
);
}
}
// Change the mesh (no inflation)
map = meshMod.changeMesh(mesh, false, true);
// Update fields
mesh.updateMesh(map);
// Move mesh (since morphing does not do this)
if (map().hasMotionPoints())
{
mesh.movePoints(map().preMotionPoints());
}
else
{
// Delete mesh volumes. No other way to do this?
mesh.clearOut();
}
}
}
else
{
Info<< "No faces merged ..." << endl;
}
return nFaceSets;
}
// Remove points not used by any face or points used by only two faces where
// the edges are in line
label mergeEdges(const scalar minCos, polyMesh& mesh)
{
Info<< "Merging all points on surface that" << nl
<< "- are used by only two boundary faces and" << nl
<< "- make an angle with a cosine of more than " << minCos
<< "." << nl << endl;
// Point removal analysis engine
removePoints pointRemover(mesh);
// Count usage of points
boolList pointCanBeDeleted;
label nRemove = pointRemover.countPointUsage(minCos, pointCanBeDeleted);
if (nRemove > 0)
{
Info<< "Removing " << nRemove
<< " straight edge points ..." << endl;
// Topology changes container
polyTopoChange meshMod(mesh);
pointRemover.setRefinement(pointCanBeDeleted, meshMod);
// Change the mesh (no inflation)
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
// Update fields
mesh.updateMesh(map);
// Move mesh (since morphing does not do this)
if (map().hasMotionPoints())
{
mesh.movePoints(map().preMotionPoints());
}
else
{
// Delete mesh volumes. No other way to do this?
mesh.clearOut();
}
}
else
{
Info<< "No straight edges simplified and no points removed ..." << endl;
}
return nRemove;
}
int main(int argc, char *argv[])
{
# include "addOverwriteOption.H"
argList::validArgs.append("featureAngle [0..180]");
argList::addOption
(
"concaveAngle",
"degrees",
"specify concave angle [0..180] (default: 30 degrees)"
);
argList::addBoolOption
(
"meshQuality",
"read user-defined mesh quality criterions from system/meshQualityDict"
);
# include "setRootCase.H"
# include "createTime.H"
runTime.functionObjects().off();
# include "createPolyMesh.H"
const word oldInstance = mesh.pointsInstance();
const scalar featureAngle = args.argRead<scalar>(1);
const scalar minCos = Foam::cos(degToRad(featureAngle));
// Sin of angle between two consecutive edges on a face.
// If sin(angle) larger than this the face will be considered concave.
scalar concaveAngle = args.optionLookupOrDefault("concaveAngle", 30.0);
scalar concaveSin = Foam::sin(degToRad(concaveAngle));
const bool overwrite = args.optionFound("overwrite");
const bool meshQuality = args.optionFound("meshQuality");
Info<< "Merging all faces of a cell" << nl
<< " - which are on the same patch" << nl
<< " - which make an angle < " << featureAngle << " degrees"
<< nl
<< " (cos:" << minCos << ')' << nl
<< " - even when resulting face becomes concave by more than "
<< concaveAngle << " degrees" << nl
<< " (sin:" << concaveSin << ')' << nl
<< endl;
autoPtr<IOdictionary> qualDict;
if (meshQuality)
{
Info<< "Enabling user-defined geometry checks." << nl << endl;
qualDict.reset
(
new IOdictionary
(
IOobject
(
"meshQualityDict",
mesh.time().system(),
mesh,
IOobject::MUST_READ,
IOobject::NO_WRITE
)
)
);
}
if (!overwrite)
{
runTime++;
}
// Merge faces on same patch
label nChanged = mergePatchFaces
(
minCos,
concaveSin,
qualDict,
runTime,
mesh
);
// Merge points on straight edges and remove unused points
if (qualDict.valid())
{
Info<< "Merging all 'loose' points on surface edges, "
<< "regardless of the angle they make." << endl;
// Surface bnound to be used to extrude. Merge all loose points.
nChanged += mergeEdges(-1, mesh);
}
else
{
nChanged += mergeEdges(minCos, mesh);
}
if (nChanged > 0)
{
if (overwrite)
{
mesh.setInstance(oldInstance);
}
Info<< "Writing morphed mesh to time " << runTime.timeName() << endl;
mesh.write();
}
else
{
Info<< "Mesh unchanged." << endl;
}
Info<< "\nEnd\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,4 @@
cellSplitter.C
modifyMesh.C
EXE = $(FOAM_APPBIN)/modifyMesh

View File

@ -0,0 +1,7 @@
EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude
EXE_LIBS = \
-lmeshTools \
-ldynamicMesh

View File

@ -0,0 +1,491 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "cellSplitter.H"
#include "polyMesh.H"
#include "polyTopoChange.H"
#include "polyAddCell.H"
#include "polyAddFace.H"
#include "polyAddPoint.H"
#include "polyModifyFace.H"
#include "mapPolyMesh.H"
#include "meshTools.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(cellSplitter, 0);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::cellSplitter::getFaceInfo
(
const label faceI,
label& patchID,
label& zoneID,
label& zoneFlip
) const
{
patchID = -1;
if (!mesh_.isInternalFace(faceI))
{
patchID = mesh_.boundaryMesh().whichPatch(faceI);
}
zoneID = mesh_.faceZones().whichZone(faceI);
zoneFlip = false;
if (zoneID >= 0)
{
const faceZone& fZone = mesh_.faceZones()[zoneID];
zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
}
}
// Find the new owner of faceI (since the original cell has been split into
// newCells
Foam::label Foam::cellSplitter::newOwner
(
const label faceI,
const Map<labelList>& cellToCells
) const
{
label oldOwn = mesh_.faceOwner()[faceI];
Map<labelList>::const_iterator fnd = cellToCells.find(oldOwn);
if (fnd == cellToCells.end())
{
// Unsplit cell
return oldOwn;
}
else
{
// Look up index of face in the cells' faces.
const labelList& newCells = fnd();
const cell& cFaces = mesh_.cells()[oldOwn];
return newCells[findIndex(cFaces, faceI)];
}
}
Foam::label Foam::cellSplitter::newNeighbour
(
const label faceI,
const Map<labelList>& cellToCells
) const
{
label oldNbr = mesh_.faceNeighbour()[faceI];
Map<labelList>::const_iterator fnd = cellToCells.find(oldNbr);
if (fnd == cellToCells.end())
{
// Unsplit cell
return oldNbr;
}
else
{
// Look up index of face in the cells' faces.
const labelList& newCells = fnd();
const cell& cFaces = mesh_.cells()[oldNbr];
return newCells[findIndex(cFaces, faceI)];
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct from components
Foam::cellSplitter::cellSplitter(const polyMesh& mesh)
:
mesh_(mesh),
addedPoints_()
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::cellSplitter::~cellSplitter()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::cellSplitter::setRefinement
(
const Map<point>& cellToMidPoint,
polyTopoChange& meshMod
)
{
addedPoints_.clear();
addedPoints_.resize(cellToMidPoint.size());
//
// Introduce cellToMidPoints.
//
forAllConstIter(Map<point>, cellToMidPoint, iter)
{
label cellI = iter.key();
label anchorPoint = mesh_.cellPoints()[cellI][0];
label addedPointI =
meshMod.setAction
(
polyAddPoint
(
iter(), // point
anchorPoint, // master point
-1, // zone for point
true // supports a cell
)
);
addedPoints_.insert(cellI, addedPointI);
//Pout<< "Added point " << addedPointI
// << iter() << " in cell " << cellI << " with centre "
// << mesh_.cellCentres()[cellI] << endl;
}
//
// Add cells (first one is modified original cell)
//
Map<labelList> cellToCells(cellToMidPoint.size());
forAllConstIter(Map<point>, cellToMidPoint, iter)
{
label cellI = iter.key();
const cell& cFaces = mesh_.cells()[cellI];
// Cells created for this cell.
labelList newCells(cFaces.size());
// First pyramid is the original cell
newCells[0] = cellI;
// Add other pyramids
for (label i = 1; i < cFaces.size(); i++)
{
label addedCellI =
meshMod.setAction
(
polyAddCell
(
-1, // master point
-1, // master edge
-1, // master face
cellI, // master cell
-1 // zone
)
);
newCells[i] = addedCellI;
}
cellToCells.insert(cellI, newCells);
//Pout<< "Split cell " << cellI
// << " with centre " << mesh_.cellCentres()[cellI] << nl
// << " faces:" << cFaces << nl
// << " into :" << newCells << endl;
}
//
// Introduce internal faces. These go from edges of the cell to the mid
// point.
//
forAllConstIter(Map<point>, cellToMidPoint, iter)
{
label cellI = iter.key();
label midPointI = addedPoints_[cellI];
const cell& cFaces = mesh_.cells()[cellI];
const labelList& cEdges = mesh_.cellEdges()[cellI];
forAll(cEdges, i)
{
label edgeI = cEdges[i];
const edge& e = mesh_.edges()[edgeI];
// Get the faces on the cell using the edge
label face0, face1;
meshTools::getEdgeFaces(mesh_, cellI, edgeI, face0, face1);
// Get the cells on both sides of the face by indexing into cFaces.
// (since newly created cells are stored in cFaces order)
const labelList& newCells = cellToCells[cellI];
label cell0 = newCells[findIndex(cFaces, face0)];
label cell1 = newCells[findIndex(cFaces, face1)];
if (cell0 < cell1)
{
// Construct face to midpoint that is pointing away from
// (pyramid split off from) cellI
const face& f0 = mesh_.faces()[face0];
label index = findIndex(f0, e[0]);
bool edgeInFaceOrder = (f0[f0.fcIndex(index)] == e[1]);
// Check if cellI is the face owner
face newF(3);
if (edgeInFaceOrder == (mesh_.faceOwner()[face0] == cellI))
{
// edge used in face order.
newF[0] = e[1];
newF[1] = e[0];
newF[2] = midPointI;
}
else
{
newF[0] = e[0];
newF[1] = e[1];
newF[2] = midPointI;
}
// Now newF points away from cell0
meshMod.setAction
(
polyAddFace
(
newF, // face
cell0, // owner
cell1, // neighbour
-1, // master point
-1, // master edge
face0, // master face for addition
false, // flux flip
-1, // patch for face
-1, // zone for face
false // face zone flip
)
);
}
else
{
// Construct face to midpoint that is pointing away from
// (pyramid split off from) cellI
const face& f1 = mesh_.faces()[face1];
label index = findIndex(f1, e[0]);
bool edgeInFaceOrder = (f1[f1.fcIndex(index)] == e[1]);
// Check if cellI is the face owner
face newF(3);
if (edgeInFaceOrder == (mesh_.faceOwner()[face1] == cellI))
{
// edge used in face order.
newF[0] = e[1];
newF[1] = e[0];
newF[2] = midPointI;
}
else
{
newF[0] = e[0];
newF[1] = e[1];
newF[2] = midPointI;
}
// Now newF points away from cell1
meshMod.setAction
(
polyAddFace
(
newF, // face
cell1, // owner
cell0, // neighbour
-1, // master point
-1, // master edge
face0, // master face for addition
false, // flux flip
-1, // patch for face
-1, // zone for face
false // face zone flip
)
);
}
}
}
//
// Update all existing faces for split owner or neighbour.
//
// Mark off affected face.
boolList faceUpToDate(mesh_.nFaces(), true);
forAllConstIter(Map<point>, cellToMidPoint, iter)
{
label cellI = iter.key();
const cell& cFaces = mesh_.cells()[cellI];
forAll(cFaces, i)
{
label faceI = cFaces[i];
faceUpToDate[faceI] = false;
}
}
forAll(faceUpToDate, faceI)
{
if (!faceUpToDate[faceI])
{
const face& f = mesh_.faces()[faceI];
if (mesh_.isInternalFace(faceI))
{
label newOwn = newOwner(faceI, cellToCells);
label newNbr = newNeighbour(faceI, cellToCells);
if (newOwn < newNbr)
{
meshMod.setAction
(
polyModifyFace
(
f,
faceI,
newOwn, // owner
newNbr, // neighbour
false, // flux flip
-1, // patch for face
false, // remove from zone
-1, // zone for face
false // face zone flip
)
);
}
else
{
meshMod.setAction
(
polyModifyFace
(
f.reverseFace(),
faceI,
newNbr, // owner
newOwn, // neighbour
false, // flux flip
-1, // patch for face
false, // remove from zone
-1, // zone for face
false // face zone flip
)
);
}
}
else
{
label newOwn = newOwner(faceI, cellToCells);
label patchID, zoneID, zoneFlip;
getFaceInfo(faceI, patchID, zoneID, zoneFlip);
meshMod.setAction
(
polyModifyFace
(
mesh_.faces()[faceI],
faceI,
newOwn, // owner
-1, // neighbour
false, // flux flip
patchID, // patch for face
false, // remove from zone
zoneID, // zone for face
zoneFlip // face zone flip
)
);
}
faceUpToDate[faceI] = true;
}
}
}
void Foam::cellSplitter::updateMesh(const mapPolyMesh& morphMap)
{
// Create copy since we're deleting entries. Only if both cell and added
// point get mapped do they get inserted.
Map<label> newAddedPoints(addedPoints_.size());
forAllConstIter(Map<label>, addedPoints_, iter)
{
label oldCellI = iter.key();
label newCellI = morphMap.reverseCellMap()[oldCellI];
label oldPointI = iter();
label newPointI = morphMap.reversePointMap()[oldPointI];
if (newCellI >= 0 && newPointI >= 0)
{
newAddedPoints.insert(newCellI, newPointI);
}
}
// Copy
addedPoints_.transfer(newAddedPoints);
}
// ************************************************************************* //

View File

@ -0,0 +1,149 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Class
Foam::cellSplitter
Description
Does pyramidal decomposition of selected cells. So all faces will become
base of pyramid with as top a user-supplied point (usually the cell centre)
SourceFiles
cellSplitter.C
\*---------------------------------------------------------------------------*/
#ifndef cellSplitter_H
#define cellSplitter_H
#include "Map.H"
#include "edge.H"
#include "typeInfo.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of classes
class polyTopoChange;
class mapPolyMesh;
class polyMesh;
/*---------------------------------------------------------------------------*\
Class cellSplitter Declaration
\*---------------------------------------------------------------------------*/
class cellSplitter
{
// Private data
//- Reference to mesh
const polyMesh& mesh_;
//- Per cell the mid point added.
Map<label> addedPoints_;
// Private Member Functions
//- Get patch and zone info for face
void getFaceInfo
(
const label faceI,
label& patchID,
label& zoneID,
label& zoneFlip
) const;
//- Find the new owner (if any) of the face.
label newOwner
(
const label faceI,
const Map<labelList>& cellToCells
) const;
//- Find the new neighbour (if any) of the face.
label newNeighbour
(
const label faceI,
const Map<labelList>& cellToCells
) const;
//- Disallow default bitwise copy construct
cellSplitter(const cellSplitter&);
//- Disallow default bitwise assignment
void operator=(const cellSplitter&);
public:
//- Runtime type information
ClassName("cellSplitter");
// Constructors
//- Construct from mesh
cellSplitter(const polyMesh& mesh);
//- Destructor
~cellSplitter();
// Member Functions
// Edit
//- Insert mesh changes into meshMod.
// cellToMidPoint : cell to cut and position of its new midpoint
void setRefinement
(
const Map<point>& cellToMidPoint,
polyTopoChange& meshMod
);
//- Force recalculation of locally stored data on topological change
void updateMesh(const mapPolyMesh&);
// Access
//- Per cell the mid point added.
const Map<label>& addedPoints() const
{
return addedPoints_;
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,692 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Application
modifyMesh
Description
Manipulates mesh elements.
Actions are:
(boundary)points:
- move
(boundary)edges:
- split and move introduced point
(boundary)faces:
- split(triangulate) and move introduced point
edges:
- collapse
cells:
- split into polygonal base pyramids around newly introduced mid
point
Is a bit of a loose collection of mesh change drivers.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "polyMesh.H"
#include "polyTopoChange.H"
#include "mapPolyMesh.H"
#include "boundaryCutter.H"
#include "cellSplitter.H"
#include "edgeCollapser.H"
#include "meshTools.H"
#include "Pair.H"
#include "globalIndex.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Locate point on patch. Returns (mesh) point label.
label findPoint(const primitivePatch& pp, const point& nearPoint)
{
const pointField& points = pp.points();
const labelList& meshPoints = pp.meshPoints();
// Find nearest and next nearest
scalar minDistSqr = GREAT;
label minI = -1;
scalar almostMinDistSqr = GREAT;
label almostMinI = -1;
forAll(meshPoints, i)
{
label pointI = meshPoints[i];
scalar distSqr = magSqr(nearPoint - points[pointI]);
if (distSqr < minDistSqr)
{
almostMinDistSqr = minDistSqr;
almostMinI = minI;
minDistSqr = distSqr;
minI = pointI;
}
else if (distSqr < almostMinDistSqr)
{
almostMinDistSqr = distSqr;
almostMinI = pointI;
}
}
// Decide if nearPoint unique enough.
Info<< "Found to point " << nearPoint << nl
<< " nearest point : " << minI
<< " distance " << Foam::sqrt(minDistSqr)
<< " at " << points[minI] << nl
<< " next nearest point : " << almostMinI
<< " distance " << Foam::sqrt(almostMinDistSqr)
<< " at " << points[almostMinI] << endl;
if (almostMinDistSqr < 4*minDistSqr)
{
Info<< "Next nearest too close to nearest. Aborting" << endl;
return -1;
}
else
{
return minI;
}
}
// Locate edge on patch. Return mesh edge label.
label findEdge
(
const primitiveMesh& mesh,
const primitivePatch& pp,
const point& nearPoint
)
{
const pointField& localPoints = pp.localPoints();
const pointField& points = pp.points();
const labelList& meshPoints = pp.meshPoints();
const edgeList& edges = pp.edges();
// Find nearest and next nearest
scalar minDist = GREAT;
label minI = -1;
scalar almostMinDist = GREAT;
label almostMinI = -1;
forAll(edges, edgeI)
{
const edge& e = edges[edgeI];
pointHit pHit(e.line(localPoints).nearestDist(nearPoint));
if (pHit.hit())
{
if (pHit.distance() < minDist)
{
almostMinDist = minDist;
almostMinI = minI;
minDist = pHit.distance();
minI = meshTools::findEdge
(
mesh,
meshPoints[e[0]],
meshPoints[e[1]]
);
}
else if (pHit.distance() < almostMinDist)
{
almostMinDist = pHit.distance();
almostMinI = meshTools::findEdge
(
mesh,
meshPoints[e[0]],
meshPoints[e[1]]
);
}
}
}
if (minI == -1)
{
Info<< "Did not find edge close to point " << nearPoint << endl;
return -1;
}
// Decide if nearPoint unique enough.
Info<< "Found to point " << nearPoint << nl
<< " nearest edge : " << minI
<< " distance " << minDist << " endpoints "
<< mesh.edges()[minI].line(points) << nl
<< " next nearest edge : " << almostMinI
<< " distance " << almostMinDist << " endpoints "
<< mesh.edges()[almostMinI].line(points) << nl
<< endl;
if (almostMinDist < 2*minDist)
{
Info<< "Next nearest too close to nearest. Aborting" << endl;
return -1;
}
else
{
return minI;
}
}
// Find face on patch. Return mesh face label.
label findFace
(
const primitiveMesh& mesh,
const primitivePatch& pp,
const point& nearPoint
)
{
const pointField& points = pp.points();
// Find nearest and next nearest
scalar minDist = GREAT;
label minI = -1;
scalar almostMinDist = GREAT;
label almostMinI = -1;
forAll(pp, patchFaceI)
{
pointHit pHit(pp[patchFaceI].nearestPoint(nearPoint, points));
if (pHit.hit())
{
if (pHit.distance() < minDist)
{
almostMinDist = minDist;
almostMinI = minI;
minDist = pHit.distance();
minI = patchFaceI + mesh.nInternalFaces();
}
else if (pHit.distance() < almostMinDist)
{
almostMinDist = pHit.distance();
almostMinI = patchFaceI + mesh.nInternalFaces();
}
}
}
if (minI == -1)
{
Info<< "Did not find face close to point " << nearPoint << endl;
return -1;
}
// Decide if nearPoint unique enough.
Info<< "Found to point " << nearPoint << nl
<< " nearest face : " << minI
<< " distance " << minDist
<< " to face centre " << mesh.faceCentres()[minI] << nl
<< " next nearest face : " << almostMinI
<< " distance " << almostMinDist
<< " to face centre " << mesh.faceCentres()[almostMinI] << nl
<< endl;
if (almostMinDist < 2*minDist)
{
Info<< "Next nearest too close to nearest. Aborting" << endl;
return -1;
}
else
{
return minI;
}
}
// Find cell with cell centre close to given point.
label findCell(const primitiveMesh& mesh, const point& nearPoint)
{
label cellI = mesh.findCell(nearPoint);
if (cellI != -1)
{
scalar distToCcSqr = magSqr(nearPoint - mesh.cellCentres()[cellI]);
const labelList& cPoints = mesh.cellPoints()[cellI];
label minI = -1;
scalar minDistSqr = GREAT;
forAll(cPoints, i)
{
label pointI = cPoints[i];
scalar distSqr = magSqr(nearPoint - mesh.points()[pointI]);
if (distSqr < minDistSqr)
{
minDistSqr = distSqr;
minI = pointI;
}
}
// Decide if nearPoint unique enough.
Info<< "Found to point " << nearPoint << nl
<< " nearest cell : " << cellI
<< " distance " << Foam::sqrt(distToCcSqr)
<< " to cell centre " << mesh.cellCentres()[cellI] << nl
<< " nearest mesh point : " << minI
<< " distance " << Foam::sqrt(minDistSqr)
<< " to " << mesh.points()[minI] << nl
<< endl;
if (minDistSqr < 4*distToCcSqr)
{
Info<< "Mesh point too close to nearest cell centre. Aborting"
<< endl;
cellI = -1;
}
}
return cellI;
}
int main(int argc, char *argv[])
{
# include "addOverwriteOption.H"
# include "setRootCase.H"
# include "createTime.H"
runTime.functionObjects().off();
# include "createPolyMesh.H"
const word oldInstance = mesh.pointsInstance();
const bool overwrite = args.optionFound("overwrite");
Info<< "Reading modifyMeshDict\n" << endl;
IOdictionary dict
(
IOobject
(
"modifyMeshDict",
runTime.system(),
mesh,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
);
// Read all from the dictionary.
List<Pair<point> > pointsToMove(dict.lookup("pointsToMove"));
List<Pair<point> > edgesToSplit(dict.lookup("edgesToSplit"));
List<Pair<point> > facesToTriangulate
(
dict.lookup("facesToTriangulate")
);
bool cutBoundary =
(
pointsToMove.size()
|| edgesToSplit.size()
|| facesToTriangulate.size()
);
List<Pair<point> > edgesToCollapse(dict.lookup("edgesToCollapse"));
bool collapseEdge = edgesToCollapse.size();
List<Pair<point> > cellsToPyramidise(dict.lookup("cellsToSplit"));
bool cellsToSplit = cellsToPyramidise.size();
// List<Tuple2<pointField,point> >
// cellsToCreate(dict.lookup("cellsToCreate"));
Info<< "Read from " << dict.name() << nl
<< " Boundary cutting module:" << nl
<< " points to move :" << pointsToMove.size() << nl
<< " edges to split :" << edgesToSplit.size() << nl
<< " faces to triangulate:" << facesToTriangulate.size() << nl
<< " Cell splitting module:" << nl
<< " cells to split :" << cellsToPyramidise.size() << nl
<< " Edge collapsing module:" << nl
<< " edges to collapse :" << edgesToCollapse.size() << nl
//<< " cells to create :" << cellsToCreate.size() << nl
<< endl;
if
(
(cutBoundary && collapseEdge)
|| (cutBoundary && cellsToSplit)
|| (collapseEdge && cellsToSplit)
)
{
FatalErrorIn(args.executable())
<< "Used more than one mesh modifying module "
<< "(boundary cutting, cell splitting, edge collapsing)" << nl
<< "Please do them in separate passes." << exit(FatalError);
}
// Get calculating engine for all of outside
const SubList<face> outsideFaces
(
mesh.faces(),
mesh.nFaces() - mesh.nInternalFaces(),
mesh.nInternalFaces()
);
primitivePatch allBoundary(outsideFaces, mesh.points());
// Look up mesh labels and convert to input for boundaryCutter.
bool validInputs = true;
Info<< nl << "Looking up points to move ..." << nl << endl;
Map<point> pointToPos(pointsToMove.size());
forAll(pointsToMove, i)
{
const Pair<point>& pts = pointsToMove[i];
label pointI = findPoint(allBoundary, pts.first());
if (pointI == -1 || !pointToPos.insert(pointI, pts.second()))
{
Info<< "Could not insert mesh point " << pointI
<< " for input point " << pts.first() << nl
<< "Perhaps the point is already marked for moving?" << endl;
validInputs = false;
}
}
Info<< nl << "Looking up edges to split ..." << nl << endl;
Map<List<point> > edgeToCuts(edgesToSplit.size());
forAll(edgesToSplit, i)
{
const Pair<point>& pts = edgesToSplit[i];
label edgeI = findEdge(mesh, allBoundary, pts.first());
if
(
edgeI == -1
|| !edgeToCuts.insert(edgeI, List<point>(1, pts.second()))
)
{
Info<< "Could not insert mesh edge " << edgeI
<< " for input point " << pts.first() << nl
<< "Perhaps the edge is already marked for cutting?" << endl;
validInputs = false;
}
}
Info<< nl << "Looking up faces to triangulate ..." << nl << endl;
Map<point> faceToDecompose(facesToTriangulate.size());
forAll(facesToTriangulate, i)
{
const Pair<point>& pts = facesToTriangulate[i];
label faceI = findFace(mesh, allBoundary, pts.first());
if (faceI == -1 || !faceToDecompose.insert(faceI, pts.second()))
{
Info<< "Could not insert mesh face " << faceI
<< " for input point " << pts.first() << nl
<< "Perhaps the face is already marked for splitting?" << endl;
validInputs = false;
}
}
Info<< nl << "Looking up cells to convert to pyramids around"
<< " cell centre ..." << nl << endl;
Map<point> cellToPyrCentre(cellsToPyramidise.size());
forAll(cellsToPyramidise, i)
{
const Pair<point>& pts = cellsToPyramidise[i];
label cellI = findCell(mesh, pts.first());
if (cellI == -1 || !cellToPyrCentre.insert(cellI, pts.second()))
{
Info<< "Could not insert mesh cell " << cellI
<< " for input point " << pts.first() << nl
<< "Perhaps the cell is already marked for splitting?" << endl;
validInputs = false;
}
}
Info<< nl << "Looking up edges to collapse ..." << nl << endl;
Map<point> edgeToPos(edgesToCollapse.size());
forAll(edgesToCollapse, i)
{
const Pair<point>& pts = edgesToCollapse[i];
label edgeI = findEdge(mesh, allBoundary, pts.first());
if (edgeI == -1 || !edgeToPos.insert(edgeI, pts.second()))
{
Info<< "Could not insert mesh edge " << edgeI
<< " for input point " << pts.first() << nl
<< "Perhaps the edge is already marked for collaping?" << endl;
validInputs = false;
}
}
if (!validInputs)
{
Info<< nl << "There was a problem in one of the inputs in the"
<< " dictionary. Not modifying mesh." << endl;
}
else if (cellToPyrCentre.size())
{
Info<< nl << "All input cells located. Modifying mesh." << endl;
// Mesh change engine
cellSplitter cutter(mesh);
// Topo change container
polyTopoChange meshMod(mesh);
// Insert commands into meshMod
cutter.setRefinement(cellToPyrCentre, meshMod);
// Do changes
autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
if (morphMap().hasMotionPoints())
{
mesh.movePoints(morphMap().preMotionPoints());
}
cutter.updateMesh(morphMap());
if (!overwrite)
{
runTime++;
}
else
{
mesh.setInstance(oldInstance);
}
// Write resulting mesh
Info<< "Writing modified mesh to time " << runTime.timeName() << endl;
mesh.write();
}
else if (edgeToPos.size())
{
Info<< nl << "All input edges located. Modifying mesh." << endl;
// Mesh change engine
edgeCollapser cutter(mesh);
const edgeList& edges = mesh.edges();
const pointField& points = mesh.points();
pointField newPoints(points);
PackedBoolList collapseEdge(mesh.nEdges());
Map<point> collapsePointToLocation(mesh.nPoints());
// Get new positions and construct collapse network
forAllConstIter(Map<point>, edgeToPos, iter)
{
label edgeI = iter.key();
const edge& e = edges[edgeI];
collapseEdge[edgeI] = true;
collapsePointToLocation.set(e[1], points[e[0]]);
newPoints[e[0]] = iter();
}
// Move master point to destination.
mesh.movePoints(newPoints);
List<pointEdgeCollapse> allPointInfo;
const globalIndex globalPoints(mesh.nPoints());
labelList pointPriority(mesh.nPoints(), 0);
cutter.consistentCollapse
(
globalPoints,
pointPriority,
collapsePointToLocation,
collapseEdge,
allPointInfo
);
// Topo change container
polyTopoChange meshMod(mesh);
// Insert
cutter.setRefinement(allPointInfo, meshMod);
// Do changes
autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
if (morphMap().hasMotionPoints())
{
mesh.movePoints(morphMap().preMotionPoints());
}
// Not implemented yet:
//cutter.updateMesh(morphMap());
if (!overwrite)
{
runTime++;
}
else
{
mesh.setInstance(oldInstance);
}
// Write resulting mesh
Info<< "Writing modified mesh to time " << runTime.timeName() << endl;
mesh.write();
}
else
{
Info<< nl << "All input points located. Modifying mesh." << endl;
// Mesh change engine
boundaryCutter cutter(mesh);
// Topo change container
polyTopoChange meshMod(mesh);
// Insert commands into meshMod
cutter.setRefinement
(
pointToPos,
edgeToCuts,
Map<labelPair>(0), // Faces to split diagonally
faceToDecompose, // Faces to triangulate
meshMod
);
// Do changes
autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
if (morphMap().hasMotionPoints())
{
mesh.movePoints(morphMap().preMotionPoints());
}
cutter.updateMesh(morphMap());
if (!overwrite)
{
runTime++;
}
else
{
mesh.setInstance(oldInstance);
}
// Write resulting mesh
Info<< "Writing modified mesh to time " << runTime.timeName() << endl;
mesh.write();
}
Info<< "\nEnd\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,79 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object modifyMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Move boundary points:
// Every entry is two coordinates. First one is location of the point to move,
// the second is the position to move to.
pointsToMove
(
(( -0.17861 -0.45073 0.75276)( -0.18 -0.45073 0.75276))
);
// Split boundary edge in two:
// First coord is a point on the (boundary) edge to cut, second is the
// position of the newly introduced point
edgesToSplit
(
(( -0.17692 -0.45312 0.74516)( -0.18 -0.45 0.742))
);
// Triangulate a boundary face:
// First coord is a point on the face to triangulate. It will introduce a
// point on the face, triangulate and move the point to the second coordinate.
facesToTriangulate
(
(( -0.039123 -0.45045 0.74083) (-0.03844 -0.45049 0.73572))
);
// Boundary edges to collapse. First coord is point on the edge, second
// is coordinate to collapse to.
edgesToCollapse
(
((0.054975 0.099987 0.0044074)(0.054975 0.099987 0.0044074))
);
// Split cells:
// First coord is a point inside the cell to split. A point inside the cell will
// be introduced and the cell will get decomposed into polygonal base pyramids
// with this new point as top. (so the original faces will not get split)
cellsToSplit
(
(( -0.039123 -0.45045 0.74083) (-0.03844 -0.45049 0.73572))
);
// Change patch:
// Changes patchID of boundary faces. Coord selects the face, label is the
// patch index.
facesToRepatch
(
(( -0.039123 -0.45045 0.74083) 1)
);
//// Create cell:
//// Creates a cell on the boundary given a face covering a cavity. Gets
//// the vertices of the face (outwards pointing normal) and a point internal
//// to the new cell. (used to check the orientation of the face). Walks all
//// boundary faces reachable from any edge on the face and constructs cell
//// from it.
//cellsToCreate
//(
// (
// ((0 0 0) (1 0 0) (1 1 0) (0 1 0)) // vertices of face
// (0.5 0.5 0.1) // cell centre
// )
//);
// ************************************************************************* //

View File

@ -0,0 +1,3 @@
refineHexMesh.C
EXE = $(FOAM_APPBIN)/refineHexMesh

View File

@ -0,0 +1,11 @@
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude
EXE_LIBS = \
-ldynamicMesh \
-lmeshTools \
-lfiniteVolume \
-lgenericPatchFields

View File

@ -0,0 +1,204 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2014 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Application
refineHexMesh
Description
Refines a hex mesh by 2x2x2 cell splitting.
\*---------------------------------------------------------------------------*/
#include "fvMesh.H"
#include "pointMesh.H"
#include "argList.H"
#include "Time.H"
#include "hexRef8.H"
#include "cellSet.H"
#include "OFstream.H"
#include "meshTools.H"
#include "IFstream.H"
#include "polyTopoChange.H"
#include "mapPolyMesh.H"
#include "volMesh.H"
#include "surfaceMesh.H"
#include "volFields.H"
#include "surfaceFields.H"
#include "pointFields.H"
#include "ReadFields.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "addOverwriteOption.H"
#include "addRegionOption.H"
argList::validArgs.append("cellSet");
argList::addBoolOption
(
"minSet",
"remove cells from input cellSet to keep to 2:1 ratio"
" (default is to extend set)"
);
#include "setRootCase.H"
#include "createTime.H"
runTime.functionObjects().off();
#include "createNamedMesh.H"
const word oldInstance = mesh.pointsInstance();
word cellSetName(args.args()[1]);
const bool overwrite = args.optionFound("overwrite");
const bool minSet = args.optionFound("minSet");
Info<< "Reading cells to refine from cellSet " << cellSetName
<< nl << endl;
cellSet cellsToRefine(mesh, cellSetName);
Info<< "Read " << returnReduce(cellsToRefine.size(), sumOp<label>())
<< " cells to refine from cellSet " << cellSetName << nl
<< endl;
// Read objects in time directory
IOobjectList objects(mesh, runTime.timeName());
// Read vol fields.
PtrList<volScalarField> vsFlds;
ReadFields(mesh, objects, vsFlds);
PtrList<volVectorField> vvFlds;
ReadFields(mesh, objects, vvFlds);
PtrList<volSphericalTensorField> vstFlds;
ReadFields(mesh, objects, vstFlds);
PtrList<volSymmTensorField> vsymtFlds;
ReadFields(mesh, objects, vsymtFlds);
PtrList<volTensorField> vtFlds;
ReadFields(mesh, objects, vtFlds);
// Read surface fields.
PtrList<surfaceScalarField> ssFlds;
ReadFields(mesh, objects, ssFlds);
PtrList<surfaceVectorField> svFlds;
ReadFields(mesh, objects, svFlds);
PtrList<surfaceSphericalTensorField> sstFlds;
ReadFields(mesh, objects, sstFlds);
PtrList<surfaceSymmTensorField> ssymtFlds;
ReadFields(mesh, objects, ssymtFlds);
PtrList<surfaceTensorField> stFlds;
ReadFields(mesh, objects, stFlds);
// Read point fields
PtrList<pointScalarField> psFlds;
ReadFields(pointMesh::New(mesh), objects, psFlds);
PtrList<pointVectorField> pvFlds;
ReadFields(pointMesh::New(mesh), objects, pvFlds);
// Construct refiner without unrefinement. Read existing point/cell level.
hexRef8 meshCutter(mesh);
// Some stats
Info<< "Read mesh:" << nl
<< " cells:" << mesh.globalData().nTotalCells() << nl
<< " faces:" << mesh.globalData().nTotalFaces() << nl
<< " points:" << mesh.globalData().nTotalPoints() << nl
<< " cellLevel :"
<< " min:" << gMin(meshCutter.cellLevel())
<< " max:" << gMax(meshCutter.cellLevel()) << nl
<< " pointLevel :"
<< " min:" << gMin(meshCutter.pointLevel())
<< " max:" << gMax(meshCutter.pointLevel()) << nl
<< endl;
// Maintain 2:1 ratio
labelList newCellsToRefine
(
meshCutter.consistentRefinement
(
cellsToRefine.toc(),
!minSet // extend set
)
);
// Mesh changing engine.
polyTopoChange meshMod(mesh);
// Play refinement commands into mesh changer.
meshCutter.setRefinement(newCellsToRefine, meshMod);
if (!overwrite)
{
runTime++;
}
// Create mesh, return map from old to new mesh.
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
// Update fields
mesh.updateMesh(map);
// Update numbering of cells/vertices.
meshCutter.updateMesh(map);
// Optionally inflate mesh
if (map().hasMotionPoints())
{
mesh.movePoints(map().preMotionPoints());
}
Info<< "Refined from " << returnReduce(map().nOldCells(), sumOp<label>())
<< " to " << mesh.globalData().nTotalCells() << " cells." << nl << endl;
if (overwrite)
{
mesh.setInstance(oldInstance);
meshCutter.setInstance(oldInstance);
}
Info<< "Writing mesh to " << runTime.timeName() << endl;
mesh.write();
meshCutter.write();
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,4 @@
refineWallLayer.C
EXE = $(FOAM_APPBIN)/refineWallLayer

View File

@ -0,0 +1,7 @@
EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude
EXE_LIBS = \
-ldynamicMesh \
-lmeshTools

View File

@ -0,0 +1,244 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Application
refineWallLayer
Description
Utility to refine cells next to patches.
Takes a patchName and number of layers to refine. Works out cells within
these layers and refines those in the wall-normal direction.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "polyTopoChange.H"
#include "polyTopoChanger.H"
#include "mapPolyMesh.H"
#include "polyMesh.H"
#include "cellCuts.H"
#include "cellSet.H"
#include "meshCutter.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "addOverwriteOption.H"
argList::noParallel();
argList::validArgs.append("patchName");
argList::validArgs.append("edgeWeight");
argList::addOption
(
"useSet",
"name",
"restrict cells to refine based on specified cellSet name"
);
# include "setRootCase.H"
# include "createTime.H"
runTime.functionObjects().off();
# include "createPolyMesh.H"
const word oldInstance = mesh.pointsInstance();
const word patchName = args[1];
const scalar weight = args.argRead<scalar>(2);
const bool overwrite = args.optionFound("overwrite");
label patchID = mesh.boundaryMesh().findPatchID(patchName);
if (patchID == -1)
{
FatalErrorIn(args.executable())
<< "Cannot find patch " << patchName << endl
<< "Valid patches are " << mesh.boundaryMesh().names()
<< exit(FatalError);
}
const polyPatch& pp = mesh.boundaryMesh()[patchID];
// Cells cut
labelHashSet cutCells(4*pp.size());
const labelList& meshPoints = pp.meshPoints();
forAll(meshPoints, pointI)
{
label meshPointI = meshPoints[pointI];
const labelList& pCells = mesh.pointCells()[meshPointI];
forAll(pCells, pCellI)
{
cutCells.insert(pCells[pCellI]);
}
}
Info<< "Selected " << cutCells.size()
<< " cells connected to patch " << pp.name() << endl << endl;
//
// List of cells to refine
//
word setName;
if (args.optionReadIfPresent("useSet", setName))
{
Info<< "Subsetting cells to cut based on cellSet"
<< setName << nl << endl;
cellSet cells(mesh, setName);
Info<< "Read " << cells.size() << " cells from cellSet "
<< cells.instance()/cells.local()/cells.name()
<< nl << endl;
forAllConstIter(cellSet, cells, iter)
{
cutCells.erase(iter.key());
}
Info<< "Removed from cells to cut all the ones not in set "
<< setName << nl << endl;
}
// Mark all meshpoints on patch
boolList vertOnPatch(mesh.nPoints(), false);
forAll(meshPoints, pointI)
{
const label meshPointI = meshPoints[pointI];
vertOnPatch[meshPointI] = true;
}
// Mark cut edges.
DynamicList<label> allCutEdges(pp.nEdges());
DynamicList<scalar> allCutEdgeWeights(pp.nEdges());
forAll(meshPoints, pointI)
{
label meshPointI = meshPoints[pointI];
const labelList& pEdges = mesh.pointEdges()[meshPointI];
forAll(pEdges, pEdgeI)
{
const label edgeI = pEdges[pEdgeI];
const edge& e = mesh.edges()[edgeI];
label otherPointI = e.otherVertex(meshPointI);
if (!vertOnPatch[otherPointI])
{
allCutEdges.append(edgeI);
if (e.start() == meshPointI)
{
allCutEdgeWeights.append(weight);
}
else
{
allCutEdgeWeights.append(1 - weight);
}
}
}
}
allCutEdges.shrink();
allCutEdgeWeights.shrink();
Info<< "Cutting:" << nl
<< " cells:" << cutCells.size() << nl
<< " edges:" << allCutEdges.size() << nl
<< endl;
// Transfer DynamicLists to straight ones.
scalarField cutEdgeWeights;
cutEdgeWeights.transfer(allCutEdgeWeights);
allCutEdgeWeights.clear();
// Gets cuts across cells from cuts through edges.
cellCuts cuts
(
mesh,
cutCells.toc(), // cells candidate for cutting
labelList(0), // cut vertices
allCutEdges, // cut edges
cutEdgeWeights // weight on cut edges
);
polyTopoChange meshMod(mesh);
// Cutting engine
meshCutter cutter(mesh);
// Insert mesh refinement into polyTopoChange.
cutter.setRefinement(cuts, meshMod);
// Do all changes
Info<< "Morphing ..." << endl;
if (!overwrite)
{
runTime++;
}
autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
if (morphMap().hasMotionPoints())
{
mesh.movePoints(morphMap().preMotionPoints());
}
// Update stored labels on meshCutter.
cutter.updateMesh(morphMap());
if (overwrite)
{
mesh.setInstance(oldInstance);
}
// Write resulting mesh
Info<< "Writing refined morphMesh to time " << runTime.timeName() << endl;
mesh.write();
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,4 @@
refinementLevel.C
EXE = $(FOAM_APPBIN)/refinementLevel

View File

@ -0,0 +1,7 @@
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude
EXE_LIBS = \
-lfiniteVolume \
-lmeshTools

View File

@ -0,0 +1,368 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Application
refinementLevel
Description
Tries to figure out what the refinement level is on refined cartesian
meshes. Run BEFORE snapping.
Writes
- volScalarField 'refinementLevel' with current refinement level.
- cellSet 'refCells' which are the cells that need to be refined to satisfy
2:1 refinement.
Works by dividing cells into volume bins.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "polyMesh.H"
#include "cellSet.H"
#include "SortableList.H"
#include "labelIOList.H"
#include "fvMesh.H"
#include "volFields.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Return true if any cells had to be split to keep a difference between
// neighbouring refinement levels < limitDiff. Puts cells into refCells and
// update refLevel to account for refinement.
bool limitRefinementLevel
(
const primitiveMesh& mesh,
labelList& refLevel,
cellSet& refCells
)
{
const labelListList& cellCells = mesh.cellCells();
label oldNCells = refCells.size();
forAll(cellCells, cellI)
{
const labelList& cCells = cellCells[cellI];
forAll(cCells, i)
{
if (refLevel[cCells[i]] > (refLevel[cellI]+1))
{
// Found neighbour with >=2 difference in refLevel.
refCells.insert(cellI);
refLevel[cellI]++;
break;
}
}
}
if (refCells.size() > oldNCells)
{
Info<< "Added an additional " << refCells.size() - oldNCells
<< " cells to satisfy 1:2 refinement level"
<< endl;
return true;
}
else
{
return false;
}
}
int main(int argc, char *argv[])
{
argList::addBoolOption
(
"readLevel",
"read level from refinementLevel file"
);
#include "setRootCase.H"
#include "createTime.H"
#include "createPolyMesh.H"
Info<< "Dividing cells into bins depending on cell volume.\nThis will"
<< " correspond to refinement levels for a mesh with only 2x2x2"
<< " refinement\n"
<< "The upper range for every bin is always 1.1 times the lower range"
<< " to allow for some truncation error."
<< nl << endl;
const bool readLevel = args.optionFound("readLevel");
const scalarField& vols = mesh.cellVolumes();
SortableList<scalar> sortedVols(vols);
// All cell labels, sorted per bin.
DynamicList<DynamicList<label> > bins;
// Lower/upper limits
DynamicList<scalar> lowerLimits;
DynamicList<scalar> upperLimits;
// Create bin0. Have upperlimit as factor times lowerlimit.
bins.append(DynamicList<label>());
lowerLimits.append(sortedVols[0]);
upperLimits.append(1.1 * lowerLimits.last());
forAll(sortedVols, i)
{
if (sortedVols[i] > upperLimits.last())
{
// New value outside of current bin
// Shrink old bin.
DynamicList<label>& bin = bins.last();
bin.shrink();
Info<< "Collected " << bin.size() << " elements in bin "
<< lowerLimits.last() << " .. "
<< upperLimits.last() << endl;
// Create new bin.
bins.append(DynamicList<label>());
lowerLimits.append(sortedVols[i]);
upperLimits.append(1.1 * lowerLimits.last());
Info<< "Creating new bin " << lowerLimits.last()
<< " .. " << upperLimits.last()
<< endl;
}
// Append to current bin.
DynamicList<label>& bin = bins.last();
bin.append(sortedVols.indices()[i]);
}
Info<< endl;
bins.last().shrink();
bins.shrink();
lowerLimits.shrink();
upperLimits.shrink();
//
// Write to cellSets.
//
Info<< "Volume bins:" << nl;
forAll(bins, binI)
{
const DynamicList<label>& bin = bins[binI];
cellSet cells(mesh, "vol" + name(binI), bin.size());
forAll(bin, i)
{
cells.insert(bin[i]);
}
Info<< " " << lowerLimits[binI] << " .. " << upperLimits[binI]
<< " : writing " << bin.size() << " cells to cellSet "
<< cells.name() << endl;
cells.write();
}
//
// Convert bins into refinement level.
//
// Construct fvMesh to be able to construct volScalarField
fvMesh fMesh
(
IOobject
(
fvMesh::defaultRegion,
runTime.timeName(),
runTime
),
xferCopy(mesh.points()), // could we safely re-use the data?
xferCopy(mesh.faces()),
xferCopy(mesh.cells())
);
// Add the boundary patches
const polyBoundaryMesh& patches = mesh.boundaryMesh();
List<polyPatch*> p(patches.size());
forAll(p, patchI)
{
p[patchI] = patches[patchI].clone(fMesh.boundaryMesh()).ptr();
}
fMesh.addFvPatches(p);
// Refinement level
IOobject refHeader
(
"refinementLevel",
runTime.timeName(),
polyMesh::defaultRegion,
runTime
);
if (!readLevel && refHeader.headerOk())
{
WarningIn(args.executable())
<< "Detected " << refHeader.name() << " file in "
<< polyMesh::defaultRegion << " directory. Please remove to"
<< " recreate it or use the -readLevel option to use it"
<< endl;
return 1;
}
labelIOList refLevel
(
IOobject
(
"refinementLevel",
runTime.timeName(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
labelList(mesh.nCells(), 0)
);
if (readLevel)
{
refLevel = labelIOList(refHeader);
}
// Construct volScalarField with same info for post processing
volScalarField postRefLevel
(
IOobject
(
"refinementLevel",
runTime.timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
fMesh,
dimensionedScalar("zero", dimless/dimTime, 0)
);
// Set cell values
forAll(bins, binI)
{
const DynamicList<label>& bin = bins[binI];
forAll(bin, i)
{
refLevel[bin[i]] = bins.size() - binI - 1;
postRefLevel[bin[i]] = refLevel[bin[i]];
}
}
// For volScalarField: set boundary values to same as cell.
// Note: could also put
// zeroGradient b.c. on postRefLevel and do evaluate.
forAll(postRefLevel.boundaryField(), patchI)
{
const polyPatch& pp = patches[patchI];
fvPatchScalarField& bField = postRefLevel.boundaryField()[patchI];
Info<< "Setting field for patch "<< endl;
forAll(bField, faceI)
{
label own = mesh.faceOwner()[pp.start() + faceI];
bField[faceI] = postRefLevel[own];
}
}
Info<< "Determined current refinement level and writing to "
<< postRefLevel.name() << " (as volScalarField; for post processing)"
<< nl
<< polyMesh::defaultRegion/refLevel.name()
<< " (as labelIOList; for meshing)" << nl
<< endl;
refLevel.write();
postRefLevel.write();
// Find out cells to refine to keep to 2:1 refinement level restriction
// Cells to refine
cellSet refCells(mesh, "refCells", 100);
while
(
limitRefinementLevel
(
mesh,
refLevel, // current refinement level
refCells // cells to refine
)
)
{}
if (refCells.size())
{
Info<< "Collected " << refCells.size() << " cells that need to be"
<< " refined to get closer to overall 2:1 refinement level limit"
<< nl
<< "Written cells to be refined to cellSet " << refCells.name()
<< nl << endl;
refCells.write();
Info<< "After refinement this tool can be run again to see if the 2:1"
<< " limit is observed all over the mesh" << nl << endl;
}
else
{
Info<< "All cells in the mesh observe the 2:1 refinement level limit"
<< nl << endl;
}
Info<< "\nEnd\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,4 @@
removeFaces.C
EXE = $(FOAM_APPBIN)/removeFaces

View File

@ -0,0 +1,10 @@
EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude
EXE_LIBS = \
-lmeshTools \
-ldynamicMesh \
-lfiniteVolume \
-lgenericPatchFields

View File

@ -0,0 +1,186 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Application
removeFaces
Description
Utility to remove faces (combines cells on both sides).
Takes faceSet of candidates for removal and writes faceSet with faces that
will actually be removed. (because e.g. would cause two faces between the
same cells). See removeFaces in dynamicMesh library for constraints.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "polyTopoChange.H"
#include "faceSet.H"
#include "removeFaces.H"
#include "ReadFields.H"
#include "volFields.H"
#include "surfaceFields.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
# include "addOverwriteOption.H"
argList::validArgs.append("faceSet");
# include "setRootCase.H"
# include "createTime.H"
runTime.functionObjects().off();
# include "createMesh.H"
const word oldInstance = mesh.pointsInstance();
const word setName = args[1];
const bool overwrite = args.optionFound("overwrite");
// Read faces
faceSet candidateSet(mesh, setName);
Pout<< "Read " << candidateSet.size() << " faces to remove" << nl
<< endl;
labelList candidates(candidateSet.toc());
// Face removal engine. No checking for not merging boundary faces.
removeFaces faceRemover(mesh, 2);
// Get compatible set of faces and connected sets of cells.
labelList cellRegion;
labelList cellRegionMaster;
labelList facesToRemove;
faceRemover.compatibleRemoves
(
candidates,
cellRegion,
cellRegionMaster,
facesToRemove
);
{
faceSet compatibleRemoves(mesh, "compatibleRemoves", facesToRemove);
Pout<< "Original faces to be removed:" << candidateSet.size() << nl
<< "New faces to be removed:" << compatibleRemoves.size() << nl
<< endl;
Pout<< "Writing new faces to be removed to faceSet "
<< compatibleRemoves.instance()
/compatibleRemoves.local()
/compatibleRemoves.name()
<< endl;
compatibleRemoves.write();
}
// Read objects in time directory
IOobjectList objects(mesh, runTime.timeName());
// Read vol fields.
PtrList<volScalarField> vsFlds;
ReadFields(mesh, objects, vsFlds);
PtrList<volVectorField> vvFlds;
ReadFields(mesh, objects, vvFlds);
PtrList<volSphericalTensorField> vstFlds;
ReadFields(mesh, objects, vstFlds);
PtrList<volSymmTensorField> vsymtFlds;
ReadFields(mesh, objects, vsymtFlds);
PtrList<volTensorField> vtFlds;
ReadFields(mesh, objects, vtFlds);
// Read surface fields.
PtrList<surfaceScalarField> ssFlds;
ReadFields(mesh, objects, ssFlds);
PtrList<surfaceVectorField> svFlds;
ReadFields(mesh, objects, svFlds);
PtrList<surfaceSphericalTensorField> sstFlds;
ReadFields(mesh, objects, sstFlds);
PtrList<surfaceSymmTensorField> ssymtFlds;
ReadFields(mesh, objects, ssymtFlds);
PtrList<surfaceTensorField> stFlds;
ReadFields(mesh, objects, stFlds);
// Topo changes container
polyTopoChange meshMod(mesh);
// Insert mesh refinement into polyTopoChange.
faceRemover.setRefinement
(
facesToRemove,
cellRegion,
cellRegionMaster,
meshMod
);
autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
mesh.updateMesh(morphMap);
// Move mesh (since morphing does not do this)
if (morphMap().hasMotionPoints())
{
mesh.movePoints(morphMap().preMotionPoints());
}
// Update numbering of cells/vertices.
faceRemover.updateMesh(morphMap);
if (!overwrite)
{
runTime++;
}
else
{
mesh.setInstance(oldInstance);
}
// Take over refinement levels and write to new time directory.
Pout<< "Writing mesh to time " << runTime.timeName() << endl;
mesh.write();
Pout<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,5 @@
edgeStats.C
selectCells.C
EXE = $(FOAM_APPBIN)/selectCells

View File

@ -0,0 +1,12 @@
EXE_INC = \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/triSurface/lnInclude \
-I$(LIB_SRC)/lagrangian/basic/lnInclude
EXE_LIBS = \
-ldynamicMesh \
-lmeshTools \
-ltriSurface \
-llagrangian

View File

@ -0,0 +1,221 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "edgeStats.H"
#include "Time.H"
#include "polyMesh.H"
#include "Ostream.H"
#include "twoDPointCorrector.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::scalar Foam::edgeStats::edgeTol_ = 1e-3;
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::direction Foam::edgeStats::getNormalDir
(
const twoDPointCorrector* correct2DPtr
) const
{
direction dir = 3;
if (correct2DPtr)
{
const vector& normal = correct2DPtr->planeNormal();
if (mag(normal & vector(1, 0, 0)) > 1-edgeTol_)
{
dir = 0;
}
else if (mag(normal & vector(0, 1, 0)) > 1-edgeTol_)
{
dir = 1;
}
else if (mag(normal & vector(0, 0, 1)) > 1-edgeTol_)
{
dir = 2;
}
}
return dir;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct from mesh
Foam::edgeStats::edgeStats(const polyMesh& mesh)
:
mesh_(mesh),
normalDir_(3)
{
IOobject motionObj
(
"motionProperties",
mesh.time().constant(),
mesh,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
);
if (motionObj.headerOk())
{
Info<< "Reading " << mesh.time().constant() / "motionProperties"
<< endl << endl;
IOdictionary motionProperties(motionObj);
Switch twoDMotion(motionProperties.lookup("twoDMotion"));
if (twoDMotion)
{
Info<< "Correcting for 2D motion" << endl << endl;
autoPtr<twoDPointCorrector> correct2DPtr
(
new twoDPointCorrector(mesh)
);
normalDir_ = getNormalDir(&correct2DPtr());
}
}
}
// Construct from components
Foam::edgeStats::edgeStats
(
const polyMesh& mesh,
const twoDPointCorrector* correct2DPtr
)
:
mesh_(mesh),
normalDir_(getNormalDir(correct2DPtr))
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::scalar Foam::edgeStats::minLen(Ostream& os) const
{
label nX = 0;
label nY = 0;
label nZ = 0;
scalar minX = GREAT;
scalar maxX = -GREAT;
vector x(1, 0, 0);
scalar minY = GREAT;
scalar maxY = -GREAT;
vector y(0, 1, 0);
scalar minZ = GREAT;
scalar maxZ = -GREAT;
vector z(0, 0, 1);
scalar minOther = GREAT;
scalar maxOther = -GREAT;
const edgeList& edges = mesh_.edges();
forAll(edges, edgeI)
{
const edge& e = edges[edgeI];
vector eVec(e.vec(mesh_.points()));
scalar eMag = mag(eVec);
eVec /= eMag;
if (mag(eVec & x) > 1-edgeTol_)
{
minX = min(minX, eMag);
maxX = max(maxX, eMag);
nX++;
}
else if (mag(eVec & y) > 1-edgeTol_)
{
minY = min(minY, eMag);
maxY = max(maxY, eMag);
nY++;
}
else if (mag(eVec & z) > 1-edgeTol_)
{
minZ = min(minZ, eMag);
maxZ = max(maxZ, eMag);
nZ++;
}
else
{
minOther = min(minOther, eMag);
maxOther = max(maxOther, eMag);
}
}
os << "Mesh bounding box:" << boundBox(mesh_.points()) << nl << nl
<< "Mesh edge statistics:" << nl
<< " x aligned : number:" << nX << "\tminLen:" << minX
<< "\tmaxLen:" << maxX << nl
<< " y aligned : number:" << nY << "\tminLen:" << minY
<< "\tmaxLen:" << maxY << nl
<< " z aligned : number:" << nZ << "\tminLen:" << minZ
<< "\tmaxLen:" << maxZ << nl
<< " other : number:" << mesh_.nEdges() - nX - nY - nZ
<< "\tminLen:" << minOther
<< "\tmaxLen:" << maxOther << nl << endl;
if (normalDir_ == 0)
{
return min(minY, min(minZ, minOther));
}
else if (normalDir_ == 1)
{
return min(minX, min(minZ, minOther));
}
else if (normalDir_ == 2)
{
return min(minX, min(minY, minOther));
}
else
{
return min(minX, min(minY, min(minZ, minOther)));
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
// ************************************************************************* //

View File

@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Class
Foam::edgeStats
Description
Helper class to calculate minimum edge length on mesh.
SourceFiles
edgeStats.C
\*---------------------------------------------------------------------------*/
#ifndef edgeStats_H
#define edgeStats_H
#include "direction.H"
#include "scalar.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of classes
class polyMesh;
class Ostream;
class twoDPointCorrector;
/*---------------------------------------------------------------------------*\
Class edgeStats Declaration
\*---------------------------------------------------------------------------*/
class edgeStats
{
// Private data
//- Reference to mesh.
const polyMesh& mesh_;
//- Component (0,1,2) of normal direction or 3 if 3D case.
direction normalDir_;
// Private Member Functions
//- If 2d get component of normal dir.
direction getNormalDir(const twoDPointCorrector*) const;
//- Disallow default bitwise copy construct
edgeStats(const edgeStats&);
//- Disallow default bitwise assignment
void operator=(const edgeStats&);
public:
// Static data members
// Max (cos of) angle for edges to be considered aligned with axis.
static const scalar edgeTol_;
// Constructors
//- Construct from mesh
edgeStats(const polyMesh& mesh);
//- Construct from mesh and corrector
edgeStats(const polyMesh& mesh, const twoDPointCorrector* );
// Member Functions
//- Calculate minimum edge length and print
scalar minLen(Ostream& os) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,522 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Application
selectCells
Description
Select cells in relation to surface.
Divides cells into three sets:
- cutCells : cells cut by surface or close to surface.
- outside : cells not in cutCells and reachable from set of
user-defined points (outsidePoints)
- inside : same but not reachable.
Finally the wanted sets are combined into a cellSet 'selected'. Apart
from straightforward adding the contents there are a few extra rules to
make sure that the surface of the 'outside' of the mesh is singly
connected.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "polyMesh.H"
#include "IOdictionary.H"
#include "twoDPointCorrector.H"
#include "OFstream.H"
#include "meshTools.H"
#include "triSurface.H"
#include "triSurfaceSearch.H"
#include "meshSearch.H"
#include "cellClassification.H"
#include "cellSet.H"
#include "cellInfo.H"
#include "MeshWave.H"
#include "edgeStats.H"
#include "treeDataTriSurface.H"
#include "indexedOctree.H"
#include "globalMeshData.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// cellType for cells included/not included in mesh.
static const label MESH = cellClassification::INSIDE;
static const label NONMESH = cellClassification::OUTSIDE;
void writeSet(const cellSet& cells, const string& msg)
{
Info<< "Writing " << msg << " (" << cells.size() << ") to cellSet "
<< cells.instance()/cells.local()/cells.name()
<< endl << endl;
cells.write();
}
void getType(const labelList& elems, const label type, labelHashSet& set)
{
forAll(elems, i)
{
if (elems[i] == type)
{
set.insert(i);
}
}
}
void cutBySurface
(
const polyMesh& mesh,
const meshSearch& queryMesh,
const triSurfaceSearch& querySurf,
const pointField& outsidePts,
const bool selectCut,
const bool selectInside,
const bool selectOutside,
const scalar nearDist,
cellClassification& cellType
)
{
// Cut with surface and classify as inside/outside/cut
cellType =
cellClassification
(
mesh,
queryMesh,
querySurf,
outsidePts
);
// Get inside/outside/cutCells cellSets.
cellSet inside(mesh, "inside", mesh.nCells()/10);
getType(cellType, cellClassification::INSIDE, inside);
writeSet(inside, "inside cells");
cellSet outside(mesh, "outside", mesh.nCells()/10);
getType(cellType, cellClassification::OUTSIDE, outside);
writeSet(outside, "outside cells");
cellSet cutCells(mesh, "cutCells", mesh.nCells()/10);
getType(cellType, cellClassification::CUT, cutCells);
writeSet(cutCells, "cells cut by surface");
// Change cellType to reflect selected part of mesh. Use
// MESH to denote selected part, NONMESH for all
// other cells.
// Is a bit of a hack but allows us to reuse all the functionality
// in cellClassification.
forAll(cellType, cellI)
{
label cType = cellType[cellI];
if (cType == cellClassification::CUT)
{
if (selectCut)
{
cellType[cellI] = MESH;
}
else
{
cellType[cellI] = NONMESH;
}
}
else if (cType == cellClassification::INSIDE)
{
if (selectInside)
{
cellType[cellI] = MESH;
}
else
{
cellType[cellI] = NONMESH;
}
}
else if (cType == cellClassification::OUTSIDE)
{
if (selectOutside)
{
cellType[cellI] = MESH;
}
else
{
cellType[cellI] = NONMESH;
}
}
else
{
FatalErrorIn("cutBySurface")
<< "Multiple mesh regions in original mesh" << endl
<< "Please use splitMeshRegions to separate these"
<< exit(FatalError);
}
}
if (nearDist > 0)
{
Info<< "Removing cells with points closer than " << nearDist
<< " to the surface ..." << nl << endl;
const pointField& pts = mesh.points();
const indexedOctree<treeDataTriSurface>& tree = querySurf.tree();
label nRemoved = 0;
forAll(pts, pointI)
{
const point& pt = pts[pointI];
pointIndexHit hitInfo = tree.findNearest(pt, sqr(nearDist));
if (hitInfo.hit())
{
const labelList& pCells = mesh.pointCells()[pointI];
forAll(pCells, i)
{
if (cellType[pCells[i]] != NONMESH)
{
cellType[pCells[i]] = NONMESH;
nRemoved++;
}
}
}
}
// tmp<pointField> tnearest = querySurf.calcNearest(pts);
// const pointField& nearest = tnearest();
//
// label nRemoved = 0;
//
// forAll(nearest, pointI)
// {
// if (mag(nearest[pointI] - pts[pointI]) < nearDist)
// {
// const labelList& pCells = mesh.pointCells()[pointI];
//
// forAll(pCells, i)
// {
// if (cellType[pCells[i]] != NONMESH)
// {
// cellType[pCells[i]] = NONMESH;
// nRemoved++;
// }
// }
// }
// }
Info<< "Removed " << nRemoved << " cells since too close to surface"
<< nl << endl;
}
}
// We're meshing the outside. Subset the currently selected mesh cells with the
// ones reachable from the outsidepoints.
label selectOutsideCells
(
const polyMesh& mesh,
const meshSearch& queryMesh,
const pointField& outsidePts,
cellClassification& cellType
)
{
//
// Check all outsidePts and for all of them inside a mesh cell
// collect the faces to start walking from
//
// Outside faces
labelHashSet outsideFacesMap(outsidePts.size() * 6 * 2);
DynamicList<label> outsideFaces(outsideFacesMap.size());
// CellInfo on outside faces
DynamicList<cellInfo> outsideFacesInfo(outsideFacesMap.size());
// cellInfo for mesh cell
const cellInfo meshInfo(MESH);
forAll(outsidePts, outsidePtI)
{
// Find cell containing point. Linear search.
label cellI = queryMesh.findCell(outsidePts[outsidePtI], -1, false);
if (cellI != -1 && cellType[cellI] == MESH)
{
Info<< "Marking cell " << cellI << " containing outside point "
<< outsidePts[outsidePtI] << " with type " << cellType[cellI]
<< " ..." << endl;
//
// Mark this cell and its faces to start walking from
//
// Mark faces of cellI
const labelList& cFaces = mesh.cells()[cellI];
forAll(cFaces, i)
{
label faceI = cFaces[i];
if (outsideFacesMap.insert(faceI))
{
outsideFaces.append(faceI);
outsideFacesInfo.append(meshInfo);
}
}
}
}
// Floodfill starting from outsideFaces (of type meshInfo)
MeshWave<cellInfo> regionCalc
(
mesh,
outsideFaces.shrink(),
outsideFacesInfo.shrink(),
mesh.globalData().nTotalCells()+1 // max iterations
);
// Now regionCalc should hold info on cells that are reachable from
// changedFaces. Use these to subset cellType
const List<cellInfo>& allCellInfo = regionCalc.allCellInfo();
label nChanged = 0;
forAll(allCellInfo, cellI)
{
if (cellType[cellI] == MESH)
{
// Original cell was selected for meshing. Check if cell was
// reached from outsidePoints
if (allCellInfo[cellI].type() != MESH)
{
cellType[cellI] = NONMESH;
nChanged++;
}
}
}
return nChanged;
}
int main(int argc, char *argv[])
{
argList::noParallel();
# include "setRootCase.H"
# include "createTime.H"
# include "createPolyMesh.H"
// Mesh edge statistics calculator
edgeStats edgeCalc(mesh);
IOdictionary refineDict
(
IOobject
(
"selectCellsDict",
runTime.system(),
mesh,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
);
fileName surfName(refineDict.lookup("surface"));
pointField outsidePts(refineDict.lookup("outsidePoints"));
bool useSurface(readBool(refineDict.lookup("useSurface")));
bool selectCut(readBool(refineDict.lookup("selectCut")));
bool selectInside(readBool(refineDict.lookup("selectInside")));
bool selectOutside(readBool(refineDict.lookup("selectOutside")));
scalar nearDist(readScalar(refineDict.lookup("nearDistance")));
if (useSurface)
{
Info<< "Cells to be used for meshing (0=false, 1=true):" << nl
<< " cells cut by surface : " << selectCut << nl
<< " cells inside of surface : " << selectInside << nl
<< " cells outside of surface : " << selectOutside << nl
<< " cells with points further than : " << nearDist << nl
<< endl;
}
else
{
Info<< "Cells to be used for meshing (0=false, 1=true):" << nl
<< " cells reachable from outsidePoints:" << selectOutside << nl
<< endl;
}
// Print edge stats on original mesh.
(void)edgeCalc.minLen(Info);
// Search engine on mesh. Face decomposition since faces might be warped.
meshSearch queryMesh(mesh);
// Check all 'outside' points
forAll(outsidePts, outsideI)
{
const point& outsidePoint = outsidePts[outsideI];
label cellI = queryMesh.findCell(outsidePoint, -1, false);
if (returnReduce(cellI, maxOp<label>()) == -1)
{
FatalErrorIn(args.executable())
<< "outsidePoint " << outsidePoint
<< " is not inside any cell"
<< exit(FatalError);
}
}
// Cell status (compared to surface if provided): inside/outside/cut.
// Start off from everything selected and cut later.
cellClassification cellType
(
mesh,
labelList
(
mesh.nCells(),
cellClassification::MESH
)
);
// Surface
autoPtr<triSurface> surf(NULL);
// Search engine on surface.
autoPtr<triSurfaceSearch> querySurf(NULL);
if (useSurface)
{
surf.reset(new triSurface(surfName));
// Dump some stats
surf().writeStats(Info);
// Search engine on surface.
querySurf.reset(new triSurfaceSearch(surf));
// Set cellType[cellI] according to relation to surface
cutBySurface
(
mesh,
queryMesh,
querySurf,
outsidePts,
selectCut,
selectInside,
selectOutside,
nearDist,
cellType
);
}
// Now 'trim' all the corners from the mesh so meshing/surface extraction
// becomes easier.
label nHanging, nRegionEdges, nRegionPoints, nOutside;
do
{
Info<< "Removing cells which after subsetting would have all points"
<< " on outside ..." << nl << endl;
nHanging = cellType.fillHangingCells
(
MESH, // meshType
NONMESH, // fill type
mesh.nCells()
);
Info<< "Removing edges connecting cells unconnected by faces ..."
<< nl << endl;
nRegionEdges = cellType.fillRegionEdges
(
MESH, // meshType
NONMESH, // fill type
mesh.nCells()
);
Info<< "Removing points connecting cells unconnected by faces ..."
<< nl << endl;
nRegionPoints = cellType.fillRegionPoints
(
MESH, // meshType
NONMESH, // fill type
mesh.nCells()
);
nOutside = 0;
if (selectOutside)
{
// Since we're selecting the cells reachable from outsidePoints
// and the set might have changed, redo the outsideCells
// calculation
nOutside = selectOutsideCells
(
mesh,
queryMesh,
outsidePts,
cellType
);
}
} while
(
nHanging != 0
|| nRegionEdges != 0
|| nRegionPoints != 0
|| nOutside != 0
);
cellSet selectedCells(mesh, "selected", mesh.nCells()/10);
getType(cellType, MESH, selectedCells);
writeSet(selectedCells, "cells selected for meshing");
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,40 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object selectCellsDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Whether to use surface. If false no surface will be read and only
// outsidePoints/selectOutside will be used to determine cells to keep.
useSurface false;
// Surface to keep to
surface "plexi.obj";
// What is outside
outsidePoints ((-1 -1 -1));
//
// Selection of final set
//
// Select based on side of surface. Usually select inside cells and project
// outwards or select outside cells and project inwards.
selectCut false;
selectInside false;
selectOutside true;
// Leave out cell closer than nearDistance to the surface. Usually
// 0.5*of the cell size. Set to <0 to disable.
nearDistance -1;
// ************************************************************************* //

View File

@ -0,0 +1,4 @@
splitCells.C
EXE = $(FOAM_APPBIN)/splitCells

View File

@ -0,0 +1,7 @@
EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude
EXE_LIBS = \
-ldynamicMesh \
-lmeshTools

View File

@ -0,0 +1,721 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ 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 3 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, see <http://www.gnu.org/licenses/>.
Application
splitCells
Description
Utility to split cells with flat faces.
Uses a geometric cut with a plane dividing the edge angle into two so
might produce funny cells. For hexes it will use by default a cut from
edge onto opposite edge (i.e. purely topological).
Options:
- split cells from cellSet only
- use geometric cut for hexes as well
The angle is the angle between two faces sharing an edge as seen from
inside each cell. So a cube will have all angles 90. If you want
to split cells with cell centre outside use e.g. angle 200
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "polyTopoChange.H"
#include "polyTopoChanger.H"
#include "mapPolyMesh.H"
#include "polyMesh.H"
#include "cellCuts.H"
#include "cellSet.H"
#include "cellModeller.H"
#include "meshCutter.H"
#include "unitConversion.H"
#include "geomCellLooper.H"
#include "plane.H"
#include "edgeVertex.H"
#include "meshTools.H"
#include "ListOps.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
labelList pack(const boolList& lst)
{
labelList packedLst(lst.size());
label packedI = 0;
forAll(lst, i)
{
if (lst[i])
{
packedLst[packedI++] = i;
}
}
packedLst.setSize(packedI);
return packedLst;
}
scalarField pack(const boolList& lst, const scalarField& elems)
{
scalarField packedElems(lst.size());
label packedI = 0;
forAll(lst, i)
{
if (lst[i])
{
packedElems[packedI++] = elems[i];
}
}
packedElems.setSize(packedI);
return packedElems;
}
// Given sin and cos of max angle between normals calculate whether f0 and f1
// on cellI make larger angle. Uses sinAngle only for quadrant detection.
bool largerAngle
(
const primitiveMesh& mesh,
const scalar cosAngle,
const scalar sinAngle,
const label cellI,
const label f0, // face label
const label f1,
const vector& n0, // normal at f0
const vector& n1
)
{
const labelList& own = mesh.faceOwner();
bool sameFaceOrder = !((own[f0] == cellI) ^ (own[f1] == cellI));
// Get cos between faceArea vectors. Correct so flat angle (180 degrees)
// gives -1.
scalar normalCosAngle = n0 & n1;
if (sameFaceOrder)
{
normalCosAngle = -normalCosAngle;
}
// Get cos between faceCentre and normal vector to determine in
// which quadrant angle is. (Is correct for unwarped faces only!)
// Correct for non-outwards pointing normal.
vector c1c0(mesh.faceCentres()[f1] - mesh.faceCentres()[f0]);
c1c0 /= mag(c1c0) + VSMALL;
scalar fcCosAngle = n0 & c1c0;
if (own[f0] != cellI)
{
fcCosAngle = -fcCosAngle;
}
if (sinAngle < 0.0)
{
// Looking for concave angles (quadrant 3 or 4)
if (fcCosAngle <= 0)
{
// Angle is convex so smaller.
return false;
}
else
{
if (normalCosAngle < cosAngle)
{
return false;
}
else
{
return true;
}
}
}
else
{
// Looking for convex angles (quadrant 1 or 2)
if (fcCosAngle > 0)
{
// Concave angle
return true;
}
else
{
// Convex. Check cos of normal vectors.
if (normalCosAngle > cosAngle)
{
return false;
}
else
{
return true;
}
}
}
}
// Split hex (and hex only) along edgeI creating two prisms
bool splitHex
(
const polyMesh& mesh,
const label cellI,
const label edgeI,
DynamicList<label>& cutCells,
DynamicList<labelList>& cellLoops,
DynamicList<scalarField>& cellEdgeWeights
)
{
// cut handling functions
edgeVertex ev(mesh);
const edgeList& edges = mesh.edges();
const faceList& faces = mesh.faces();
const edge& e = edges[edgeI];
// Get faces on the side, i.e. faces not using edge but still using one of
// the edge endpoints.
label leftI = -1;
label rightI = -1;
label leftFp = -1;
label rightFp = -1;
const cell& cFaces = mesh.cells()[cellI];
forAll(cFaces, i)
{
label faceI = cFaces[i];
const face& f = faces[faceI];
label fp0 = findIndex(f, e[0]);
label fp1 = findIndex(f, e[1]);
if (fp0 == -1)
{
if (fp1 != -1)
{
// Face uses e[1] but not e[0]
rightI = faceI;
rightFp = fp1;
if (leftI != -1)
{
// Have both faces so exit
break;
}
}
}
else
{
if (fp1 != -1)
{
// Face uses both e[1] and e[0]
}
else
{
leftI = faceI;
leftFp = fp0;
if (rightI != -1)
{
break;
}
}
}
}
if (leftI == -1 || rightI == -1)
{
FatalErrorIn("splitHex") << "Problem : leftI:" << leftI
<< " rightI:" << rightI << abort(FatalError);
}
// Walk two vertices further on faces.
const face& leftF = faces[leftI];
label leftV = leftF[(leftFp + 2) % leftF.size()];
const face& rightF = faces[rightI];
label rightV = rightF[(rightFp + 2) % rightF.size()];
labelList loop(4);
loop[0] = ev.vertToEVert(e[0]);
loop[1] = ev.vertToEVert(leftV);
loop[2] = ev.vertToEVert(rightV);
loop[3] = ev.vertToEVert(e[1]);
scalarField loopWeights(4);
loopWeights[0] = -GREAT;
loopWeights[1] = -GREAT;
loopWeights[2] = -GREAT;
loopWeights[3] = -GREAT;
cutCells.append(cellI);
cellLoops.append(loop);
cellEdgeWeights.append(loopWeights);
return true;
}
// Split cellI along edgeI with a plane along halfNorm direction.
bool splitCell
(
const polyMesh& mesh,
const geomCellLooper& cellCutter,
const label cellI,
const label edgeI,
const vector& halfNorm,
const boolList& vertIsCut,
const boolList& edgeIsCut,
const scalarField& edgeWeight,
DynamicList<label>& cutCells,
DynamicList<labelList>& cellLoops,
DynamicList<scalarField>& cellEdgeWeights
)
{
const edge& e = mesh.edges()[edgeI];
vector eVec = e.vec(mesh.points());
eVec /= mag(eVec);
vector planeN = eVec ^ halfNorm;
// Slightly tilt plane to make it not cut edges exactly
// halfway on fully regular meshes (since we want cuts
// to be snapped to vertices)
planeN += 0.01*halfNorm;
planeN /= mag(planeN);
// Define plane through edge
plane cutPlane(mesh.points()[e.start()], planeN);
labelList loop;
scalarField loopWeights;
if
(
cellCutter.cut
(
cutPlane,
cellI,
vertIsCut,
edgeIsCut,
edgeWeight,
loop,
loopWeights
)
)
{
// Did manage to cut cell. Copy into overall list.
cutCells.append(cellI);
cellLoops.append(loop);
cellEdgeWeights.append(loopWeights);
return true;
}
else
{
return false;
}
}
// Collects cuts for all cells in cellSet
void collectCuts
(
const polyMesh& mesh,
const geomCellLooper& cellCutter,
const bool geometry,
const scalar minCos,
const scalar minSin,
const cellSet& cellsToCut,
DynamicList<label>& cutCells,
DynamicList<labelList>& cellLoops,
DynamicList<scalarField>& cellEdgeWeights
)
{
// Get data from mesh
const cellShapeList& cellShapes = mesh.cellShapes();
const labelList& own = mesh.faceOwner();
const labelListList& cellEdges = mesh.cellEdges();
const vectorField& faceAreas = mesh.faceAreas();
// Hex shape
const cellModel& hex = *(cellModeller::lookup("hex"));
// cut handling functions
edgeVertex ev(mesh);
// Cut information per mesh entity
boolList vertIsCut(mesh.nPoints(), false);
boolList edgeIsCut(mesh.nEdges(), false);
scalarField edgeWeight(mesh.nEdges(), -GREAT);
forAllConstIter(cellSet, cellsToCut, iter)
{
const label cellI = iter.key();
const labelList& cEdges = cellEdges[cellI];
forAll(cEdges, i)
{
label edgeI = cEdges[i];
label f0, f1;
meshTools::getEdgeFaces(mesh, cellI, edgeI, f0, f1);
vector n0 = faceAreas[f0];
n0 /= mag(n0);
vector n1 = faceAreas[f1];
n1 /= mag(n1);
if
(
largerAngle
(
mesh,
minCos,
minSin,
cellI,
f0,
f1,
n0,
n1
)
)
{
bool splitOk = false;
if (!geometry && cellShapes[cellI].model() == hex)
{
splitOk =
splitHex
(
mesh,
cellI,
edgeI,
cutCells,
cellLoops,
cellEdgeWeights
);
}
else
{
vector halfNorm;
if ((own[f0] == cellI) ^ (own[f1] == cellI))
{
// Opposite owner orientation
halfNorm = 0.5*(n0 - n1);
}
else
{
// Faces have same owner or same neighbour so
// normals point in same direction
halfNorm = 0.5*(n0 + n1);
}
splitOk =
splitCell
(
mesh,
cellCutter,
cellI,
edgeI,
halfNorm,
vertIsCut,
edgeIsCut,
edgeWeight,
cutCells,
cellLoops,
cellEdgeWeights
);
}
if (splitOk)
{
// Update cell/edge/vertex wise info.
label index = cellLoops.size() - 1;
const labelList& loop = cellLoops[index];
const scalarField& loopWeights = cellEdgeWeights[index];
forAll(loop, i)
{
label cut = loop[i];
if (ev.isEdge(cut))
{
edgeIsCut[ev.getEdge(cut)] = true;
edgeWeight[ev.getEdge(cut)] = loopWeights[i];
}
else
{
vertIsCut[ev.getVertex(cut)] = true;
}
}
// Stop checking edges for this cell.
break;
}
}
}
}
cutCells.shrink();
cellLoops.shrink();
cellEdgeWeights.shrink();
}
int main(int argc, char *argv[])
{
argList::addNote
(
"split cells with flat faces"
);
#include "addOverwriteOption.H"
argList::noParallel();
argList::validArgs.append("edgeAngle [0..360]");
argList::addOption
(
"set",
"name",
"split cells from specified cellSet only"
);
argList::addBoolOption
(
"geometry",
"use geometric cut for hexes as well"
);
argList::addOption
(
"tol",
"scalar", "edge snap tolerance (default 0.2)"
);
#include "setRootCase.H"
#include "createTime.H"
runTime.functionObjects().off();
#include "createPolyMesh.H"
const word oldInstance = mesh.pointsInstance();
const scalar featureAngle = args.argRead<scalar>(1);
const scalar minCos = Foam::cos(degToRad(featureAngle));
const scalar minSin = Foam::sin(degToRad(featureAngle));
const bool readSet = args.optionFound("set");
const bool geometry = args.optionFound("geometry");
const bool overwrite = args.optionFound("overwrite");
const scalar edgeTol = args.optionLookupOrDefault("tol", 0.2);
Info<< "Trying to split cells with internal angles > feature angle\n" << nl
<< "featureAngle : " << featureAngle << nl
<< "edge snapping tol : " << edgeTol << nl;
if (readSet)
{
Info<< "candidate cells : cellSet " << args["set"] << nl;
}
else
{
Info<< "candidate cells : all cells" << nl;
}
if (geometry)
{
Info<< "hex cuts : geometric; using edge tolerance" << nl;
}
else
{
Info<< "hex cuts : topological; cut to opposite edge" << nl;
}
Info<< endl;
// Cell circumference cutter
geomCellLooper cellCutter(mesh);
// Snap all edge cuts close to endpoints to vertices.
geomCellLooper::setSnapTol(edgeTol);
// Candidate cells to cut
cellSet cellsToCut(mesh, "cellsToCut", mesh.nCells()/100);
if (readSet)
{
// Read cells to cut from cellSet
cellSet cells(mesh, args["set"]);
cellsToCut = cells;
}
while (true)
{
if (!readSet)
{
// Try all cells for cutting
for (label cellI = 0; cellI < mesh.nCells(); cellI++)
{
cellsToCut.insert(cellI);
}
}
// Cut information per cut cell
DynamicList<label> cutCells(mesh.nCells()/10 + 10);
DynamicList<labelList> cellLoops(mesh.nCells()/10 + 10);
DynamicList<scalarField> cellEdgeWeights(mesh.nCells()/10 + 10);
collectCuts
(
mesh,
cellCutter,
geometry,
minCos,
minSin,
cellsToCut,
cutCells,
cellLoops,
cellEdgeWeights
);
cellSet cutSet(mesh, "cutSet", cutCells.size());
forAll(cutCells, i)
{
cutSet.insert(cutCells[i]);
}
// Gets cuts across cells from cuts through edges.
Info<< "Writing " << cutSet.size() << " cells to cut to cellSet "
<< cutSet.instance()/cutSet.local()/cutSet.name()
<< endl << endl;
cutSet.write();
// Analyze cuts for clashes.
cellCuts cuts
(
mesh,
cutCells, // cells candidate for cutting
cellLoops,
cellEdgeWeights
);
Info<< "Actually cut cells:" << cuts.nLoops() << nl << endl;
if (cuts.nLoops() == 0)
{
break;
}
// Remove cut cells from cellsToCut (Note:only relevant if -readSet)
forAll(cuts.cellLoops(), cellI)
{
if (cuts.cellLoops()[cellI].size())
{
//Info<< "Removing cut cell " << cellI << " from wishlist"
// << endl;
cellsToCut.erase(cellI);
}
}
// At least some cells are cut.
polyTopoChange meshMod(mesh);
// Cutting engine
meshCutter cutter(mesh);
// Insert mesh refinement into polyTopoChange.
cutter.setRefinement(cuts, meshMod);
// Do all changes
Info<< "Morphing ..." << endl;
if (!overwrite)
{
runTime++;
}
autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
if (morphMap().hasMotionPoints())
{
mesh.movePoints(morphMap().preMotionPoints());
}
// Update stored labels on meshCutter
cutter.updateMesh(morphMap());
// Update cellSet
cellsToCut.updateMesh(morphMap());
Info<< "Remaining:" << cellsToCut.size() << endl;
// Write resulting mesh
if (overwrite)
{
mesh.setInstance(oldInstance);
}
Info<< "Writing refined morphMesh to time " << runTime.timeName()
<< endl;
mesh.write();
}
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //