Merge branch 'feature-runtime-selection-geometry' into 'develop'

Feature runtime selection geometry

See merge request Development/openfoam!411
This commit is contained in:
Andrew Heather
2020-12-11 10:31:34 +00:00
70 changed files with 10039 additions and 895 deletions

View File

@ -704,7 +704,7 @@ int main(int argc, char *argv[])
regionName, regionName,
runTimeExtruded.constant(), runTimeExtruded.constant(),
runTimeExtruded, runTimeExtruded,
IOobject::NO_READ, IOobject::READ_IF_PRESENT, // Read fv* if present
IOobject::AUTO_WRITE, IOobject::AUTO_WRITE,
false false
), ),

View File

@ -154,6 +154,7 @@ int main(int argc, char *argv[])
"cellShapes", "cellShapes",
"cellVolume", "cellVolume",
"cellVolumeRatio", "cellVolumeRatio",
"cellAspectRatio",
"minTetVolume", "minTetVolume",
"minPyrVolume", "minPyrVolume",
"cellRegion", "cellRegion",

View File

@ -7,6 +7,7 @@
#include "tetPointRef.H" #include "tetPointRef.H"
#include "regionSplit.H" #include "regionSplit.H"
#include "wallDist.H" #include "wallDist.H"
#include "cellAspectRatio.H"
using namespace Foam; using namespace Foam;
@ -318,6 +319,32 @@ void Foam::writeFields
aspectRatio.write(); aspectRatio.write();
} }
if (selectedFields.found("cellAspectRatio"))
{
volScalarField aspectRatio
(
IOobject
(
"cellAspectRatio",
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE,
false
),
mesh,
dimensionedScalar(dimless, Zero),
zeroGradientFvPatchScalarField::typeName
);
aspectRatio.ref().field() = cellAspectRatio(mesh);
aspectRatio.correctBoundaryConditions();
Info<< " Writing approximate aspect ratio to "
<< aspectRatio.name() << endl;
aspectRatio.write();
}
// cell type // cell type
// ~~~~~~~~~ // ~~~~~~~~~

View File

@ -680,7 +680,7 @@ autoPtr<mapPolyMesh> createRegionMesh
regionName, regionName,
mesh.time().timeName(), mesh.time().timeName(),
mesh.time(), mesh.time(),
IOobject::NO_READ, IOobject::READ_IF_PRESENT, // read fv* if present
IOobject::AUTO_WRITE IOobject::AUTO_WRITE
), ),
mesh mesh

View File

@ -36,6 +36,7 @@ License
#include "pointSet.H" #include "pointSet.H"
#include "faceSet.H" #include "faceSet.H"
#include "cellSet.H" #include "cellSet.H"
#include "basicFvGeometryScheme.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
@ -254,6 +255,19 @@ Foam::autoPtr<Foam::fvMesh> Foam::loadOrCreateMesh
auto meshPtr = autoPtr<fvMesh>::New(io); auto meshPtr = autoPtr<fvMesh>::New(io);
fvMesh& mesh = *meshPtr; fvMesh& mesh = *meshPtr;
// Make sure to use a non-parallel geometry calculation method
{
tmp<fvGeometryScheme> basicGeometry
(
fvGeometryScheme::New
(
mesh,
dictionary(),
basicFvGeometryScheme::typeName
)
);
mesh.geometry(basicGeometry);
}
// Sync patches // Sync patches

View File

@ -92,6 +92,7 @@ Usage
#include "zeroGradientFvPatchFields.H" #include "zeroGradientFvPatchFields.H"
#include "topoSet.H" #include "topoSet.H"
#include "regionProperties.H" #include "regionProperties.H"
#include "basicFvGeometryScheme.H"
#include "parFvFieldReconstructor.H" #include "parFvFieldReconstructor.H"
#include "parLagrangianRedistributor.H" #include "parLagrangianRedistributor.H"
@ -152,6 +153,30 @@ scalar getMergeDistance
} }
void setBasicGeometry(fvMesh& mesh)
{
// Set the fvGeometryScheme to basic since it does not require
// any parallel communication to construct the geometry. During
// redistributePar one might temporarily end up with processors
// with zero procBoundaries. Normally procBoundaries trigger geometry
// calculation (e.g. send over cellCentres) so on the processors without
// procBoundaries this will not happen. The call to the geometry calculation
// is not synchronised and this might lead to a hang for geometry schemes
// that do require synchronisation
tmp<fvGeometryScheme> basicGeometry
(
fvGeometryScheme::New
(
mesh,
dictionary(),
basicFvGeometryScheme::typeName
)
);
mesh.geometry(basicGeometry);
}
void printMeshData(const polyMesh& mesh) void printMeshData(const polyMesh& mesh)
{ {
// Collect all data on master // Collect all data on master
@ -2675,6 +2700,10 @@ int main(int argc, char *argv[])
); );
fvMesh& mesh = meshPtr(); fvMesh& mesh = meshPtr();
// Use basic geometry calculation to avoid synchronisation
// problems. See comment in routine
setBasicGeometry(mesh);
// Global matching tolerance // Global matching tolerance
const scalar tolDim = getMergeDistance const scalar tolDim = getMergeDistance
( (
@ -2736,6 +2765,8 @@ int main(int argc, char *argv[])
), ),
true // read on master only true // read on master only
); );
setBasicGeometry(baseMeshPtr());
Info<< "Reading local, decomposed mesh" << endl; Info<< "Reading local, decomposed mesh" << endl;
autoPtr<fvMesh> meshPtr = loadOrCreateMesh autoPtr<fvMesh> meshPtr = loadOrCreateMesh

View File

@ -438,6 +438,20 @@ Foam::IOobject::IOobject
{} {}
Foam::IOobject::IOobject
(
const IOobject& io,
readOption ro,
writeOption wo
)
:
IOobject(io)
{
rOpt_ = ro;
wOpt_ = wo;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::objectRegistry& Foam::IOobject::db() const const Foam::objectRegistry& Foam::IOobject::db() const

View File

@ -340,6 +340,14 @@ public:
const word& name const word& name
); );
//- Copy construct, resetting io options
IOobject
(
const IOobject& io,
readOption,
writeOption
);
//- Clone //- Clone
autoPtr<IOobject> clone() const autoPtr<IOobject> clone() const
{ {

View File

@ -63,9 +63,11 @@ else
runTime.timeName(), runTime.timeName(),
runTime, runTime,
Foam::IOobject::MUST_READ Foam::IOobject::MUST_READ
) ),
false
) )
); );
meshPtr().init(true); // initialise all (lower levels and current)
} }
Foam::fvMesh& mesh = meshPtr(); Foam::fvMesh& mesh = meshPtr();

View File

@ -21,5 +21,7 @@ Foam::fvMesh mesh
runTime.timeName(), runTime.timeName(),
runTime, runTime,
Foam::IOobject::MUST_READ Foam::IOobject::MUST_READ
) ),
false
); );
mesh.init(true); // initialise all (lower levels and current)

View File

@ -155,6 +155,50 @@ Foam::solution::solution
} }
Foam::solution::solution
(
const objectRegistry& obr,
const fileName& dictName,
const dictionary& dict
)
:
IOdictionary
(
IOobject
(
dictName,
obr.time().system(),
obr,
(
obr.readOpt() == IOobject::MUST_READ
|| obr.readOpt() == IOobject::READ_IF_PRESENT
? IOobject::MUST_READ_IF_MODIFIED
: obr.readOpt()
),
IOobject::NO_WRITE
),
dict
),
cache_(dictionary::null),
caching_(false),
fieldRelaxDict_(dictionary::null),
eqnRelaxDict_(dictionary::null),
fieldRelaxDefault_(0),
eqnRelaxDefault_(0),
solvers_(dictionary::null)
{
if
(
readOpt() == IOobject::MUST_READ
|| readOpt() == IOobject::MUST_READ_IF_MODIFIED
|| (readOpt() == IOobject::READ_IF_PRESENT && headerOk())
)
{
read(solutionDict());
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::solution::upgradeSolverDict Foam::label Foam::solution::upgradeSolverDict

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -101,13 +102,22 @@ public:
// Constructors // Constructors
//- Construct for given objectRegistry and dictionary //- Construct for given objectRegistry and dictionary name
solution solution
( (
const objectRegistry& obr, const objectRegistry& obr,
const fileName& dictName const fileName& dictName
); );
//- Construct for given objectRegistry, dictionary name and (optional)
// content (gets used in case of NO_READ or dictionary cannot be read)
solution
(
const objectRegistry& obr,
const fileName& dictName,
const dictionary& dict
);
// Member Functions // Member Functions

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -54,6 +55,24 @@ Foam::data::data(const objectRegistry& obr)
} }
Foam::data::data(const objectRegistry& obr, const dictionary& dict)
:
IOdictionary
(
IOobject
(
"data",
obr.time().system(),
obr,
IOobject::NO_READ,
IOobject::NO_WRITE
),
dict
),
prevTimeIndex_(0)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::dictionary& Foam::data::solverPerformanceDict() const const Foam::dictionary& Foam::data::solverPerformanceDict() const

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -82,6 +83,9 @@ public:
//- Construct for objectRegistry //- Construct for objectRegistry
data(const objectRegistry& obr); data(const objectRegistry& obr);
//- Construct for objectRegistry and initial contents
data(const objectRegistry& obr, const dictionary& dict);
// Member Functions // Member Functions

View File

@ -70,20 +70,29 @@ void Foam::polyMesh::calcDirections() const
forAll(boundaryMesh(), patchi) forAll(boundaryMesh(), patchi)
{ {
if (boundaryMesh()[patchi].size()) const polyPatch& pp = boundaryMesh()[patchi];
if (isA<emptyPolyPatch>(pp))
{ {
if (isA<emptyPolyPatch>(boundaryMesh()[patchi])) // Force calculation of geometric properties, independent of
// size. This avoids parallel synchronisation problems.
const vectorField::subField fa(pp.faceAreas());
if (pp.size())
{ {
nEmptyPatches++; nEmptyPatches++;
emptyDirVec += sum(cmptMag(boundaryMesh()[patchi].faceAreas())); emptyDirVec += sum(cmptMag(fa));
} }
else if (isA<wedgePolyPatch>(boundaryMesh()[patchi])) }
{ else if (isA<wedgePolyPatch>(pp))
const wedgePolyPatch& wpp = refCast<const wedgePolyPatch> {
( const wedgePolyPatch& wpp = refCast<const wedgePolyPatch>(pp);
boundaryMesh()[patchi]
);
// Force calculation of geometric properties, independent of
// size. This avoids parallel synchronisation problems.
(void)wpp.faceNormals();
if (pp.size())
{
nWedgePatches++; nWedgePatches++;
wedgeDirVec += cmptMag(wpp.centreNormal()); wedgeDirVec += cmptMag(wpp.centreNormal());
} }
@ -161,7 +170,7 @@ Foam::autoPtr<Foam::labelIOList> Foam::polyMesh::readTetBasePtIs() const
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::polyMesh::polyMesh(const IOobject& io) Foam::polyMesh::polyMesh(const IOobject& io, const bool doInit)
: :
objectRegistry(io), objectRegistry(io),
primitiveMesh(), primitiveMesh(),
@ -328,12 +337,6 @@ Foam::polyMesh::polyMesh(const IOobject& io)
neighbour_.write(); neighbour_.write();
} }
// Calculate topology for the patches (processor-processor comms etc.)
boundary_.updateMesh();
// Calculate the geometry for the patches (transformation tensors etc.)
boundary_.calcGeometry();
// Warn if global empty mesh // Warn if global empty mesh
if (returnReduce(boundary_.empty(), orOp<bool>())) if (returnReduce(boundary_.empty(), orOp<bool>()))
{ {
@ -352,8 +355,30 @@ Foam::polyMesh::polyMesh(const IOobject& io)
} }
} }
if (doInit)
{
polyMesh::init(false); // do not init lower levels
}
}
bool Foam::polyMesh::init(const bool doInit)
{
if (doInit)
{
primitiveMesh::init(doInit);
}
// Calculate topology for the patches (processor-processor comms etc.)
boundary_.updateMesh();
// Calculate the geometry for the patches (transformation tensors etc.)
boundary_.calcGeometry();
// Initialise demand-driven data // Initialise demand-driven data
calcDirections(); calcDirections();
return false;
} }
@ -377,7 +402,7 @@ Foam::polyMesh::polyMesh
instance(), instance(),
meshSubDir, meshSubDir,
*this, *this,
io.readOpt(), IOobject::NO_READ, //io.readOpt(),
io.writeOpt() io.writeOpt()
), ),
std::move(points) std::move(points)
@ -390,7 +415,7 @@ Foam::polyMesh::polyMesh
instance(), instance(),
meshSubDir, meshSubDir,
*this, *this,
io.readOpt(), IOobject::NO_READ, //io.readOpt(),
io.writeOpt() io.writeOpt()
), ),
std::move(faces) std::move(faces)
@ -403,7 +428,7 @@ Foam::polyMesh::polyMesh
instance(), instance(),
meshSubDir, meshSubDir,
*this, *this,
io.readOpt(), IOobject::NO_READ, //io.readOpt(),
io.writeOpt() io.writeOpt()
), ),
std::move(owner) std::move(owner)
@ -416,7 +441,7 @@ Foam::polyMesh::polyMesh
instance(), instance(),
meshSubDir, meshSubDir,
*this, *this,
io.readOpt(), IOobject::NO_READ, //io.readOpt(),
io.writeOpt() io.writeOpt()
), ),
std::move(neighbour) std::move(neighbour)
@ -430,7 +455,7 @@ Foam::polyMesh::polyMesh
instance(), instance(),
meshSubDir, meshSubDir,
*this, *this,
io.readOpt(), IOobject::NO_READ, //io.readOpt(),
io.writeOpt() io.writeOpt()
), ),
*this, *this,
@ -440,7 +465,7 @@ Foam::polyMesh::polyMesh
comm_(UPstream::worldComm), comm_(UPstream::worldComm),
geometricD_(Zero), geometricD_(Zero),
solutionD_(Zero), solutionD_(Zero),
tetBasePtIsPtr_(readTetBasePtIs()), tetBasePtIsPtr_(nullptr),
cellTreePtr_(nullptr), cellTreePtr_(nullptr),
pointZones_ pointZones_
( (
@ -450,7 +475,7 @@ Foam::polyMesh::polyMesh
instance(), instance(),
meshSubDir, meshSubDir,
*this, *this,
io.readOpt(), IOobject::NO_READ, //io.readOpt(),
IOobject::NO_WRITE IOobject::NO_WRITE
), ),
*this, *this,
@ -464,7 +489,7 @@ Foam::polyMesh::polyMesh
instance(), instance(),
meshSubDir, meshSubDir,
*this, *this,
io.readOpt(), IOobject::NO_READ, //io.readOpt(),
IOobject::NO_WRITE IOobject::NO_WRITE
), ),
*this, *this,
@ -478,7 +503,7 @@ Foam::polyMesh::polyMesh
instance(), instance(),
meshSubDir, meshSubDir,
*this, *this,
io.readOpt(), IOobject::NO_READ, //io.readOpt(),
IOobject::NO_WRITE IOobject::NO_WRITE
), ),
*this, *this,
@ -591,7 +616,7 @@ Foam::polyMesh::polyMesh
comm_(UPstream::worldComm), comm_(UPstream::worldComm),
geometricD_(Zero), geometricD_(Zero),
solutionD_(Zero), solutionD_(Zero),
tetBasePtIsPtr_(readTetBasePtIs()), tetBasePtIsPtr_(nullptr),
cellTreePtr_(nullptr), cellTreePtr_(nullptr),
pointZones_ pointZones_
( (

View File

@ -319,11 +319,11 @@ public:
// Constructors // Constructors
//- Read construct from IOobject //- Read construct from IOobject
explicit polyMesh(const IOobject& io); polyMesh(const IOobject& io, const bool doInit = true);
//- Construct from IOobject or as zero-sized mesh //- Construct from IOobject or as zero-sized mesh
// Boundary is added using addPatches() member function // Boundary is added using addPatches() member function
polyMesh(const IOobject& io, const zero, bool syncPar=true); polyMesh(const IOobject& io, const zero, const bool syncPar=true);
//- Construct from IOobject or from components. //- Construct from IOobject or from components.
// Boundary is added using addPatches() member function // Boundary is added using addPatches() member function
@ -593,6 +593,9 @@ public:
const List<cellZone*>& cz const List<cellZone*>& cz
); );
//- Initialise all non-demand-driven data
virtual bool init(const bool doInit);
//- Update the mesh based on the mesh files saved in //- Update the mesh based on the mesh files saved in
// time directories // time directories
virtual readUpdateState readUpdate(); virtual readUpdateState readUpdate();

View File

@ -753,13 +753,26 @@ bool Foam::polyMesh::checkMeshMotion
vectorField fCtrs(nFaces()); vectorField fCtrs(nFaces());
vectorField fAreas(nFaces()); vectorField fAreas(nFaces());
makeFaceCentresAndAreas(newPoints, fCtrs, fAreas); primitiveMeshTools::makeFaceCentresAndAreas
(
*this,
newPoints,
fCtrs,
fAreas
);
// Check cell volumes and calculate new cell centres // Check cell volumes and calculate new cell centres
vectorField cellCtrs(nCells()); vectorField cellCtrs(nCells());
scalarField cellVols(nCells()); scalarField cellVols(nCells());
makeCellCentresAndVols(fCtrs, fAreas, cellCtrs, cellVols); primitiveMeshTools::makeCellCentresAndVols
(
*this,
fCtrs,
fAreas,
cellCtrs,
cellVols
);
// Check cell volumes // Check cell volumes
bool error = checkCellVolumes bool error = checkCellVolumes

View File

@ -281,6 +281,44 @@ void Foam::primitiveMesh::reset
} }
void Foam::primitiveMesh::resetGeometry
(
pointField&& faceCentres,
pointField&& faceAreas,
pointField&& cellCentres,
scalarField&& cellVolumes
)
{
if
(
faceCentres.size() != nFaces_
|| faceAreas.size() != nFaces_
|| cellCentres.size() != nCells_
|| cellVolumes.size() != nCells_
)
{
FatalErrorInFunction
<< "Wrong sizes of passed in face/cell data"
<< abort(FatalError);
}
// Remove old geometry
clearGeom();
faceCentresPtr_ = new pointField(std::move(faceCentres));
faceAreasPtr_ = new pointField(std::move(faceAreas));
cellCentresPtr_ = new pointField(std::move(cellCentres));
cellVolumesPtr_ = new scalarField(std::move(cellVolumes));
if (debug)
{
Pout<< "primitiveMesh::resetGeometry : geometry reset for"
<< " nFaces:" << faceCentresPtr_->size()
<< " nCells:" << cellCentresPtr_->size() << endl;
}
}
Foam::tmp<Foam::scalarField> Foam::primitiveMesh::movePoints Foam::tmp<Foam::scalarField> Foam::primitiveMesh::movePoints
( (
const pointField& newPoints, const pointField& newPoints,
@ -324,4 +362,26 @@ const Foam::cellShapeList& Foam::primitiveMesh::cellShapes() const
} }
void Foam::primitiveMesh::updateGeom()
{
if (!faceCentresPtr_)
{
calcFaceCentresAndAreas();
}
if (!faceAreasPtr_)
{
calcFaceCentresAndAreas();
}
if (!cellCentresPtr_)
{
calcCellCentresAndVols();
}
if (!cellVolumesPtr_)
{
calcCellCentresAndVols();
}
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -255,22 +255,9 @@ protected:
//- Calculate face centres and areas //- Calculate face centres and areas
void calcFaceCentresAndAreas() const; void calcFaceCentresAndAreas() const;
void makeFaceCentresAndAreas
(
const pointField& p,
vectorField& fCtrs,
vectorField& fAreas
) const;
//- Calculate cell centres and volumes //- Calculate cell centres and volumes
void calcCellCentresAndVols() const; void calcCellCentresAndVols() const;
void makeCellCentresAndVols
(
const vectorField& fCtrs,
const vectorField& fAreas,
vectorField& cellCtrs,
scalarField& cellVols
) const;
//- Calculate edge vectors //- Calculate edge vectors
void calcEdgeVectors() const; void calcEdgeVectors() const;
@ -476,6 +463,21 @@ public:
cellList& cells cellList& cells
); );
//- Reset the local geometry
void resetGeometry
(
pointField&& faceCentres,
pointField&& faceAreas,
pointField&& cellCentres,
scalarField&& cellVolumes
);
//- Initialise all non-demand-driven data
virtual bool init(const bool doInit)
{
return false;
}
// Access // Access
@ -891,6 +893,8 @@ public:
const labelList& cellEdges(const label celli) const; const labelList& cellEdges(const label celli) const;
//- Update all geometric data
virtual void updateGeom();
//- Clear geometry //- Clear geometry
void clearGeom(); void clearGeom();

View File

