mirror of
https://github.com/OpenFOAM/OpenFOAM-6.git
synced 2025-12-08 06:57:46 +00:00
Add the OpenFOAM source tree
This commit is contained in:
3
applications/utilities/mesh/advanced/PDRMesh/Make/files
Normal file
3
applications/utilities/mesh/advanced/PDRMesh/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
PDRMesh.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/PDRMesh
|
||||
10
applications/utilities/mesh/advanced/PDRMesh/Make/options
Normal file
10
applications/utilities/mesh/advanced/PDRMesh/Make/options
Normal 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
|
||||
1182
applications/utilities/mesh/advanced/PDRMesh/PDRMesh.C
Normal file
1182
applications/utilities/mesh/advanced/PDRMesh/PDRMesh.C
Normal file
File diff suppressed because it is too large
Load Diff
37
applications/utilities/mesh/advanced/PDRMesh/PDRMeshDict
Normal file
37
applications/utilities/mesh/advanced/PDRMesh/PDRMeshDict
Normal 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;
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,4 @@
|
||||
autoRefineMesh.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/autoRefineMesh
|
||||
|
||||
@ -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
|
||||
1006
applications/utilities/mesh/advanced/autoRefineMesh/autoRefineMesh.C
Normal file
1006
applications/utilities/mesh/advanced/autoRefineMesh/autoRefineMesh.C
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
collapseEdges.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/collapseEdges
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -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;
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,4 @@
|
||||
combinePatchFaces.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/combinePatchFaces
|
||||
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,4 @@
|
||||
cellSplitter.C
|
||||
modifyMesh.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/modifyMesh
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/dynamicMesh/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ldynamicMesh
|
||||
491
applications/utilities/mesh/advanced/modifyMesh/cellSplitter.C
Normal file
491
applications/utilities/mesh/advanced/modifyMesh/cellSplitter.C
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
149
applications/utilities/mesh/advanced/modifyMesh/cellSplitter.H
Normal file
149
applications/utilities/mesh/advanced/modifyMesh/cellSplitter.H
Normal 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
|
||||
|
||||
// ************************************************************************* //
|
||||
692
applications/utilities/mesh/advanced/modifyMesh/modifyMesh.C
Normal file
692
applications/utilities/mesh/advanced/modifyMesh/modifyMesh.C
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -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
|
||||
// )
|
||||
//);
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,3 @@
|
||||
refineHexMesh.C
|
||||
EXE = $(FOAM_APPBIN)/refineHexMesh
|
||||
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,4 @@
|
||||
refineWallLayer.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/refineWallLayer
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/dynamicMesh/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ldynamicMesh \
|
||||
-lmeshTools
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,4 @@
|
||||
refinementLevel.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/refinementLevel
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lfiniteVolume \
|
||||
-lmeshTools
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,4 @@
|
||||
removeFaces.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/removeFaces
|
||||
|
||||
@ -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
|
||||
186
applications/utilities/mesh/advanced/removeFaces/removeFaces.C
Normal file
186
applications/utilities/mesh/advanced/removeFaces/removeFaces.C
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,5 @@
|
||||
edgeStats.C
|
||||
selectCells.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/selectCells
|
||||
|
||||
@ -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
|
||||
221
applications/utilities/mesh/advanced/selectCells/edgeStats.C
Normal file
221
applications/utilities/mesh/advanced/selectCells/edgeStats.C
Normal 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 * * * * * * * * * * * * * //
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
110
applications/utilities/mesh/advanced/selectCells/edgeStats.H
Normal file
110
applications/utilities/mesh/advanced/selectCells/edgeStats.H
Normal 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
|
||||
|
||||
// ************************************************************************* //
|
||||
522
applications/utilities/mesh/advanced/selectCells/selectCells.C
Normal file
522
applications/utilities/mesh/advanced/selectCells/selectCells.C
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -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;
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,4 @@
|
||||
splitCells.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/splitCells
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/dynamicMesh/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ldynamicMesh \
|
||||
-lmeshTools
|
||||
721
applications/utilities/mesh/advanced/splitCells/splitCells.C
Normal file
721
applications/utilities/mesh/advanced/splitCells/splitCells.C
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user