@ -30,7 +30,7 @@ Description
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "primitiveMesh.H" #include "primitiveMesh.H"
#include "PrecisionAdaptor.H" #include "primitiveMeshTools.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -61,7 +61,14 @@ void Foam::primitiveMesh::calcCellCentresAndVols() const
scalarField& cellVols = *cellVolumesPtr_; scalarField& cellVols = *cellVolumesPtr_;
// Make centres and volumes // Make centres and volumes
makeCellCentresAndVols(faceCentres(), faceAreas(), cellCtrs, cellVols); primitiveMeshTools::makeCellCentresAndVols
(
*this,
faceCentres(),
faceAreas(),
cellCtrs,
cellVols
);
if (debug) if (debug)
{ {
@ -72,111 +79,14 @@ void Foam::primitiveMesh::calcCellCentresAndVols() const
} }
void Foam::primitiveMesh::makeCellCentresAndVols
(
const vectorField& fCtrs,
const vectorField& fAreas,
vectorField& cellCtrs_s,
scalarField& cellVols_s
) const
{
typedef Vector<solveScalar> solveVector;
PrecisionAdaptor<solveVector, vector> tcellCtrs(cellCtrs_s, false);
Field<solveVector>& cellCtrs = tcellCtrs.ref();
PrecisionAdaptor<solveScalar, scalar> tcellVols(cellVols_s, false);
Field<solveScalar>& cellVols = tcellVols.ref();
cellCtrs = Zero;
cellVols = 0.0;
const labelList& own = faceOwner();
const labelList& nei = faceNeighbour();
// first estimate the approximate cell centre as the average of
// face centres
Field<solveVector> cEst(nCells(), Zero);
labelField nCellFaces(nCells(), Zero);
forAll(own, facei)
{
cEst[own[facei]] += solveVector(fCtrs[facei]);
++nCellFaces[own[facei]];
}
forAll(nei, facei)
{
cEst[nei[facei]] += solveVector(fCtrs[facei]);
++nCellFaces[nei[facei]];
}
forAll(cEst, celli)
{
cEst[celli] /= nCellFaces[celli];
}
forAll(own, facei)
{
const solveVector fc(fCtrs[facei]);
const solveVector fA(fAreas[facei]);
// Calculate 3*face-pyramid volume
solveScalar pyr3Vol =
fA & (fc - cEst[own[facei]]);
// Calculate face-pyramid centre
solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cEst[own[facei]];
// Accumulate volume-weighted face-pyramid centre
cellCtrs[own[facei]] += pyr3Vol*pc;
// Accumulate face-pyramid volume
cellVols[own[facei]] += pyr3Vol;
}
forAll(nei, facei)
{
const solveVector fc(fCtrs[facei]);
const solveVector fA(fAreas[facei]);
// Calculate 3*face-pyramid volume
solveScalar pyr3Vol =
fA & (cEst[nei[facei]] - fc);
// Calculate face-pyramid centre
solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cEst[nei[facei]];
// Accumulate volume-weighted face-pyramid centre
cellCtrs[nei[facei]] += pyr3Vol*pc;
// Accumulate face-pyramid volume
cellVols[nei[facei]] += pyr3Vol;
}
forAll(cellCtrs, celli)
{
if (mag(cellVols[celli]) > VSMALL)
{
cellCtrs[celli] /= cellVols[celli];
}
else
{
cellCtrs[celli] = cEst[celli];
}
}
cellVols *= (1.0/3.0);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::vectorField& Foam::primitiveMesh::cellCentres() const const Foam::vectorField& Foam::primitiveMesh::cellCentres() const
{ {
if (!cellCentresPtr_) if (!cellCentresPtr_)
{ {
calcCellCentresAndVols(); //calcCellCentresAndVols();
const_cast<primitiveMesh&>(*this).updateGeom();
} }
return *cellCentresPtr_; return *cellCentresPtr_;
@ -187,7 +97,8 @@ const Foam::scalarField& Foam::primitiveMesh::cellVolumes() const
{ {
if (!cellVolumesPtr_) if (!cellVolumesPtr_)
{ {
calcCellCentresAndVols(); //calcCellCentresAndVols();
const_cast<primitiveMesh&>(*this).updateGeom();
} }
return *cellVolumesPtr_; return *cellVolumesPtr_;

View File

@ -27,11 +27,182 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "primitiveMeshTools.H" #include "primitiveMeshTools.H"
#include "primitiveMesh.H"
#include "syncTools.H" #include "syncTools.H"
#include "pyramidPointFaceRef.H" #include "pyramidPointFaceRef.H"
#include "PrecisionAdaptor.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::primitiveMeshTools::makeFaceCentresAndAreas
(
const primitiveMesh& mesh,
const pointField& p,
vectorField& fCtrs,
vectorField& fAreas
)
{
const faceList& fs = mesh.faces();
forAll(fs, facei)
{
const labelList& f = fs[facei];
const label nPoints = f.size();
// If the face is a triangle, do a direct calculation for efficiency
// and to avoid round-off error-related problems
if (nPoints == 3)
{
fCtrs[facei] = (1.0/3.0)*(p[f[0]] + p[f[1]] + p[f[2]]);
fAreas[facei] = 0.5*((p[f[1]] - p[f[0]])^(p[f[2]] - p[f[0]]));
}
else
{
typedef Vector<solveScalar> solveVector;
solveVector sumN = Zero;
solveScalar sumA = 0.0;
solveVector sumAc = Zero;
solveVector fCentre = p[f[0]];
for (label pi = 1; pi < nPoints; pi++)
{
fCentre += solveVector(p[f[pi]]);
}
fCentre /= nPoints;
for (label pi = 0; pi < nPoints; pi++)
{
const label nextPi(pi == nPoints-1 ? 0 : pi+1);
const solveVector nextPoint(p[f[nextPi]]);
const solveVector thisPoint(p[f[pi]]);
solveVector c = thisPoint + nextPoint + fCentre;
solveVector n = (nextPoint - thisPoint)^(fCentre - thisPoint);
solveScalar a = mag(n);
sumN += n;
sumA += a;
sumAc += a*c;
}
// This is to deal with zero-area faces. Mark very small faces
// to be detected in e.g., processorPolyPatch.
if (sumA < ROOTVSMALL)
{
fCtrs[facei] = fCentre;
fAreas[facei] = Zero;
}
else
{
fCtrs[facei] = (1.0/3.0)*sumAc/sumA;
fAreas[facei] = 0.5*sumN;
}
}
}
}
void Foam::primitiveMeshTools::makeCellCentresAndVols
(
const primitiveMesh& mesh,
const vectorField& fCtrs,
const vectorField& fAreas,
vectorField& cellCtrs_s,
scalarField& cellVols_s
)
{
typedef Vector<solveScalar> solveVector;
PrecisionAdaptor<solveVector, vector> tcellCtrs(cellCtrs_s);
Field<solveVector>& cellCtrs = tcellCtrs.ref();
PrecisionAdaptor<solveScalar, scalar> tcellVols(cellVols_s);
Field<solveScalar>& cellVols = tcellVols.ref();
// Clear the fields for accumulation
cellCtrs = Zero;
cellVols = 0.0;
const labelList& own = mesh.faceOwner();
const labelList& nei = mesh.faceNeighbour();
// first estimate the approximate cell centre as the average of
// face centres
Field<solveVector> cEst(mesh.nCells(), Zero);
labelField nCellFaces(mesh.nCells(), Zero);
forAll(own, facei)
{
cEst[own[facei]] += solveVector(fCtrs[facei]);
++nCellFaces[own[facei]];
}
forAll(nei, facei)
{
cEst[nei[facei]] += solveVector(fCtrs[facei]);
++nCellFaces[nei[facei]];
}
forAll(cEst, celli)
{
cEst[celli] /= nCellFaces[celli];
}
forAll(own, facei)
{
const solveVector fc(fCtrs[facei]);
const solveVector fA(fAreas[facei]);
// Calculate 3*face-pyramid volume
solveScalar pyr3Vol =
fA & (fc - cEst[own[facei]]);
// Calculate face-pyramid centre
solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cEst[own[facei]];
// Accumulate volume-weighted face-pyramid centre
cellCtrs[own[facei]] += pyr3Vol*pc;
// Accumulate face-pyramid volume
cellVols[own[facei]] += pyr3Vol;
}
forAll(nei, facei)
{
const solveVector fc(fCtrs[facei]);
const solveVector fA(fAreas[facei]);
// Calculate 3*face-pyramid volume
solveScalar pyr3Vol =
fA & (cEst[nei[facei]] - fc);
// Calculate face-pyramid centre
solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cEst[nei[facei]];
// Accumulate volume-weighted face-pyramid centre
cellCtrs[nei[facei]] += pyr3Vol*pc;
// Accumulate face-pyramid volume
cellVols[nei[facei]] += pyr3Vol;
}
forAll(cellCtrs, celli)
{
if (mag(cellVols[celli]) > VSMALL)
{
cellCtrs[celli] /= cellVols[celli];
}
else
{
cellCtrs[celli] = cEst[celli];
}
}
cellVols *= (1.0/3.0);
}
Foam::scalar Foam::primitiveMeshTools::faceSkewness Foam::scalar Foam::primitiveMeshTools::faceSkewness
( (
const primitiveMesh& mesh, const primitiveMesh& mesh,

View File

@ -38,22 +38,45 @@ SourceFiles
#ifndef primitiveMeshTools_H #ifndef primitiveMeshTools_H
#define primitiveMeshTools_H #define primitiveMeshTools_H
#include "primitiveMesh.H"
#include "bitSet.H" #include "bitSet.H"
#include "primitiveFields.H"
#include "pointField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam namespace Foam
{ {
// Forward declarations
class primitiveMesh;
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Namespace primitiveMeshTools Declaration Namespace primitiveMeshTools Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
class primitiveMeshTools class primitiveMeshTools
{ {
public: public:
//- Calculate face centres and areas
static void makeFaceCentresAndAreas
(
const primitiveMesh& mesh,
const pointField& p,
vectorField& fCtrs,
vectorField& fAreas
);
//- Calculate cell centres and volumes from face properties
static void makeCellCentresAndVols
(
const primitiveMesh& mesh,
const vectorField& fCtrs,
const vectorField& fAreas,
vectorField& cellCtrs,
scalarField& cellVols
);
//- Generate non-orthogonality field (internal faces only) //- Generate non-orthogonality field (internal faces only)
static tmp<scalarField> faceOrthogonality static tmp<scalarField> faceOrthogonality
( (

View File

@ -33,6 +33,7 @@ Description
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "primitiveMesh.H" #include "primitiveMesh.H"
#include "primitiveMeshTools.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -60,7 +61,7 @@ void Foam::primitiveMesh::calcFaceCentresAndAreas() const
faceAreasPtr_ = new vectorField(nFaces()); faceAreasPtr_ = new vectorField(nFaces());
vectorField& fAreas = *faceAreasPtr_; vectorField& fAreas = *faceAreasPtr_;
makeFaceCentresAndAreas(points(), fCtrs, fAreas); primitiveMeshTools::makeFaceCentresAndAreas(*this, points(), fCtrs, fAreas);
if (debug) if (debug)
{ {
@ -71,81 +72,14 @@ void Foam::primitiveMesh::calcFaceCentresAndAreas() const
} }
void Foam::primitiveMesh::makeFaceCentresAndAreas
(
const pointField& p,
vectorField& fCtrs,
vectorField& fAreas
) const
{
const faceList& fs = faces();
forAll(fs, facei)
{
const labelList& f = fs[facei];
const label nPoints = f.size();
// If the face is a triangle, do a direct calculation for efficiency
// and to avoid round-off error-related problems
if (nPoints == 3)
{
fCtrs[facei] = (1.0/3.0)*(p[f[0]] + p[f[1]] + p[f[2]]);
fAreas[facei] = 0.5*((p[f[1]] - p[f[0]])^(p[f[2]] - p[f[0]]));
}
else
{
typedef Vector<solveScalar> solveVector;
solveVector sumN = Zero;
solveScalar sumA = 0.0;
solveVector sumAc = Zero;
solveVector fCentre = p[f[0]];
for (label pi = 1; pi < nPoints; pi++)
{
fCentre += solveVector(p[f[pi]]);
}
fCentre /= nPoints;
for (label pi = 0; pi < nPoints; pi++)
{
const label nextPi(pi == nPoints-1 ? 0 : pi+1);
const solveVector nextPoint(p[f[nextPi]]);
const solveVector thisPoint(p[f[pi]]);
solveVector c = thisPoint + nextPoint + fCentre;
solveVector n = (nextPoint - thisPoint)^(fCentre - thisPoint);
solveScalar a = mag(n);
sumN += n;
sumA += a;
sumAc += a*c;
}
// This is to deal with zero-area faces. Mark very small faces
// to be detected in e.g., processorPolyPatch.
if (sumA < ROOTVSMALL)
{
fCtrs[facei] = fCentre;
fAreas[facei] = Zero;
}
else
{
fCtrs[facei] = (1.0/3.0)*sumAc/sumA;
fAreas[facei] = 0.5*sumN;
}
}
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::vectorField& Foam::primitiveMesh::faceCentres() const const Foam::vectorField& Foam::primitiveMesh::faceCentres() const
{ {
if (!faceCentresPtr_) if (!faceCentresPtr_)
{ {
calcFaceCentresAndAreas(); //calcFaceCentresAndAreas();
const_cast<primitiveMesh&>(*this).updateGeom();
} }
return *faceCentresPtr_; return *faceCentresPtr_;
@ -156,7 +90,8 @@ const Foam::vectorField& Foam::primitiveMesh::faceAreas() const
{ {
if (!faceAreasPtr_) if (!faceAreasPtr_)
{ {
calcFaceCentresAndAreas(); //calcFaceCentresAndAreas();
const_cast<primitiveMesh&>(*this).updateGeom();
} }
return *faceAreasPtr_; return *faceAreasPtr_;

View File

@ -104,7 +104,7 @@ public:
// Constructors // Constructors
//- Construct from an IOobject //- Construct from an IOobject
explicit dynamicFvMesh(const IOobject& io); explicit dynamicFvMesh(const IOobject& io); //, const bool doInit=true);
//- Construct from components without boundary. //- Construct from components without boundary.
// Boundary is added using addFvPatches() member function // Boundary is added using addFvPatches() member function
@ -139,7 +139,11 @@ public:
//- Select, construct and return the dynamicFvMesh //- Select, construct and return the dynamicFvMesh
// If the constant/dynamicMeshDict does not exist // If the constant/dynamicMeshDict does not exist
// a staticFvMesh is returned // a staticFvMesh is returned
static autoPtr<dynamicFvMesh> New(const IOobject& io); static autoPtr<dynamicFvMesh> New
(
const IOobject& io //,
//const bool doInit=true
);
//- Select, construct and return the dynamicFvMesh //- Select, construct and return the dynamicFvMesh
@ -148,7 +152,8 @@ public:
static autoPtr<dynamicFvMesh> New static autoPtr<dynamicFvMesh> New
( (
const argList& args, const argList& args,
const Time& runTime const Time& runTime //,
//const bool doInit=true
); );
@ -158,6 +163,9 @@ public:
// Member Functions // Member Functions
//- Initialise all non-demand-driven data
//virtual bool init(const bool doInit);
//- Is mesh dynamic //- Is mesh dynamic
virtual bool dynamic() const virtual bool dynamic() const
{ {

View File

@ -1,6 +1,9 @@
Info<< "Create mesh for time = " Info<< "Create mesh for time = "
<< runTime.timeName() << nl << endl; << runTime.timeName() << nl << endl;
autoPtr<dynamicFvMesh> meshPtr(dynamicFvMesh::New(args, runTime)); autoPtr<dynamicFvMesh> meshPtr(dynamicFvMesh::New(args, runTime));//, false));
dynamicFvMesh& mesh = meshPtr(); dynamicFvMesh& mesh = meshPtr();
// initialise all (lower levels and current)
mesh.init(true);

View File

@ -268,7 +268,7 @@ void Foam::fvMeshSubset::removeCellsImpl
baseMesh().name(), baseMesh().name(),
baseMesh().time().timeName(), baseMesh().time().timeName(),
baseMesh().time(), baseMesh().time(),
IOobject::NO_READ, IOobject::READ_IF_PRESENT, // read fv* if present
IOobject::NO_WRITE IOobject::NO_WRITE
), ),
baseMesh(), baseMesh(),
@ -980,9 +980,10 @@ void Foam::fvMeshSubset::setCellSubset
baseMesh().name(), baseMesh().name(),
baseMesh().time().timeName(), baseMesh().time().timeName(),
baseMesh().time(), baseMesh().time(),
IOobject::NO_READ, IOobject::NO_READ, // do not read any dictionaries
IOobject::NO_WRITE IOobject::NO_WRITE
), ),
baseMesh(), // get dictionaries from base mesh
std::move(newPoints), std::move(newPoints),
std::move(newFaces), std::move(newFaces),
std::move(newCells), std::move(newCells),

View File

@ -79,7 +79,7 @@ Foam::autoPtr<Foam::fvMesh> Foam::polyMeshFilter::copyMesh(const fvMesh& mesh)
mesh.name(), mesh.name(),
mesh.polyMesh::instance(), mesh.polyMesh::instance(),
mesh.time(), mesh.time(),
IOobject::NO_READ, IOobject::READ_IF_PRESENT, // read fv* if present
IOobject::NO_WRITE, IOobject::NO_WRITE,
false false
), ),

View File

@ -1,6 +1,17 @@
fvMesh/fvMeshGeometry.C fvMesh/fvMeshGeometry.C
fvMesh/fvMesh.C fvMesh/fvMesh.C
fvGeometryScheme = fvMesh/fvGeometryScheme
$(fvGeometryScheme)/fvGeometryScheme/fvGeometryScheme.C
$(fvGeometryScheme)/basic/basicFvGeometryScheme.C
$(fvGeometryScheme)/highAspectRatio/highAspectRatioFvGeometryScheme.C
$(fvGeometryScheme)/highAspectRatio/cellAspectRatio.C
$(fvGeometryScheme)/averageNeighbour/averageNeighbourFvGeometryScheme.C
$(fvGeometryScheme)/stabilised/stabilisedFvGeometryScheme.C
surfaceInterpolation = interpolation/surfaceInterpolation
$(surfaceInterpolation)/surfaceInterpolation/surfaceInterpolation.C
fvMesh/singleCellFvMesh/singleCellFvMesh.C fvMesh/singleCellFvMesh/singleCellFvMesh.C
fvMesh/simplifiedFvMesh/simplifiedFvMesh/simplifiedFvMesh.C fvMesh/simplifiedFvMesh/simplifiedFvMesh/simplifiedFvMesh.C
@ -53,7 +64,6 @@ fvMeshMapper = fvMesh/fvMeshMapper
$(fvMeshMapper)/fvPatchMapper.C $(fvMeshMapper)/fvPatchMapper.C
$(fvMeshMapper)/fvSurfaceMapper.C $(fvMeshMapper)/fvSurfaceMapper.C
extendedStencil = fvMesh/extendedStencil extendedStencil = fvMesh/extendedStencil
cellToCell = $(extendedStencil)/cellToCell cellToCell = $(extendedStencil)/cellToCell
@ -316,8 +326,6 @@ volPointInterpolation = interpolation/volPointInterpolation
$(volPointInterpolation)/volPointInterpolation.C $(volPointInterpolation)/volPointInterpolation.C
$(volPointInterpolation)/pointConstraints.C $(volPointInterpolation)/pointConstraints.C
surfaceInterpolation = interpolation/surfaceInterpolation
$(surfaceInterpolation)/surfaceInterpolation/surfaceInterpolation.C
$(surfaceInterpolation)/surfaceInterpolationScheme/surfaceInterpolationSchemes.C $(surfaceInterpolation)/surfaceInterpolationScheme/surfaceInterpolationSchemes.C
$(surfaceInterpolation)/blendedSchemeBase/blendedSchemeBaseName.C $(surfaceInterpolation)/blendedSchemeBase/blendedSchemeBaseName.C

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd. Copyright (C) 2019-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -327,6 +327,140 @@ Foam::fvSchemes::fvSchemes(const objectRegistry& obr)
} }
Foam::fvSchemes::fvSchemes(const objectRegistry& obr, const dictionary& dict)
:
IOdictionary
(
IOobject
(
"fvSchemes",
obr.time().system(),
obr,
(
obr.readOpt() == IOobject::MUST_READ
|| obr.readOpt() == IOobject::READ_IF_PRESENT
? IOobject::MUST_READ_IF_MODIFIED
: obr.readOpt()
),
IOobject::NO_WRITE
),
dict
),
ddtSchemes_
(
ITstream
(
objectPath() + ".ddtSchemes",
tokenList()
)()
),
defaultDdtScheme_
(
ddtSchemes_.name() + ".default",
tokenList()
),
d2dt2Schemes_
(
ITstream
(
objectPath() + ".d2dt2Schemes",
tokenList()
)()
),
defaultD2dt2Scheme_
(
d2dt2Schemes_.name() + ".default",
tokenList()
),
interpolationSchemes_
(
ITstream
(
objectPath() + ".interpolationSchemes",
tokenList()
)()
),
defaultInterpolationScheme_
(
interpolationSchemes_.name() + ".default",
tokenList()
),
divSchemes_
(
ITstream
(
objectPath() + ".divSchemes",
tokenList()
)()
),
defaultDivScheme_
(
divSchemes_.name() + ".default",
tokenList()
),
gradSchemes_
(
ITstream
(
objectPath() + ".gradSchemes",
tokenList()
)()
),
defaultGradScheme_
(
gradSchemes_.name() + ".default",
tokenList()
),
snGradSchemes_
(
ITstream
(
objectPath() + ".snGradSchemes",
tokenList()
)()
),
defaultSnGradScheme_
(
snGradSchemes_.name() + ".default",
tokenList()
),
laplacianSchemes_
(
ITstream
(
objectPath() + ".laplacianSchemes",
tokenList()
)()
),
defaultLaplacianScheme_
(
laplacianSchemes_.name() + ".default",
tokenList()
),
fluxRequired_
(
ITstream
(
objectPath() + ".fluxRequired",
tokenList()
)()
),
defaultFluxRequired_(false),
steady_(false)
{
if
(
readOpt() == IOobject::MUST_READ
|| readOpt() == IOobject::MUST_READ_IF_MODIFIED
|| (readOpt() == IOobject::READ_IF_PRESENT && headerOk())
)
{
read(schemesDict());
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::fvSchemes::read() bool Foam::fvSchemes::read()

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -111,6 +112,11 @@ public:
//- Construct for objectRegistry //- Construct for objectRegistry
fvSchemes(const objectRegistry& obr); fvSchemes(const objectRegistry& obr);
//- Construct from objectRegistry and supplied (optional) content
// (gets used in case of NO_READ or fvSchemes dictionary cannot be
// read)
fvSchemes(const objectRegistry& obr, const dictionary& dict);
// Member Functions // Member Functions

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -69,6 +70,12 @@ public:
: :
solution(obr, "fvSolution") solution(obr, "fvSolution")
{} {}
//- Construct for objectRegistry and optional contents
fvSolution(const objectRegistry& obr, const dictionary& dict)
:
solution(obr, "fvSolution", dict)
{}
}; };

View File

@ -0,0 +1,880 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "averageNeighbourFvGeometryScheme.H"
#include "addToRunTimeSelectionTable.H"
#include "fvMesh.H"
#include "cellAspectRatio.H"
#include "syncTools.H"
#include "polyMeshTools.H"
#include "unitConversion.H"
#include "OBJstream.H"
#include "surfaceWriter.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(averageNeighbourFvGeometryScheme, 0);
addToRunTimeSelectionTable
(
fvGeometryScheme,
averageNeighbourFvGeometryScheme,
dict
);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::label Foam::averageNeighbourFvGeometryScheme::clipFaceTet
(
const scalar minRatio,
const vectorField& faceCentres,
const vectorField& faceNormals,
vectorField& faceCorrection
) const
{
// Clip correction vector if any triangle becomes too small. Return number
// of correction vectors clipped
typedef Vector<solveScalar> solveVector;
const pointField& p = mesh_.points();
label nClipped = 0;
for (label facei = 0; facei < mesh_.nFaces(); facei++)
{
const vector& fcCorr = faceCorrection[facei];
if (fcCorr != vector::zero)
{
const vector& fn = faceNormals[facei];
const point& fc = faceCentres[facei];
const face& f = mesh_.faces()[facei];
forAll(f, fp)
{
const solveVector thisPt(p[f[fp]]);
const solveVector nextPt(p[f.fcValue(fp)]);
const solveVector d(nextPt-thisPt);
// Calculate triangle area with correction
const solveVector nCorr(d^(fc+fcCorr - thisPt));
if ((nCorr & fn) < 0)
{
// Triangle points wrong way
faceCorrection[facei] = vector::zero;
nClipped++;
break;
}
else
{
// Calculate triangle area without correction
const solveVector n(d^(fc - thisPt));
if ((n & fn) < 0)
{
// Original triangle points the wrong way, new one is ok
}
else
{
// Both point correctly. Make sure triangle doesn't get
// too small
if (mag(nCorr) < minRatio*mag(n))
{
faceCorrection[facei] = vector::zero;
nClipped++;
break;
}
}
}
}
}
}
return returnReduce(nClipped, sumOp<label>());
}
void Foam::averageNeighbourFvGeometryScheme::makePyrHeights
(
const pointField& cellCentres,
const vectorField& faceCentres,
const vectorField& faceNormals,
scalarField& ownHeight,
scalarField& neiHeight
) const
{
ownHeight.setSize(mesh_.nFaces());
neiHeight.setSize(mesh_.nInternalFaces());
typedef Vector<solveScalar> solveVector;
const labelList& own = mesh_.faceOwner();
const labelList& nei = mesh_.faceNeighbour();
for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
{
const solveVector n = faceNormals[facei];
const solveVector fc = faceCentres[facei];
ownHeight[facei] = ((fc-cellCentres[own[facei]])&n);
neiHeight[facei] = ((cellCentres[nei[facei]]-fc)&n);
}
for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); facei++)
{
const solveVector n = faceNormals[facei];
const solveVector fc = faceCentres[facei];
ownHeight[facei] = ((fc-cellCentres[own[facei]])&n);
}
}
Foam::label Foam::averageNeighbourFvGeometryScheme::clipPyramids
(
const pointField& cellCentres,
const vectorField& faceCentres,
const vectorField& faceNormals,
const scalarField& minOwnHeight,
const scalarField& minNeiHeight,
vectorField& correction
) const
{
// Clip correction vector if any pyramid becomes too small. Return number of
// cells clipped
typedef Vector<solveScalar> solveVector;
const labelList& own = mesh_.faceOwner();
const labelList& nei = mesh_.faceNeighbour();
label nClipped = 0;
for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
{
const vector& n = faceNormals[facei];
const point& fc = faceCentres[facei];
const label ownCelli = own[facei];
if (correction[ownCelli] != vector::zero)
{
const solveVector ownCc(cellCentres[ownCelli]+correction[ownCelli]);
const scalar ownHeight = ((fc-ownCc)&n);
if (ownHeight < minOwnHeight[facei])
{
//Pout<< " internalface:" << fc
// << " own:" << ownCc
// << " pyrHeight:" << ownHeight
// << " minHeight:" << minOwnHeight[facei]
// << endl;
correction[ownCelli] = vector::zero;
nClipped++;
}
}
const label neiCelli = nei[facei];
if (correction[neiCelli] != vector::zero)
{
const solveVector neiCc(cellCentres[neiCelli]+correction[neiCelli]);
const scalar neiHeight = ((neiCc-fc)&n);
if (neiHeight < minNeiHeight[facei])
{
//Pout<< " internalface:" << fc
// << " nei:" << neiCc
// << " pyrHeight:" << neiHeight
// << " minHeight:" << minNeiHeight[facei]
// << endl;
correction[neiCelli] = vector::zero;
nClipped++;
}
}
}
for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); facei++)
{
const vector& n = faceNormals[facei];
const point& fc = faceCentres[facei];
const label ownCelli = own[facei];
if (correction[ownCelli] != vector::zero)
{
const solveVector ownCc(cellCentres[ownCelli]+correction[ownCelli]);
const scalar ownHeight = ((fc-ownCc)&n);
if (ownHeight < minOwnHeight[facei])
{
//Pout<< " boundaryface:" << fc
// << " own:" << ownCc
// << " pyrHeight:" << ownHeight
// << " minHeight:" << minOwnHeight[facei]
// << endl;
correction[ownCelli] = vector::zero;
nClipped++;
}
}
}
return returnReduce(nClipped, sumOp<label>());
}
Foam::tmp<Foam::pointField>
Foam::averageNeighbourFvGeometryScheme::averageNeighbourCentres
(
const pointField& cellCentres,
const vectorField& faceNormals,
const scalarField& faceWeights
) const
{
typedef Vector<solveScalar> solveVector;
const labelList& own = mesh_.faceOwner();
const labelList& nei = mesh_.faceNeighbour();
tmp<pointField> tcc(new pointField(mesh_.nCells(), Zero));
pointField& cc = tcc.ref();
Field<solveScalar> cellWeights(mesh_.nCells(), Zero);
// Internal faces
for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
{
const vector& n = faceNormals[facei];
const point& ownCc = cellCentres[own[facei]];
const point& neiCc = cellCentres[nei[facei]];
solveVector d(neiCc-ownCc);
// 1. Normalise contribution. This increases actual non-ortho
// since it does not 'see' the tangential offset of neighbours
//neiCc = ownCc + (d&n)*n;
// 2. Remove normal contribution, i.e. get tangential vector
// (= non-ortho correction vector?)
d -= (d&n)*n;
// Apply half to both sides (as a correction)
// Note: should this be linear weights instead of 0.5?
const scalar w = 0.5*faceWeights[facei];
cc[own[facei]] += w*d;
cellWeights[own[facei]] += w;
cc[nei[facei]] -= w*d;
cellWeights[nei[facei]] += w;
}
// Boundary faces. Bypass stored cell centres
pointField neiCellCentres;
syncTools::swapBoundaryCellPositions(mesh_, cellCentres, neiCellCentres);
const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
forAll(pbm, patchi)
{
const polyPatch& pp = pbm[patchi];
if (pp.coupled())
{
const labelUList& fc = pp.faceCells();
forAll(fc, i)
{
const label meshFacei = pp.start()+i;
const label bFacei = meshFacei-mesh_.nInternalFaces();
const vector& n = faceNormals[meshFacei];
const point& ownCc = cellCentres[fc[i]];
const point& neiCc = neiCellCentres[bFacei];
solveVector d(neiCc-ownCc);
// 1. Normalise contribution. This increases actual non-ortho
// since it does not 'see' the tangential offset of neighbours
//neiCc = ownCc + (d&n)*n;
// 2. Remove normal contribution, i.e. get tangential vector
// (= non-ortho correction vector?)
d -= (d&n)*n;
// Apply half to both sides (as a correction)
const scalar w = 0.5*faceWeights[meshFacei];
cc[fc[i]] += w*d;
cellWeights[fc[i]] += w;
}
}
}
// Now cc is still the correction vector. Add to cell original centres.
forAll(cc, celli)
{
if (cellWeights[celli] > VSMALL)
{
cc[celli] = cellCentres[celli] + cc[celli]/cellWeights[celli];
}
else
{
cc[celli] = cellCentres[celli];
}
}
return tcc;
}
Foam::tmp<Foam::pointField>
Foam::averageNeighbourFvGeometryScheme::averageCentres
(
// const scalar ratio, // Amount of change in face-triangles area
const pointField& cellCentres,
const pointField& faceCentres,
const vectorField& faceNormals
) const
{
typedef Vector<solveScalar> solveVector;
const labelList& own = mesh_.faceOwner();
const labelList& nei = mesh_.faceNeighbour();
tmp<pointField> tnewFc(new pointField(faceCentres));
pointField& newFc = tnewFc.ref();
// Internal faces
for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
{
const vector& n = faceNormals[facei];
const point& oldFc = faceCentres[facei];
const solveVector ownCc(cellCentres[own[facei]]);
const solveVector neiCc(cellCentres[nei[facei]]);
solveVector deltaCc(neiCc-ownCc);
solveVector deltaFc(oldFc-ownCc);
//solveVector d(neiCc-ownCc);
//// 1. Normalise contribution. This increases actual non-ortho
//// since it does not 'see' the tangential offset of neighbours
////neiCc = ownCc + s*n;
//
//// 2. Remove normal contribution, i.e. get tangential vector
//// (= non-ortho correction vector?)
//d -= s*n;
//newFc[facei] = faceCentres[facei]+d;
// Get linear weight (normal distance to face)
const solveScalar f = (deltaFc&n)/(deltaCc&n);
const solveVector avgCc((1.0-f)*ownCc + f*neiCc);
solveVector d(avgCc-oldFc);
// Remove normal contribution, i.e. get tangential vector
// (= non-ortho correction vector?)
d -= (d&n)*n;
// // Clip to limit change in
// d *= ratio;
newFc[facei] = oldFc + d;
}
// Boundary faces. Bypass stored cell centres
pointField neiCellCentres;
syncTools::swapBoundaryCellPositions(mesh_, cellCentres, neiCellCentres);
const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
forAll(pbm, patchi)
{
const polyPatch& pp = pbm[patchi];
const labelUList& fc = pp.faceCells();
if (pp.coupled())
{
forAll(fc, i)
{
// Same as internal faces
const label facei = pp.start()+i;
const label bFacei = facei-mesh_.nInternalFaces();
const vector& n = faceNormals[facei];
const point& oldFc = faceCentres[facei];
const solveVector ownCc(cellCentres[fc[i]]);
const solveVector neiCc(neiCellCentres[bFacei]);
solveVector deltaCc(neiCc-ownCc);
solveVector deltaFc(oldFc-ownCc);
// Get linear weight (normal distance to face)
const solveScalar f = (deltaFc&n)/(deltaCc&n);
const solveVector avgCc((1.0-f)*ownCc + f*neiCc);
solveVector d(avgCc-oldFc);
// Remove normal contribution, i.e. get tangential vector
// (= non-ortho correction vector?)
d -= (d&n)*n;
newFc[facei] = oldFc + d;
}
}
else
{
// Zero-grad?
forAll(fc, i)
{
const label facei = pp.start()+i;
const vector& n = faceNormals[facei];
const point& oldFc = faceCentres[facei];
const solveVector ownCc(cellCentres[fc[i]]);
solveVector d(ownCc-oldFc);
// Remove normal contribution, i.e. get tangential vector
// (= non-ortho correction vector?)
d -= (d&n)*n;
newFc[facei] = oldFc+d;
}
}
}
return tnewFc;
}
void Foam::averageNeighbourFvGeometryScheme::makeNonOrthoWeights
(
const pointField& cellCentres,
const vectorField& faceNormals,
scalarField& cosAngles,
scalarField& faceWeights
) const
{
cosAngles =
max
(
scalar(0),
min
(
scalar(1),
polyMeshTools::faceOrthogonality
(
mesh_,
faceNormals,
cellCentres
)
)
);
// Make weight: 0 for ortho faces, 1 for 90degrees non-ortho
//const scalarField faceWeights(scalar(1)-cosAngles);
faceWeights.setSize(cosAngles.size());
{
const scalar minCos = Foam::cos(degToRad(80));
const scalar maxCos = Foam::cos(degToRad(10));
forAll(cosAngles, facei)
{
const scalar cosAngle = cosAngles[facei];
if (cosAngle < minCos)
{
faceWeights[facei] = 1.0;
}
else if (cosAngle > maxCos)
{
faceWeights[facei] = 0.0;
}
else
{
faceWeights[facei] =
1.0-(cosAngle-minCos)/(maxCos-minCos);
}
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::averageNeighbourFvGeometryScheme::averageNeighbourFvGeometryScheme
(
const fvMesh& mesh,
const dictionary& dict
)
:
highAspectRatioFvGeometryScheme(mesh, dict),
nIters_
(
dict.getCheckOrDefault<label>
(
"nIters",
1,
[&](const label& nIters)
{
return nIters >= 0;
}
)
),
relax_
(
dict.getCheck<scalar>
(
"relax",
[&](const scalar& relax)
{
return relax > 0 && relax <= 1;
}
)
),
minRatio_
(
dict.getCheckOrDefault<scalar>
(
"minRatio",
0.5,
[&](const scalar& minRatio)
{
return minRatio >= 0 && minRatio <= 1;
}
)
)
{
if (debug)
{
Pout<< "averageNeighbourFvGeometryScheme :"
<< " nIters:" << nIters_
<< " relax:" << relax_
<< " minRatio:" << minRatio_ << endl;
}
// Force local calculation
movePoints();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::averageNeighbourFvGeometryScheme::movePoints()
{
if (debug)
{
Pout<< "averageNeighbourFvGeometryScheme::movePoints() : "
<< "recalculating primitiveMesh centres" << endl;
}
//if
//(
// !mesh_.hasCellCentres()
//&& !mesh_.hasFaceCentres()
//&& !mesh_.hasCellVolumes()
//&& !mesh_.hasFaceAreas()
//)
{
highAspectRatioFvGeometryScheme::movePoints();
// Note: at this point the highAspectRatioFvGeometryScheme constructor
// will have already reset the primitive geometry!
vectorField faceAreas(mesh_.faceAreas());
const scalarField magFaceAreas(mag(faceAreas));
const vectorField faceNormals(faceAreas/magFaceAreas);
// Calculate aspectratio weights
// - 0 if aratio < minAspect_
// - 1 if aratio >= maxAspect_
scalarField cellWeight, faceWeight;
calcAspectRatioWeights(cellWeight, faceWeight);
// Relaxation
cellWeight *= relax_;
//faceWeight *= relax_;
// Calculate current pyramid heights
scalarField minOwnHeight;
scalarField minNeiHeight;
makePyrHeights
(
mesh_.cellCentres(),
mesh_.faceCentres(),
faceNormals,
minOwnHeight,
minNeiHeight
);
// How much is the cell centre to vary inside the cell.
minOwnHeight *= minRatio_;
minNeiHeight *= minRatio_;
autoPtr<OBJstream> osPtr;
autoPtr<surfaceWriter> writerPtr;
if (debug)
{
osPtr.set
(
new OBJstream
(
mesh_.time().timePath()
/ "cellCentre_correction.obj"
)
);
Pout<< "averageNeighbourFvGeometryScheme::movePoints() :"
<< " writing cell centre path to " << osPtr().name() << endl;
// Write current non-ortho
fileName outputDir =
(
mesh_.time().globalPath()
/ functionObject::outputPrefix
/ mesh_.pointsInstance()
);
outputDir.clean();
writerPtr = surfaceWriter::New
(
"ensight" //"vtk"
// options
);
// Use outputDir/TIME/surface-name
writerPtr->useTimeDir() = true;
writerPtr->beginTime(mesh_.time());
writerPtr->open
(
mesh_.points(),
mesh_.faces(),
(outputDir / "cosAngle"),
true // merge parallel bits
);
writerPtr->endTime();
}
// Current cellCentres. These get adjusted to lower the
// non-orthogonality
pointField cellCentres(mesh_.cellCentres());
// Modify cell centres to be more in-line with the face normals
for (label iter = 0; iter < nIters_; iter++)
{
// Get neighbour average (weighted by face area). This gives
// preference to the dominant faces. However if the non-ortho
// is not caused by the dominant faces this moves to the wrong
// direction.
//tmp<pointField> tcc
//(
// averageNeighbourCentres
// (
// cellCentres,
// faceNormals,
// magFaceAreas
// )
//);
// Get neighbour average weighted by non-ortho. Question: how to
// weight boundary faces?
tmp<pointField> tcc;
{
scalarField cosAngles;
scalarField faceWeights;
makeNonOrthoWeights
(
cellCentres,
faceNormals,
cosAngles,
faceWeights
);
if (writerPtr.valid())
{
writerPtr->beginTime(instant(scalar(iter)));
writerPtr->write("cosAngles", cosAngles);
writerPtr->endTime();
}
if (debug)
{
forAll(cosAngles, facei)
{
if (cosAngles[facei] < Foam::cos(degToRad(85.0)))
{
Pout<< " face:" << facei
<< " at:" << mesh_.faceCentres()[facei]
<< " cosAngle:" << cosAngles[facei]
<< " faceWeight:" << faceWeights[facei]
<< endl;
}
}
}
tcc = averageNeighbourCentres
(
cellCentres,
faceNormals,
faceWeights
);
}
// Calculate correction for cell centres. Leave low-aspect
// ratio cells unaffected (i.e. correction = 0)
vectorField correction(cellWeight*(tcc-cellCentres));
// Clip correction vector if pyramid becomes too small
const label nClipped = clipPyramids
(
cellCentres,
mesh_.faceCentres(),
faceNormals,
minOwnHeight, // minimum owner pyramid height. Usually fraction
minNeiHeight, // of starting mesh
correction
);
cellCentres += correction;
if (debug)
{
forAll(cellCentres, celli)
{
const point& cc = cellCentres[celli];
osPtr().write(linePointRef(cc-correction[celli], cc));
}
const scalarField magCorrection(mag(correction));
const scalarField faceOrthogonality
(
min
(
scalar(1),
polyMeshTools::faceOrthogonality
(
mesh_,
faceAreas,
cellCentres
)
)
);
const scalarField nonOrthoAngle
(
radToDeg
(
Foam::acos(faceOrthogonality)
)
);
Pout<< " iter:" << iter
<< " nClipped:" << nClipped
<< " average displacement:" << gAverage(magCorrection)
<< " non-ortho angle : average:" << gAverage(nonOrthoAngle)
<< " max:" << gMax(nonOrthoAngle) << endl;
}
}
tmp<pointField> tfc
(
averageCentres
(
cellCentres,
mesh_.faceCentres(),
faceNormals
)
);
vectorField faceCorrection(faceWeight*(tfc-mesh_.faceCentres()));
// Clip correction vector to not have min triangle shrink
// by more than minRatio
clipFaceTet
(
minRatio_,
mesh_.faceCentres(),
faceNormals,
faceCorrection
);
vectorField faceCentres(mesh_.faceCentres() + faceCorrection);
if (debug)
{
Pout<< "averageNeighbourFvGeometryScheme::movePoints() :"
<< " averageNeighbour weight"
<< " max:" << gMax(cellWeight) << " min:" << gMin(cellWeight)
<< " average:" << gAverage(cellWeight) << endl;
// Dump lines from old to new location
const fileName tp(mesh_.time().timePath());
mkDir(tp);
OBJstream str(tp/"averageNeighbourCellCentres.obj");
Pout<< "Writing lines from old to new cell centre to " << str.name()
<< endl;
forAll(mesh_.cellCentres(), celli)
{
const point& oldCc = mesh_.cellCentres()[celli];
const point& newCc = cellCentres[celli];
str.write(linePointRef(oldCc, newCc));
}
}
if (debug)
{
// Dump lines from old to new location
const fileName tp(mesh_.time().timePath());
OBJstream str(tp/"averageFaceCentres.obj");
Pout<< "Writing lines from old to new face centre to " << str.name()
<< endl;
forAll(mesh_.faceCentres(), facei)
{
const point& oldFc = mesh_.faceCentres()[facei];
const point& newFc = faceCentres[facei];
str.write(linePointRef(oldFc, newFc));
}
}
scalarField cellVolumes(mesh_.cellVolumes());
// Store on primitiveMesh
//const_cast<fvMesh&>(mesh_).clearGeom();
const_cast<fvMesh&>(mesh_).primitiveMesh::resetGeometry
(
std::move(faceCentres),
std::move(faceAreas),
std::move(cellCentres),
std::move(cellVolumes)
);
}
}
// ************************************************************************* //

View File

@ -0,0 +1,178 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::averageNeighbourFvGeometryScheme
Description
Geometry calculation scheme to minimise non-orthogonality/
SourceFiles
averageNeighbourFvGeometryScheme.C
\*---------------------------------------------------------------------------*/
#ifndef averageNeighbourFvGeometryScheme_H
#define averageNeighbourFvGeometryScheme_H
#include "highAspectRatioFvGeometryScheme.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class primitiveMesh;
/*---------------------------------------------------------------------------*\
Class averageNeighbourFvGeometryScheme Declaration
\*---------------------------------------------------------------------------*/
class averageNeighbourFvGeometryScheme
:
public highAspectRatioFvGeometryScheme
{
private:
//- No copy construct
averageNeighbourFvGeometryScheme
(
const averageNeighbourFvGeometryScheme&
) = delete;
//- No copy assignment
void operator=(const averageNeighbourFvGeometryScheme&) = delete;
protected:
//- Number of averaging iterations
const label nIters_;
//- Blending between old-iteration cell centres and current average
const scalar relax_;
//- Clipping for pyramid heights - allowable shrinkage as fraction
// of original
const scalar minRatio_;
//- Clip face-centre correction vector if new triangle area
//- would get below min. Return number of clipped faces.
label clipFaceTet
(
const scalar minRatio,
const vectorField& faceCentres,
const vectorField& faceNormals,
vectorField& faceCorrection
) const;
//- Calculate pyramid heights
void makePyrHeights
(
const pointField& cellCentres,
const vectorField& faceCentres,
const vectorField& faceNormals,
scalarField& ownHeight,
scalarField& neiHeight
) const;
//- Clip correction vector if new pyramid height would get below min.
//- Return number of clipped cells.
label clipPyramids
(
const pointField& cellCentres,
const vectorField& faceCentres,
const vectorField& faceNormals,
const scalarField& minOwnHeight,
const scalarField& minNeiHeight,
vectorField& correction
) const;
//- Average neighbouring cell centres to minimise non-ortho
tmp<pointField> averageNeighbourCentres
(
const pointField& cellCentres,
const vectorField& faceNormals,
const scalarField& faceWeights
) const;
tmp<pointField> averageCentres
(
const pointField& cellCentres,
const pointField& faceCentres,
const vectorField& faceNormals
) const;
//- Make weights based on non-orthogonality
void makeNonOrthoWeights
(
const pointField& cellCentres,
const vectorField& faceNormals,
scalarField& cosAngles,
scalarField& faceWeights
) const;
public:
//- Runtime type information
TypeName("averageNeighbour");
// Constructors
//- Construct from mesh
averageNeighbourFvGeometryScheme
(
const fvMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~averageNeighbourFvGeometryScheme() = default;
// Member Functions
//- Do what is necessary if the mesh has moved
virtual void movePoints();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,388 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "basicFvGeometryScheme.H"
#include "addToRunTimeSelectionTable.H"
#include "surfaceFields.H"
#include "volFields.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(basicFvGeometryScheme, 0);
addToRunTimeSelectionTable(fvGeometryScheme, basicFvGeometryScheme, dict);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::basicFvGeometryScheme::basicFvGeometryScheme
(
const fvMesh& mesh,
const dictionary& dict
)
:
fvGeometryScheme(mesh, dict)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::basicFvGeometryScheme::movePoints()
{
if (debug)
{
Pout<< "basicFvGeometryScheme::movePoints() : "
<< "recalculating primitiveMesh centres" << endl;
}
// Use lower level to calculate the geometry
const_cast<fvMesh&>(mesh_).primitiveMesh::updateGeom();
}
Foam::tmp<Foam::surfaceScalarField> Foam::basicFvGeometryScheme::weights() const
{
if (debug)
{
Pout<< "basicFvGeometryScheme::weights() : "
<< "Constructing weighting factors for face interpolation"
<< endl;
}
tmp<surfaceScalarField> tweights
(
new surfaceScalarField
(
IOobject
(
"weights",
mesh_.pointsInstance(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false // Do not register
),
mesh_,
dimless
)
);
surfaceScalarField& weights = tweights.ref();
weights.setOriented();
// Set local references to mesh data
// Note that we should not use fvMesh sliced fields at this point yet
// since this causes a loop when generating weighting factors in
// coupledFvPatchField evaluation phase
const labelUList& owner = mesh_.owner();
const labelUList& neighbour = mesh_.neighbour();
const vectorField& Cf = mesh_.faceCentres();
const vectorField& C = mesh_.cellCentres();
const vectorField& Sf = mesh_.faceAreas();
// ... and reference to the internal field of the weighting factors
scalarField& w = weights.primitiveFieldRef();
forAll(owner, facei)
{
// Note: mag in the dot-product.
// For all valid meshes, the non-orthogonality will be less than
// 90 deg and the dot-product will be positive. For invalid
// meshes (d & s <= 0), this will stabilise the calculation
// but the result will be poor.
scalar SfdOwn = mag(Sf[facei] & (Cf[facei] - C[owner[facei]]));
scalar SfdNei = mag(Sf[facei] & (C[neighbour[facei]] - Cf[facei]));
w[facei] = SfdNei/(SfdOwn + SfdNei);
}
surfaceScalarField::Boundary& wBf = weights.boundaryFieldRef();
forAll(mesh_.boundary(), patchi)
{
mesh_.boundary()[patchi].makeWeights(wBf[patchi]);
}
if (debug)
{
Pout<< "basicFvGeometryScheme::weights : "
<< "Finished constructing weighting factors for face interpolation"
<< endl;
}
return tweights;
}
Foam::tmp<Foam::surfaceScalarField>
Foam::basicFvGeometryScheme::deltaCoeffs() const
{
if (debug)
{
Pout<< "basicFvGeometryScheme::deltaCoeffs() : "
<< "Constructing differencing factors array for face gradient"
<< endl;
}
// Force the construction of the weighting factors
// needed to make sure deltaCoeffs are calculated for parallel runs.
(void)mesh_.weights();
tmp<surfaceScalarField> tdeltaCoeffs
(
new surfaceScalarField
(
IOobject
(
"deltaCoeffs",
mesh_.pointsInstance(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false // Do not register
),
mesh_,
dimless/dimLength
)
);
surfaceScalarField& deltaCoeffs = tdeltaCoeffs.ref();
deltaCoeffs.setOriented();
// Set local references to mesh data
const volVectorField& C = mesh_.C();
const labelUList& owner = mesh_.owner();
const labelUList& neighbour = mesh_.neighbour();
forAll(owner, facei)
{
deltaCoeffs[facei] = 1.0/mag(C[neighbour[facei]] - C[owner[facei]]);
}
surfaceScalarField::Boundary& deltaCoeffsBf =
deltaCoeffs.boundaryFieldRef();
forAll(deltaCoeffsBf, patchi)
{
const fvPatch& p = mesh_.boundary()[patchi];
deltaCoeffsBf[patchi] = 1.0/mag(p.delta());
// Optionally correct
p.makeDeltaCoeffs(deltaCoeffsBf[patchi]);
}
return tdeltaCoeffs;
}
Foam::tmp<Foam::surfaceScalarField>
Foam::basicFvGeometryScheme::nonOrthDeltaCoeffs() const
{
if (debug)
{
Pout<< "basicFvGeometryScheme::nonOrthDeltaCoeffs() : "
<< "Constructing differencing factors array for face gradient"
<< endl;
}
// Force the construction of the weighting factors
// needed to make sure deltaCoeffs are calculated for parallel runs.
weights();
tmp<surfaceScalarField> tnonOrthDeltaCoeffs
(
new surfaceScalarField
(
IOobject
(
"nonOrthDeltaCoeffs",
mesh_.pointsInstance(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false // Do not register
),
mesh_,
dimless/dimLength
)
);
surfaceScalarField& nonOrthDeltaCoeffs = tnonOrthDeltaCoeffs.ref();
nonOrthDeltaCoeffs.setOriented();
// Set local references to mesh data
const volVectorField& C = mesh_.C();
const labelUList& owner = mesh_.owner();
const labelUList& neighbour = mesh_.neighbour();
const surfaceVectorField& Sf = mesh_.Sf();
const surfaceScalarField& magSf = mesh_.magSf();
forAll(owner, facei)
{
vector delta = C[neighbour[facei]] - C[owner[facei]];
vector unitArea = Sf[facei]/magSf[facei];
// Standard cell-centre distance form
//NonOrthDeltaCoeffs[facei] = (unitArea & delta)/magSqr(delta);
// Slightly under-relaxed form
//NonOrthDeltaCoeffs[facei] = 1.0/mag(delta);
// More under-relaxed form
//NonOrthDeltaCoeffs[facei] = 1.0/(mag(unitArea & delta) + VSMALL);
// Stabilised form for bad meshes
nonOrthDeltaCoeffs[facei] = 1.0/max(unitArea & delta, 0.05*mag(delta));
}
surfaceScalarField::Boundary& nonOrthDeltaCoeffsBf =
nonOrthDeltaCoeffs.boundaryFieldRef();
forAll(nonOrthDeltaCoeffsBf, patchi)
{
fvsPatchScalarField& patchDeltaCoeffs = nonOrthDeltaCoeffsBf[patchi];
const fvPatch& p = patchDeltaCoeffs.patch();
const vectorField patchDeltas(mesh_.boundary()[patchi].delta());
forAll(p, patchFacei)
{
vector unitArea =
Sf.boundaryField()[patchi][patchFacei]
/magSf.boundaryField()[patchi][patchFacei];
const vector& delta = patchDeltas[patchFacei];
patchDeltaCoeffs[patchFacei] =
1.0/max(unitArea & delta, 0.05*mag(delta));
}
// Optionally correct
p.makeNonOrthoDeltaCoeffs(patchDeltaCoeffs);
}
return tnonOrthDeltaCoeffs;
}
Foam::tmp<Foam::surfaceVectorField>
Foam::basicFvGeometryScheme::nonOrthCorrectionVectors() const
{
if (debug)
{
Pout<< "surfaceInterpolation::makeNonOrthCorrectionVectors() : "
<< "Constructing non-orthogonal correction vectors"
<< endl;
}
tmp<surfaceVectorField> tnonOrthCorrectionVectors
(
new surfaceVectorField
(
IOobject
(
"nonOrthCorrectionVectors",
mesh_.pointsInstance(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false // Do not register
),
mesh_,
dimless
)
);
surfaceVectorField& corrVecs = tnonOrthCorrectionVectors.ref();
corrVecs.setOriented();
// Set local references to mesh data
const volVectorField& C = mesh_.C();
const labelUList& owner = mesh_.owner();
const labelUList& neighbour = mesh_.neighbour();
const surfaceVectorField& Sf = mesh_.Sf();
const surfaceScalarField& magSf = mesh_.magSf();
tmp<surfaceScalarField> tNonOrthDeltaCoeffs(nonOrthDeltaCoeffs());
const surfaceScalarField& NonOrthDeltaCoeffs = tNonOrthDeltaCoeffs();
forAll(owner, facei)
{
vector unitArea = Sf[facei]/magSf[facei];
vector delta = C[neighbour[facei]] - C[owner[facei]];
corrVecs[facei] = unitArea - delta*NonOrthDeltaCoeffs[facei];
}
// Boundary correction vectors set to zero for boundary patches
// and calculated consistently with internal corrections for
// coupled patches
surfaceVectorField::Boundary& corrVecsBf = corrVecs.boundaryFieldRef();
forAll(corrVecsBf, patchi)
{
fvsPatchVectorField& patchCorrVecs = corrVecsBf[patchi];
const fvPatch& p = patchCorrVecs.patch();
if (!patchCorrVecs.coupled())
{
patchCorrVecs = Zero;
}
else
{
const fvsPatchScalarField& patchNonOrthDeltaCoeffs =
NonOrthDeltaCoeffs.boundaryField()[patchi];
const vectorField patchDeltas(mesh_.boundary()[patchi].delta());
forAll(p, patchFacei)
{
vector unitArea =
Sf.boundaryField()[patchi][patchFacei]
/magSf.boundaryField()[patchi][patchFacei];
const vector& delta = patchDeltas[patchFacei];
patchCorrVecs[patchFacei] =
unitArea - delta*patchNonOrthDeltaCoeffs[patchFacei];
}
}
// Optionally correct
p.makeNonOrthoCorrVectors(patchCorrVecs);
}
if (debug)
{
Pout<< "surfaceInterpolation::makeNonOrthCorrectionVectors() : "
<< "Finished constructing non-orthogonal correction vectors"
<< endl;
}
return tnonOrthCorrectionVectors;
}
// ************************************************************************* //

View File

@ -0,0 +1,107 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::basicFvGeometryScheme
Description
Default geometry calculation scheme. Slight stabilisation for bad meshes.
SourceFiles
basicFvGeometryScheme.C
\*---------------------------------------------------------------------------*/
#ifndef basicFvGeometryScheme_H
#define basicFvGeometryScheme_H
#include "fvGeometryScheme.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class basicFvGeometryScheme Declaration
\*---------------------------------------------------------------------------*/
class basicFvGeometryScheme
:
public fvGeometryScheme
{
// Private Member Functions
//- No copy construct
basicFvGeometryScheme(const basicFvGeometryScheme&) = delete;
//- No copy assignment
void operator=(const basicFvGeometryScheme&) = delete;
public:
//- Runtime type information
TypeName("basic");
// Constructors
//- Construct from mesh
basicFvGeometryScheme(const fvMesh& mesh, const dictionary& dict);
//- Destructor
virtual ~basicFvGeometryScheme() = default;
// Member Functions
//- Do what is necessary if the mesh has moved
virtual void movePoints();
//- Return linear difference weighting factors
virtual tmp<surfaceScalarField> weights() const;
//- Return cell-centre difference coefficients
virtual tmp<surfaceScalarField> deltaCoeffs() const;
//- Return non-orthogonal cell-centre difference coefficients
virtual tmp<surfaceScalarField> nonOrthDeltaCoeffs() const;
//- Return non-orthogonality correction vectors
virtual tmp<surfaceVectorField> nonOrthCorrectionVectors() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,80 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "fvGeometryScheme.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(fvGeometryScheme, 0);
defineRunTimeSelectionTable(fvGeometryScheme, dict);
}
// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
Foam::tmp<Foam::fvGeometryScheme>
Foam::fvGeometryScheme::New
(
const fvMesh& mesh,
const dictionary& dict,
const word& defaultScheme
)
{
const entry* ePtr = dict.findEntry("method");
const word schemeName
(
ePtr
? word(ePtr->stream())
: dict.getOrDefault<word>("type", defaultScheme)
);
if (debug)
{
InfoInFunction << "Geometry scheme = " << schemeName << endl;
}
auto cstrIter = dictConstructorTablePtr_->cfind(schemeName);
if (!cstrIter.found())
{
FatalIOErrorInLookup
(
dict,
"fvGeometryScheme",
schemeName,
*dictConstructorTablePtr_
) << exit(FatalIOError);
}
return cstrIter()(mesh, dict);
}
// ************************************************************************* //

View File

@ -0,0 +1,164 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::fvGeometryScheme
Description
Abstract base class for geometry calculation schemes.
SourceFiles
fvGeometryScheme.C
\*---------------------------------------------------------------------------*/
#ifndef fvGeometryScheme_H
#define fvGeometryScheme_H
#include "tmp.H"
#include "surfaceFieldsFwd.H"
#include "typeInfo.H"
#include "runTimeSelectionTables.H"
#include "pointField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class fvMesh;
/*---------------------------------------------------------------------------*\
Class fvGeometryScheme Declaration
\*---------------------------------------------------------------------------*/
class fvGeometryScheme
:
public refCount
{
// Private Member Functions
//- No copy construct
fvGeometryScheme(const fvGeometryScheme&) = delete;
//- No copy assignment
void operator=(const fvGeometryScheme&) = delete;
protected:
//- Hold reference to mesh
const fvMesh& mesh_;
public:
//- Runtime type information
TypeName("fvGeometryScheme");
// Declare run-time constructor selection tables
declareRunTimeSelectionTable
(
tmp,
fvGeometryScheme,
dict,
(
const fvMesh& mesh,
const dictionary& dict
),
(mesh, dict)
);
// Constructors
//- Construct from mesh
fvGeometryScheme(const fvMesh& mesh, const dictionary& dict)
:
mesh_(mesh)
{}
// Selectors
//- Return new tmp interpolation scheme
static tmp<fvGeometryScheme> New
(
const fvMesh& mesh,
const dictionary& dict,
const word& defaultScheme
);
//- Destructor
virtual ~fvGeometryScheme() = default;
// Member Functions
//- Return mesh reference
const fvMesh& mesh() const
{
return mesh_;
}
//- Update basic geometric properties from provided points
virtual void movePoints()
{}
//- Return linear difference weighting factors
virtual tmp<surfaceScalarField> weights() const = 0;
//- Return cell-centre difference coefficients
virtual tmp<surfaceScalarField> deltaCoeffs() const = 0;
//- Return non-orthogonal cell-centre difference coefficients
virtual tmp<surfaceScalarField> nonOrthDeltaCoeffs() const = 0;
//- Return non-orthogonality correction vectors
virtual tmp<surfaceVectorField> nonOrthCorrectionVectors() const = 0;
////- Selector for wall distance method. WIP. Ideally return wall
//// distance or meshObject?
//virtual autoPtr<patchDistMethod> newPatchDistMethod
//(
// const dictionary& dict,
// const labelHashSet& patchIDs,
// const word& defaultPatchDistMethod
//) const = 0;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,123 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "cellAspectRatio.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(cellAspectRatio, 0);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::cellAspectRatio::cellAspectRatio(const polyMesh& mesh)
:
MeshObject<polyMesh, Foam::MoveableMeshObject, cellAspectRatio>(mesh)
{
calcAspectRatio();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::cellAspectRatio::~cellAspectRatio()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::cellAspectRatio::calcAspectRatio()
{
if (debug)
{
InfoInFunction << "Calculating cell aspect ratio" << endl;
}
const polyMesh& mesh = mesh_;
const pointField& cellCentres = mesh.cellCentres();
const scalarField& cellVolumes = mesh.cellVolumes();
const vectorField& faceAreas = mesh.faceAreas();
const vectorField& faceCentres = mesh.faceCentres();
const cellList& cells = mesh.cells();
//const faceList& faces = mesh.faces();
//const pointField& points = mesh.points();
scalarField& aRatio = *this;
aRatio.setSize(mesh.nCells());
forAll(cells, celli)
{
const point& cc = cellCentres[celli];
const cell& cFaces = cells[celli];
scalar sumA = Zero;
scalar maxMag = Zero;
for (const label facei : cFaces)
{
const vector& n = faceAreas[facei];
sumA += mag(n);
//// Max distance from point to cell centre
//const face& f = faces[facei];
//for (const label pointi : f)
//{
// const point& pt = points[pointi];
// const vector d(pt-cc);
// maxMag = max(maxMag, magSqr(d));
//}
// Max distance from face centre to cell centre
const point& fc = faceCentres[facei];
maxMag = max(maxMag, magSqr(fc-cc));
}
sumA /= cFaces.size();
// Local length scale
const scalar length = cellVolumes[celli]/sumA;
// Max edge length
maxMag = Foam::sqrt(maxMag);
//aRatio[celli] = Foam::sqrt(4.0/3.0)*maxMag/length;
aRatio[celli] = 2.0*maxMag/length;
}
if (debug)
{
InfoInFunction << "Calculated cell aspect ratio min:" << gMin(aRatio)
<< " max:" << gMax(aRatio) << " average:" << gAverage(aRatio)
<< endl;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,97 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::cellAspectRatio
Description
(Rough approximation of) cell aspect ratio
SourceFiles
cellAspectRatio.C
\*---------------------------------------------------------------------------*/
#ifndef cellAspectRatio_H
#define cellAspectRatio_H
#include "MeshObject.H"
#include "polyMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class cellAspectRatio Declaration
\*---------------------------------------------------------------------------*/
class cellAspectRatio
:
public MeshObject<polyMesh, MoveableMeshObject, cellAspectRatio>,
public scalarField
{
// Private Member Functions
//- Construct aspect ratio
void calcAspectRatio();
public:
// Declare name of the class and its debug switch
TypeName("cellAspectRatio");
// Constructors
//- Construct given an polyMesh
explicit cellAspectRatio(const polyMesh&);
//- Destructor
virtual ~cellAspectRatio();
// Member functions
//- Ignore mesh motion for now
virtual bool movePoints()
{
return false;
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,466 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "highAspectRatioFvGeometryScheme.H"
#include "addToRunTimeSelectionTable.H"
#include "fvMesh.H"
#include "syncTools.H"
#include "cellAspectRatio.H"
#include "emptyPolyPatch.H"
#include "wedgePolyPatch.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(highAspectRatioFvGeometryScheme, 0);
addToRunTimeSelectionTable
(
fvGeometryScheme,
highAspectRatioFvGeometryScheme,
dict
);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
//void Foam::highAspectRatioFvGeometryScheme::cellClosedness
//(
// const vectorField& areas,
// const scalarField& vols,
// const tensorField& cellCoords,
//
// scalarField& aratio
//) const
//{
// // From primitiveMeshTools::cellClosedness:
// // calculate aspect ratio in given direction
// const labelList& own = mesh_.faceOwner();
// const labelList& nei = mesh_.faceNeighbour();
//
// // Loop through cell faces and sum up the face area vectors for each cell.
// // This should be zero in all vector components
//
// vectorField sumMagClosed(mesh_.nCells(), Zero);
//
// forAll(own, facei)
// {
// // Add to owner
// vector& v = sumMagClosed[own[facei]];
// v += cmptMag(cellCoords[own[facei]] & areas[facei]);
// }
//
// forAll(nei, facei)
// {
// // Subtract from neighbour
// vector& v = sumMagClosed[nei[facei]];
// v += cmptMag(cellCoords[nei[facei]] & areas[facei]);
// }
//
// // Check the sums
// aratio.setSize(mesh_.nCells());
//
// forAll(sumMagClosed, celli)
// {
// // Calculate the aspect ration as the maximum of Cartesian component
// // aspect ratio to the total area hydraulic area aspect ratio
// scalar minCmpt = VGREAT;
// scalar maxCmpt = -VGREAT;
// for (direction dir = 0; dir < vector::nComponents; dir++)
// {
// minCmpt = min(minCmpt, sumMagClosed[celli][dir]);
// maxCmpt = max(maxCmpt, sumMagClosed[celli][dir]);
// }
//
// scalar aspectRatio = maxCmpt/(minCmpt + ROOTVSMALL);
// const scalar v = max(ROOTVSMALL, vols[celli]);
//
// aspectRatio = max
// (
// aspectRatio,
// 1.0/6.0*cmptSum(sumMagClosed[celli])/Foam::pow(v, 2.0/3.0)
// );
//
// aratio[celli] = aspectRatio;
// }
//}
//
//
//void Foam::highAspectRatioFvGeometryScheme::cellDirections
//(
// tensorField& T,
// vectorField& lambda
//) const
//{
// // Calculate principal directions in increasing order
//
// T.setSize(mesh_.nCells());
// lambda.setSize(mesh_.nCells());
//
// forAll(T, celli)
// {
// tensor J = Zero;
// {
// const List<tetIndices> cellTets
// (
// polyMeshTetDecomposition::cellTetIndices
// (
// mesh_,
// celli
// )
// );
// triFaceList faces(cellTets.size());
// forAll(cellTets, cTI)
// {
// faces[cTI] = cellTets[cTI].faceTriIs(mesh_);
// }
//
// scalar m = 0.0;
// vector cM = Zero;
// J = Zero;
// momentOfInertia::massPropertiesShell
// (
// mesh_.points(),
// faces,
// 1.0,
// m,
// cM,
// J
// );
// }
//
// lambda[celli] = Foam::eigenValues(J);
// T[celli] = Foam::eigenVectors(J, lambda[celli]);
// }
//}
void Foam::highAspectRatioFvGeometryScheme::calcAspectRatioWeights
(
scalarField& cellWeight,
scalarField& faceWeight
) const
{
//scalarField aratio;
//{
// tensorField principalDirections;
// vectorField lambdas;
// cellDirections(principalDirections, lambdas);
//
// cellClosedness
// (
// mesh_.faceAreas(),
// mesh_.cellVolumes(),
// principalDirections,
// aratio
// );
//}
const cellAspectRatio aratio(mesh_);
// Weighting for correction
// - 0 if aratio < minAspect_
// - 1 if aratio >= maxAspect_
scalar delta(maxAspect_-minAspect_);
if (delta < ROOTVSMALL)
{
delta = SMALL;
}
cellWeight =
max
(
min
(
(aratio-minAspect_)/delta,
1.0
),
0.0
);
faceWeight.setSize(mesh_.nFaces());
for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
{
const label own = mesh_.faceOwner()[facei];
const label nei = mesh_.faceNeighbour()[facei];
faceWeight[facei] = max(cellWeight[own], cellWeight[nei]);
}
scalarField nbrCellWeight;
syncTools::swapBoundaryCellList
(
mesh_,
cellWeight,
nbrCellWeight
);
for
(
label facei = mesh_.nInternalFaces();
facei < mesh_.nFaces();
facei++
)
{
const label own = mesh_.faceOwner()[facei];
const label bFacei = facei-mesh_.nInternalFaces();
faceWeight[facei] = max(cellWeight[own], nbrCellWeight[bFacei]);
}
}
void Foam::highAspectRatioFvGeometryScheme::makeAverageCentres
(
const polyMesh& mesh,
const pointField& p,
const pointField& faceAreas,
const scalarField& magFaceAreas,
pointField& faceCentres,
pointField& cellCentres
)
{
if (debug)
{
Pout<< "highAspectRatioFvGeometryScheme::makeAverageCentres() : "
<< "calculating weighted average face/cell centre" << endl;
}
typedef Vector<solveScalar> solveVector;
const faceList& fs = mesh.faces();
// Start off from primitiveMesh faceCentres (preserved for triangles)
faceCentres.setSize(mesh.nFaces());
forAll(fs, facei)
{
const labelList& f = fs[facei];
const label nPoints = f.size();
if (nPoints == 3)
{
faceCentres[facei] = (1.0/3.0)*(p[f[0]] + p[f[1]] + p[f[2]]);
}
else
{
solveScalar sumA = 0.0;
solveVector sumAc = Zero;
for (label pi = 0; pi < nPoints; pi++)
{
const label nextPi(pi == nPoints-1 ? 0 : pi+1);
const solveVector nextPoint(p[f[nextPi]]);
const solveVector thisPoint(p[f[pi]]);
const solveVector eMid = 0.5*(thisPoint+nextPoint);
const solveScalar a = mag(nextPoint-thisPoint);
sumAc += a*eMid;
sumA += a;
}
// This is to deal with zero-area faces. Mark very small faces
// to be detected in e.g. processorPolyPatch.
if (sumA >= ROOTVSMALL)
{
faceCentres[facei] = sumAc/sumA;
}
else
{
// Unweighted average of points
sumAc = Zero;
for (label pi = 0; pi < nPoints; pi++)
{
sumAc += p[f[pi]];
}
faceCentres[facei] = sumAc/nPoints;
}
}
}
cellCentres.setSize(mesh.nCells());
cellCentres = Zero;
{
const labelList& own = mesh.faceOwner();
const labelList& nei = mesh.faceNeighbour();
Field<solveScalar> cellWeights(mesh.nCells(), Zero);
for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
{
const solveScalar magfA(magFaceAreas[facei]);
const solveVector weightedFc(magfA*faceCentres[facei]);
// Accumulate area-weighted face-centre
cellCentres[own[facei]] += weightedFc;
cellCentres[nei[facei]] += weightedFc;
// Accumulate weights
cellWeights[own[facei]] += magfA;
cellWeights[nei[facei]] += magfA;
}
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
for (const polyPatch& pp : pbm)
{
if (!isA<emptyPolyPatch>(pp) && !isA<wedgePolyPatch>(pp))
{
for
(
label facei = pp.start();
facei < pp.start()+pp.size();
facei++
)
{
const solveScalar magfA(magFaceAreas[facei]);
const solveVector weightedFc(magfA*faceCentres[facei]);
cellCentres[own[facei]] += weightedFc;
cellWeights[own[facei]] += magfA;
}
}
}
forAll(cellCentres, celli)
{
if (mag(cellWeights[celli]) > VSMALL)
{
cellCentres[celli] /= cellWeights[celli];
}
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::highAspectRatioFvGeometryScheme::highAspectRatioFvGeometryScheme
(
const fvMesh& mesh,
const dictionary& dict
)
:
basicFvGeometryScheme(mesh, dict),
minAspect_(dict.get<scalar>("minAspect")),
maxAspect_(dict.get<scalar>("maxAspect"))
{
if (maxAspect_ < minAspect_)
{
FatalIOErrorInFunction(dict)
<< "minAspect " << minAspect_
<< " has to be less than maxAspect " << maxAspect_
<< exit(FatalIOError);
}
if (minAspect_ < 0 || maxAspect_ < 0)
{
FatalIOErrorInFunction(dict)
<< "Illegal aspect ratio : minAspect:" << minAspect_
<< " maxAspect:" << maxAspect_
<< exit(FatalIOError);
}
// Force local calculation
movePoints();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::highAspectRatioFvGeometryScheme::movePoints()
{
if (debug)
{
Pout<< "highAspectRatioFvGeometryScheme::movePoints() : "
<< "recalculating primitiveMesh centres" << endl;
}
if
(
!mesh_.hasCellCentres()
&& !mesh_.hasFaceCentres()
&& !mesh_.hasCellVolumes()
&& !mesh_.hasFaceAreas()
)
{
// Use lower level to calculate the geometry
const_cast<fvMesh&>(mesh_).primitiveMesh::updateGeom();
pointField avgFaceCentres;
pointField avgCellCentres;
makeAverageCentres
(
mesh_,
mesh_.points(),
mesh_.faceAreas(),
mag(mesh_.faceAreas()),
avgFaceCentres,
avgCellCentres
);
// Calculate aspectratio weights
// - 0 if aratio < minAspect_
// - 1 if aratio >= maxAspect_
scalarField cellWeight, faceWeight;
calcAspectRatioWeights(cellWeight, faceWeight);
// Weight with average ones
vectorField faceCentres
(
(1.0-faceWeight)*mesh_.faceCentres()
+ faceWeight*avgFaceCentres
);
vectorField cellCentres
(
(1.0-cellWeight)*mesh_.cellCentres()
+ cellWeight*avgCellCentres
);
if (debug)
{
Pout<< "highAspectRatioFvGeometryScheme::movePoints() :"
<< " highAspectRatio weight"
<< " max:" << gMax(cellWeight) << " min:" << gMin(cellWeight)
<< " average:" << gAverage(cellWeight) << endl;
}
vectorField faceAreas(mesh_.faceAreas());
scalarField cellVolumes(mesh_.cellVolumes());
// Store on primitiveMesh
//const_cast<fvMesh&>(mesh_).clearGeom();
const_cast<fvMesh&>(mesh_).primitiveMesh::resetGeometry
(
std::move(faceCentres),
std::move(faceAreas),
std::move(cellCentres),
std::move(cellVolumes)
);
}
}
// ************************************************************************* //

View File

@ -0,0 +1,137 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::highAspectRatioFvGeometryScheme
Description
Geometry calculation scheme with automatic stabilisation for high-aspect
ratio cells.
SourceFiles
highAspectRatioFvGeometryScheme.C
\*---------------------------------------------------------------------------*/
#ifndef highAspectRatioFvGeometryScheme_H
#define highAspectRatioFvGeometryScheme_H
#include "basicFvGeometryScheme.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class primitiveMesh;
class polyMesh;
/*---------------------------------------------------------------------------*\
Class highAspectRatioFvGeometryScheme Declaration
\*---------------------------------------------------------------------------*/
class highAspectRatioFvGeometryScheme
:
public basicFvGeometryScheme
{
protected:
const scalar minAspect_;
const scalar maxAspect_;
// Protected Member Functions
//- Calculate cell and face weight. Is 0 for cell < minAspect, 1 for
// cell > maxAspect
void calcAspectRatioWeights
(
scalarField& cellWeight,
scalarField& faceWeight
) const;
//- Helper : calculate (weighted) average face and cell centres
static void makeAverageCentres
(
const polyMesh& mesh,
const pointField& points,
const pointField& faceAreas,
const scalarField& magFaceAreas,
pointField& faceCentres,
pointField& cellCentres
);
private:
// Private Member Functions
//- No copy construct
highAspectRatioFvGeometryScheme
(
const highAspectRatioFvGeometryScheme&
) = delete;
//- No copy assignment
void operator=(const highAspectRatioFvGeometryScheme&) = delete;
public:
//- Runtime type information
TypeName("highAspectRatio");
// Constructors
//- Construct from mesh
highAspectRatioFvGeometryScheme
(
const fvMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~highAspectRatioFvGeometryScheme() = default;
// Member Functions
//- Do what is necessary if the mesh has moved
virtual void movePoints();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,210 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "stabilisedFvGeometryScheme.H"
#include "addToRunTimeSelectionTable.H"
#include "fvMesh.H"
#include "PrecisionAdaptor.H"
#include "primitiveMeshTools.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(stabilisedFvGeometryScheme, 0);
addToRunTimeSelectionTable
(
fvGeometryScheme,
stabilisedFvGeometryScheme,
dict
);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::stabilisedFvGeometryScheme::makeFaceCentresAndAreas
(
const polyMesh& mesh,
const pointField& p,
vectorField& fCtrs,
vectorField& fAreas
)
{
const faceList& fs = mesh.faces();
forAll(fs, facei)
{
const labelList& f = fs[facei];
label nPoints = f.size();
// If the face is a triangle, do a direct calculation for efficiency
// and to avoid round-off error-related problems
if (nPoints == 3)
{
fCtrs[facei] = (1.0/3.0)*(p[f[0]] + p[f[1]] + p[f[2]]);
fAreas[facei] = 0.5*((p[f[1]] - p[f[0]])^(p[f[2]] - p[f[0]]));
}
// For more complex faces, decompose into triangles
else
{
typedef Vector<solveScalar> solveVector;
// Compute an estimate of the centre as the average of the points
solveVector fCentre = p[f[0]];
for (label pi = 1; pi < nPoints; pi++)
{
fCentre += solveVector(p[f[pi]]);
}
fCentre /= nPoints;
// Compute the face area normal and unit normal by summing up the
// normals of the triangles formed by connecting each edge to the
// point average.
solveVector sumA = Zero;
for (label pi = 0; pi < nPoints; pi++)
{
const label nextPi(pi == nPoints-1 ? 0 : pi+1);
const solveVector nextPoint(p[f[nextPi]]);
const solveVector thisPoint(p[f[pi]]);
const solveVector a =
(nextPoint - thisPoint)^(fCentre - thisPoint);
sumA += a;
}
const solveVector sumAHat = normalised(sumA);
// Compute the area-weighted sum of the triangle centres. Note use
// the triangle area projected in the direction of the face normal
// as the weight, *not* the triangle area magnitude. Only the
// former makes the calculation independent of the initial estimate.
solveScalar sumAn = 0.0;
solveVector sumAnc = Zero;
for (label pi = 0; pi < nPoints; pi++)
{
const label nextPi(pi == nPoints-1 ? 0 : pi+1);
const solveVector nextPoint(p[f[nextPi]]);
const solveVector thisPoint(p[f[pi]]);
const solveVector c = thisPoint + nextPoint + fCentre;
const solveVector a =
(nextPoint - thisPoint)^(fCentre - thisPoint);
const scalar an = a & sumAHat;
sumAn += an;
sumAnc += an*c;
}
// Complete calculating centres and areas. If the face is too small
// for the sums to be reliably divided then just set the centre to
// the initial estimate.
if (sumAn > ROOTVSMALL)
{
fCtrs[facei] = (1.0/3.0)*sumAnc/sumAn;
}
else
{
fCtrs[facei] = fCentre;
}
fAreas[facei] = 0.5*sumA;
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::stabilisedFvGeometryScheme::stabilisedFvGeometryScheme
(
const fvMesh& mesh,
const dictionary& dict
)
:
basicFvGeometryScheme(mesh, dict)
{
// Force local calculation
movePoints();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::stabilisedFvGeometryScheme::movePoints()
{
if (debug)
{
Pout<< "stabilisedFvGeometryScheme::movePoints() : "
<< "recalculating primitiveMesh centres" << endl;
}
if
(
!mesh_.hasCellCentres()
&& !mesh_.hasFaceCentres()
&& !mesh_.hasCellVolumes()
&& !mesh_.hasFaceAreas()
)
{
vectorField faceCentres(mesh_.nFaces());
vectorField faceAreas(mesh_.nFaces());
makeFaceCentresAndAreas
(
mesh_,
mesh_.points(),
faceCentres,
faceAreas
);
vectorField cellCentres(mesh_.nCells());
scalarField cellVolumes(mesh_.nCells());
primitiveMeshTools::makeCellCentresAndVols
(
mesh_,
faceCentres,
faceAreas,
cellCentres,
cellVolumes
);
const_cast<fvMesh&>(mesh_).primitiveMesh::resetGeometry
(
std::move(faceCentres),
std::move(faceAreas),
std::move(cellCentres),
std::move(cellVolumes)
);
}
}
// ************************************************************************* //

View File

@ -0,0 +1,126 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::stabilisedFvGeometryScheme
Description
Geometry calculation scheme that implements face geometry calculation
using normal-component-of-area weighted triangle contributions.
This implements the Foundation 'Corrected face-centre calculations'
as a separate geometry scheme. Only implements the primitiveMesh parts,
not the individual face calculation.
SourceFiles
stabilisedFvGeometryScheme.C
\*---------------------------------------------------------------------------*/
#ifndef stabilisedFvGeometryScheme_H
#define stabilisedFvGeometryScheme_H
#include "basicFvGeometryScheme.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class primitiveMesh;
class polyMesh;
/*---------------------------------------------------------------------------*\
Class stabilisedFvGeometryScheme Declaration
\*---------------------------------------------------------------------------*/
class stabilisedFvGeometryScheme
:
public basicFvGeometryScheme
{
protected:
// Protected Member Functions
//- Calculate face area and centre weighted using pyramid height
static void makeFaceCentresAndAreas
(
const polyMesh& mesh,
const pointField& p,
vectorField& fCtrs,
vectorField& fAreas
);
private:
// Private Member Functions
//- No copy construct
stabilisedFvGeometryScheme
(
const stabilisedFvGeometryScheme&
) = delete;
//- No copy assignment
void operator=(const stabilisedFvGeometryScheme&) = delete;
public:
//- Runtime type information
TypeName("stabilised");
// Constructors
//- Construct from mesh
stabilisedFvGeometryScheme
(
const fvMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~stabilisedFvGeometryScheme() = default;
// Member Functions
//- Do what is necessary if the mesh has moved
virtual void movePoints();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -240,11 +240,11 @@ void Foam::fvMesh::clearOut()
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fvMesh::fvMesh(const IOobject& io) Foam::fvMesh::fvMesh(const IOobject& io, const bool doInit)
: :
polyMesh(io), polyMesh(io, doInit),
surfaceInterpolation(*this),
fvSchemes(static_cast<const objectRegistry&>(*this)), fvSchemes(static_cast<const objectRegistry&>(*this)),
surfaceInterpolation(*this),
fvSolution(static_cast<const objectRegistry&>(*this)), fvSolution(static_cast<const objectRegistry&>(*this)),
data(static_cast<const objectRegistry&>(*this)), data(static_cast<const objectRegistry&>(*this)),
boundary_(*this, boundaryMesh()), boundary_(*this, boundaryMesh()),
@ -261,6 +261,25 @@ Foam::fvMesh::fvMesh(const IOobject& io)
{ {
DebugInFunction << "Constructing fvMesh from IOobject" << endl; DebugInFunction << "Constructing fvMesh from IOobject" << endl;
if (doInit)
{
fvMesh::init(false); // do not initialise lower levels
}
}
bool Foam::fvMesh::init(const bool doInit)
{
if (doInit)
{
// Construct basic geometry calculation engine. Note: do before
// doing anything with primitiveMesh::cellCentres etc.
(void)geometry();
// Intialise my data
polyMesh::init(doInit);
}
// Check the existence of the cell volumes and read if present // Check the existence of the cell volumes and read if present
// and set the storage of V00 // and set the storage of V00
if (fileHandler().isFile(time().timePath()/dbDir()/"V0")) if (fileHandler().isFile(time().timePath()/dbDir()/"V0"))
@ -322,6 +341,7 @@ Foam::fvMesh::fvMesh(const IOobject& io)
moving(true); moving(true);
} }
return false;
} }
@ -344,11 +364,11 @@ Foam::fvMesh::fvMesh
std::move(allNeighbour), std::move(allNeighbour),
syncPar syncPar
), ),
surfaceInterpolation(*this),
fvSchemes(static_cast<const objectRegistry&>(*this)), fvSchemes(static_cast<const objectRegistry&>(*this)),
surfaceInterpolation(*this),
fvSolution(static_cast<const objectRegistry&>(*this)), fvSolution(static_cast<const objectRegistry&>(*this)),
data(static_cast<const objectRegistry&>(*this)), data(static_cast<const objectRegistry&>(*this)),
boundary_(*this, boundaryMesh()), boundary_(*this),
lduPtr_(nullptr), lduPtr_(nullptr),
curTimeIndex_(time().timeIndex()), curTimeIndex_(time().timeIndex()),
VPtr_(nullptr), VPtr_(nullptr),
@ -381,8 +401,8 @@ Foam::fvMesh::fvMesh
std::move(cells), std::move(cells),
syncPar syncPar
), ),
surfaceInterpolation(*this),
fvSchemes(static_cast<const objectRegistry&>(*this)), fvSchemes(static_cast<const objectRegistry&>(*this)),
surfaceInterpolation(*this),
fvSolution(static_cast<const objectRegistry&>(*this)), fvSolution(static_cast<const objectRegistry&>(*this)),
data(static_cast<const objectRegistry&>(*this)), data(static_cast<const objectRegistry&>(*this)),
boundary_(*this), boundary_(*this),
@ -407,6 +427,108 @@ Foam::fvMesh::fvMesh(const IOobject& io, const zero, const bool syncPar)
{} {}
Foam::fvMesh::fvMesh
(
const IOobject& io,
const fvMesh& baseMesh,
pointField&& points,
faceList&& faces,
labelList&& allOwner,
labelList&& allNeighbour,
const bool syncPar
)
:
polyMesh
(
io,
std::move(points),
std::move(faces),
std::move(allOwner),
std::move(allNeighbour),
syncPar
),
fvSchemes
(
static_cast<const objectRegistry&>(*this),
static_cast<const fvSchemes&>(baseMesh)
),
surfaceInterpolation(*this),
fvSolution
(
static_cast<const objectRegistry&>(*this),
static_cast<const fvSolution&>(baseMesh)
),
data
(
static_cast<const objectRegistry&>(*this),
static_cast<const data&>(baseMesh)
),
boundary_(*this),
lduPtr_(nullptr),
curTimeIndex_(time().timeIndex()),
VPtr_(nullptr),
V0Ptr_(nullptr),
V00Ptr_(nullptr),
SfPtr_(nullptr),
magSfPtr_(nullptr),
CPtr_(nullptr),
CfPtr_(nullptr),
phiPtr_(nullptr)
{
DebugInFunction << "Constructing fvMesh as copy and primitives" << endl;
}
Foam::fvMesh::fvMesh
(
const IOobject& io,
const fvMesh& baseMesh,
pointField&& points,
faceList&& faces,
cellList&& cells,
const bool syncPar
)
:
polyMesh
(
io,
std::move(points),
std::move(faces),
std::move(cells),
syncPar
),
fvSchemes
(
static_cast<const objectRegistry&>(*this),
static_cast<const fvSchemes&>(baseMesh)
),
surfaceInterpolation(*this),
fvSolution
(
static_cast<const objectRegistry&>(*this),
static_cast<const fvSolution&>(baseMesh)
),
data
(
static_cast<const objectRegistry&>(*this),
static_cast<const data&>(baseMesh)
),
boundary_(*this),
lduPtr_(nullptr),
curTimeIndex_(time().timeIndex()),
VPtr_(nullptr),
V0Ptr_(nullptr),
V00Ptr_(nullptr),
SfPtr_(nullptr),
magSfPtr_(nullptr),
CPtr_(nullptr),
CfPtr_(nullptr),
phiPtr_(nullptr)
{
DebugInFunction << "Constructing fvMesh as copy and primitives" << endl;
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::fvMesh::~fvMesh() Foam::fvMesh::~fvMesh()
@ -804,6 +926,13 @@ Foam::tmp<Foam::scalarField> Foam::fvMesh::movePoints(const pointField& p)
} }
void Foam::fvMesh::updateGeom()
{
// Let surfaceInterpolation handle geometry calculation
surfaceInterpolation::updateGeom();
}
void Foam::fvMesh::updateMesh(const mapPolyMesh& mpm) void Foam::fvMesh::updateMesh(const mapPolyMesh& mpm)
{ {
DebugInFunction << endl; DebugInFunction << endl;

View File

@ -77,7 +77,6 @@ class volMesh;
template<class Type> template<class Type>
class fvMatrix; class fvMatrix;
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class fvMesh Declaration Class fvMesh Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -86,8 +85,8 @@ class fvMesh
: :
public polyMesh, public polyMesh,
public lduMesh, public lduMesh,
public surfaceInterpolation,
public fvSchemes, public fvSchemes,
public surfaceInterpolation, // needs input from fvSchemes
public fvSolution, public fvSolution,
public data public data
{ {
@ -98,7 +97,6 @@ protected:
//- Boundary mesh //- Boundary mesh
fvBoundaryMesh boundary_; fvBoundaryMesh boundary_;
// Demand-driven data // Demand-driven data
mutable fvMeshLduAddressing* lduPtr_; mutable fvMeshLduAddressing* lduPtr_;
@ -186,7 +184,7 @@ public:
// Constructors // Constructors
//- Construct from IOobject //- Construct from IOobject
explicit fvMesh(const IOobject& io); explicit fvMesh(const IOobject& io, const bool doInit=true);
//- Construct from IOobject or as zero-sized mesh //- Construct from IOobject or as zero-sized mesh
// Boundary is added using addFvPatches() member function // Boundary is added using addFvPatches() member function
@ -215,6 +213,32 @@ public:
const bool syncPar = true const bool syncPar = true
); );
//- Construct as copy (for dictionaries) and components without
// boundary. Boundary is added using addFvPatches() member function
fvMesh
(
const IOobject& io,
const fvMesh& baseMesh,
pointField&& points,
faceList&& faces,
labelList&& allOwner,
labelList&& allNeighbour,
const bool syncPar = true
);
//- Construct as copy (for dictionaries) without boundary from cells
// rather than owner/neighbour. Boundary is added using addFvPatches()
// member function
fvMesh
(
const IOobject& io,
const fvMesh& baseMesh,
pointField&& points,
faceList&& faces,
cellList&& cells,
const bool syncPar = true
);
//- Destructor //- Destructor
virtual ~fvMesh(); virtual ~fvMesh();
@ -224,6 +248,9 @@ public:
// Helpers // Helpers
//- Initialise all non-demand-driven data
virtual bool init(const bool doInit);
//- Add boundary patches. Constructor helper //- Add boundary patches. Constructor helper
void addFvPatches void addFvPatches
( (
@ -438,6 +465,10 @@ public:
//- Move points, returns volumes swept by faces in motion //- Move points, returns volumes swept by faces in motion
virtual tmp<scalarField> movePoints(const pointField&); virtual tmp<scalarField> movePoints(const pointField&);
//- Update all geometric data. This gets redirected up from
// primitiveMesh level
virtual void updateGeom();
//- Map all fields in time using given map. //- Map all fields in time using given map.
virtual void mapFields(const mapPolyMesh& mpm); virtual void mapFields(const mapPolyMesh& mpm);

View File

@ -74,7 +74,16 @@ class fvPatch
const fvBoundaryMesh& boundaryMesh_; const fvBoundaryMesh& boundaryMesh_;
protected: // Private Member Functions
//- No copy construct
fvPatch(const fvPatch&) = delete;
//- No copy assignment
void operator=(const fvPatch&) = delete;
public:
// Protected Member Functions // Protected Member Functions
@ -96,11 +105,6 @@ protected:
//- Correct patches after moving points //- Correct patches after moving points
virtual void movePoints(); virtual void movePoints();
//- No copy construct
fvPatch(const fvPatch&) = delete;
//- No copy assignment
void operator=(const fvPatch&) = delete;
public: public:

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017 OpenCFD Ltd. Copyright (C) 2017-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -29,11 +29,12 @@ Description
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "surfaceInterpolation.H"
#include "fvMesh.H" #include "fvMesh.H"
#include "volFields.H" #include "volFields.H"
#include "surfaceFields.H" #include "surfaceFields.H"
#include "demandDrivenData.H"
#include "coupledFvPatch.H" #include "coupledFvPatch.H"
#include "basicFvGeometryScheme.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -47,10 +48,10 @@ namespace Foam
void Foam::surfaceInterpolation::clearOut() void Foam::surfaceInterpolation::clearOut()
{ {
deleteDemandDrivenData(weights_); weights_.clear();
deleteDemandDrivenData(deltaCoeffs_); deltaCoeffs_.clear();
deleteDemandDrivenData(nonOrthDeltaCoeffs_); nonOrthDeltaCoeffs_.clear();
deleteDemandDrivenData(nonOrthCorrectionVectors_); nonOrthCorrectionVectors_.clear();
} }
@ -76,358 +77,107 @@ Foam::surfaceInterpolation::~surfaceInterpolation()
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::surfaceScalarField& Foam::surfaceInterpolation::weights() const const Foam::fvGeometryScheme& Foam::surfaceInterpolation::geometry() const
{ {
if (!weights_) if (!geometryPtr_.valid())
{ {
makeWeights(); geometryPtr_ = fvGeometryScheme::New
(
mesh_,
mesh_.schemesDict().subOrEmptyDict("geometry"),
basicFvGeometryScheme::typeName
);
} }
return (*weights_); return geometryPtr_();
}
void Foam::surfaceInterpolation::geometry(tmp<fvGeometryScheme>& schemePtr)
{
geometryPtr_ = schemePtr;
}
const Foam::surfaceScalarField& Foam::surfaceInterpolation::weights() const
{
if (!weights_.valid())
{
weights_.set(geometry().weights().ptr());
}
return weights_();
} }
const Foam::surfaceScalarField& Foam::surfaceInterpolation::deltaCoeffs() const const Foam::surfaceScalarField& Foam::surfaceInterpolation::deltaCoeffs() const
{ {
if (!deltaCoeffs_) if (!deltaCoeffs_.valid())
{ {
makeDeltaCoeffs(); deltaCoeffs_.set(geometry().deltaCoeffs().ptr());
} }
return (*deltaCoeffs_); return deltaCoeffs_();
} }
const Foam::surfaceScalarField& const Foam::surfaceScalarField&
Foam::surfaceInterpolation::nonOrthDeltaCoeffs() const Foam::surfaceInterpolation::nonOrthDeltaCoeffs() const
{ {
if (!nonOrthDeltaCoeffs_) if (!nonOrthDeltaCoeffs_.valid())
{ {
makeNonOrthDeltaCoeffs(); nonOrthDeltaCoeffs_.set(geometry().nonOrthDeltaCoeffs().ptr());
} }
return (*nonOrthDeltaCoeffs_); return nonOrthDeltaCoeffs_();
} }
const Foam::surfaceVectorField& const Foam::surfaceVectorField&
Foam::surfaceInterpolation::nonOrthCorrectionVectors() const Foam::surfaceInterpolation::nonOrthCorrectionVectors() const
{ {
if (!nonOrthCorrectionVectors_) if (!nonOrthCorrectionVectors_.valid())
{ {
makeNonOrthCorrectionVectors(); nonOrthCorrectionVectors_.set
(
geometry().nonOrthCorrectionVectors().ptr()
);
} }
return (*nonOrthCorrectionVectors_); return nonOrthCorrectionVectors_();
} }
bool Foam::surfaceInterpolation::movePoints() bool Foam::surfaceInterpolation::movePoints()
{ {
deleteDemandDrivenData(weights_); if (debug)
deleteDemandDrivenData(deltaCoeffs_); {
deleteDemandDrivenData(nonOrthDeltaCoeffs_); Pout<< "surfaceInterpolation::movePoints() : "
deleteDemandDrivenData(nonOrthCorrectionVectors_); << "Updating geometric properties using the fvGeometryScheme"
<< endl;
}
// Do any primitive geometry calculation
const_cast<fvGeometryScheme&>(geometry()).movePoints();
weights_.clear();
deltaCoeffs_.clear();
nonOrthDeltaCoeffs_.clear();
nonOrthCorrectionVectors_.clear();
return true; return true;
} }
void Foam::surfaceInterpolation::makeWeights() const void Foam::surfaceInterpolation::updateGeom()
{ {
if (debug) if (debug)
{ {
Pout<< "surfaceInterpolation::makeWeights() : " Pout<< "surfaceInterpolation::updateGeom() : "
<< "Constructing weighting factors for face interpolation" << "Updating geometric properties" << endl;
<< endl;
} }
weights_ = new surfaceScalarField const_cast<fvGeometryScheme&>(geometry()).movePoints();
(
IOobject
(
"weights",
mesh_.pointsInstance(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false // Do not register
),
mesh_,
dimless
);
surfaceScalarField& weights = *weights_;
weights.setOriented();
// Set local references to mesh data
// Note that we should not use fvMesh sliced fields at this point yet
// since this causes a loop when generating weighting factors in
// coupledFvPatchField evaluation phase
const labelUList& owner = mesh_.owner();
const labelUList& neighbour = mesh_.neighbour();
const vectorField& Cf = mesh_.faceCentres();
const vectorField& C = mesh_.cellCentres();
const vectorField& Sf = mesh_.faceAreas();
// ... and reference to the internal field of the weighting factors
scalarField& w = weights.primitiveFieldRef();
forAll(owner, facei)
{
// Note: mag in the dot-product.
// For all valid meshes, the non-orthogonality will be less than
// 90 deg and the dot-product will be positive. For invalid
// meshes (d & s <= 0), this will stabilise the calculation
// but the result will be poor.
scalar SfdOwn = mag(Sf[facei] & (Cf[facei] - C[owner[facei]]));
scalar SfdNei = mag(Sf[facei] & (C[neighbour[facei]] - Cf[facei]));
w[facei] = SfdNei/(SfdOwn + SfdNei);
}
surfaceScalarField::Boundary& wBf = weights.boundaryFieldRef();
forAll(mesh_.boundary(), patchi)
{
mesh_.boundary()[patchi].makeWeights(wBf[patchi]);
}
if (debug)
{
Pout<< "surfaceInterpolation::makeWeights() : "
<< "Finished constructing weighting factors for face interpolation"
<< endl;
}
}
void Foam::surfaceInterpolation::makeDeltaCoeffs() const
{
if (debug)
{
Pout<< "surfaceInterpolation::makeDeltaCoeffs() : "
<< "Constructing differencing factors array for face gradient"
<< endl;
}
// Force the construction of the weighting factors
// needed to make sure deltaCoeffs are calculated for parallel runs.
weights();
deltaCoeffs_ = new surfaceScalarField
(
IOobject
(
"deltaCoeffs",
mesh_.pointsInstance(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false // Do not register
),
mesh_,
dimless/dimLength
);
surfaceScalarField& deltaCoeffs = *deltaCoeffs_;
deltaCoeffs.setOriented();
// Set local references to mesh data
const volVectorField& C = mesh_.C();
const labelUList& owner = mesh_.owner();
const labelUList& neighbour = mesh_.neighbour();
forAll(owner, facei)
{
deltaCoeffs[facei] = 1.0/mag(C[neighbour[facei]] - C[owner[facei]]);
}
surfaceScalarField::Boundary& deltaCoeffsBf =
deltaCoeffs.boundaryFieldRef();
forAll(deltaCoeffsBf, patchi)
{
const fvPatch& p = mesh_.boundary()[patchi];
deltaCoeffsBf[patchi] = 1.0/mag(p.delta());
// Optionally correct
p.makeDeltaCoeffs(deltaCoeffsBf[patchi]);
}
}
void Foam::surfaceInterpolation::makeNonOrthDeltaCoeffs() const
{
if (debug)
{
Pout<< "surfaceInterpolation::makeNonOrthDeltaCoeffs() : "
<< "Constructing differencing factors array for face gradient"
<< endl;
}
// Force the construction of the weighting factors
// needed to make sure deltaCoeffs are calculated for parallel runs.
weights();
nonOrthDeltaCoeffs_ = new surfaceScalarField
(
IOobject
(
"nonOrthDeltaCoeffs",
mesh_.pointsInstance(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false // Do not register
),
mesh_,
dimless/dimLength
);
surfaceScalarField& nonOrthDeltaCoeffs = *nonOrthDeltaCoeffs_;
nonOrthDeltaCoeffs.setOriented();
// Set local references to mesh data
const volVectorField& C = mesh_.C();
const labelUList& owner = mesh_.owner();
const labelUList& neighbour = mesh_.neighbour();
const surfaceVectorField& Sf = mesh_.Sf();
const surfaceScalarField& magSf = mesh_.magSf();
forAll(owner, facei)
{
vector delta = C[neighbour[facei]] - C[owner[facei]];
vector unitArea = Sf[facei]/magSf[facei];
// Standard cell-centre distance form
//NonOrthDeltaCoeffs[facei] = (unitArea & delta)/magSqr(delta);
// Slightly under-relaxed form
//NonOrthDeltaCoeffs[facei] = 1.0/mag(delta);
// More under-relaxed form
//NonOrthDeltaCoeffs[facei] = 1.0/(mag(unitArea & delta) + VSMALL);
// Stabilised form for bad meshes
nonOrthDeltaCoeffs[facei] = 1.0/max(unitArea & delta, 0.05*mag(delta));
}
surfaceScalarField::Boundary& nonOrthDeltaCoeffsBf =
nonOrthDeltaCoeffs.boundaryFieldRef();
forAll(nonOrthDeltaCoeffsBf, patchi)
{
fvsPatchScalarField& patchDeltaCoeffs = nonOrthDeltaCoeffsBf[patchi];
const fvPatch& p = patchDeltaCoeffs.patch();
const vectorField patchDeltas(mesh_.boundary()[patchi].delta());
forAll(p, patchFacei)
{
vector unitArea =
Sf.boundaryField()[patchi][patchFacei]
/magSf.boundaryField()[patchi][patchFacei];
const vector& delta = patchDeltas[patchFacei];
patchDeltaCoeffs[patchFacei] =
1.0/max(unitArea & delta, 0.05*mag(delta));
}
// Optionally correct
p.makeNonOrthoDeltaCoeffs(patchDeltaCoeffs);
}
}
void Foam::surfaceInterpolation::makeNonOrthCorrectionVectors() const
{
if (debug)
{
Pout<< "surfaceInterpolation::makeNonOrthCorrectionVectors() : "
<< "Constructing non-orthogonal correction vectors"
<< endl;
}
nonOrthCorrectionVectors_ = new surfaceVectorField
(
IOobject
(
"nonOrthCorrectionVectors",
mesh_.pointsInstance(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false // Do not register
),
mesh_,
dimless
);
surfaceVectorField& corrVecs = *nonOrthCorrectionVectors_;
corrVecs.setOriented();
// Set local references to mesh data
const volVectorField& C = mesh_.C();
const labelUList& owner = mesh_.owner();
const labelUList& neighbour = mesh_.neighbour();
const surfaceVectorField& Sf = mesh_.Sf();
const surfaceScalarField& magSf = mesh_.magSf();
const surfaceScalarField& NonOrthDeltaCoeffs = nonOrthDeltaCoeffs();
forAll(owner, facei)
{
vector unitArea = Sf[facei]/magSf[facei];
vector delta = C[neighbour[facei]] - C[owner[facei]];
corrVecs[facei] = unitArea - delta*NonOrthDeltaCoeffs[facei];
}
// Boundary correction vectors set to zero for boundary patches
// and calculated consistently with internal corrections for
// coupled patches
surfaceVectorField::Boundary& corrVecsBf = corrVecs.boundaryFieldRef();
forAll(corrVecsBf, patchi)
{
fvsPatchVectorField& patchCorrVecs = corrVecsBf[patchi];
const fvPatch& p = patchCorrVecs.patch();
if (!patchCorrVecs.coupled())
{
patchCorrVecs = Zero;
}
else
{
const fvsPatchScalarField& patchNonOrthDeltaCoeffs =
NonOrthDeltaCoeffs.boundaryField()[patchi];
const vectorField patchDeltas(mesh_.boundary()[patchi].delta());
forAll(p, patchFacei)
{
vector unitArea =
Sf.boundaryField()[patchi][patchFacei]
/magSf.boundaryField()[patchi][patchFacei];
const vector& delta = patchDeltas[patchFacei];
patchCorrVecs[patchFacei] =
unitArea - delta*patchNonOrthDeltaCoeffs[patchFacei];
}
}
// Optionally correct
p.makeNonOrthoCorrVectors(patchCorrVecs);
}
if (debug)
{
Pout<< "surfaceInterpolation::makeNonOrthCorrectionVectors() : "
<< "Finished constructing non-orthogonal correction vectors"
<< endl;
}
} }

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -48,8 +49,11 @@ SourceFiles
namespace Foam namespace Foam
{ {
class fvMesh;
class fvGeometryScheme;
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class surfaceInterpolation Declaration Class surfaceInterpolation Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
class surfaceInterpolation class surfaceInterpolation
@ -59,34 +63,23 @@ class surfaceInterpolation
// Reference to fvMesh // Reference to fvMesh
const fvMesh& mesh_; const fvMesh& mesh_;
// Demand-driven data // Demand-driven data
//- Geometry calculation
mutable tmp<fvGeometryScheme> geometryPtr_;
//- Linear difference weighting factors //- Linear difference weighting factors
mutable surfaceScalarField* weights_; mutable autoPtr<surfaceScalarField> weights_;
//- Cell-centre difference coefficients //- Cell-centre difference coefficients
mutable surfaceScalarField* deltaCoeffs_; mutable autoPtr<surfaceScalarField> deltaCoeffs_;
//- Non-orthogonal cell-centre difference coefficients //- Non-orthogonal cell-centre difference coefficients
mutable surfaceScalarField* nonOrthDeltaCoeffs_; mutable autoPtr<surfaceScalarField> nonOrthDeltaCoeffs_;
//- Non-orthogonality correction vectors //- Non-orthogonality correction vectors
mutable surfaceVectorField* nonOrthCorrectionVectors_; mutable autoPtr<surfaceVectorField> nonOrthCorrectionVectors_;
// Private Member Functions
//- Construct central-differencing weighting factors
void makeWeights() const;
//- Construct face-gradient difference factors
void makeDeltaCoeffs() const;
//- Construct face-gradient difference factors
void makeNonOrthDeltaCoeffs() const;
//- Construct non-orthogonality correction vectors
void makeNonOrthCorrectionVectors() const;
protected: protected:
@ -112,26 +105,35 @@ public:
//- Destructor //- Destructor
~surfaceInterpolation(); virtual ~surfaceInterpolation();
// Member functions // Member functions
//- Return reference to geometry calculation scheme
virtual const fvGeometryScheme& geometry() const;
//- Set geometry calculation scheme
void geometry(tmp<fvGeometryScheme>&);
//- Return reference to linear difference weighting factors //- Return reference to linear difference weighting factors
const surfaceScalarField& weights() const; virtual const surfaceScalarField& weights() const;
//- Return reference to cell-centre difference coefficients //- Return reference to cell-centre difference coefficients
const surfaceScalarField& deltaCoeffs() const; virtual const surfaceScalarField& deltaCoeffs() const;
//- Return reference to non-orthogonal cell-centre difference //- Return reference to non-orthogonal cell-centre difference
// coefficients // coefficients
const surfaceScalarField& nonOrthDeltaCoeffs() const; virtual const surfaceScalarField& nonOrthDeltaCoeffs() const;
//- Return reference to non-orthogonality correction vectors //- Return reference to non-orthogonality correction vectors
const surfaceVectorField& nonOrthCorrectionVectors() const; virtual const surfaceVectorField& nonOrthCorrectionVectors() const;
//- Do what is necessary if the mesh has moved //- Do what is necessary if the mesh has moved
bool movePoints(); virtual bool movePoints();
//- Update all geometric data
virtual void updateGeom();
}; };

View File

@ -35,6 +35,20 @@ License
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::Enum
<
Foam::layerParameters::thicknessModelType
>
Foam::layerParameters::thicknessModelTypeNames_
({
{ thicknessModelType::FIRST_AND_TOTAL, "firstAndOverall" },
{ thicknessModelType::FIRST_AND_EXPANSION, "firstAndExpansion" },
{ thicknessModelType::FINAL_AND_TOTAL, "finalAndOverall" },
{ thicknessModelType::FINAL_AND_EXPANSION, "finalAndExpansion" },
{ thicknessModelType::TOTAL_AND_EXPANSION, "overallAndExpansion" },
{ thicknessModelType::FIRST_AND_RELATIVE_FINAL, "firstAndRelativeFinal" },
});
const Foam::scalar Foam::layerParameters::defaultConcaveAngle = 90; const Foam::scalar Foam::layerParameters::defaultConcaveAngle = 90;
@ -44,7 +58,7 @@ Foam::scalar Foam::layerParameters::layerExpansionRatio
( (
const label n, const label n,
const scalar totalOverFirst const scalar totalOverFirst
) const )
{ {
if (n <= 1) if (n <= 1)
{ {
@ -66,11 +80,11 @@ Foam::scalar Foam::layerParameters::layerExpansionRatio
if (totalOverFirst < n) if (totalOverFirst < n)
{ {
minR = 0.0; minR = 0.0;
maxR = pow(totalOverFirst/n, 1/(n-1)); maxR = pow(totalOverFirst/n, scalar(1)/(n-1));
} }
else else
{ {
minR = pow(totalOverFirst/n, 1/(n-1)); minR = pow(totalOverFirst/n, scalar(1)/(n-1));
maxR = totalOverFirst/(n - 1); maxR = totalOverFirst/(n - 1);
} }
@ -94,6 +108,253 @@ Foam::scalar Foam::layerParameters::layerExpansionRatio
} }
void Foam::layerParameters::readLayerParameters
(
const bool verbose,
const dictionary& dict,
const thicknessModelType& spec,
scalar& firstLayerThickness,
scalar& finalLayerThickness,
scalar& thickness,
scalar& expansionRatio
)
{
// Now we have determined the layer-specification read the actual fields
switch (spec)
{
case FIRST_AND_TOTAL:
if (verbose)
{
Info<< "Layer specification as" << nl
<< "- first layer thickness ('firstLayerThickness')" << nl
<< "- overall thickness ('thickness')" << endl;
}
firstLayerThickness = readScalar
(
dict.lookup("firstLayerThickness")
);
thickness = readScalar(dict.lookup("thickness"));
break;
case FIRST_AND_EXPANSION:
if (verbose)
{
Info<< "Layer specification as" << nl
<< "- first layer thickness ('firstLayerThickness')" << nl
<< "- expansion ratio ('expansionRatio')" << endl;
}
firstLayerThickness = readScalar
(
dict.lookup("firstLayerThickness")
);
expansionRatio = readScalar(dict.lookup("expansionRatio"));
break;
case FINAL_AND_TOTAL:
if (verbose)
{
Info<< "Layer specification as" << nl
<< "- final layer thickness ('finalLayerThickness')" << nl
<< "- overall thickness ('thickness')" << endl;
}
finalLayerThickness = readScalar
(
dict.lookup("finalLayerThickness")
);
thickness = readScalar(dict.lookup("thickness"));
break;
case FINAL_AND_EXPANSION:
if (verbose)
{
Info<< "Layer specification as" << nl
<< "- final layer thickness ('finalLayerThickness')" << nl
<< "- expansion ratio ('expansionRatio')" << endl;
}
finalLayerThickness = readScalar
(
dict.lookup("finalLayerThickness")
);
expansionRatio = readScalar(dict.lookup("expansionRatio"));
break;
case TOTAL_AND_EXPANSION:
if (verbose)
{
Info<< "Layer specification as" << nl
<< "- overall thickness ('thickness')" << nl
<< "- expansion ratio ('expansionRatio')" << endl;
}
thickness = readScalar(dict.lookup("thickness"));
expansionRatio = readScalar(dict.lookup("expansionRatio"));
break;
case FIRST_AND_RELATIVE_FINAL:
if (verbose)
{
Info<< "Layer specification as" << nl
<< "- absolute first layer thickness"
<< " ('firstLayerThickness')"
<< nl
<< "- and final layer thickness"
<< " ('finalLayerThickness')" << nl
<< endl;
}
firstLayerThickness = readScalar
(
dict.lookup("firstLayerThickness")
);
finalLayerThickness = readScalar
(
dict.lookup("finalLayerThickness")
);
break;
default:
FatalIOErrorIn
(
"layerParameters::layerParameters(..)",
dict
) << "problem." << exit(FatalIOError);
break;
}
}
void Foam::layerParameters::calculateLayerParameters
(
const thicknessModelType& spec,
const label nLayers,
scalar& firstThickness,
scalar& finalThickness,
scalar& thickness,
scalar& expansionRatio
)
{
// Calculate the non-read parameters
switch (spec)
{
case FIRST_AND_TOTAL:
expansionRatio = layerExpansionRatio
(
spec,
nLayers,
firstThickness,
VGREAT,
thickness, //totalThickness
VGREAT //expansionRatio
);
finalThickness =
thickness
*finalLayerThicknessRatio(nLayers, expansionRatio);
break;
case FIRST_AND_EXPANSION:
thickness = layerThickness
(
spec,
nLayers,
firstThickness, //firstThickness
VGREAT, //finalThickness
VGREAT, //totalThickness
expansionRatio //expansionRatio
);
finalThickness =
thickness
*finalLayerThicknessRatio(nLayers, expansionRatio);
break;
case FINAL_AND_TOTAL:
firstThickness = firstLayerThickness
(
spec,
nLayers,
VGREAT, //firstThickness
VGREAT, //finalThickness
thickness, //totalThickness
VGREAT //expansionRatio
);
expansionRatio = layerExpansionRatio
(
spec,
nLayers,
VGREAT, //firstThickness
finalThickness, //finalThickness
thickness, //totalThickness
VGREAT //expansionRatio
);
break;
case FINAL_AND_EXPANSION:
firstThickness = firstLayerThickness
(
spec,
nLayers,
VGREAT, //firstThickness
finalThickness, //finalThickness
VGREAT, //thickness
expansionRatio //expansionRatio
);
thickness = layerThickness
(
spec,
nLayers,
VGREAT, //firstThickness
finalThickness, //finalThickness
VGREAT, //totalThickness
expansionRatio //expansionRatio
);
break;
case TOTAL_AND_EXPANSION:
firstThickness = firstLayerThickness
(
spec,
nLayers,
VGREAT, //firstThickness
finalThickness, //finalThickness
VGREAT, //thickness
expansionRatio //expansionRatio
);
finalThickness =
thickness
*finalLayerThicknessRatio(nLayers, expansionRatio);
break;
case FIRST_AND_RELATIVE_FINAL:
thickness = layerThickness
(
spec,
nLayers,
firstThickness, //firstThickness
finalThickness, //finalThickness
VGREAT, //totalThickness
VGREAT //expansionRatio
);
expansionRatio = layerExpansionRatio
(
spec,
nLayers,
firstThickness, //firstThickness
finalThickness, //finalThickness
VGREAT, //totalThickness
VGREAT //expansionRatio
);
break;
default:
FatalErrorInFunction << "Illegal thicknessModel " << spec
<< exit(FatalError);
break;
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::layerParameters::layerParameters Foam::layerParameters::layerParameters
@ -105,10 +366,13 @@ Foam::layerParameters::layerParameters
: :
dict_(dict), dict_(dict),
dryRun_(dryRun), dryRun_(dryRun),
relativeSizes_(meshRefinement::get<bool>(dict, "relativeSizes", dryRun)),
additionalReporting_(dict.getOrDefault("additionalReporting", false)),
layerSpec_(ILLEGAL),
numLayers_(boundaryMesh.size(), -1), numLayers_(boundaryMesh.size(), -1),
relativeSizes_
(
boundaryMesh.size(),
meshRefinement::get<bool>(dict, "relativeSizes", dryRun)
),
layerModels_(boundaryMesh.size(), FIRST_AND_TOTAL),
firstLayerThickness_(boundaryMesh.size(), -123), firstLayerThickness_(boundaryMesh.size(), -123),
finalLayerThickness_(boundaryMesh.size(), -123), finalLayerThickness_(boundaryMesh.size(), -123),
thickness_(boundaryMesh.size(), -123), thickness_(boundaryMesh.size(), -123),
@ -142,6 +406,7 @@ Foam::layerParameters::layerParameters
), ),
nLayerIter_(meshRefinement::get<label>(dict, "nLayerIter", dryRun)), nLayerIter_(meshRefinement::get<label>(dict, "nLayerIter", dryRun)),
nRelaxedIter_(labelMax), nRelaxedIter_(labelMax),
additionalReporting_(dict.getOrDefault("additionalReporting", false)),
meshShrinker_ meshShrinker_
( (
dict.getOrDefault dict.getOrDefault
@ -153,100 +418,112 @@ Foam::layerParameters::layerParameters
{ {
// Detect layer specification mode // Detect layer specification mode
label nSpec = 0; word spec;
if (dict.readIfPresent("thicknessModel", spec))
{
layerModels_ = thicknessModelTypeNames_[spec];
}
else
{
// Count number of specifications
label nSpec = 0;
bool haveFirst = dict.found("firstLayerThickness"); bool haveFirst = dict.found("firstLayerThickness");
if (haveFirst) if (haveFirst)
{ {
firstLayerThickness_ = scalarField nSpec++;
( }
boundaryMesh.size(), bool haveFinal = dict.found("finalLayerThickness");
dict.get<scalar>("firstLayerThickness") if (haveFinal)
); {
nSpec++; nSpec++;
} }
bool haveFinal = dict.found("finalLayerThickness"); bool haveTotal = dict.found("thickness");
if (haveFinal) if (haveTotal)
{ {
finalLayerThickness_ = scalarField nSpec++;
( }
boundaryMesh.size(), bool haveExp = dict.found("expansionRatio");
dict.get<scalar>("finalLayerThickness") if (haveExp)
); {
nSpec++; nSpec++;
} }
bool haveTotal = dict.found("thickness");
if (haveTotal) if (nSpec == 2 && haveFirst && haveTotal)
{ {
thickness_ = scalarField layerModels_ = FIRST_AND_TOTAL;
( //Info<< "Layer thickness specified as first layer"
boundaryMesh.size(), // << " and overall thickness." << endl;
dict.get<scalar>("thickness") }
); else if (nSpec == 2 && haveFirst && haveExp)
nSpec++; {
} layerModels_ = FIRST_AND_EXPANSION;
bool haveExp = dict.found("expansionRatio"); //Info<< "Layer thickness specified as first layer"
if (haveExp) // << " and expansion ratio." << endl;
{ }
expansionRatio_ = scalarField else if (nSpec == 2 && haveFinal && haveTotal)
( {
boundaryMesh.size(), layerModels_ = FINAL_AND_TOTAL;
dict.get<scalar>("expansionRatio") //Info<< "Layer thickness specified as final layer"
); // << " and overall thickness." << endl;
nSpec++; }
else if (nSpec == 2 && haveFinal && haveExp)
{
layerModels_ = FINAL_AND_EXPANSION;
//Info<< "Layer thickness specified as final layer"
// << " and expansion ratio." << endl;
}
else if (nSpec == 2 && haveTotal && haveExp)
{
layerModels_ = TOTAL_AND_EXPANSION;
//Info<< "Layer thickness specified as overall thickness"
// << " and expansion ratio." << endl;
}
else if (nSpec == 2 && haveFirst && haveFinal)
{
layerModels_ = FIRST_AND_RELATIVE_FINAL;
//Info<< "Layer thickness specified as absolute first and"
// << " relative final layer ratio." << endl;
}
else
{
FatalIOErrorInFunction(dict)
<< "Over- or underspecified layer thickness."
<< " Please specify" << nl
<< " first layer thickness ('firstLayerThickness')"
<< " and overall thickness ('thickness') or" << nl
<< " first layer thickness ('firstLayerThickness')"
<< " and expansion ratio ('expansionRatio') or" << nl
<< " final layer thickness ('finalLayerThickness')"
<< " and expansion ratio ('expansionRatio') or" << nl
<< " final layer thickness ('finalLayerThickness')"
<< " and overall thickness ('thickness') or" << nl
<< " overall thickness ('thickness')"
<< " and expansion ratio ('expansionRatio'"
<< exit(FatalIOError);
}
} }
if (haveFirst && haveTotal) // Now we have determined the layer-specification read the actual fields
{ scalar firstThickness;
layerSpec_ = FIRST_AND_TOTAL; scalar finalThickness;
Info<< "Layer thickness specified as first layer and overall thickness." scalar thickness;
<< endl; scalar expansionRatio;
} readLayerParameters
else if (haveFirst && haveExp) (
{ true, // verbose
layerSpec_ = FIRST_AND_EXPANSION; dict,
Info<< "Layer thickness specified as first layer and expansion ratio." layerModels_[0], // spec
<< endl; firstThickness,
} finalThickness,
else if (haveFinal && haveTotal) thickness,
{ expansionRatio
layerSpec_ = FINAL_AND_TOTAL; );
Info<< "Layer thickness specified as final layer and overall thickness." firstLayerThickness_ = firstThickness;
<< endl; finalLayerThickness_ = finalThickness;
} thickness_ = thickness;
else if (haveFinal && haveExp) expansionRatio_ = expansionRatio;
{
layerSpec_ = FINAL_AND_EXPANSION;
Info<< "Layer thickness specified as final layer and expansion ratio."
<< endl;
}
else if (haveTotal && haveExp)
{
layerSpec_ = TOTAL_AND_EXPANSION;
Info<< "Layer thickness specified as overall thickness"
<< " and expansion ratio." << endl;
}
if (layerSpec_ == ILLEGAL || nSpec != 2)
{
FatalIOErrorInFunction(dict)
<< "Over- or underspecified layer thickness."
<< " Please specify" << nl
<< " first layer thickness ('firstLayerThickness')"
<< " and overall thickness ('thickness') or" << nl
<< " first layer thickness ('firstLayerThickness')"
<< " and expansion ratio ('expansionRatio') or" << nl
<< " final layer thickness ('finalLayerThickness')"
<< " and expansion ratio ('expansionRatio') or" << nl
<< " final layer thickness ('finalLayerThickness')"
<< " and overall thickness ('thickness') or" << nl
<< " overall thickness ('thickness')"
<< " and expansion ratio ('expansionRatio'"
<< exit(FatalIOError);
}
dict.readIfPresent("nRelaxedIter", nRelaxedIter_); dict.readIfPresent("nRelaxedIter", nRelaxedIter_);
@ -293,88 +570,147 @@ Foam::layerParameters::layerParameters
numLayers_[patchi] = numLayers_[patchi] =
layerDict.get<label>("nSurfaceLayers"); layerDict.get<label>("nSurfaceLayers");
switch (layerSpec_) word spec;
if (layerDict.readIfPresent("thicknessModel", spec))
{ {
case FIRST_AND_TOTAL: // If the thickness model is explicitly specified
layerDict.readIfPresent // we want full specification of all parameters
( layerModels_[patchi] = thicknessModelTypeNames_[spec];
"firstLayerThickness", readLayerParameters
firstLayerThickness_[patchi] (
); false, // verbose
layerDict.readIfPresent layerDict,
( layerModels_[patchi], // spec
"thickness", firstLayerThickness_[patchi],
thickness_[patchi] finalLayerThickness_[patchi],
); thickness_[patchi],
break; expansionRatio_[patchi]
);
minThickness_[patchi] = readScalar
(
layerDict.lookup("minThickness")
);
}
else
{
// Optional override of thickness parameters
switch (layerModels_[patchi])
{
case FIRST_AND_TOTAL:
layerDict.readIfPresent
(
"firstLayerThickness",
firstLayerThickness_[patchi]
);
layerDict.readIfPresent
(
"thickness",
thickness_[patchi]
);
break;
case FIRST_AND_EXPANSION: case FIRST_AND_EXPANSION:
layerDict.readIfPresent layerDict.readIfPresent
( (
"firstLayerThickness", "firstLayerThickness",
firstLayerThickness_[patchi] firstLayerThickness_[patchi]
); );
layerDict.readIfPresent layerDict.readIfPresent
( (
"expansionRatio", "expansionRatio",
expansionRatio_[patchi] expansionRatio_[patchi]
); );
break; break;
case FINAL_AND_TOTAL: case FINAL_AND_TOTAL:
layerDict.readIfPresent layerDict.readIfPresent
( (
"finalLayerThickness", "finalLayerThickness",
finalLayerThickness_[patchi] finalLayerThickness_[patchi]
); );
layerDict.readIfPresent layerDict.readIfPresent
( (
"thickness", "thickness",
thickness_[patchi] thickness_[patchi]
); );
break; break;
case FINAL_AND_EXPANSION: case FINAL_AND_EXPANSION:
layerDict.readIfPresent layerDict.readIfPresent
( (
"finalLayerThickness", "finalLayerThickness",
finalLayerThickness_[patchi] finalLayerThickness_[patchi]
); );
layerDict.readIfPresent layerDict.readIfPresent
( (
"expansionRatio", "expansionRatio",
expansionRatio_[patchi] expansionRatio_[patchi]
); );
break; break;
case TOTAL_AND_EXPANSION: case TOTAL_AND_EXPANSION:
layerDict.readIfPresent layerDict.readIfPresent
( (
"thickness", "thickness",
thickness_[patchi] thickness_[patchi]
); );
layerDict.readIfPresent layerDict.readIfPresent
( (
"expansionRatio", "expansionRatio",
expansionRatio_[patchi] expansionRatio_[patchi]
); );
break; break;
default: case FIRST_AND_RELATIVE_FINAL:
FatalIOErrorInFunction(dict) layerDict.readIfPresent
<< "problem." << exit(FatalIOError); (
break; "firstLayerThickness",
firstLayerThickness_[patchi]
);
layerDict.readIfPresent
(
"finalLayerThickness",
finalLayerThickness_[patchi]
);
break;
default:
FatalIOErrorInFunction(dict)
<< "problem." << exit(FatalIOError);
break;
}
layerDict.readIfPresent
(
"minThickness",
minThickness_[patchi]
);
} }
layerDict.readIfPresent layerDict.readIfPresent
( (
"minThickness", "relativeSizes",
minThickness_[patchi] relativeSizes_[patchi]
); );
} }
} }
} }
} }
forAll(numLayers_, patchi)
{
// Calculate the remaining parameters
calculateLayerParameters
(
layerModels_[patchi],
numLayers_[patchi],
firstLayerThickness_[patchi],
finalLayerThickness_[patchi],
thickness_[patchi],
expansionRatio_[patchi]
);
}
} }
@ -382,14 +718,15 @@ Foam::layerParameters::layerParameters
Foam::scalar Foam::layerParameters::layerThickness Foam::scalar Foam::layerParameters::layerThickness
( (
const thicknessModelType layerSpec,
const label nLayers, const label nLayers,
const scalar firstLayerThickess, const scalar firstLayerThickness,
const scalar finalLayerThickess, const scalar finalLayerThickness,
const scalar totalThickness, const scalar totalThickness,
const scalar expansionRatio const scalar expansionRatio
) const )
{ {
switch (layerSpec_) switch (layerSpec)
{ {
case FIRST_AND_TOTAL: case FIRST_AND_TOTAL:
case FINAL_AND_TOTAL: case FINAL_AND_TOTAL:
@ -403,11 +740,11 @@ Foam::scalar Foam::layerParameters::layerThickness
{ {
if (mag(expansionRatio-1) < SMALL) if (mag(expansionRatio-1) < SMALL)
{ {
return firstLayerThickess * nLayers; return firstLayerThickness * nLayers;
} }
else else
{ {
return firstLayerThickess return firstLayerThickness
*(1.0 - pow(expansionRatio, nLayers)) *(1.0 - pow(expansionRatio, nLayers))
/(1.0 - expansionRatio); /(1.0 - expansionRatio);
} }
@ -418,22 +755,54 @@ Foam::scalar Foam::layerParameters::layerThickness
{ {
if (mag(expansionRatio-1) < SMALL) if (mag(expansionRatio-1) < SMALL)
{ {
return finalLayerThickess * nLayers; return finalLayerThickness * nLayers;
} }
else else
{ {
scalar invExpansion = 1.0 / expansionRatio; scalar invExpansion = 1.0 / expansionRatio;
return finalLayerThickess return finalLayerThickness
*(1.0 - pow(invExpansion, nLayers)) *(1.0 - pow(invExpansion, nLayers))
/(1.0 - invExpansion); /(1.0 - invExpansion);
} }
} }
break; break;
case FIRST_AND_RELATIVE_FINAL:
{
if (mag(expansionRatio-1) < SMALL)
{
return firstLayerThickness * nLayers;
}
else
{
scalar ratio = layerExpansionRatio
(
layerSpec,
nLayers,
firstLayerThickness,
finalLayerThickness,
totalThickness,
expansionRatio
);
if (mag(ratio-1) < SMALL)
{
return firstLayerThickness * nLayers;
}
else
{
return firstLayerThickness *
(1.0 - pow(ratio, nLayers))
/ (1.0 - ratio);
}
}
}
break;
default: default:
{ {
FatalErrorInFunction FatalErrorInFunction
<< exit(FatalError); << layerSpec << exit(FatalError);
return -VGREAT; return -VGREAT;
} }
} }
@ -442,14 +811,15 @@ Foam::scalar Foam::layerParameters::layerThickness
Foam::scalar Foam::layerParameters::layerExpansionRatio Foam::scalar Foam::layerParameters::layerExpansionRatio
( (
const thicknessModelType layerSpec,
const label nLayers, const label nLayers,
const scalar firstLayerThickess, const scalar firstLayerThickness,
const scalar finalLayerThickess, const scalar finalLayerThickness,
const scalar totalThickness, const scalar totalThickness,
const scalar expansionRatio const scalar expansionRatio
) const )
{ {
switch (layerSpec_) switch (layerSpec)
{ {
case FIRST_AND_EXPANSION: case FIRST_AND_EXPANSION:
case FINAL_AND_EXPANSION: case FINAL_AND_EXPANSION:
@ -461,23 +831,58 @@ Foam::scalar Foam::layerParameters::layerExpansionRatio
case FIRST_AND_TOTAL: case FIRST_AND_TOTAL:
{ {
return layerExpansionRatio if (firstLayerThickness < SMALL)
( {
nLayers, // Do what?
totalThickness/firstLayerThickess return 1;
); }
else
{
return layerExpansionRatio
(
nLayers,
totalThickness/firstLayerThickness
);
}
} }
break; break;
case FINAL_AND_TOTAL: case FINAL_AND_TOTAL:
{ {
return if (finalLayerThickness < SMALL)
1.0 {
/layerExpansionRatio // Do what?
return 1;
}
else
{
return
1.0
/ layerExpansionRatio
(
nLayers,
totalThickness/finalLayerThickness
);
}
}
break;
case FIRST_AND_RELATIVE_FINAL:
{
if (firstLayerThickness < SMALL || nLayers <= 1)
{
return 1.0;
}
else
{
// Note: at this point the finalLayerThickness is already
// absolute
return pow
( (
nLayers, finalLayerThickness/firstLayerThickness,
totalThickness/finalLayerThickess 1.0/(nLayers-1)
); );
}
} }
break; break;
@ -493,24 +898,34 @@ Foam::scalar Foam::layerParameters::layerExpansionRatio
Foam::scalar Foam::layerParameters::firstLayerThickness Foam::scalar Foam::layerParameters::firstLayerThickness
( (
const thicknessModelType layerSpec,
const label nLayers, const label nLayers,
const scalar firstLayerThickess, const scalar firstLayerThickness,
const scalar finalLayerThickess, const scalar finalLayerThickness,
const scalar totalThickness, const scalar totalThickness,
const scalar expansionRatio const scalar expansionRatio
) const )
{ {
switch (layerSpec_) switch (layerSpec)
{ {
case FIRST_AND_EXPANSION: case FIRST_AND_EXPANSION:
case FIRST_AND_TOTAL: case FIRST_AND_TOTAL:
case FIRST_AND_RELATIVE_FINAL:
{ {
return firstLayerThickess; return firstLayerThickness;
} }
case FINAL_AND_EXPANSION: case FINAL_AND_EXPANSION:
{ {
return finalLayerThickess*pow(1.0/expansionRatio, nLayers-1); if (expansionRatio < SMALL)
{
// Do what?
return 0.0;
}
else
{
return finalLayerThickness*pow(1.0/expansionRatio, nLayers-1);
}
} }
break; break;
@ -518,13 +933,14 @@ Foam::scalar Foam::layerParameters::firstLayerThickness
{ {
scalar r = layerExpansionRatio scalar r = layerExpansionRatio
( (
layerSpec,
nLayers, nLayers,
firstLayerThickess, firstLayerThickness,
finalLayerThickess, finalLayerThickness,
totalThickness, totalThickness,
expansionRatio expansionRatio
); );
return finalLayerThickess/pow(r, nLayers-1); return finalLayerThickness/pow(r, nLayers-1);
} }
break; break;
@ -554,7 +970,7 @@ Foam::scalar Foam::layerParameters::finalLayerThicknessRatio
( (
const label nLayers, const label nLayers,
const scalar expansionRatio const scalar expansionRatio
) const )
{ {
if (nLayers > 0) if (nLayers > 0)
{ {

View File

@ -41,6 +41,7 @@ SourceFiles
#include "scalarField.H" #include "scalarField.H"
#include "labelList.H" #include "labelList.H"
#include "Switch.H" #include "Switch.H"
#include "Enum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -67,14 +68,14 @@ public:
// - final and total thickness specified // - final and total thickness specified
// - final and expansion ratio specified // - final and expansion ratio specified
// - total thickness and expansion ratio specified // - total thickness and expansion ratio specified
enum layerSpecification enum thicknessModelType
{ {
ILLEGAL,
FIRST_AND_TOTAL, FIRST_AND_TOTAL,
FIRST_AND_EXPANSION, FIRST_AND_EXPANSION,
FINAL_AND_TOTAL, FINAL_AND_TOTAL,
FINAL_AND_EXPANSION, FINAL_AND_EXPANSION,
TOTAL_AND_EXPANSION TOTAL_AND_EXPANSION,
FIRST_AND_RELATIVE_FINAL
}; };
@ -85,6 +86,9 @@ private:
//- Default angle for faces to be concave //- Default angle for faces to be concave
static const scalar defaultConcaveAngle; static const scalar defaultConcaveAngle;
//- thicknessModelType names
static const Enum<thicknessModelType> thicknessModelTypeNames_;
// Private Data // Private Data
@ -93,28 +97,25 @@ private:
//- In dry-run mode? //- In dry-run mode?
const bool dryRun_; const bool dryRun_;
//- Are sizes relative to local cell size
bool relativeSizes_;
//- Any additional reporting
bool additionalReporting_;
// Per patch (not region!) information // Per patch (not region!) information
//- How thickness is specified.
layerSpecification layerSpec_;
//- How many layers to add. //- How many layers to add.
labelList numLayers_; labelList numLayers_;
scalarField firstLayerThickness_; //- Are sizes relative to local cell size
boolList relativeSizes_;
scalarField finalLayerThickness_; //- How thickness is specified.
List<thicknessModelType> layerModels_;
scalarField thickness_; scalarField firstLayerThickness_;
scalarField expansionRatio_; scalarField finalLayerThickness_;
scalarField thickness_;
scalarField expansionRatio_;
//- Minimum total thickness //- Minimum total thickness
scalarField minThickness_; scalarField minThickness_;
@ -136,6 +137,9 @@ private:
label nRelaxedIter_; label nRelaxedIter_;
//- Any additional reporting
bool additionalReporting_;
word meshShrinker_; word meshShrinker_;
@ -143,11 +147,33 @@ private:
//- Calculate expansion ratio from overall size v.s. thickness of //- Calculate expansion ratio from overall size v.s. thickness of
// first layer. // first layer.
scalar layerExpansionRatio static scalar layerExpansionRatio
( (
const label n, const label n,
const scalar totalOverFirst const scalar totalOverFirst
) const; );
//- Read parameters according to thickness model
static void readLayerParameters
(
const bool verbose,
const dictionary&,
const thicknessModelType& spec,
scalar& firstLayerThickness,
scalar& finalLayerThickness,
scalar& thickness,
scalar& expansionRatio
);
void calculateLayerParameters
(
const thicknessModelType& spec,
const label nLayers,
scalar& firstLayerThickness,
scalar& finalLayerThickness,
scalar& thickness,
scalar& expansionRatio
);
//- No copy construct //- No copy construct
layerParameters(const layerParameters&) = delete; layerParameters(const layerParameters&) = delete;
@ -191,15 +217,15 @@ public:
//- Are size parameters relative to inner cell size or //- Are size parameters relative to inner cell size or
// absolute distances. // absolute distances.
bool relativeSizes() const const boolList& relativeSizes() const
{ {
return relativeSizes_; return relativeSizes_;
} }
//- Any additional reporting requested? //- Specification of layer thickness
bool additionalReporting() const const List<thicknessModelType>& layerModels() const
{ {
return additionalReporting_; return layerModels_;
} }
// Expansion factor for layer mesh // Expansion factor for layer mesh
@ -296,6 +322,12 @@ public:
return nBufferCellsNoExtrude_; return nBufferCellsNoExtrude_;
} }
//- Any additional reporting requested?
bool additionalReporting() const
{
return additionalReporting_;
}
//- Type of mesh shrinker //- Type of mesh shrinker
const word& meshShrinker() const const word& meshShrinker() const
{ {
@ -306,45 +338,48 @@ public:
// Helper // Helper
//- Determine overall thickness. Uses two of the four parameters //- Determine overall thickness. Uses two of the four parameters
// according to the layerSpecification // according to the thicknessModel
scalar layerThickness static scalar layerThickness
( (
const thicknessModelType,
const label nLayers, const label nLayers,
const scalar firstLayerThickess, const scalar firstLayerThickness,
const scalar finalLayerThickess, const scalar finalLayerThickness,
const scalar totalThickness, const scalar totalThickness,
const scalar expansionRatio const scalar expansionRatio
) const; );
//- Determine expansion ratio. Uses two of the four parameters //- Determine expansion ratio. Uses two of the four parameters
// according to the layerSpecification // according to the thicknessModel
scalar layerExpansionRatio static scalar layerExpansionRatio
( (
const thicknessModelType,
const label nLayers, const label nLayers,
const scalar firstLayerThickess, const scalar firstLayerThickness,
const scalar finalLayerThickess, const scalar finalLayerThickness,
const scalar totalThickness, const scalar totalThickness,
const scalar expansionRatio const scalar expansionRatio
) const; );
//- Determine first layer (near-wall) thickness. Uses two of the //- Determine first layer (near-wall) thickness. Uses two of the
// four parameters according to the layerSpecification // four parameters according to the thicknessModel
scalar firstLayerThickness static scalar firstLayerThickness
( (
const thicknessModelType,
const label nLayers, const label nLayers,
const scalar firstLayerThickess, const scalar firstLayerThickness,
const scalar finalLayerThickess, const scalar finalLayerThickness,
const scalar totalThickness, const scalar totalThickness,
const scalar expansionRatio const scalar expansionRatio
) const; );
//- Determine ratio of final layer thickness to //- Determine ratio of final layer thickness to
// overall layer thickness // overall layer thickness
scalar finalLayerThicknessRatio static scalar finalLayerThicknessRatio
( (
const label nLayers, const label nLayers,
const scalar expansionRatio const scalar expansionRatio
) const; );
}; };

View File

@ -820,6 +820,7 @@ void Foam::snappyLayerDriver::handleWarpedFaces
( (
const indirectPrimitivePatch& pp, const indirectPrimitivePatch& pp,
const scalar faceRatio, const scalar faceRatio,
const boolList& relativeSizes,
const scalar edge0Len, const scalar edge0Len,
const labelList& cellLevel, const labelList& cellLevel,
pointField& patchDisp, pointField& patchDisp,
@ -828,6 +829,7 @@ void Foam::snappyLayerDriver::handleWarpedFaces
) const ) const
{ {
const fvMesh& mesh = meshRefiner_.mesh(); const fvMesh& mesh = meshRefiner_.mesh();
const polyBoundaryMesh& patches = mesh.boundaryMesh();
Info<< nl << "Handling cells with warped patch faces ..." << nl; Info<< nl << "Handling cells with warped patch faces ..." << nl;
@ -838,16 +840,19 @@ void Foam::snappyLayerDriver::handleWarpedFaces
forAll(pp, i) forAll(pp, i)
{ {
const face& f = pp[i]; const face& f = pp[i];
label faceI = pp.addressing()[i];
label patchI = patches.patchID()[faceI-mesh.nInternalFaces()];
if (f.size() > 3) // It is hard to calculate some length scale if not in relative
// mode so disable this check.
if (relativeSizes[patchI] && f.size() > 3)
{ {
label facei = pp.addressing()[i]; label ownLevel = cellLevel[mesh.faceOwner()[faceI]];
label ownLevel = cellLevel[mesh.faceOwner()[facei]];
scalar edgeLen = edge0Len/(1<<ownLevel); scalar edgeLen = edge0Len/(1<<ownLevel);
// Normal distance to face centre plane // Normal distance to face centre plane
const point& fc = mesh.faceCentres()[facei]; const point& fc = mesh.faceCentres()[faceI];
const vector& fn = pp.faceNormals()[i]; const vector& fn = pp.faceNormals()[i];
scalarField vProj(f.size()); scalarField vProj(f.size());
@ -1412,10 +1417,14 @@ void Foam::snappyLayerDriver::calculateLayerThickness
minThickness.setSize(pp.nPoints()); minThickness.setSize(pp.nPoints());
minThickness = GREAT; minThickness = GREAT;
forAll(patchIDs, i) thickness.setSize(pp.nPoints());
{ thickness = GREAT;
label patchi = patchIDs[i];
expansionRatio.setSize(pp.nPoints());
expansionRatio = GREAT;
for (const label patchi : patchIDs)
{
const labelList& meshPoints = patches[patchi].meshPoints(); const labelList& meshPoints = patches[patchi].meshPoints();
forAll(meshPoints, patchPointi) forAll(meshPoints, patchPointi)
@ -1495,32 +1504,11 @@ void Foam::snappyLayerDriver::calculateLayerThickness
// Now the thicknesses are set according to the minimum of connected // Now the thicknesses are set according to the minimum of connected
// patches. // patches.
// Determine per point the max cell level of connected cells
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Rework relative thickness into absolute labelList maxPointLevel(pp.nPoints(), labelMin);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// by multiplying with the internal cell size.
if (layerParams.relativeSizes())
{ {
if
(
min(layerParams.minThickness()) < 0
|| max(layerParams.minThickness()) > 2
)
{
FatalErrorInFunction
<< "Thickness should be factor of local undistorted cell size."
<< " Valid values are [0..2]." << nl
<< " minThickness:" << layerParams.minThickness()
<< exit(FatalError);
}
// Determine per point the max cell level of connected cells
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
labelList maxPointLevel(pp.nPoints(), labelMin);
forAll(pp, i) forAll(pp, i)
{ {
label ownLevel = cellLevel[mesh.faceOwner()[pp.addressing()[i]]]; label ownLevel = cellLevel[mesh.faceOwner()[pp.addressing()[i]]];
@ -1541,44 +1529,149 @@ void Foam::snappyLayerDriver::calculateLayerThickness
maxEqOp<label>(), maxEqOp<label>(),
labelMin // null value labelMin // null value
); );
}
forAll(maxPointLevel, pointi) // Rework relative thickness into absolute
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// by multiplying with the internal cell size.
// Note that we cannot loop over the patches since then points on
// multiple patches would get multiplied with edgeLen twice ..
{
// Multiplication factor for relative sizes
scalarField edgeLen(pp.nPoints(), GREAT);
labelList spec(pp.nPoints(), layerParameters::FIRST_AND_TOTAL);
bitSet isRelativePoint(mesh.nPoints());
for (const label patchi : patchIDs)
{ {
// Find undistorted edge size for this level. const labelList& meshPoints = patches[patchi].meshPoints();
scalar edgeLen = edge0Len/(1<<maxPointLevel[pointi]); const layerParameters::thicknessModelType patchSpec =
firstLayerThickness[pointi] *= edgeLen; layerParams.layerModels()[patchi];
finalLayerThickness[pointi] *= edgeLen; const bool relSize = layerParams.relativeSizes()[patchi];
totalThickness[pointi] *= edgeLen;
minThickness[pointi] *= edgeLen; for (const label meshPointi : meshPoints)
{
const label ppPointi = pp.meshPointMap()[meshPointi];
// Note: who wins if different specs?
// Calculate undistorted edge size for this level.
edgeLen[ppPointi] = min
(
edgeLen[ppPointi],
edge0Len/(1<<maxPointLevel[ppPointi])
);
spec[ppPointi] = max(spec[ppPointi], patchSpec);
isRelativePoint[meshPointi] =
isRelativePoint[meshPointi]
|| relSize;
}
}
syncTools::syncPointList
(
mesh,
pp.meshPoints(),
edgeLen,
minEqOp<scalar>(),
GREAT // null value
);
syncTools::syncPointList
(
mesh,
pp.meshPoints(),
spec,
maxEqOp<label>(),
label(layerParameters::FIRST_AND_TOTAL) // null value
);
syncTools::syncPointList
(
mesh,
isRelativePoint,
orEqOp<unsigned int>(),
0
);
forAll(pp.meshPoints(), pointi)
{
const label meshPointi = pp.meshPoints()[pointi];
const layerParameters::thicknessModelType pointSpec =
static_cast<layerParameters::thicknessModelType>(spec[pointi]);
if (pointSpec == layerParameters::FIRST_AND_RELATIVE_FINAL)
{
// This overrules the relative sizes flag for
// first (always absolute) and final (always relative)
finalLayerThickness[pointi] *= edgeLen[pointi];
if (isRelativePoint[meshPointi])
{
totalThickness[pointi] *= edgeLen[pointi];
minThickness[pointi] *= edgeLen[pointi];
}
}
else if (isRelativePoint[meshPointi])
{
firstLayerThickness[pointi] *= edgeLen[pointi];
finalLayerThickness[pointi] *= edgeLen[pointi];
totalThickness[pointi] *= edgeLen[pointi];
minThickness[pointi] *= edgeLen[pointi];
}
thickness[pointi] = min
(
thickness[pointi],
layerParameters::layerThickness
(
pointSpec,
patchNLayers[pointi],
firstLayerThickness[pointi],
finalLayerThickness[pointi],
totalThickness[pointi],
expRatio[pointi]
)
);
expansionRatio[pointi] = min
(
expansionRatio[pointi],
layerParameters::layerExpansionRatio
(
pointSpec,
patchNLayers[pointi],
firstLayerThickness[pointi],
finalLayerThickness[pointi],
totalThickness[pointi],
expRatio[pointi]
)
);
} }
} }
// Synchronise the determined thicknes. Note that this should not be
// necessary since the inputs to the calls to layerThickness,
// layerExpansionRatio above are already parallel consistent
syncTools::syncPointList
// Rework thickness parameters into overall thickness (
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ mesh,
pp.meshPoints(),
forAll(firstLayerThickness, pointi) thickness,
{ minEqOp<scalar>(),
thickness[pointi] = layerParams.layerThickness GREAT // null value
( );
patchNLayers[pointi], syncTools::syncPointList
firstLayerThickness[pointi], (
finalLayerThickness[pointi], mesh,
totalThickness[pointi], pp.meshPoints(),
expRatio[pointi] expansionRatio,
); minEqOp<scalar>(),
GREAT // null value
expansionRatio[pointi] = layerParams.layerExpansionRatio );
(
patchNLayers[pointi],
firstLayerThickness[pointi],
finalLayerThickness[pointi],
totalThickness[pointi],
expRatio[pointi]
);
}
//Info<< "calculateLayerThickness : min:" << gMin(thickness) //Info<< "calculateLayerThickness : min:" << gMin(thickness)
// << " max:" << gMax(thickness) << endl; // << " max:" << gMax(thickness) << endl;
@ -1614,6 +1707,8 @@ void Foam::snappyLayerDriver::calculateLayerThickness
label patchi = patchIDs[i]; label patchi = patchIDs[i];
const labelList& meshPoints = patches[patchi].meshPoints(); const labelList& meshPoints = patches[patchi].meshPoints();
const layerParameters::thicknessModelType spec =
layerParams.layerModels()[patchi];
scalar sumThickness = 0; scalar sumThickness = 0;
scalar sumNearWallThickness = 0; scalar sumNearWallThickness = 0;
@ -1629,6 +1724,7 @@ void Foam::snappyLayerDriver::calculateLayerThickness
sumThickness += thickness[ppPointi]; sumThickness += thickness[ppPointi];
sumNearWallThickness += layerParams.firstLayerThickness sumNearWallThickness += layerParams.firstLayerThickness
( (
spec,
patchNLayers[ppPointi], patchNLayers[ppPointi],
firstLayerThickness[ppPointi], firstLayerThickness[ppPointi],
finalLayerThickness[ppPointi], finalLayerThickness[ppPointi],
@ -1806,6 +1902,8 @@ void Foam::snappyLayerDriver::getPatchDisplacement
const indirectPrimitivePatch& pp, const indirectPrimitivePatch& pp,
const scalarField& thickness, const scalarField& thickness,
const scalarField& minThickness, const scalarField& minThickness,
const scalarField& expansionRatio,
pointField& patchDisp, pointField& patchDisp,
labelList& patchNLayers, labelList& patchNLayers,
List<extrudeMode>& extrudeStatus List<extrudeMode>& extrudeStatus
@ -1836,6 +1934,98 @@ void Foam::snappyLayerDriver::getPatchDisplacement
label nExtrudeRemove = 0; label nExtrudeRemove = 0;
////XXXXXXXX
// {
// OBJstream twoStr
// (
// mesh.time().path()
// / "twoFacePoints_"
// + meshRefiner_.timeName()
// + ".obj"
// );
// OBJstream multiStr
// (
// mesh.time().path()
// / "multiFacePoints_"
// + meshRefiner_.timeName()
// + ".obj"
// );
// Pout<< "Writing points inbetween two faces on same cell to "
// << twoStr.name() << endl;
// Pout<< "Writing points inbetween three or more faces on same cell to "
// << multiStr.name() << endl;
// // Check whether inbetween patch faces on same cell
// Map<labelList> cellToFaces;
// forAll(pointNormals, patchPointi)
// {
// const labelList& pFaces = pointFaces[patchPointi];
//
// cellToFaces.clear();
// forAll(pFaces, pFacei)
// {
// const label patchFacei = pFaces[pFacei];
// const label meshFacei = pp.addressing()[patchFacei];
// const label celli = mesh.faceOwner()[meshFacei];
// Map<labelList>::iterator faceFnd = cellToFaces.find(celli);
// if (faceFnd.found())
// {
// labelList& faces = faceFnd();
// if (!faces.found(patchFacei))
// {
// faces.append(patchFacei);
// }
// }
// else
// {
// cellToFaces.insert(celli, labelList(1, patchFacei));
// }
// }
//
// forAllConstIter(Map<labelList>, cellToFaces, iter)
// {
// if (iter().size() == 2)
// {
// twoStr.write(pp.localPoints()[patchPointi]);
// }
// else if (iter().size() > 2)
// {
// multiStr.write(pp.localPoints()[patchPointi]);
//
// const scalar ratio =
// layerParameters::finalLayerThicknessRatio
// (
// patchNLayers[patchPointi],
// expansionRatio[patchPointi]
// );
// // Get thickness of cell next to bulk
// const vector finalDisp
// (
// ratio*patchDisp[patchPointi]
// );
//
// //Pout<< "** point:" << pp.localPoints()[patchPointi]
// // << " on cell:" << iter.key()
// // << " faces:" << iter()
// // << " displacement was:" << patchDisp[patchPointi]
// // << " ratio:" << ratio
// // << " finalDispl:" << finalDisp;
//
// // Half this thickness
// patchDisp[patchPointi] -= 0.8*finalDisp;
//
// //Pout<< " new displacement:"
// // << patchDisp[patchPointi] << endl;
// }
// }
// }
//
// Pout<< "Written " << multiStr.nVertices()
// << " points inbetween three or more faces on same cell to "
// << multiStr.name() << endl;
// }
////XXXXXXXX
// Check if no extrude possible. // Check if no extrude possible.
forAll(pointNormals, patchPointi) forAll(pointNormals, patchPointi)
{ {
@ -3724,7 +3914,7 @@ void Foam::snappyLayerDriver::addLayers
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// It is hard to calculate some length scale if not in relative // It is hard to calculate some length scale if not in relative
// mode so disable this check. // mode so disable this check.
if (layerParams.relativeSizes()) if (!layerParams.relativeSizes().found(false))
{ {
// Undistorted edge length // Undistorted edge length
const scalar edge0Len = const scalar edge0Len =
@ -3735,6 +3925,7 @@ void Foam::snappyLayerDriver::addLayers
( (
*pp, *pp,
layerParams.maxFaceThicknessRatio(), layerParams.maxFaceThicknessRatio(),
layerParams.relativeSizes(),
edge0Len, edge0Len,
cellLevel, cellLevel,
@ -3948,6 +4139,8 @@ void Foam::snappyLayerDriver::addLayers
*pp, *pp,
thickness, thickness,
minThickness, minThickness,
expansionRatio,
patchDisp, patchDisp,
patchNLayers, patchNLayers,
extrudeStatus extrudeStatus
@ -4077,7 +4270,7 @@ void Foam::snappyLayerDriver::addLayers
forAll(nPatchPointLayers, i) forAll(nPatchPointLayers, i)
{ {
scalar ratio = layerParams.finalLayerThicknessRatio scalar ratio = layerParameters::finalLayerThicknessRatio
( (
nPatchPointLayers[i], nPatchPointLayers[i],
expansionRatio[i] expansionRatio[i]
@ -4133,7 +4326,7 @@ void Foam::snappyLayerDriver::addLayers
mesh.name(), mesh.name(),
static_cast<polyMesh&>(mesh).instance(), static_cast<polyMesh&>(mesh).instance(),
mesh.time(), // register with runTime mesh.time(), // register with runTime
IOobject::NO_READ, IOobject::READ_IF_PRESENT, // read fv* if present
static_cast<polyMesh&>(mesh).writeOpt() static_cast<polyMesh&>(mesh).writeOpt()
), // io params from original mesh but new name ), // io params from original mesh but new name
mesh, // original mesh mesh, // original mesh

View File

@ -235,6 +235,7 @@ private:
( (
const indirectPrimitivePatch& pp, const indirectPrimitivePatch& pp,
const scalar faceRatio, const scalar faceRatio,
const boolList& relativeSizes,
const scalar edge0Len, const scalar edge0Len,
const labelList& cellLevel, const labelList& cellLevel,
pointField& patchDisp, pointField& patchDisp,
@ -328,6 +329,8 @@ private:
const indirectPrimitivePatch& pp, const indirectPrimitivePatch& pp,
const scalarField& thickness, const scalarField& thickness,
const scalarField& minThickness, const scalarField& minThickness,
const scalarField& expansionRatio,
pointField& patchDisp, pointField& patchDisp,
labelList& patchNLayers, labelList& patchNLayers,
List<extrudeMode>& extrudeStatus List<extrudeMode>& extrudeStatus

View File

@ -1476,6 +1476,261 @@ Foam::label Foam::snappyRefineDriver::refinementInterfaceRefine
return iter; return iter;
} }
bool Foam::snappyRefineDriver::usesHigherLevel
(
const labelUList& boundaryPointLevel,
const labelUList& f,
const label cLevel
) const
{
for (const label pointi : f)
{
if (boundaryPointLevel[pointi] > cLevel)
{
return true;
}
}
return false;
}
Foam::label Foam::snappyRefineDriver::boundaryRefinementInterfaceRefine
(
const refinementParameters& refineParams,
const label maxIter
)
{
if (refineParams.minRefineCells() == -1)
{
// Special setting to be able to restart shm on meshes with inconsistent
// cellLevel/pointLevel
return 0;
}
if (dryRun_)
{
return 0;
}
addProfiling(interface, "snappyHexMesh::refine::transition");
const fvMesh& mesh = meshRefiner_.mesh();
label iter = 0;
if (refineParams.interfaceRefine())
{
for (;iter < maxIter; iter++)
{
Info<< nl
<< "Boundary refinement iteration " << iter << nl
<< "-------------------------------" << nl
<< endl;
const labelList& surfaceIndex = meshRefiner_.surfaceIndex();
const hexRef8& cutter = meshRefiner_.meshCutter();
const labelList& cellLevel = cutter.cellLevel();
const faceList& faces = mesh.faces();
const cellList& cells = mesh.cells();
// Determine cells to refine
// ~~~~~~~~~~~~~~~~~~~~~~~~~
// Point/face on boundary
bitSet isBoundaryPoint(mesh.nPoints());
bitSet isBoundaryFace(mesh.nFaces());
{
forAll(surfaceIndex, facei)
{
if (surfaceIndex[facei] != -1)
{
isBoundaryFace.set(facei);
isBoundaryPoint.set(faces[facei]);
}
}
const labelList meshPatchIDs(meshRefiner_.meshedPatches());
for (const label patchi : meshPatchIDs)
{
const polyPatch& pp = mesh.boundaryMesh()[patchi];
forAll(pp, i)
{
isBoundaryFace.set(pp.start()+i);
isBoundaryPoint.set(pp[i]);
}
}
syncTools::syncPointList
(
mesh,
isBoundaryPoint,
orEqOp<unsigned int>(),
0
);
}
// Mark max boundary face level onto boundary points. All points
// not on a boundary face stay 0.
labelList boundaryPointLevel(mesh.nPoints(), 0);
{
forAll(cells, celli)
{
const cell& cFaces = cells[celli];
const label cLevel = cellLevel[celli];
for (const label facei : cFaces)
{
if (isBoundaryFace(facei))
{
const face& f = faces[facei];
for (const label pointi : f)
{
boundaryPointLevel[pointi] =
max
(
boundaryPointLevel[pointi],
cLevel
);
}
}
}
}
syncTools::syncPointList
(
mesh,
boundaryPointLevel,
maxEqOp<label>(),
0
);
}
// Detect cells with a point but not face on the boundary
labelList candidateCells;
{
const cellList& cells = mesh.cells();
cellSet candidateCellSet
(
mesh,
"candidateCells",
cells.size()/100
);
forAll(cells, celli)
{
const cell& cFaces = cells[celli];
const label cLevel = cellLevel[celli];
bool isBoundaryCell = false;
for (const label facei : cFaces)
{
if (isBoundaryFace(facei))
{
isBoundaryCell = true;
break;
}
}
if (!isBoundaryCell)
{
for (const label facei : cFaces)
{
const face& f = mesh.faces()[facei];
if (usesHigherLevel(boundaryPointLevel, f, cLevel))
{
candidateCellSet.insert(celli);
break;
}
}
}
}
if (debug&meshRefinement::MESH)
{
Pout<< "Dumping " << candidateCellSet.size()
<< " cells to cellSet candidateCellSet." << endl;
candidateCellSet.instance() = meshRefiner_.timeName();
candidateCellSet.write();
}
candidateCells = candidateCellSet.toc();
}
labelList cellsToRefine
(
meshRefiner_.meshCutter().consistentRefinement
(
candidateCells,
true
)
);
Info<< "Determined cells to refine in = "
<< mesh.time().cpuTimeIncrement() << " s" << endl;
label nCellsToRefine = cellsToRefine.size();
reduce(nCellsToRefine, sumOp<label>());
Info<< "Selected for refinement : " << nCellsToRefine
<< " cells (out of " << mesh.globalData().nTotalCells()
<< ')' << endl;
// Stop when no cells to refine. After a few iterations check if too
// few cells
if
(
nCellsToRefine == 0
// || (
// iter >= 1
// && nCellsToRefine <= refineParams.minRefineCells()
// )
)
{
Info<< "Stopping refining since too few cells selected."
<< nl << endl;
break;
}
if (debug)
{
const_cast<Time&>(mesh.time())++;
}
if
(
returnReduce
(
(mesh.nCells() >= refineParams.maxLocalCells()),
orOp<bool>()
)
)
{
meshRefiner_.balanceAndRefine
(
"boundary cell refinement iteration " + name(iter),
decomposer_,
distributor_,
cellsToRefine,
refineParams.maxLoadUnbalance()
);
}
else
{
meshRefiner_.refineAndBalance
(
"boundary cell refinement iteration " + name(iter),
decomposer_,
distributor_,
cellsToRefine,
refineParams.maxLoadUnbalance()
);
}
}
}
return iter;
}
void Foam::snappyRefineDriver::removeInsideCells void Foam::snappyRefineDriver::removeInsideCells
( (
@ -3195,6 +3450,18 @@ void Foam::snappyRefineDriver::doRefine
motionDict motionDict
); );
//- Commented out for now since causes zoning errors (sigsegv) on
// case with faceZones. TBD.
//// Refine any cells are point/edge connected to the boundary and have a
//// lower refinement level than the neighbouring cells
//boundaryRefinementInterfaceRefine
//(
// refineParams,
// 10 // maxIter
//);
// Mesh is at its finest. Do optional zoning (cellZones and faceZones) // Mesh is at its finest. Do optional zoning (cellZones and faceZones)
wordPairHashTable zonesToFaceZone; wordPairHashTable zonesToFaceZone;
zonify(refineParams, zonesToFaceZone); zonify(refineParams, zonesToFaceZone);

View File

@ -165,6 +165,21 @@ class snappyRefineDriver
const label maxIter const label maxIter
); );
//- Helper: see if any element in f has higher level than cLevel
bool usesHigherLevel
(
const labelUList& boundaryPointLevel,
const labelUList& f,
const label cLevel
) const;
//- Refine cells with a point/edge but not face on the boundary
label boundaryRefinementInterfaceRefine
(
const refinementParameters& refineParams,
const label maxIter
);
//- Remove all cells within intersected region //- Remove all cells within intersected region
void removeInsideCells void removeInsideCells
( (

View File

@ -617,7 +617,8 @@ public:
const bool orderPoints = false const bool orderPoints = false
); );
//- Create new mesh with old mesh patches //- Create new mesh with old mesh patches. Additional dictionaries
// (fv* etc) read according to IO flags
template<class Type> template<class Type>
autoPtr<mapPolyMesh> makeMesh autoPtr<mapPolyMesh> makeMesh
( (

View File

@ -182,14 +182,14 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::polyTopoChange::makeMesh
// Create the mesh // Create the mesh
// ~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~
IOobject noReadIO(io); //IOobject noReadIO(io);
noReadIO.readOpt() = IOobject::NO_READ; //noReadIO.readOpt() = IOobject::NO_READ;
noReadIO.writeOpt() = IOobject::AUTO_WRITE; //noReadIO.writeOpt() = IOobject::AUTO_WRITE;
newMeshPtr.reset newMeshPtr.reset
( (
new Type new Type
( (
noReadIO, io, //noReadIO
std::move(newPoints), std::move(newPoints),
std::move(faces_), std::move(faces_),
std::move(faceOwner_), std::move(faceOwner_),

View File

@ -0,0 +1,9 @@
#!/bin/sh
cd "${0%/*}" || exit # Run from this directory
. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions
#------------------------------------------------------------------------------
cleanCase0
rm -rf constant/extendedFeatureEdgeMesh
#------------------------------------------------------------------------------

View File

@ -0,0 +1,22 @@
#!/bin/sh
cd "${0%/*}" || exit # Run from this directory
. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions
#------------------------------------------------------------------------------
runApplication blockMesh
runApplication surfaceFeatureExtract
mkdir -p 0
# Run with basic
foamDictionary -entry geometry.type -set basic system/fvSchemes
runApplication -s basic snappyHexMesh
runApplication -s basic checkMesh -writeAllFields
foamListTimes -rm
# Run with highAspectRatio
foamDictionary -entry geometry.type -set highAspectRatio system/fvSchemes
runApplication -s highAspectRatio snappyHexMesh
runApplication -s highAspectRatio checkMesh -writeAllFields
#------------------------------------------------------------------------------

View File

@ -0,0 +1,32 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2006 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object transportProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Air temperature at standard atmospheric pressure = 540 R = 300 K
// See README.md
// c = 347.336 [m/s]
// Ma = UInf/c = 0.15
// UInf = 52.1004 [m/s]
// ReChord = 6e6 (per chord)
// Chord = 1 [m]
// ReChord = UInf*Chord/nuFluid
// nuFluid = UInf*Chord/ReChord = 8.6834e-06 [m2/s]
transportModel Newtonian;
nu 8.6834e-06;
// ************************************************************************* //

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,72 @@
solid PART_6
facet normal -0.000000000e+00 -1.767905329e-06 -1.000000000e+00
outer loop
vertex 2.000000000e+00 -1.000000000e+00 5.352202629e-08
vertex 1.000000000e+00 -1.000000000e+00 5.352202629e-08
vertex 1.000000125e+00 0.000000000e+00 -1.714383303e-06
endloop
endfacet
facet normal -2.117582368e-22 -1.767905329e-06 -1.000000000e+00
outer loop
vertex 1.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 2.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 2.000000000e+00 -1.000000000e+00 5.352202629e-08
endloop
endfacet
facet normal -0.000000000e+00 -1.767905329e-06 -1.000000000e+00
outer loop
vertex 3.000000000e+00 -1.000000000e+00 5.352202629e-08
vertex 2.000000000e+00 -1.000000000e+00 5.352202629e-08
vertex 2.000000125e+00 0.000000000e+00 -1.714383303e-06
endloop
endfacet
facet normal 2.117582368e-22 -1.767905329e-06 -1.000000000e+00
outer loop
vertex 2.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 3.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 3.000000000e+00 -1.000000000e+00 5.352202629e-08
endloop
endfacet
facet normal -0.000000000e+00 -1.767905329e-06 -1.000000000e+00
outer loop
vertex 4.000000000e+00 -1.000000000e+00 5.352202629e-08
vertex 3.000000000e+00 -1.000000000e+00 5.352202629e-08
vertex 3.000000125e+00 0.000000000e+00 -1.714383303e-06
endloop
endfacet
facet normal 0.000000000e+00 -1.767905329e-06 -1.000000000e+00
outer loop
vertex 3.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 4.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 4.000000000e+00 -1.000000000e+00 5.352202629e-08
endloop
endfacet
facet normal 2.117582368e-22 -1.767905329e-06 -1.000000000e+00
outer loop
vertex 5.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 6.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 6.000000000e+00 -1.000000000e+00 5.352202629e-08
endloop
endfacet
facet normal 0.000000000e+00 -1.767905329e-06 -1.000000000e+00
outer loop
vertex 5.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 6.000000000e+00 -1.000000000e+00 5.352202629e-08
vertex 5.000000000e+00 -1.000000000e+00 5.352202629e-08
endloop
endfacet
facet normal -2.117582368e-22 -1.767905329e-06 -1.000000000e+00
outer loop
vertex 4.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 5.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 5.000000000e+00 -1.000000000e+00 5.352202629e-08
endloop
endfacet
facet normal 0.000000000e+00 -1.767905329e-06 -1.000000000e+00
outer loop
vertex 4.000000000e+00 -1.000000000e+00 5.352202629e-08
vertex 4.000000125e+00 0.000000000e+00 -1.714383303e-06
vertex 5.000000000e+00 -1.000000000e+00 5.352202629e-08
endloop
endfacet
endsolid

View File

@ -0,0 +1,56 @@
/*--------------------------------*- 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 blockMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
convertToMeters 1;
vertices
(
(-1 -1 -1)
( 2 -1 -1)
( 2 0 -1)
(-1 0 -1)
(-1 -1 1)
( 2 -1 1)
( 2 0 1)
(-1 0 1)
);
blocks
(
// hex (0 1 2 3 4 5 6 7) (15 10 10) simpleGrading (1 1 1)
hex (0 1 2 3 4 5 6 7) (15 5 10) simpleGrading (1 1 1)
);
edges
();
boundary
(
airFlow
{
type patch;
faces
(
(3 7 6 2)
(1 5 4 0) //back
(2 6 5 1) //outlet
(0 4 7 3) //inlet
(0 3 2 1) //lowerWall
(4 5 6 7) //upperWall
);
}
);

View File

@ -0,0 +1,55 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2006 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object controlDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//DebugSwitches
//{
// fvGeometryScheme 1;
// highAspectRatio 1;
// basic 1;
//}
application simpleFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 15000;
deltaT 1;
writeControl timeStep;
writeInterval 5000;
purgeWrite 2;
writeFormat binary;
writePrecision 15;
writeCompression off;
timeFormat general;
timePrecision 8;
runTimeModifiable false;
// ************************************************************************* //

View File

@ -0,0 +1,73 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2006 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
FoamFile
{
version 2;
format ascii;
class dictionary;
object fvSchemes;
}
ddtSchemes
{
default steadyState;
}
gradSchemes
{
default Gauss linear;
grad(p) Gauss linear;
unlimitedGrad(U) Gauss linear;
}
divSchemes
{
default none;
div(phi,U) bounded Gauss linearUpwindV unlimitedGrad(U);
turbulence bounded Gauss limitedLinear 1;
div(phi,k) bounded Gauss limitedLinear 1;
div(phi,omega) bounded Gauss limitedLinear 1;
div(phi,nuTilda) bounded Gauss limitedLinear 1;
div(phi,epsilon) bounded Gauss limitedLinear 1;
div(phi,phit) bounded Gauss limitedLinear 1;
div(phi,f) bounded Gauss limitedLinear 1;
div(phi,gammaInt) bounded Gauss linearUpwind grad;
div(phi,ReThetat) bounded Gauss linearUpwind grad;
div((nuEff*dev2(T(grad(U))))) Gauss linear;
}
laplacianSchemes
{
default Gauss linear limited corrected 0.33;
}
interpolationSchemes
{
default linear;
}
snGradSchemes
{
default limited corrected 0.33;
}
wallDist
{
method meshWave;
}
geometry
{
type highAspectRatio;
minAspect 10;
maxAspect 100;
}
// ************************************************************************* //

View File

@ -0,0 +1,71 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2006 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object fvSolution;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
solvers
{
p
{
solver GAMG;
smoother GaussSeidel;
tolerance 1e-06;
relTol 0.1;
}
"(U|k|omega|nuTilda|gammaInt|ReThetat)"
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-08;
relTol 0.1;
maxIter 50;
}
"(epsilon|phit)"
{
solver PBiCGStab;
preconditioner DILU;
tolerance 1e-8;
relTol 0;
}
f
{
solver PBiCGStab;
preconditioner DIC;
tolerance 1e-8;
relTol 0;
}
}
SIMPLE
{
nNonOrthogonalCorrectors 0;
consistent true;
}
relaxationFactors
{
equations
{
".*" 0.9;
"(gammaInt|ReThetat|k|nuTilda)" 0.8;
"(phit|f)" 0.7;
epsilon 0.5;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,78 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1912 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ 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 20;
maxInternalSkewness 4;
//- 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-13;
//- Minimum quality of the tet formed by the face-centre
// and variable base point minimum decomposition triangles and
// the cell centre. Set to very negative number (e.g. -1E30) to
// disable.
// <0 = inside out tet,
// 0 = flat tet
// 1 = regular tet
minTetQuality 1e-15;
//- Minimum face area. Set to <0 to disable.
minArea -1;
//- Minimum face twist. Set to <-1 to disable. dot product of face normal
// (itself the average of the triangle normals)
// and face centre triangles normal
minTwist 0.02;
//- Minimum normalised cell determinant. This is the determinant of all
// the areas of internal faces. It is a measure of how much of the
// outside area of the cell is to other cells. The idea is that if all
// outside faces of the cell are 'floating' (zeroGradient) the
// 'fixedness' of the cell is determined by the area of the internal faces.
// 1 = hex, <= 0 = folded or flattened illegal cell
minDeterminant 0.001;
//- Relative position of face in relation to cell centres (0.5 for orthogonal
// mesh) (0 -> 0.5)
minFaceWeight 0.05;
//- Volume ratio of neighbouring cells (0 -> 1)
minVolRatio 0.01;
//- Per triangle normal compared to that of preceding triangle. Must be >0
// for Fluent compatibility
minTriangleTwist -1;
//- If >0 : preserve cells with all points on the surface if the
// resulting volume after snapping (by approximation) is larger than
// minVolCollapseRatio times old volume (i.e. not collapsed to flat cell).
// If <0 : delete always.
//minVolCollapseRatio 0.1;
// ************************************************************************* //

View File

@ -0,0 +1,753 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1912 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object snappyHexMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Which of the steps to run
castellatedMesh true;
snap true;
addLayers true;
// Optional: single region surfaces get patch names according to
// surface only. Multi-region surfaces get patch name
// surface "_ "region. Default is true
// singleRegionName false;
// Optional: avoid patch-face merging. Allows mesh to be used for
// refinement/unrefinement
// mergePatchFaces false; // default true
// Optional: preserve all generated patches. Default is to remove
// zero-sized patches.
// keepPatches true;
// Geometry. Definition of all surfaces. All surfaces are of class
// searchableSurface.
// Surfaces are used
// - to specify refinement for any mesh cell intersecting it
// - to specify refinement for any mesh cell inside/outside/near
// - to 'snap' the mesh boundary to the surface
geometry
{
refinement1
{
type searchableBox;
min (-1 -2 -1);
max ( 1 2 1);
}
/*
// Shell for directional refinement
wakeBox
{
type searchableBox;
min (1.5 1 -0.5);
max (3.5 2 0.5);
}
*/
internalFace.stl { name internalFace; type triSurfaceMesh;}
aerofoil.stl
{
name aerofoil;
type triSurfaceMesh;
//tolerance 1E-5; // optional:non-default tolerance on intersections
//maxTreeDepth 10; // optional:depth of octree. Decrease only in case
// of memory limitations.
// Per region the patchname. If not provided will be <surface>_<region>.
// Note: this name cannot be used to identity this region in any
// other part of this dictionary; it is only a name
// for the combination of surface+region (which is only used
// when creating patches)
// regions
// {
// secondSolid
// {
// name mySecondPatch;
// }
// }
}
/*
sphere2
{
type searchableSphere;
centre (1.5 1.5 1.5);
radius 1.03;
}
*/
};
// Settings for the castellatedMesh generation.
castellatedMeshControls
{
// Refinement parameters
// ~~~~~~~~~~~~~~~~~~~~~
// If local number of cells is >= maxLocalCells on any processor
// switches from from refinement followed by balancing
// (current method) to (weighted) balancing before refinement.
maxLocalCells 1000000;
// Overall cell limit (approximately). Refinement will stop immediately
// upon reaching this number so a refinement level might not complete.
// Note that this is the number of cells before removing the part which
// is not 'visible' from the keepPoint. The final number of cells might
// actually be a lot less.
maxGlobalCells 20000000;
// The surface refinement loop might spend lots of iterations refining just
// a few cells. This setting will cause refinement to stop if
// <= minRefinementCells cells are selected for refinement. Note: it will
// at least do one iteration unless
// a: the number of cells to refine is 0
// b: minRefinementCells = -1. This is a special value indicating
// no refinement.
minRefinementCells 0;
// Allow a certain level of imbalance during refining
// (since balancing is quite expensive)
// Expressed as fraction of perfect balance (= overall number of cells /
// nProcs). 0=balance always.
maxLoadUnbalance 0.10;
// Number of buffer layers between different levels.
// 1 means normal 2:1 refinement restriction, larger means slower
// refinement.
nCellsBetweenLevels 4;
// Explicit feature edge refinement
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Specifies a level for any cell intersected by explicitly provided
// edges.
// This is a featureEdgeMesh, read from constant/triSurface for now.
// Specify 'levels' in the same way as the 'distance' mode in the
// refinementRegions (see below). The old specification
// level 2;
// is equivalent to
// levels ((0 2));
features
(
{
file "aerofoil.eMesh";
level 0; // Have level 2 for all cells intersected
// // by feature.
// levels ((0.1 2)); // Have level 2 for all cells within
// // 0.1 of feature.
}
);
// Surface based refinement
// ~~~~~~~~~~~~~~~~~~~~~~~~
// Specifies two levels for every surface. The first is the minimum level,
// every cell intersecting a surface gets refined up to the minimum level.
// The second level is the maximum level. Cells that 'see' multiple
// intersections where the intersections make an
// angle > resolveFeatureAngle get refined up to the maximum level.
refinementSurfaces
{
internalFace { level (0 0); faceZone internalFace; }//faceType baffle;}
aerofoil
{
// Surface-wise min and max refinement level
level (2 2);
//- Optional increment (on top of max level) in small gaps
//gapLevelIncrement 2;
//- Optional angle to detect small-large cell situation
// perpendicular to the surface. Is the angle of face w.r.t.
// the local surface normal. Use on flat(ish) surfaces only.
// Otherwise leave out or set to negative number.
//perpendicularAngle 10;
//- Optional faceZone and (for closed surface) cellZone with
// how to select the cells that are in the cellZone
// (inside / outside / specified insidePoint)
// The orientation of the faceZone is
// - if on cellZone(s) : point out of (minimum) cellZone
// - if freestanding : oriented according to surface
//faceZone sphere;
//cellZone sphere;
//cellZoneInside inside; // outside/insidePoint
//insidePoint (1 1 1); // if (cellZoneInside == insidePoint)
//- Optional specification of what to do with faceZone faces:
// internal : keep them as internal faces (default)
// baffle : create baffles from them. This gives more
// freedom in mesh motion
// boundary : create free-standing boundary faces (baffles
// but without the shared points)
//faceType baffle;
}
}
// Feature angle:
// - used if min and max refinement level of a surface differ
// - used if feature snapping (see snapControls below) is used
resolveFeatureAngle 30;
//- Optional increment (on top of max level) in small gaps
//gapLevelIncrement 2;
// Planar angle:
// - used to determine if surface normals
// are roughly the same or opposite. Used
// - in proximity refinement
// - to decide when to merge free-standing baffles
// (if e.g. running in surfaceSimplify mode set this to 180 to
// merge all baffles)
// - in snapping to avoid snapping to nearest on 'wrong' side
// of thin gap
//
// If not specified same as resolveFeatureAngle
planarAngle 30;
// Region-wise refinement
// ~~~~~~~~~~~~~~~~~~~~~~
// Specifies refinement level for cells in relation to a surface. One of
// three modes
// - distance. 'levels' specifies per distance to the surface the
// wanted refinement level. The distances need to be specified in
// increasing order.
// - inside. 'levels' is only one entry and only the level is used. All
// cells inside the surface get refined up to the level. The surface
// needs to be closed for this to be possible.
// - outside. Same but cells outside.
refinementRegions
{
// refinement1
// {
// mode inside;
// levels ((1.0 1));
// }
/*
//sphere.stl
//{
// mode inside;
// levels ((1.0 4));
// // Optional override of uniform refinement level such
// // that in small gaps we're getting more cells.
// // The specification is
// // - numGapCells : minimum number of cells in the gap
// // (usually >3; lower than this might not
// // resolve correctly)
// // - minLevel : min refinement level at which to kick in
// // - maxLevel : upper refinement level (to avoid refinement
// // continuing on a single extraneous feature)
// // All three settings can be overridden on a surface by
// // surface basis in the refinementSurfaces section.
// gapLevel (<numGapCells> <minLevel> <maxlevel>);
// // Optional: when doing the gapLevel refinement directly remove
// // based on orientation w.r.t. gap. This limits the
// // amount of cells before doing the 'locationInMesh'
// // cell selection. Default is 'mixed' i.e. keep cells
// // whilst doing the gap-level refinement.
// //gapMode inside; // inside/outside/mixed
//}
//wakeBox
//{
// mode inside;
// // Dummy base level
// levels ((10000 0));
//
// // Optional directional refinement (after all other refinement)
// // Directional refinement
// // for all cells according to 'mode' ('inside' or 'outside';
// // 'distance' not supported) and within certain range. E.g.
// // - for all cells with level 2-5
// // - do one split in x direction
// levelIncrement (2 5 (1 0 0));
//
// // Note
// // - ignores 'levels' and gap* settings.
// // - the cellLevel/pointLevels files are no longer consistent
// // with the mesh, the resulting mesh is no longer compatible
// // with e.g. dynamic refinement/unrefinement.
// // - cellLevel will include any directional refinement
// // (i.e. it will be the maximum of all three directions)
//}
//wakeBox
//{
// mode inside;
// // Dummy base level
// levels ((10000 0));
//
// // Optional directional refinement (after all other refinement)
// // Directional refinement
// // for all cells according to 'mode' ('inside' or 'outside';
// // 'distance' not supported) and within certain range. E.g.
// // - for all cells with level 2-5
// // - do one split in x direction
// levelIncrement (2 5 (1 0 0));
//
// // Note
// // - ignores 'levels' and gap* settings.
// // - the cellLevel/pointLevels files are no longer consistent
// // with the mesh, the resulting mesh is no longer compatible
// // with e.g. dynamic refinement/unrefinement.
// // - cellLevel will include any directional refinement
// // (i.e. it will be the maximum of all three directions)
//
// // Optional directional expansion-ratio smoothing (after all
// // refinement). This will try to smooth out edge/cell size jumps
// // Specify smoothing direction and number of iterations
// smoothDirection (1 0 0);
// // Smoothing of expansion ratio
// nSmoothExpansion 100;
// // Smoothing of positions
// nSmoothPosition 100;
//}
*/
}
// Optionally limit refinement in geometric region. This limits all
// refinement (from features, refinementSurfaces, refinementRegions)
// in a given geometric region. The syntax is exactly the same as for the
// refinementRegions; the cell level now specifies the upper limit
// for any cell. (a special setting is cell level -1 which will remove
// any cells inside the region). Note that it does not override the
// refinement constraints given by the nCellsBetweenLevels setting.
limitRegions
{
}
// Mesh selection
// ~~~~~~~~~~~~~~
// After refinement patches get added for all refinementSurfaces and
// all cells intersecting the surfaces get put into these patches. The
// section reachable from the location(s)InMesh is kept.
// NOTE: This point should never be on a face, always inside a cell, even
// after refinement.
//
// There are two different ways of specifying the regions to keep:
// 1. a single locationInMesh. This is the unzoned part of the mesh.
// All the 'zoned' surfaces are marked as such
// in the refinementSurfaces with the faceZone and cellZone keywords.
// It is illegal to have the locationInMesh inside a surface for which
// a cellZone is specified.
//
// or
//
// 2. multiple locationsInMesh, with per location the name of the cellZone.
// This uses walking to determine zones and automatically creates
// faceZones on the outside of cellZones. The special name 'none' is
// used to indicate the unzoned/background part of the mesh.
// Ad 1. Specify a single location and how to treat faces inbetween
// cellZones
locationInMesh (-0.457 -0.5 0.43);
// Whether any faceZones (as specified in the refinementSurfaces)
// are only on the boundary of corresponding cellZones.
// Not used if there are no faceZones. The behaviour has changed
// with respect to previous versions:
// true : all intersections with surface are put in faceZone
// (same behaviour as before)
// false : depending on the type of surface intersected:
// - if intersecting surface has faceZone only (so no cellZone)
// leave in faceZone (so behave as if set to true) (= changed
// behaviour)
// - if intersecting surface has faceZone and cellZone
// remove if inbetween same cellZone or if on boundary
// (same behaviour as before)
allowFreeStandingZoneFaces true;
// 2. Specify multiple locations with optional cellZones for the
// regions (use cellZone "none" to specify the unzoned cells)
// FaceZones are automatically constructed from the
// names of the cellZones: <cellZoneA> _to_ <cellZoneB>
// where the cellZoneA is the lowest numbered cellZone (non-cellZone
// cells are in a special region called "none" which is always
// last).
// Optional locations that should not be reachable from
// location(s)InMesh
// locationsOutsideMesh ((100 100 100));
// Optional: do not remove cells likely to give snapping problems
// handleSnapProblems false;
// Optional: switch off topological test for cells to-be-squashed
// and use geometric test instead
//useTopologicalSnapDetection false;
// Optional: do not refine surface cells with opposite faces of
// differing refinement levels
//interfaceRefine false;
// Optional: use an erosion instead of region assignment to allocate
// left-over cells to the background region (i.e. make cellZones
// consistent with the intersections of the surface).
// Erosion is specified as a number of erosion iterations.
// Erosion has less chance of bleeding and changing the zone
// for a complete region.
//nCellZoneErodeIter 2;
}
// Settings for the snapping.
snapControls
{
// Number of patch smoothing iterations before finding correspondence
// to surface
nSmoothPatch 3;
// Optional: number of smoothing iterations for internal points on
// refinement interfaces. This will reduce non-orthogonality on
// refinement interfaces.
//nSmoothInternal $nSmoothPatch;
// Maximum relative distance for points to be attracted by surface.
// True distance is this factor times local maximum edge length.
tolerance 1.0;
// Number of mesh displacement relaxation iterations.
nSolveIter 30;
// Maximum number of snapping relaxation iterations. Should stop
// before upon reaching a correct mesh.
nRelaxIter 5;
// (wip) disable snapping to opposite near surfaces (revert to 22x
// behaviour)
// detectNearSurfacesSnap false;
// Feature snapping
// Number of feature edge snapping iterations.
// Leave out altogether to disable.
nFeatureSnapIter 10;
// Detect (geometric only) features by sampling the surface
// (default=false).
implicitFeatureSnap false;
// Use castellatedMeshControls::features (default = true)
explicitFeatureSnap true;
// Detect features between multiple surfaces
// (only for explicitFeatureSnap, default = false)
multiRegionFeatureSnap false;
//- When to run face splitting (never at first iteration, always
// at last iteration). Is interval. Default -1 (disabled)
//nFaceSplitInterval 5;
// (wip) Optional for explicit feature snapping:
//- Detect baffle edges. Default is true.
//detectBaffles false;
//- On any faces where points are on multiple regions (see
// multiRegionFeatureSnap) have the other points follow these points
// instead of having their own independent movement, i.e. have snapping
// to multi-region edges/points take priority. This might aid snapping
// to sharp edges that are also region edges. The default is false.
//releasePoints true;
//- Walk along feature edges, adding missing ones. Default is true.
//stringFeatures false;
//- If diagonal attraction also attract other face points. Default is
// false
//avoidDiagonal true;
//- When splitting what concave faces to leave intact. Default is 45
// degrees.
//concaveAngle 30;
//- When splitting the minimum area ratio of faces. If face split
// causes ratio of area less than this do not split. Default is 0.3
//minAreaRatio 0.3;
//- Attract points only to the surface they originate from. Default
// false. This can improve snapping of intersecting surfaces.
strictRegionSnap true;
}
// Settings for the layer addition.
addLayersControls
{
// Are the thickness parameters below relative to the undistorted
// size of the refined cell outside layer (true) or absolute sizes (false).
relativeSizes true;
// Layer thickness specification. This can be specified in one of following
// ways:
// - expansionRatio and finalLayerThickness (cell nearest internal mesh)
// - expansionRatio and firstLayerThickness (cell on surface)
// - overall thickness and firstLayerThickness
// - overall thickness and finalLayerThickness
// - overall thickness and expansionRatio
//
// Note: the mode thus selected is global, i.e. one cannot override the
// mode on a per-patch basis (only the values can be overridden)
// Expansion factor for layer mesh
expansionRatio 1.5;
// Wanted thickness of the layer furthest away from the wall.
// If relativeSizes this is relative to undistorted size of cell
// outside layer.
finalLayerThickness 0.3;
// Wanted thickness of the layer next to the wall.
// If relativeSizes this is relative to undistorted size of cell
// outside layer.
//firstLayerThickness 0.3;
// Wanted overall thickness of layers.
// If relativeSizes this is relative to undistorted size of cell
// outside layer.
//thickness 0.5
// Minimum overall thickness of total layers. If for any reason layer
// cannot be above minThickness do not add layer.
// If relativeSizes this is relative to undistorted size of cell
// outside layer..
minThickness 0.1;
// Per final patch or faceZone (so not geometry!) the layer information
// Note: This behaviour changed after 21x. Any non-mentioned patches
// now slide unless:
// - nSurfaceLayers is explicitly mentioned to be 0.
// - angle to nearest surface < slipFeatureAngle (see below)
layers
{
"internalFace.*" {nSurfaceLayers 20; }
aerofoil
{
nSurfaceLayers 20;
}
}
// If points get not extruded do nGrow layers of connected faces that are
// also not grown. This helps convergence of the layer addition process
// close to features.
// Note: changed(corrected) w.r.t 1.7.x! (didn't do anything in 1.7.x)
nGrow -1;
// Advanced settings
// Static analysis of starting mesh
// When not to extrude surface. 0 is flat surface, 90 is when two faces
// are perpendicular. Note: was not working correctly < 1806
featureAngle 180;
// When to merge patch faces. Default is featureAngle. Useful when
// featureAngle is large.
//mergePatchFacesAngle 45;
// Stop layer growth on highly warped cells
maxFaceThicknessRatio 1000;//0.5;
// Patch displacement
// Number of smoothing iterations of surface normals
nSmoothSurfaceNormals 1;
// Smooth layer thickness over surface patches
nSmoothThickness 10;
// Choice of mesh shrinking algorithm
// Optional mesh shrinking algorithm (default is displacementMedialAxis)
// The displacementMotionSolver is a wrapper around the displacement
// motion solvers. It needs specification of the solver to use and
// its control dictionary.
//meshShrinker displacementMotionSolver;
//solver displacementLaplacian;
//displacementLaplacianCoeffs
//{
// diffusivity quadratic inverseDistance
// (
// sphere.stl_firstSolid
// maxY
// );
//}
// Note that e.g. displacementLaplacian needs entries in
// fvSchemes, fvSolution. Also specify a minIter > 1 when solving
// cellDisplacement since otherwise solution might not be sufficiently
// accurate on points.
// Medial axis analysis (for use with default displacementMedialAxis)
// Angle used to pick up medial axis points
// Note: changed(corrected) w.r.t 1.7.x! 90 degrees corresponds to 130
// in 1.7.x.
minMedialAxisAngle 90;
// Reduce layer growth where ratio thickness to medial
// distance is large
maxThicknessToMedialRatio 0.3;
// Number of smoothing iterations of interior mesh movement direction
nSmoothNormals 3;
// Optional: limit the number of steps walking away from the surface.
// Default is unlimited.
//nMedialAxisIter 10;
// Optional: smooth displacement after medial axis determination.
// default is 0.
//nSmoothDisplacement 90;
// (wip)Optional: do not extrude any point where
// (false) : all surrounding faces are not fully extruded
// (true) : all surrounding points are not extruded
// Default is false.
//detectExtrusionIsland true;
// Optional: do not extrude around sharp edges if both faces are not
// fully extruded i.e. if one of the faces on either side would
// become a wedge.
// Default is 0.5*featureAngle. Set to -180 always attempt extrusion
//layerTerminationAngle 25;
// Optional: disable shrinking of edges that have one (or two) points
// on an extruded patch.
// Default is false to enable single/two cell thick channels to still
// have layers. In <=1806 this was true by default. On larger gaps it
// should have no effect.
//disableWallEdges true;
// Optional: at non-patched sides allow mesh to slip if extrusion
// direction makes angle larger than slipFeatureAngle. Default is
// 0.5*featureAngle.
slipFeatureAngle 10;
// Maximum number of snapping relaxation iterations. Should stop
// before upon reaching a correct mesh.
nRelaxIter 5;
// Mesh shrinking
// Create buffer region for new layer terminations, i.e. gradually
// step down number of layers. Set to <0 to terminate layer in one go.
nBufferCellsNoExtrude 0;
// Overall max number of layer addition iterations. The mesher will
// exit if it reaches this number of iterations; possibly with an
// illegal mesh.
nLayerIter 50;
// Max number of iterations after which relaxed meshQuality controls
// get used. Up to nRelaxedIter it uses the settings in
// meshQualityControls,
// after nRelaxedIter it uses the values in
// meshQualityControls::relaxed.
nRelaxedIter 0;
// Additional reporting: if there are just a few faces where there
// are mesh errors (after adding the layers) print their face centres.
// This helps in tracking down problematic mesh areas.
//additionalReporting true;
}
// Generic mesh quality settings. At any undoable phase these determine
// where to undo.
meshQualityControls
{
// Specify mesh quality constraints in separate dictionary so can
// be reused (e.g. checkMesh -meshQuality)
#include "meshQualityDict"
minDeterminant 1e-8;
// Optional : some meshing phases allow usage of relaxed rules.
// See e.g. addLayersControls::nRelaxedIter.
relaxed
{
// Maximum non-orthogonality allowed. Set to 180 to disable.
maxNonOrtho 75;
minTetQuality -1e30;
minTwist -1;
}
// Advanced
// Number of error distribution iterations
nSmoothScale 4;
// amount to scale back displacement at error points
errorReduction 0.75;
}
// Advanced
//// Debug flags
//debugFlags
//(
// mesh // write intermediate meshes
// intersections // write current mesh intersections as .obj files
// featureSeeds // write information about explicit feature edge
// // refinement
// attraction // write attraction as .obj files
// layerInfo // write information about layers
//);
//
//// Write flags
//writeFlags
//(
// scalarLevels // write volScalarField with cellLevel for postprocessing
// layerSets // write cellSets, faceSets of faces in layer
// layerFields // write volScalarField for layer coverage
//);
//// Format for writing lines. E.g. leak path. Default is vtk format.
//setFormat ensight;
// Merge tolerance. Is fraction of overall bounding box of initial mesh.
// Note: the write tolerance needs to be higher than this.
mergeTolerance 1e-6;
// ************************************************************************* //

View File

@ -0,0 +1,47 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1912 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object surfaceFeatureExtractDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
aerofoil.stl
{
// Extract raw features (none | extractFromFile | extractFromSurface)
extractionMethod extractFromSurface;
// Mark edges whose adjacent surface normals are at an angle less
// than includedAngle as features
// - 0 : selects no edges
// - 180: selects all edges
includedAngle 120;
curvature true;
// Do not mark region edges
geometricTestOnly yes;
// Generate additional intersection features (none | self | region)
intersectionMethod none;
// Tolerance for surface intersections
// tolerance 1e-3;
// Output options:
// Write features to obj format for postprocessing
writeObj yes;
}
// ************************************************************************* //