ENH: snappyHexMesh: add buffer layers before snapping

This commit is contained in:
Mattijs Janssens
2024-12-12 16:13:32 +00:00
parent e7cf8a1d59
commit de5d34787c
231 changed files with 46574 additions and 963 deletions

View File

@ -0,0 +1,11 @@
#!/bin/sh
cd "${0%/*}" || exit # Run from this directory
. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions
#------------------------------------------------------------------------------
cleanCase
# Remove surface and features
rm -rf constant/triSurface
#------------------------------------------------------------------------------

View File

@ -0,0 +1,27 @@
#!/bin/sh
cd "${0%/*}" || exit # Run from this directory
. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions
#------------------------------------------------------------------------------
#- Generate 2x2x1 cells
runApplication blockMesh
#- Remove cell0
runApplication topoSet
runApplication subsetMesh c0 -patch exposed0 -overwrite
#- Put exposed faces (2) into separate patches
runApplication -s face topoSet
runApplication createPatch -overwrite
#- Decompose - creates one processor without any faces in patches
runApplication decomposePar
#- Extract inter-patch points. Should include processor that does not
#- have faces on patch ...
mkdir -p constant/triSurface
runParallel surfaceMeshExtract \
-patches '(exposed0 exposed1)' -featureAngle 180 \
constant/triSurface/blockMesh.obj
#------------------------------------------------------------------------------

View File

@ -0,0 +1,7 @@
- 2x2x1 mesh
- remove one cell, exposing two faces
- move exposed faces into two patches
- decompose onto 3
- run surfaceMeshExtract -featureAngle 180
- should also mark points on the processor that has no
faces but is coupled

View File

@ -0,0 +1,21 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object transportProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
nu 0.01;
// ************************************************************************* //

View File

@ -0,0 +1,88 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object blockMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
scale 1;
vertices
(
//- Single block
(0 0 0)
(2 0 0)
(2 2 0)
(0 2 0)
(0 0 2)
(2 0 2)
(2 2 2)
(0 2 2)
);
blocks
(
hex (0 1 2 3 4 5 6 7) (2 2 1) simpleGrading (1 1 1)
);
edges
(
);
boundary
(
topWall
{
type wall;
faces
(
(3 7 6 2)
);
}
bottomWall
{
type wall;
faces
(
(1 5 4 0)
);
}
fixedWalls
{
type wall;
faces
(
(0 4 7 3)
(2 6 5 1)
);
}
frontAndBack
{
type patch;
faces
(
(0 3 2 1)
(4 5 6 7)
);
}
exposed0
{
type patch;
faces ();
}
);
mergePatchPairs
(
);
// ************************************************************************* //

View File

@ -0,0 +1,48 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object controlDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
application icoFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 0.5;
deltaT 0.005;
writeControl timeStep;
writeInterval 20;
purgeWrite 0;
writeFormat ascii;
writePrecision 16;
writeCompression off;
timeFormat general;
timePrecision 6;
runTimeModifiable true;
// ************************************************************************* //

View File

@ -0,0 +1,44 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object createPatchDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
pointSync false;
// Patches to create.
patches
(
// Example of creating mapped patches using geometric matching
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
// Name of new patch
name exposed1;
// Dictionary to construct new patch from
patchInfo
{
type patch;
}
// How to select the faces:
// - set : specify faceSet in 'set'
// - patches : specify names in 'patches'
// - autoPatch : attempts automatic patching of the specified
// candidates in 'patches'.
constructFrom set;
set exposed0;
}
);
// ************************************************************************* //

View File

@ -0,0 +1,24 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
note "mesh decomposition control dictionary";
object decomposeParDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- The total number of domains (mandatory)
numberOfSubdomains 3;
//- The decomposition method (mandatory)
method scotch;
// ************************************************************************* //

View File

@ -0,0 +1,51 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object fvSchemes;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
ddtSchemes
{
default Euler;
}
gradSchemes
{
default Gauss linear;
grad(p) Gauss linear;
}
divSchemes
{
default none;
div(phi,U) Gauss linear;
}
laplacianSchemes
{
default Gauss linear orthogonal;
}
interpolationSchemes
{
default linear;
}
snGradSchemes
{
default orthogonal;
}
// ************************************************************************* //

View File

@ -0,0 +1,52 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object fvSolution;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
solvers
{
p
{
solver PCG;
preconditioner DIC;
tolerance 1e-06;
relTol 0.05;
}
pFinal
{
$p;
relTol 0;
}
U
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-05;
relTol 0;
}
}
PISO
{
nCorrectors 2;
nNonOrthogonalCorrectors 0;
pRefCell 0;
pRefValue 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,48 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object topoSetDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
actions
(
{
name c0;
type cellSet;
action new;
source labelToCell;
value (0);
}
{
name c0;
type cellSet;
action invert;
}
{
name exposed0;
type faceSet;
action new;
source patchToFace;
patch exposed0;
}
{
name exposed0;
type faceSet;
action subset;
source boxToFace;
box (-100 1 -100)(100 100 100);
}
);
// ************************************************************************* //

View File

@ -99,21 +99,21 @@ label findPatchID(const polyBoundaryMesh& patches, const word& name)
}
labelList patchFaces(const polyBoundaryMesh& patches, const wordList& names)
labelList patchFaces(const polyBoundaryMesh& patches, const wordRes& names)
{
const labelList patchIDs(patches.indices(names));
label n = 0;
forAll(names, i)
for (label patchi : patchIDs)
{
const polyPatch& pp = patches[findPatchID(patches, names[i])];
n += pp.size();
n += patches[patchi].size();
}
labelList faceLabels(n);
n = 0;
forAll(names, i)
for (label patchi : patchIDs)
{
const polyPatch& pp = patches[findPatchID(patches, names[i])];
const polyPatch& pp = patches[patchi];
forAll(pp, j)
{
@ -128,24 +128,25 @@ labelList patchFaces(const polyBoundaryMesh& patches, const wordList& names)
void zoneFaces
(
const faceZoneMesh& fzs,
const wordList& names,
const wordRes& names,
labelList& faceLabels,
bitSet& faceFlip
)
{
const labelList zoneIDs(fzs.indices(names));
label n = 0;
forAll(names, i)
for (label zonei : zoneIDs)
{
const auto& pp = fzs[fzs.findZoneID(names[i])];
n += pp.size();
n += fzs[zonei].size();
}
faceLabels.setSize(n);
faceFlip.setSize(n);
n = 0;
forAll(names, i)
for (label zonei : zoneIDs)
{
const auto& pp = fzs[fzs.findZoneID(names[i])];
const auto& pp = fzs[zonei];
const boolList& ppFlip = pp.flipMap();
forAll(pp, i)
{
@ -345,8 +346,8 @@ int main(int argc, char *argv[])
sourceCaseDir =
sourceCaseDir/("processor" + Foam::name(Pstream::myProcNo()));
}
wordList sourcePatches;
wordList sourceFaceZones;
wordRes sourcePatches;
wordRes sourceFaceZones;
if
(
dict.readIfPresent
@ -868,13 +869,13 @@ int main(int argc, char *argv[])
frontPatchFaces = patchFaces
(
meshFromSurface().boundaryMesh(),
wordList(1, frontPatchName)
wordRes(1, frontPatchName)
);
backPatchName = "otherSide";
backPatchFaces = patchFaces
(
meshFromSurface().boundaryMesh(),
wordList(1, backPatchName)
wordRes(1, backPatchName)
);
}

View File

@ -825,6 +825,17 @@ int main(int argc, char *argv[])
#include "setSystemMeshDictionaryIO.H"
const IOdictionary meshDict(dictIO);
// Overall mesh generation mode
const meshRefinement::MeshType meshType
(
meshRefinement::MeshTypeNames.getOrDefault
(
"type",
meshDict,
meshRefinement::CASTELLATED
)
);
// all surface geometry
const dictionary& geometryDict =
@ -1339,6 +1350,7 @@ int main(int argc, char *argv[])
shells, // for volume (inside/outside) refinement
limitShells, // limit of volume refinement
labelList(), // initial faces to test
meshType, // how to operate
dryRun
);

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2023 OpenCFD Ltd.
Copyright (C) 2016-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -220,7 +220,7 @@ PtrList<FieldType> subsetFields
const pointMesh& pMesh
)
{
const fvMesh& baseMesh = subsetter.baseMesh();
//const fvMesh& baseMesh = subsetter.baseMesh();
const UPtrList<const IOobject> fieldObjects
(
@ -247,8 +247,8 @@ PtrList<FieldType> subsetFields
IOobject
(
io.name(),
baseMesh.time().timeName(),
baseMesh,
pMesh.thisDb().time().timeName(),
pMesh.thisDb(),
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
@ -382,6 +382,8 @@ int main(int argc, char *argv[])
#include "createTime.H"
#include "createNamedMesh.H"
// Make sure pointMesh gets constructed/read as well
(void)pointMesh::New(mesh, IOobject::READ_IF_PRESENT);
// arg[1] = word (cellSet) or wordRes (cellZone)
// const word selectionName = args[1];
@ -583,7 +585,7 @@ int main(int argc, char *argv[])
// Read point fields and subset
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const pointMesh& pMesh = pointMesh::New(mesh);
const pointMesh& pMesh = pointMesh::New(mesh, IOobject::READ_IF_PRESENT);
#undef createSubsetFields
#define createSubsetFields(FieldType, Variable) \
@ -663,6 +665,18 @@ int main(int argc, char *argv[])
subsetter.subMesh().write();
processorMeshes::removeFiles(subsetter.subMesh());
auto* subPointMeshPtr =
subsetter.subMesh().thisDb().findObject<pointMesh>
(
pointMesh::typeName
);
if (subPointMeshPtr)
{
pointMesh& subPointMesh = const_cast<pointMesh&>(*subPointMeshPtr);
subPointMesh.setInstance(subsetter.subMesh().facesInstance());
subPointMesh.write();
}
// Volume fields
for (const auto& fld : vScalarFlds) { fld.write(); }

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2022 OpenCFD Ltd.
Copyright (C) 2016-2022,2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -666,6 +666,9 @@ int main(int argc, char *argv[])
),
decompDictFile
);
// Make sure pointMesh gets read as well
(void)pointMesh::New(mesh, IOobject::READ_IF_PRESENT);
// Decompose the mesh
if (!decomposeFieldsOnly)
@ -785,6 +788,7 @@ int main(int argc, char *argv[])
PtrList<labelIOList> cellProcAddressingList(mesh.nProcs());
PtrList<labelIOList> boundaryProcAddressingList(mesh.nProcs());
PtrList<labelIOList> pointProcAddressingList(mesh.nProcs());
PtrList<labelIOList> pointBoundaryProcAddressingList(mesh.nProcs());
PtrList<fvFieldDecomposer> fieldDecomposerList(mesh.nProcs());
PtrList<pointFieldDecomposer> pointFieldDecomposerList
@ -869,7 +873,10 @@ int main(int argc, char *argv[])
// Point fields
// ~~~~~~~~~~~~
const pointMesh& pMesh = pointMesh::New(mesh);
// Read decomposed pointMesh
const pointMesh& pMesh =
pointMesh::New(mesh, IOobject::READ_IF_PRESENT);
pointFieldDecomposer::fieldsCache pointFieldCache;
@ -1138,7 +1145,34 @@ int main(int argc, char *argv[])
pointProcAddressingList
);
const pointMesh& procPMesh = pointMesh::New(procMesh);
const pointMesh& procPMesh =
pointMesh::New(procMesh, IOobject::READ_IF_PRESENT);
if (!pointBoundaryProcAddressingList.set(proci))
{
pointBoundaryProcAddressingList.set
(
proci,
autoPtr<labelIOList>::New
(
IOobject
(
"boundaryProcAddressing",
procMesh.facesInstance(),
polyMesh::meshSubDir
/pointMesh::meshSubDir,
procPMesh.thisDb(),
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
boundaryProcAddressing
)
);
}
const auto& pointBoundaryProcAddressing =
pointBoundaryProcAddressingList[proci];
if (!pointFieldDecomposerList.set(proci))
{
@ -1150,7 +1184,7 @@ int main(int argc, char *argv[])
pMesh,
procPMesh,
pointProcAddressing,
boundaryProcAddressing
pointBoundaryProcAddressing
)
);
}
@ -1162,6 +1196,12 @@ int main(int argc, char *argv[])
if (times.size() == 1)
{
// Early deletion
pointBoundaryProcAddressingList.set
(
proci,
nullptr
);
pointProcAddressingList.set(proci, nullptr);
pointFieldDecomposerList.set(proci, nullptr);
}

View File

@ -44,6 +44,12 @@ License
#include "decompositionModel.H"
#include "hexRef8Data.H"
// For handling pointMeshes with additional patches
#include "pointMesh.H"
#include "meshPointPatch.H"
#include "processorPointPatch.H"
#include "DynamicField.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::domainDecomposition::mark
@ -740,6 +746,101 @@ bool Foam::domainDecomposition::writeDecomposition(const bool decomposeSets)
procMesh.write();
// Add pointMesh if it was available
const auto* pMeshPtr =
thisDb().cfindObject<pointMesh>(pointMesh::typeName);
if (pMeshPtr)
{
const auto& pMesh = *pMeshPtr;
const auto& pMeshBoundary = pMesh.boundary();
// 1. Generate pointBoundaryMesh from polyBoundaryMesh (so ignoring
// any additional patches
const auto& procPointMesh = pointMesh::New(procMesh);
pointBoundaryMesh& procBoundary =
const_cast<pointBoundaryMesh&>(procPointMesh.boundary());
// 2. Explicitly add subsetted meshPointPatches
forAll(pMeshBoundary, patchi)
{
const auto* mppPtr = isA<meshPointPatch>(pMeshBoundary[patchi]);
if (mppPtr && (procBoundary.findPatchID(mppPtr->name()) == -1))
{
const auto& mpp = *mppPtr;
DynamicList<label> procMeshPoints(mpp.size());
DynamicField<vector> procNormals(mpp.size());
forAll(mpp.meshPoints(), i)
{
const label pointi = mpp.meshPoints()[i];
const label procPointi = pointLookup[pointi];
if (procPointi != -1)
{
procMeshPoints.append(procPointi);
procNormals.append(mpp.pointNormals()[i]);
}
}
procBoundary.push_back
(
new meshPointPatch
(
mpp.name(),
procMeshPoints,
procNormals,
procBoundary.size(),
procBoundary,
meshPointPatch::typeName
)
);
}
}
// 3. Shuffle new patches before any processor patches
labelList oldToNew(procBoundary.size());
label newPatchi = 0;
forAll(procBoundary, patchi)
{
if (!isA<processorPointPatch>(procBoundary[patchi]))
{
oldToNew[patchi] = newPatchi;
newPatchi++;
}
}
// decomposed-to-undecomposed patch numbering
labelList boundaryProcAddressing(identity(newPatchi));
boundaryProcAddressing.setSize(procBoundary.size(), -1);
forAll(procBoundary, patchi)
{
if (isA<processorPointPatch>(procBoundary[patchi]))
{
oldToNew[patchi] = newPatchi++;
}
}
procBoundary.reorder(oldToNew, true);
// Write pointMesh/boundary
procBoundary.write();
// Write pointMesh/boundaryProcAddressing
IOobject ioAddr
(
"boundaryProcAddressing",
procMesh.facesInstance(),
polyMesh::meshSubDir/pointMesh::meshSubDir,
procPointMesh.thisDb(),
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
IOListRef<label>(ioAddr, boundaryProcAddressing).write();
}
// Write points if pointsInstance differing from facesInstance
if (facesInstancePointsPtr_)
{

View File

@ -427,24 +427,18 @@ int main(int argc, char *argv[])
{
Info<< "Reconstructing point fields" << nl << endl;
const pointMesh& pMesh = pointMesh::New(mesh);
PtrList<pointMesh> pMeshes(procMeshes.meshes().size());
forAll(pMeshes, proci)
{
pMeshes.set
(
proci,
new pointMesh(procMeshes.meshes()[proci])
);
}
const pointMesh& pMesh = pointMesh::New
(
mesh,
IOobject::READ_IF_PRESENT
);
pointFieldReconstructor reconstructor
(
pMesh,
pMeshes,
procMeshes.pointMeshes(),
procMeshes.pointProcAddressing(),
procMeshes.boundaryProcAddressing()
procMeshes.pointMeshBoundaryProcAddressing()
);
reconstructor.reconstructAllFields(objects, selectedFields);

View File

@ -1,7 +1,9 @@
EXE_INC = \
-I$(LIB_SRC)/surfMesh/lnInclude \
-I$(LIB_SRC)/fileFormats/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude
EXE_LIBS = \
-lsurfMesh \
-lfileFormats \
-lmeshTools

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2023 OpenCFD Ltd.
Copyright (C) 2017-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -34,13 +34,39 @@ Description
Extract patch or faceZone surfaces from a polyMesh.
Depending on output surface format triangulates faces.
Region numbers on faces no guaranteed to be the same as the patch indices.
Region numbers on faces not guaranteed to be the same as the patch indices.
Optionally only extracts named patches.
Optionally filters out points on faceZones, feature-edges and
featurePoints and generates pointPatches
for these - written to pointMesh/boundary.
If run in parallel, processor patches get filtered out by default and
the mesh is merged (based on topology).
Usage
\b surfaceMeshExtract [OPTION] \<surfacefile\>
Options:
- \par -patches NAME | LIST
Specify single patch or multiple patches (name or regex) to extract
- \par -faceZones NAME | LIST
Specify single zone or multiple face zones (name or regex) to extract
- \par -exclude-patches NAME | LIST
Exclude single or multiple patches (name or regex) from extraction
- \par -excludeProcPatches
Exclude processor patches (default if parallel)
- \par -featureAngle \<angle\>
Extract feature edges/points and put into separate point-patches
- \par -extractZonePoints
Extract all face zone points and put into separate point-patches
\*---------------------------------------------------------------------------*/
#include "MeshedSurface.H"
@ -48,6 +74,7 @@ Description
#include "argList.H"
#include "Time.H"
#include "polyMesh.H"
#include "pointMesh.H"
#include "emptyPolyPatch.H"
#include "processorPolyPatch.H"
#include "ListListOps.H"
@ -56,11 +83,79 @@ Description
#include "globalMeshData.H"
#include "globalIndex.H"
#include "timeSelector.H"
#include "meshPointPatch.H"
#include "unitConversion.H"
#include "dummyTransform.H"
#include "syncTools.H"
#include "processorPointPatch.H"
#include "pointMeshTools.H"
#include "OBJstream.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void writeOBJ
(
const fileName& path,
const pointPatch& pp
)
{
const meshPointPatch& ppp = refCast<const meshPointPatch>(pp);
const polyMesh& mesh = ppp.boundaryMesh().mesh().mesh();
// Count constraints
label maxConstraint = 0;
const auto& constraints = ppp.constraints();
forAll(constraints, i)
{
maxConstraint = max(maxConstraint, constraints[i].first());
}
reduce(maxConstraint, maxOp<label>());
const pointField localPoints(mesh.points(), ppp.meshPoints());
if (maxConstraint == 3)
{
OBJstream os
(
path
/ ppp.name()+"_fixedPoints.obj"
);
os.write(localPoints);
Info<< "Written pointPatch " << ppp.name() << " to " << os.name()
<< endl;
}
else if (maxConstraint == 2)
{
OBJstream os
(
path
/ ppp.name()+"_slidingPoints.obj"
);
forAll(localPoints, i)
{
os.write(localPoints[i], constraints[i].second());
}
Info<< "Written pointPatch " << ppp.name() << " to " << os.name()
<< " as coordinates and normals"
<< endl;
}
else if (maxConstraint == 1)
{
OBJstream os
(
path
/ ppp.name()+"_surfacePoints.obj"
);
os.write(localPoints);
Info<< "Written pointPatch " << ppp.name() << " to " << os.name()
<< " as coordinates"
<< endl;
}
}
labelList getSelectedPatches
(
const polyBoundaryMesh& patches,
@ -107,6 +202,286 @@ labelList getSelectedPatches
}
label addMeshPointPatches
(
const polyMesh& mesh,
const pointMesh& pMesh,
const uindirectPrimitivePatch& allBoundary,
const labelUList& faceToZone,
const surfZoneIdentifierList& surfZones,
const labelList& faceZoneToCompactZone,
const scalar edgeFeatureAngle,
const scalar pointFeatureAngle,
const bool verbose = true,
const bool writePoints = false
)
{
const auto& pointBm = pMesh.boundary();
const auto& fzs = mesh.faceZones();
const label nPointPatches = pointBm.size();
const pointField& points = mesh.points();
// Feature edge(points) internal to a zone
labelListList zoneToMeshPoints;
List<pointConstraintList> zoneToConstraints;
// Feature edge(points) in between zones
labelList twoZoneMeshPoints;
pointConstraintList twoZoneConstraints;
// Feature points on > 2 zones
labelList multiZoneMeshPoints;
pointConstraintList multiZoneConstraints;
pointMeshTools::featurePointsEdges
(
mesh,
allBoundary,
// Per boundary face to zone
faceToZone,
// Number of zones
surfZones.size(),
edgeFeatureAngle,
//const scalar pointFeatureAngle, //not yet done
// Feature edge(points) internal to a zone
zoneToMeshPoints,
zoneToConstraints,
// Feature edge(points) in between zones
twoZoneMeshPoints,
twoZoneConstraints,
// Feature points on > 2 zones
multiZoneMeshPoints,
multiZoneConstraints
);
// Add per-zone patches
if (faceZoneToCompactZone.size())
{
// Calculate point normals consistent across whole patch
const pointField pointNormals
(
PatchTools::pointNormals
(
mesh,
allBoundary
)
);
forAll(faceZoneToCompactZone, zonei)
{
const label compacti = faceZoneToCompactZone[zonei];
if (compacti != -1)
{
const word patchName(surfZones[compacti].name());
if (pointBm.findPatchID(patchName) == -1)
{
// Extract the points originating from the faceZone. Can
// - re-call featurePointsEdges with 0 feature angle so
// all points go into the feature edges
// - mark using faceToZone the correct points
// - or assume the whole faceZone was extracted:
const uindirectPrimitivePatch fzPatch
(
UIndirectList<face>
(
mesh.faces(),
fzs[zonei].addressing()
),
points
);
const auto& mp = fzPatch.meshPoints();
const vector nullVector(vector::uniform(0));
// Extract pointNormal (or 0) on all patch/connected points
vectorField meshPointNormals(mesh.nPoints(), nullVector);
for (const label pointi : mp)
{
const label allPointi =
allBoundary.meshPointMap()[pointi];
meshPointNormals[pointi] = pointNormals[allPointi];
}
syncTools::syncPointList
(
mesh,
meshPointNormals,
maxMagSqrEqOp<vector>(),
nullVector
);
// Extract indices with non-zero pointNormal
DynamicList<label> meshPoints(mp.size());
forAll(meshPointNormals, pointi)
{
if (meshPointNormals[pointi] != nullVector)
{
meshPoints.append(pointi);
}
}
const_cast<pointBoundaryMesh&>(pointBm).push_back
(
new meshPointPatch
(
patchName,
meshPoints,
vectorField(meshPointNormals, meshPoints),
pointBm.size(),
pointBm,
meshPointPatch::typeName
)
);
if (verbose)
{
const auto& ppp = pointBm.last();
Info<< "Added zone pointPatch " << ppp.name()
<< " with "
<< returnReduce(meshPoints.size(), sumOp<label>())
<< " points" << endl;
}
if (writePoints)
{
writeOBJ(mesh.path(), pointBm.last());
}
}
}
}
}
// Add per-patch feature-edges
forAll(zoneToMeshPoints, zonei)
{
const label nPoints =
returnReduce(zoneToMeshPoints[zonei].size(), sumOp<label>());
const word patchName(surfZones[zonei].name() + "Edges");
if (nPoints && (pointBm.findPatchID(patchName) == -1))
{
const_cast<pointBoundaryMesh&>(pointBm).push_back
(
new meshPointPatch
(
patchName,
zoneToMeshPoints[zonei],
zoneToConstraints[zonei],
pointBm.size(),
pointBm,
meshPointPatch::typeName
)
);
if (verbose)
{
const auto& ppp = pointBm.last();
Info<< "Added feature-edges pointPatch " << ppp.name()
<< " with " << nPoints << " points" << endl;
}
if (writePoints)
{
writeOBJ(mesh.path(), pointBm.last());
}
}
}
// Add inter-patch points
const word allEdgePatchName("boundaryEdges");
const label nPatchEdgePoints =
returnReduce(twoZoneMeshPoints.size(), sumOp<label>());
if (nPatchEdgePoints && (pointBm.findPatchID(allEdgePatchName) == -1))
{
const_cast<pointBoundaryMesh&>(pointBm).push_back
(
new meshPointPatch
(
allEdgePatchName,
twoZoneMeshPoints,
twoZoneConstraints,
pointBm.size(),
pointBm,
meshPointPatch::typeName
)
);
if (verbose)
{
const auto& ppp = pointBm.last();
Info<< "Added inter-patch pointPatch " << ppp.name()
<< " with " << nPatchEdgePoints << " points" << endl;
}
if (writePoints)
{
writeOBJ(mesh.path(), pointBm.last());
}
}
const word allPointPatchName("boundaryPoints");
const label nMultiPoints =
returnReduce(multiZoneMeshPoints.size(), sumOp<label>());
if (nMultiPoints && (pointBm.findPatchID(allPointPatchName) == -1))
{
const_cast<pointBoundaryMesh&>(pointBm).push_back
(
new meshPointPatch
(
allPointPatchName,
multiZoneMeshPoints,
multiZoneConstraints,
pointBm.size(),
pointBm,
meshPointPatch::typeName
)
);
if (verbose)
{
const auto& ppp = pointBm.last();
Info<< "Added multi-patch pointPatch " << ppp.name()
<< " with " << nMultiPoints << " points" << endl;
}
if (writePoints)
{
writeOBJ(mesh.path(), pointBm.last());
}
}
// Shuffle into order
labelList oldToNew(pointBm.size());
label newPatchi = 0;
forAll(pointBm, patchi)
{
if (!isA<processorPointPatch>(pointBm[patchi]))
{
oldToNew[patchi] = newPatchi++;
}
}
forAll(pointBm, patchi)
{
if (isA<processorPointPatch>(pointBm[patchi]))
{
oldToNew[patchi] = newPatchi++;
}
}
const_cast<pointBoundaryMesh&>(pointBm).reorder(oldToNew, true);
return pointBm.size() - nPointPatches;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
@ -114,8 +489,6 @@ int main(int argc, char *argv[])
argList::addNote
(
"Extract patch or faceZone surfaces from a polyMesh."
" The name is historical, it only triangulates faces"
" when the output format requires it."
);
timeSelector::addOptions();
@ -153,6 +526,22 @@ int main(int argc, char *argv[])
true // mark as an advanced option
);
argList::addOptionCompat("exclude-patches", {"excludePatches", 2306});
argList::addOption
(
"featureAngle",
"angle",
"Auto-extract feature edges/points and put into separate point-patches"
);
argList::addBoolOption
(
"extractZonePoints",
"Extract point-patches for selected faceZones"
);
argList::addBoolOption
(
"writeOBJ",
"Write added pointPatch points to .obj files"
);
#include "setRootCase.H"
#include "createTime.H"
@ -200,9 +589,37 @@ int main(int argc, char *argv[])
<< nl << endl;
}
scalar featureAngle = 180.0;
const bool specifiedFeature = args.readIfPresent
(
"featureAngle",
featureAngle
);
const bool extractZonePoints = args.found("extractZonePoints");
const bool writeOBJ = args.found("writeOBJ");
Info<< "Reading mesh from time " << runTime.value() << endl;
#include "createNamedPolyMesh.H"
if (specifiedFeature)
{
Info<< "Detecting all sharp (>" << featureAngle
<< " degrees) patch edges." << nl << endl;
if (extractZonePoints)
{
Info<< "Extracting all faceZone points as pointPatches."
<< nl << endl;
}
//#include "createNamedPointMesh.H"
// Do not read constant/pointMesh - construct from polyMesh only
Info<< "Create pointMesh for time = "
<< runTime.timeName() << Foam::nl << Foam::endl;
(void)pointMesh::New(mesh);
}
// User specified times
instantList timeDirs = timeSelector::select0(runTime, args);
@ -249,7 +666,7 @@ int main(int argc, char *argv[])
// Construct table of patches to include.
const polyBoundaryMesh& bMesh = mesh.boundaryMesh();
labelList patchIds =
const labelList patchIds =
(
(includePatches.size() || excludePatches.size())
? getSelectedPatches(bMesh, includePatches, excludePatches)
@ -276,7 +693,13 @@ int main(int argc, char *argv[])
// Mesh face and compact zone indx
DynamicList<label> faceLabels;
DynamicList<label> compactZones;
// Per compact 'zone' index the name and location
surfZoneIdentifierList surfZones;
// Per local patch to compact 'zone' index (or -1)
labelList patchToCompactZone(bMesh.size(), -1);
// Per local faceZone to compact 'zone' index (or -1)
labelList faceZoneToCompactZone(bMesh.size(), -1);
{
// Collect sizes. Hash on names to handle local-only patches (e.g.
// processor patches)
@ -317,9 +740,18 @@ int main(int argc, char *argv[])
Pstream::broadcast(compactZoneID);
// Zones
surfZones.resize_nocopy(compactZoneID.size());
forAllConstIters(compactZoneID, iter)
{
surfZones[*iter] = surfZoneIdentifier(iter.key(), *iter);
Info<< "surfZone " << *iter
<< " : " << surfZones[*iter].name()
<< endl;
}
// Rework HashTable into labelList just for speed of conversion
labelList patchToCompactZone(bMesh.size(), -1);
labelList faceZoneToCompactZone(bMesh.size(), -1);
forAllConstIters(compactZoneID, iter)
{
label patchi = bMesh.findPatchID(iter.key());
@ -362,7 +794,7 @@ int main(int argc, char *argv[])
// Addressing engine for all faces
uindirectPrimitivePatch allBoundary
const uindirectPrimitivePatch allBoundary
(
UIndirectList<face>(mesh.faces(), faceLabels),
mesh.points()
@ -400,7 +832,7 @@ int main(int argc, char *argv[])
// Gather all ZoneIDs
List<labelList> gatheredZones(Pstream::nProcs());
gatheredZones[Pstream::myProcNo()].transfer(compactZones);
gatheredZones[Pstream::myProcNo()] = compactZones;
Pstream::gatherList(gatheredZones);
// On master combine all points, faces, zones
@ -428,16 +860,6 @@ int main(int argc, char *argv[])
gatheredZones.clear();
// Zones
surfZoneIdentifierList surfZones(compactZoneID.size());
forAllConstIters(compactZoneID, iter)
{
surfZones[*iter] = surfZoneIdentifier(iter.key(), *iter);
Info<< "surfZone " << *iter
<< " : " << surfZones[*iter].name()
<< endl;
}
UnsortedMeshedSurface<face> unsortedFace
(
std::move(allPoints),
@ -464,6 +886,39 @@ int main(int argc, char *argv[])
sortedFace.write(globalCasePath);
}
if (specifiedFeature)
{
// Add edge patches
const auto& pMesh = pointMesh::New(mesh);
const label nAdded = addMeshPointPatches
(
mesh,
pMesh,
allBoundary, // all patches together
compactZones, // originating compactZone
surfZones, // per compactZone the index
(
extractZonePoints
? faceZoneToCompactZone // per faceZone the compactZone
: labelList::null()
),
featureAngle,
featureAngle,
true,
writeOBJ
);
if (nAdded)
{
pMesh.boundary().write();
}
}
}
Info<< "End\n" << endl;

View File

@ -26,6 +26,7 @@ constructFrom patch;
// If construct from patch/mesh:
sourceCase "<case>";
// and one of sourcePatches or sourceFaceZones (but not both):
// (note: wildcards allowed)
sourceFaceZones (someFacesZone);
sourcePatches (movingWall);

View File

@ -14,6 +14,12 @@ FoamFile
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Type of mesh generation:
// - castellated (default)
// - castellatedBufferLayer
//type castellatedBufferLayer;
// Which of the steps to run
castellatedMesh true;
snap true;
@ -267,6 +273,10 @@ castellatedMeshControls
// these can be done with feature edge snapping (so can leave
// level (0 0))
//curvatureLevel (10 0 10 -1);
// Optional disabling of buffer layer addition (if switched on by
// type = castellatedBufferLayer)
addBufferLayers false;
}
}
@ -605,6 +615,18 @@ snapControls
//- Attract points only to the surface they originate from. Default
// false. This can improve snapping of intersecting surfaces.
// strictRegionSnap true;
// Choice of mesh motion algorithm to inflate layers (only used for mode
// castellatedBufferLayer)
//solver displacementPointSmoothing;
//displacementPointSmoothingCoeffs
//{
// // Use laplacian to untangle problem areas
// pointSmoother laplacian;
// nPointSmootherIter 10;
//}
}
// Settings for the layer addition.

View File

@ -501,6 +501,15 @@ pointSet_doc
}
//- All points of pointpatch
{
source patchToPoint;
patches ("patch.*");
// or
patch somePatch;
}
//- Copy elements from pointSet
{
source pointToPoint;

View File

@ -715,10 +715,15 @@ pointMeshMapper = $(pointMesh)/pointMeshMapper
$(pointMeshMapper)/pointMapper.C
$(pointMeshMapper)/pointPatchMapper.C
pointMeshTools = $(pointMesh)/pointMeshTools
$(pointMeshTools)/pointMeshTools.C
pointPatches = $(pointMesh)/pointPatches
$(pointPatches)/pointPatch/pointPatch.C
$(pointPatches)/pointPatch/pointPatchNew.C
$(pointPatches)/facePointPatch/facePointPatch.C
$(pointPatches)/facePointPatch/facePointPatchNew.C
$(pointPatches)/meshPointPatch/meshPointPatch.C
basicPointPatches = $(pointPatches)/basic
$(basicPointPatches)/coupled/coupledPointPatch.C
@ -792,6 +797,7 @@ $(Fields)/fieldTypes.C
pointPatchFields = fields/pointPatchFields
$(pointPatchFields)/pointPatchField/pointPatchFieldBase.C
$(pointPatchFields)/pointPatchField/pointPatchFields.C
$(pointPatchFields)/pointPatchField/pointConstraint/pointConstraint.C
basicPointPatchFields = $(pointPatchFields)/basic
$(basicPointPatchFields)/calculated/calculatedPointPatchFields.C

View File

@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "pointConstraint.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
const char* const pTraits<pointConstraint>::typeName = "pointConstraint";
}
// ************************************************************************* //

View File

@ -73,6 +73,9 @@ public:
//- Construct from components
inline pointConstraint(const Tuple2<label, vector>&);
//- Construct from components
inline pointConstraint(const label count, const vector& n);
//- Construct from Istream
inline pointConstraint(Istream&);
@ -97,8 +100,19 @@ public:
};
//! List of pointConstraint
typedef List<pointConstraint> pointConstraintList;
// * * * * * * * * * * * * * * * * * Traits * * * * * * * * * * * * * * * * //
//- Template specialisation for pTraits\<pointConstraint\> to enable IO
template<>
struct pTraits<pointConstraint>
{
static const char* const typeName;
};
//- Contiguous data for pointConstraint
template<> struct is_contiguous<pointConstraint> : std::true_type {};

View File

@ -39,6 +39,16 @@ inline Foam::pointConstraint::pointConstraint(const Tuple2<label, vector>& pc)
{}
inline Foam::pointConstraint::pointConstraint
(
const label count,
const vector& n
)
:
Tuple2<label, vector>(count, n)
{}
inline Foam::pointConstraint::pointConstraint(Istream& is)
:
Tuple2<label, vector>(is)

View File

@ -0,0 +1,10 @@
Foam::Info
<< "Create pointMesh for time = "
<< runTime.timeName() << Foam::nl << Foam::endl;
// Register pointMesh on the database
const Foam::pointMesh& pMesh = pointMesh::New
(
mesh,
Foam::IOobject::READ_IF_PRESENT
);

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2018-2023 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -33,9 +33,74 @@ License
#include "PstreamBuffers.H"
#include "lduSchedule.H"
#include "globalMeshData.H"
#include "processorPointPatch.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(pointBoundaryMesh, 0);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
bool Foam::pointBoundaryMesh::hasGroupIDs() const
{
if (groupIDsPtr_)
{
// Use existing cache
return !groupIDsPtr_->empty();
}
const auto& patches = *this;
for (const auto& p : patches)
{
if (!p.inGroups().empty())
{
return true;
}
}
return false;
}
void Foam::pointBoundaryMesh::calcGroupIDs() const
{
if (groupIDsPtr_)
{
return; // Or FatalError
}
groupIDsPtr_.emplace(16);
auto& groupLookup = *groupIDsPtr_;
const auto& patches = *this;
forAll(patches, patchi)
{
for (const word& groupName : patches[patchi].inGroups())
{
groupLookup(groupName).push_back(patchi);
}
}
// Remove groups that clash with patch names
forAll(patches, patchi)
{
if (groupLookup.erase(patches[patchi].name()))
{
WarningInFunction
<< "Removed group '" << patches[patchi].name()
<< "' which clashes with patch " << patchi
<< " of the same name."
<< endl;
}
}
}
void Foam::pointBoundaryMesh::addPatches(const polyBoundaryMesh& pbm)
{
// Set boundary patches
@ -43,7 +108,7 @@ void Foam::pointBoundaryMesh::addPatches(const polyBoundaryMesh& pbm)
patches.resize_null(pbm.size());
forAll(patches, patchi)
forAll(pbm, patchi)
{
// NB: needs ptr() to get *pointPatch instead of *facePointPatch
patches.set(patchi, facePointPatch::New(pbm[patchi], *this).ptr());
@ -60,21 +125,301 @@ Foam::pointBoundaryMesh::pointBoundaryMesh
)
:
pointPatchList(),
regIOobject
(
IOobject
(
"boundary",
//m.thisDb().time().findInstance(m.meshDir(), "boundary"),
pbm.mesh().facesInstance(),
polyMesh::meshSubDir/pointMesh::meshSubDir,
m.thisDb(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false // Avoid conflict with polyMesh/boundary
)
),
mesh_(m)
{
addPatches(pbm);
if (debug)
{
pointPatchList& Patches = *this;
Pout<< "pointBoundaryMesh::pointBoundaryMesh"
<< "(const pointMesh&, const polyBoundaryMesh&): "
<< "constructed pointBoundaryMesh:" << endl;
Pout<< incrIndent;
for (const auto& pp : Patches)
{
Pout<< indent
<< "index:" << pp.index() << " patch:" << pp.name()
<< " type:" << pp.type() << endl;
}
Pout<< decrIndent;
}
}
Foam::pointBoundaryMesh::pointBoundaryMesh
(
const IOobject& io,
const pointMesh& m,
const polyBoundaryMesh& pbm
)
:
pointPatchList(),
regIOobject
(
IOobject
(
"boundary",
io.instance(),
polyMesh::meshSubDir/pointMesh::meshSubDir,
io.db(),
io.readOpt(),
io.writeOpt(),
false //io.registerObject() // or always set to false?
)
),
mesh_(m)
{
pointPatchList& Patches = *this;
if (isReadRequired() || (isReadOptional() && headerOk()))
{
if (readOpt() == IOobject::MUST_READ_IF_MODIFIED)
{
WarningInFunction
<< "Specified IOobject::MUST_READ_IF_MODIFIED but class"
<< " does not support automatic rereading."
<< endl;
}
if (debug)
{
Pout<< "pointBoundaryMesh::pointBoundaryMesh"
<< "(const IOobject&, const pointMesh&,"
<< " const polyBoundaryMesh&): "
<< "Constructing from boundary file " << objectRelPath()
<< endl;
}
// Read pointPatchList
Istream& is = readStream(typeName);
PtrList<entry> patchEntries(is);
Patches.setSize(patchEntries.size());
forAll(Patches, patchi)
{
// Try construct-from-dictionary first
const word& name = patchEntries[patchi].keyword();
autoPtr<pointPatch> pPtr
(
pointPatch::New
(
name,
patchEntries[patchi].dict(),
patchi,
*this
)
);
if (!pPtr)
{
const label polyPatchi = pbm.findPatchID(name, false);
// Try as facePointPatch from polyPatch
pPtr = facePointPatch::New(pbm[polyPatchi], *this);
pPtr->index() = patchi;
}
Patches.set(patchi, pPtr);
}
// Check state of IOstream
is.check
(
"pointBoundaryMesh::pointBoundaryMesh"
"(const IOobject&, const pointMesh&,"
" const polyBoundaryMesh&)"
);
close();
}
else
{
if (debug)
{
Pout<< "pointBoundaryMesh::pointBoundaryMesh"
<< "(const IOobject&, const pointMesh&,"
<< " const polyBoundaryMesh&): "
<< "Constructing from polyBoundaryMesh only"
<< endl;
}
addPatches(pbm);
}
if (debug)
{
Pout<< "pointBoundaryMesh::pointBoundaryMesh"
<< "(const IOobject&, const pointMesh&, const polyBoundaryMesh&): "
<< "constructed pointBoundaryMesh:" << endl;
Pout<< incrIndent;
for (const auto& pp : Patches)
{
Pout<< indent
<< "index:" << pp.index() << " patch:" << pp.name()
<< " type:" << pp.type() << endl;
}
Pout<< decrIndent;
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::pointBoundaryMesh::nNonProcessor() const
{
const pointPatchList& patches = *this;
label count = 0;
for (const auto& p : patches)
{
if (isA<processorPointPatch>(p))
{
break;
}
++count;
}
return count;
}
Foam::label Foam::pointBoundaryMesh::nProcessorPatches() const
{
const pointPatchList& patches = *this;
label count = 0;
for (const auto& p : patches)
{
if (isA<processorPointPatch>(p))
{
++count;
}
}
return count;
}
Foam::wordList Foam::pointBoundaryMesh::names() const
{
return PtrListOps::get<word>(*this, nameOp<pointPatch>());
}
Foam::wordList Foam::pointBoundaryMesh::types() const
{
return PtrListOps::get<word>(*this, typeOp<pointPatch>());
}
Foam::wordList Foam::pointBoundaryMesh::physicalTypes() const
{
return
PtrListOps::get<word>
(
*this,
[](const pointPatch& p) { return p.physicalType(); }
);
}
const Foam::HashTable<Foam::labelList>&
Foam::pointBoundaryMesh::groupPatchIDs() const
{
if (!groupIDsPtr_)
{
calcGroupIDs();
}
return *groupIDsPtr_;
}
Foam::labelList Foam::pointBoundaryMesh::indices
(
const wordRe& matcher,
const bool useGroups
) const
{
return mesh().boundaryMesh().indices(matcher, useGroups);
if (matcher.empty())
{
return labelList();
}
// Only check groups if requested and they exist
const bool checkGroups = (useGroups && this->hasGroupIDs());
labelHashSet ids(0);
if (matcher.isPattern())
{
if (checkGroups)
{
const auto& groupLookup = groupPatchIDs();
forAllConstIters(groupLookup, iter)
{
if (matcher(iter.key()))
{
// Add patch ids associated with the group
ids.insert(iter.val());
}
}
}
if (ids.empty())
{
return PtrListOps::findMatching(*this, matcher);
}
else
{
ids.insert(PtrListOps::findMatching(*this, matcher));
}
}
else
{
// Literal string.
// Special version of above for reduced memory footprint.
const label patchId = PtrListOps::firstMatching(*this, matcher);
if (patchId >= 0)
{
return labelList(one{}, patchId);
}
else if (checkGroups)
{
const auto iter = groupPatchIDs().cfind(matcher);
if (iter.good())
{
// Hash ids associated with the group
ids.insert(iter.val());
}
}
}
return ids.sortedToc();
}
@ -84,7 +429,43 @@ Foam::labelList Foam::pointBoundaryMesh::indices
const bool useGroups
) const
{
return mesh().boundaryMesh().indices(matcher, useGroups);
if (matcher.empty())
{
return labelList();
}
else if (matcher.size() == 1)
{
return this->indices(matcher.front(), useGroups);
}
labelHashSet ids(0);
// Only check groups if requested and they exist
if (useGroups && this->hasGroupIDs())
{
ids.reserve(this->size());
const auto& groupLookup = groupPatchIDs();
forAllConstIters(groupLookup, iter)
{
if (matcher(iter.key()))
{
// Add patch ids associated with the group
ids.insert(iter.val());
}
}
}
if (ids.empty())
{
return PtrListOps::findMatching(*this, matcher);
}
else
{
ids.insert(PtrListOps::findMatching(*this, matcher));
}
return ids.sortedToc();
}
@ -95,13 +476,91 @@ Foam::labelList Foam::pointBoundaryMesh::indices
const bool useGroups
) const
{
return mesh().boundaryMesh().indices(select, ignore, useGroups);
//return mesh().boundaryMesh().indices(select, ignore, useGroups);
if (ignore.empty())
{
return this->indices(select, useGroups);
}
const wordRes::filter matcher(select, ignore);
labelHashSet ids(0);
// Only check groups if requested and they exist
if (useGroups && this->hasGroupIDs())
{
ids.reserve(this->size());
const auto& groupLookup = groupPatchIDs();
forAllConstIters(groupLookup, iter)
{
if (matcher(iter.key()))
{
// Add patch ids associated with the group
ids.insert(iter.val());
}
}
}
if (ids.empty())
{
return PtrListOps::findMatching(*this, matcher);
}
else
{
ids.insert(PtrListOps::findMatching(*this, matcher));
}
return ids.sortedToc();
}
Foam::label Foam::pointBoundaryMesh::findPatchID(const word& patchName) const
Foam::label Foam::pointBoundaryMesh::findPatchID
(
const word& patchName,
bool allowNotFound
) const
{
return mesh().boundaryMesh().findPatchID(patchName);
//return mesh().boundaryMesh().findPatchID(patchName);
if (patchName.empty())
{
return -1;
}
const label patchId = PtrListOps::firstMatching(*this, patchName);
if (patchId >= 0)
{
return patchId;
}
if (!allowNotFound)
{
FatalErrorInFunction
<< "Patch '" << patchName << "' not found. "
<< "Available patch names";
if (polyMesh::defaultRegion != mesh_.name())
{
FatalError
<< " in region '" << mesh_.name() << "'";
}
FatalError
<< " include: " << names() << endl
<< exit(FatalError);
}
// Patch not found
if (debug)
{
Pout<< "label pointBoundaryMesh::findPatchID(const word&) const"
<< " Patch named " << patchName << " not found. "
<< "Available patch names: " << names() << endl;
}
// Not found, return -1
return -1;
}
@ -243,4 +702,80 @@ void Foam::pointBoundaryMesh::updateMesh()
}
void Foam::pointBoundaryMesh::reorder
(
const labelUList& oldToNew,
const bool validBoundary
)
{
// Change order of patches
pointPatchList::reorder(oldToNew);
// Adapt indices
pointPatchList& patches = *this;
forAll(patches, patchi)
{
patches[patchi].index() = patchi;
}
// Clear group-to-patch addressing. Note: could re-calculate
groupIDsPtr_.reset(nullptr);
if (validBoundary)
{
updateMesh();
}
if (debug)
{
pointPatchList& Patches = *this;
Pout<< "pointBoundaryMesh::reorder"
<< "(const labelUList&, const bool): "
<< "reordered pointBoundaryMesh:" << endl;
Pout<< incrIndent;
for (const auto& pp : Patches)
{
Pout<< indent
<< "index:" << pp.index() << " patch:" << pp.name()
<< " type:" << pp.type() << endl;
}
Pout<< decrIndent;
}
}
bool Foam::pointBoundaryMesh::writeData(Ostream& os) const
{
const pointPatchList& patches = *this;
os << patches.size() << nl << token::BEGIN_LIST << incrIndent << nl;
forAll(patches, patchi)
{
os << indent << patches[patchi].name() << nl
<< indent << token::BEGIN_BLOCK << nl
<< incrIndent << patches[patchi] << decrIndent
<< indent << token::END_BLOCK << endl;
}
os << decrIndent << token::END_LIST;
// Check state of IOstream
os.check("pointBoundaryMesh::writeData(Ostream& os) const");
return os.good();
}
//bool Foam::pointBoundaryMesh::writeObject
//(
// IOstreamOption
//) const
//{
// return regIOobject::writeObject(fmt, ver, IOstream::UNCOMPRESSED);
//}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2013 OpenFOAM Foundation
Copyright (C) 2018-2023 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -39,6 +39,7 @@ SourceFiles
#define Foam_pointBoundaryMesh_H
#include "pointPatch.H"
#include "regIOobject.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -56,19 +57,29 @@ class wordRes;
class pointBoundaryMesh
:
public pointPatchList
public pointPatchList,
public regIOobject
{
// Private Data
//- Reference to mesh
const pointMesh& mesh_;
//- Demand-driven: list of patch ids per group
mutable autoPtr<HashTable<labelList>> groupIDsPtr_;
// Private Member Functions
//- Calculate geometry for the patches (transformation tensors etc.)
void calcGeometry();
//- Some patches have inGroup entries
bool hasGroupIDs() const;
//- Calculate group name to patch ids lookup
void calcGroupIDs() const;
//- Assign facePointPatches corresponding to the given polyBoundaryMesh
void addPatches(const polyBoundaryMesh& pbm);
@ -85,11 +96,27 @@ public:
friend class pointMesh;
//- Runtime type information
TypeName("pointBoundaryMesh");
// Constructors
//- Construct from polyBoundaryMesh
pointBoundaryMesh(const pointMesh&, const polyBoundaryMesh&);
//- Construct from IOobject and polyBoundaryMesh
pointBoundaryMesh
(
const IOobject& io,
const pointMesh&,
const polyBoundaryMesh&
);
//- Destructor
virtual ~pointBoundaryMesh() = default;
// Member Functions
@ -99,6 +126,21 @@ public:
return mesh_;
}
//- The number of patches before the first processor patch.
label nNonProcessor() const;
//- The number of processorPointPatch patches
label nProcessorPatches() const;
//- Return a list of patch names
wordList names() const;
//- Return a list of patch types
wordList types() const;
//- Return a list of physical types
wordList physicalTypes() const;
//- Return (sorted) patch indices for all matches.
// A no-op (returns empty list) for an empty matcher
labelList indices(const wordRe& matcher, const bool useGroups) const;
@ -121,14 +163,31 @@ public:
//- Find patch index given a name
// A no-op (returns -1) for an empty patchName
label findPatchID(const word& patchName) const;
label findPatchID
(
const word& patchName,
const bool allowNotFound = true
) const;
//- Correct polyBoundaryMesh after moving points
//- The patch indices per patch group
const HashTable<labelList>& groupPatchIDs() const;
//- Correct pointBoundaryMesh after moving points
void movePoints(const pointField&);
//- Correct polyBoundaryMesh after topology update
//- Correct pointBoundaryMesh after topology update
void updateMesh();
//- Reorders patches. Ordering does not have to be done in
// ascending or descending order. Reordering has to be unique.
// (is shuffle) If validBoundary calls updateMesh()
// after reordering to recalculate data (so call needs to be parallel
// sync in that case)
void reorder(const labelUList& oldToNew, const bool validBoundary);
//- writeData member function required by regIOobject
virtual bool writeData(Ostream&) const;
// Housekeeping

View File

@ -40,6 +40,8 @@ namespace Foam
defineTypeNameAndDebug(pointMesh, 0);
}
Foam::word Foam::pointMesh::meshSubDir = "pointMesh";
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -89,8 +91,66 @@ Foam::pointMesh::pointMesh(const polyMesh& pMesh)
}
Foam::pointMesh::pointMesh(const polyMesh& pMesh, const IOobject& io)
:
MeshObject<polyMesh, Foam::UpdateableMeshObject, pointMesh>(pMesh),
GeoMesh<polyMesh>(pMesh),
boundary_(io, *this, pMesh.boundaryMesh())
{
if (debug)
{
Pout<< "pointMesh::pointMesh(const polyMesh&): "
<< "Constructing from IO " << io.objectRelPath()
<< endl;
}
// Calculate the geometry for the patches (transformation tensors etc.)
boundary_.calcGeometry();
}
Foam::pointMesh::pointMesh
(
const polyMesh& pMesh,
const IOobjectOption::readOption rOpt
)
:
pointMesh
(
pMesh,
IOobject
(
pMesh.name(), // polyMesh region
pMesh.facesInstance(), // polyMesh topology instance
pMesh.time(),
rOpt,
Foam::IOobject::NO_WRITE
)
)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::pointMesh::setInstance
(
const fileName& inst,
const IOobjectOption::writeOption wOpt
)
{
if (debug)
{
Pout<< "pointMesh::setInstance(): "
<< "Setting instance to " << inst << endl;
}
this->writeOpt(wOpt);
this->instance() = inst;
boundary_.writeOpt(wOpt);
boundary_.instance() = inst;
}
bool Foam::pointMesh::movePoints()
{
if (debug)
@ -119,4 +179,19 @@ void Foam::pointMesh::updateMesh(const mapPolyMesh& mpm)
}
bool Foam::pointMesh::writeObject
(
IOstreamOption streamOpt,
const bool writeOnProc
) const
{
if (debug)
{
Pout<< "pointMesh::writeObject(IOstreamOption, const bool): "
<< "Writing to " << boundary_.objectRelPath() << endl;
}
return boundary_.writeObject(streamOpt, writeOnProc);
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2013 OpenFOAM Foundation
Copyright (C) 2021-2023 OpenCFD Ltd.
Copyright (C) 2021-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -96,12 +96,26 @@ public:
// Declare name of the class and its debug switch
ClassName("pointMesh");
//- Return the mesh sub-directory name (usually "pointMesh")
static word meshSubDir;
// Constructors
//- Construct from polyMesh
explicit pointMesh(const polyMesh& pMesh);
//- Construct from polyMesh and IOobject (used when reading boundary)
explicit pointMesh(const polyMesh& pMesh, const IOobject& io);
//- Construct from polyMesh and readOpt. Takes instance, time etc
//- from polyMesh. Used when reading boundary.
explicit pointMesh
(
const polyMesh& pMesh,
const IOobjectOption::readOption rOpt
);
//- Destructor
~pointMesh() = default;
@ -151,6 +165,13 @@ public:
return GeoMesh<polyMesh>::mesh_.time();
}
//- Set the instance for mesh files
void setInstance
(
const fileName& instance,
const IOobjectOption::writeOption wOpt = IOobject::AUTO_WRITE
);
// Volume Mesh
@ -181,6 +202,16 @@ public:
{
return &pm == this;
}
// Write
//- Write
virtual bool writeObject
(
IOstreamOption streamOpt,
const bool writeOnProc = true
) const;
};

View File

@ -0,0 +1,542 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "pointMeshTools.H"
#include "syncTools.H"
#include "PatchTools.H"
#include "dummyTransform.H"
#include "unitConversion.H"
//#include "OFstream.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
void Foam::pointMeshTools::featurePointsEdges
(
const polyMesh& mesh,
const uindirectPrimitivePatch& allBoundary,
// Per boundary face to zone
const labelUList& faceToZone,
// Number of zones
const label nZones,
const scalar edgeFeatureAngle,
//const scalar pointFeatureAngle, //not yet done
// Feature edge(points) internal to a zone
labelListList& zoneToMeshPoints,
List<pointConstraintList>& zoneToConstraints,
// Feature edge(points) in between zones
labelList& twoZoneMeshPoints,
pointConstraintList& twoZoneConstraints,
// Feature points on > 2 zones
labelList& multiZoneMeshPoints,
pointConstraintList& multiZoneConstraints
)
{
// Analyses edges on mesh faces and splits them up according to topology
// and geometry:
// - edges in between faces on same zone but making a feature angle
// - edges in between faces on two different zones
// - points on faces on > 2 zones
const globalMeshData& globalData = mesh.globalData();
const indirectPrimitivePatch& cpp = globalData.coupledPatch();
const mapDistribute& map = globalData.globalEdgeSlavesMap();
const auto& mp = allBoundary.meshPoints();
const vector nullVector(vector::uniform(0));
const auto assignNonNull = [&](vector& x, const vector& y)
{
if (x == nullVector && y != nullVector)
{
x = y;
}
};
// Calculate parallel-consistent point normals (as unweighted average
// of faceNormals). Note: only valid on patch points, not on mesh points
// that are coupled to these.
const pointField pointNormals
(
PatchTools::pointNormals
(
mesh,
allBoundary
)
);
// Find correspondence between allBoundary and coupled edges
labelList allEdges;
labelList coupledEdges;
bitSet sameEdgeOrientation;
PatchTools::matchEdges
(
allBoundary,
cpp,
allEdges,
coupledEdges,
sameEdgeOrientation
);
// To construct the patches we need to know per edge:
// - patch on either side (if topological feature edge)
// - faceNormal on either side (if feature angle)
// We need to know per point:
// - patches on all connected faces
// - faceNormals on all connected faces? And compare to average?
// or edge normals on all connected edges
typedef Tuple2<label, vector> PN;
const PN nullPN(-1, nullVector);
// Point-based analysis
// ~~~~~~~~~~~~~~~~~~~~
// Collect per (mesh)point the zones (1, 2 or >2). Note: per mesh to
// make it easier to sync. See edge-based code below where we explicitly
// have to transfer from patch-edge to mesh-point etc. Note sure which one
// fits better....
// State:
// (-1, -1) : initial state
// (-2, -2) : more than 2 zones
// (>=0, >=0) : zones from connected faces
labelPairList pointToZones(mesh.nPoints(), labelPair(-1, -1));
{
// Combine zones.
const auto combineZones = [&](labelPair& x, const labelPair& y)
{
if (x == labelPair(-2, -2))
{
// Already marked as having >2 zones
}
else if (y == labelPair(-2, -2))
{
x = y;
}
else
{
// Find first free slot
if (x[0] == -1)
{
if (y[0] != -1)
{
x[0] = y[0];
}
else
{
x[0] = y[1];
}
}
else if (x[1] == -1)
{
if (y[0] != -1 && y[0] != x[0])
{
x[1] = y[0];
}
else if (y[1] != -1 && y[1] != x[1])
{
x[1] = y[1];
}
}
else
{
// Both x slots filled. See if y adds a 3rd element
if (y[0] != -1 && y[0] != x[0] && y[0] != x[1])
{
x = labelPair(-2, -2);
}
else if (y[1] != -1 && y[1] != x[0] && y[1] != x[1])
{
x = labelPair(-2, -2);
}
}
}
};
forAll(allBoundary, facei)
{
const auto& f = allBoundary[facei];
const label zonei = faceToZone[facei];
for (const label pointi : f)
{
auto& pZones = pointToZones[pointi];
if (pZones != labelPair(-2, -2) && !pZones.contains(zonei))
{
if (pZones.first() == -1)
{
pZones.first() = zonei;
}
else if (pZones.second() == -1)
{
pZones.second() = zonei;
}
else
{
// Mark as >2 zones
pZones = labelPair(-2, -2);
}
}
}
}
syncTools::syncPointList
(
mesh,
pointToZones,
combineZones,
labelPair(-1, -1),
dummyTransform()
);
}
// Edge-based analysis
// ~~~~~~~~~~~~~~~~~~~~
// 1. Local analysis
List<Pair<PN>> allEdgeToFaces
(
allBoundary.nEdges(),
Pair<PN>(nullPN, nullPN)
);
{
const auto& edgeFaces = allBoundary.edgeFaces();
const auto& faceNormals = allBoundary.faceNormals();
forAll(edgeFaces, edgei)
{
const auto& eFaces = edgeFaces[edgei];
const vector& n0 = faceNormals[eFaces[0]];
const label zone0 = faceToZone[eFaces[0]];
if (eFaces.size() == 1)
{
allEdgeToFaces[edgei] = Pair<PN>(PN(zone0, n0), nullPN);
}
else
{
const vector& n1 = faceNormals[eFaces[1]];
const label zone1 = faceToZone[eFaces[1]];
allEdgeToFaces[edgei] = Pair<PN>
(
PN(zone0, n0),
PN(zone1, n1)
);
}
}
}
// 2. Sync across coupled patches
{
// Combine pair of normals
const auto vectorPairMax = [&](Pair<PN>& x, const Pair<PN>& y)
{
if (x[0] == nullPN)
{
if (y[0] != nullPN)
{
x[0] = y[0];
}
else
{
x[0] = y[1];
}
}
else if (x[1] == nullPN)
{
if (y[0] != nullPN && y[0] != x[0])
{
x[1] = y[0];
}
else
{
x[1] = y[1];
}
}
};
List<Pair<PN>> cppEdgeData
(
map.constructSize(),
Pair<PN>(nullPN, nullPN)
);
UIndirectList<Pair<PN>>(cppEdgeData, coupledEdges) =
UIndirectList<Pair<PN>>(allEdgeToFaces, allEdges);
globalData.syncData
(
cppEdgeData,
globalData.globalEdgeSlaves(),
globalData.globalEdgeTransformedSlaves(),
map,
globalData.globalTransforms(),
vectorPairMax,
dummyTransform()
);
UIndirectList<Pair<PN>>(allEdgeToFaces, allEdges) =
UIndirectList<Pair<PN>>(cppEdgeData, coupledEdges);
}
// Now we have all the per-patch edge information
// - do inter-patch edges
// - do feature-angle edges
// Store on mesh points
const auto assignNonNullPN = [&](PN& x, const PN& y)
{
if (x.second() == nullVector && y.second() != nullVector)
{
x = y;
}
};
const scalar featEdgeCos = Foam::cos(degToRad(edgeFeatureAngle));
//OFstream os("allBoundary.obj");
//Pout<< "Dumping feature edges to " << os.name() << endl;
//OFstream interOs("interZoneBoundary.obj");
//Pout<< "Dumping inter-zone edges to " << os.name() << endl;
// Storing the normal for points that are on inter-patch edges
vectorField patchEdgeNormal(mesh.nPoints(), nullVector);
// Storing the constraint for points that are on patch-internal feat edges
List<PN> featEdgeNormal(mesh.nPoints(), nullPN);
// Use point-based sync
{
forAll(allEdgeToFaces, edgei)
{
const edge& e = allBoundary.edges()[edgei];
const label mp0 = mp[e[0]];
const label mp1 = mp[e[1]];
const Pair<PN>& facesInfo = allEdgeToFaces[edgei];
if (facesInfo[1] == nullPN)
{
// Real boundary edge. On single patch only so no need
// to put in separate point patch ... (? tbd)
}
else
{
const label zone0 = facesInfo[0].first();
const label zone1 = facesInfo[1].first();
const point& p0 = allBoundary.points()[mp0];
const point& p1 = allBoundary.points()[mp1];
vector eVec(p1-p0);
eVec.normalise();
if (zone0 != zone1)
{
// Inter-patch. TBD: check for feature angle as well?
//patchEdgeNormal[mp0] = pointNormals[e[0]];
//patchEdgeNormal[mp1] = pointNormals[e[1]];
patchEdgeNormal[mp0] = eVec;
patchEdgeNormal[mp1] = eVec;
}
else
{
// Same patch - check for feature angle
const vector& n0 = facesInfo[0].second();
const vector& n1 = facesInfo[1].second();
if ((n0 & n1) < featEdgeCos)
{
//Pout<< "** feature edge:" << edgei
// << " points:" << allBoundary.points()[mp0]
// << allBoundary.points()[mp1]
// << nl
// << " faceNormal0:" << n0
// << " faceNormal1:" << n1 << nl
// << " zone0:" << zone0
// << " zone1:" << zone1 << nl
// << " pointNormals0:" << pointNormals[e[0]]
// << " pointNormals1:" << pointNormals[e[1]]
// << nl
// << endl;
if (patchEdgeNormal[mp0] == nullVector)
{
//featEdgeNormal[mp0] = PN
//(
// zone0, // zone
// pointNormals[e[0]]
//);
featEdgeNormal[mp0].first() = zone0;
// Assign edge direction. TBD: average & parallel
featEdgeNormal[mp0].second() = eVec;
}
if (patchEdgeNormal[mp1] == nullVector)
{
//featEdgeNormal[mp1] = PN
//(
// zone1, // zone
// pointNormals[e[1]]
//);
featEdgeNormal[mp1].first() = zone1;
// Assign edge direction. TBD: average & parallel
featEdgeNormal[mp1].second() = eVec;
}
}
}
}
}
syncTools::syncPointList
(
mesh,
patchEdgeNormal,
assignNonNull,
nullVector
);
syncTools::syncPointList
(
mesh,
featEdgeNormal,
assignNonNullPN,
nullPN,
dummyTransform()
);
}
// Make sure that inter-patch points are not also in feature-edge
// points. Note: not absolutely necessary since all inter-patch points
// will also be in the 'normal' facePointPatches.
DynamicList<label> dynMultiZoneMeshPoints(allBoundary.nPoints());
DynamicList<pointConstraint> dynMultiZoneConstraints(allBoundary.nPoints());
forAll(pointToZones, pointi)
{
if (pointToZones[pointi] == labelPair(-2, -2))
{
dynMultiZoneMeshPoints.append(pointi);
// Note: pointConstraint just a slip constraint for now
dynMultiZoneConstraints.append
(
pointConstraint
(
3, // feature point
Zero //meshPointNormals[pointi]
)
);
// Unmark as feature angle point
patchEdgeNormal[pointi] = nullVector;
featEdgeNormal[pointi] = nullPN;
}
}
multiZoneMeshPoints = std::move(dynMultiZoneMeshPoints);
multiZoneConstraints = std::move(dynMultiZoneConstraints);
DynamicList<label> dynTwoZoneMeshPoints(allBoundary.nPoints());
DynamicList<pointConstraint> dynTwoZoneConstraints(allBoundary.nPoints());
forAll(patchEdgeNormal, pointi)
{
if (patchEdgeNormal[pointi] != nullVector)
{
dynTwoZoneMeshPoints.append(pointi);
// Note: pointConstraint just a slip constraint for now
dynTwoZoneConstraints.append
(
pointConstraint
(
2, // feature edge
patchEdgeNormal[pointi]
)
);
// Unmark as feature angle point
featEdgeNormal[pointi] = nullPN;
}
}
twoZoneMeshPoints = std::move(dynTwoZoneMeshPoints);
twoZoneConstraints = std::move(dynTwoZoneConstraints);
// Sort featEdgeNormal according to zone
zoneToMeshPoints.resize_nocopy(nZones);
zoneToConstraints.resize_nocopy(nZones);
{
labelList sizes(nZones, 0);
forAll(featEdgeNormal, pointi)
{
const auto& pInfo = featEdgeNormal[pointi];
if (pInfo != nullPN)
{
const label zonei = pInfo.first();
sizes[zonei]++;
}
}
forAll(zoneToMeshPoints, zonei)
{
zoneToMeshPoints[zonei].setSize(sizes[zonei]);
zoneToConstraints[zonei].setSize(sizes[zonei]);
}
sizes = 0;
forAll(featEdgeNormal, pointi)
{
const auto& pInfo = featEdgeNormal[pointi];
if (pInfo != nullPN)
{
const label zonei = pInfo.first();
const label index = sizes[zonei]++;
zoneToMeshPoints[zonei][index] = pointi;
zoneToConstraints[zonei][index] =
pointConstraint(2, pInfo.second()); // constrained to slide
}
}
}
}
// ************************************************************************* //

View File

@ -0,0 +1,95 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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::polyMeshTools
Description
Collection of static functions operating on pointMesh.
SourceFiles
pointMeshTools.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_pointMeshTools_H
#define Foam_pointMeshTools_H
#include "pointMesh.H"
#include "pointConstraint.H"
#include "uindirectPrimitivePatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class pointMeshTools Declaration
\*---------------------------------------------------------------------------*/
class pointMeshTools
{
public:
//- Analyse patch for feature edges, feature points. Handles points
//- not being on a face of patch but coupled to it.
static void featurePointsEdges
(
const polyMesh& mesh,
const uindirectPrimitivePatch& boundary,
// Per boundary face to zone
const labelUList& faceToZone,
// Number of zones
const label nZones,
const scalar edgeFeatureAngle,
//const scalar pointFeatureAngle, //not yet done
// Feature edge(points) internal to a zone
labelListList& zoneToMeshPoints,
List<pointConstraintList>& zoneToConstraints,
// Feature edge(points) in between zones
labelList& twoZoneMeshPoints,
pointConstraintList& twoZoneConstraints,
// Feature points on > 2 zones
labelList& multiZoneMeshPoints,
pointConstraintList& multiZoneConstraints
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -72,6 +72,39 @@ public:
:
facePointPatch(patch, bm)
{}
//- Construct given the original patch and a map
genericPointPatch
(
const genericPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
facePointPatch(patch, bm, index, mapAddressing, reversePointMap)
{}
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<genericPointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
};

View File

@ -91,6 +91,20 @@ Foam::cyclicPointPatch::cyclicPointPatch
{}
Foam::cyclicPointPatch::cyclicPointPatch
(
const cyclicPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
coupledFacePointPatch(patch, bm, index, mapAddressing, reversePointMap),
cyclicPolyPatch_(refCast<const cyclicPolyPatch>(patch.patch()))
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::cyclicPointPatch::~cyclicPointPatch()

View File

@ -105,6 +105,36 @@ public:
const pointBoundaryMesh& bm
);
//- Construct given the original patch and a map
cyclicPointPatch
(
const cyclicPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
);
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<cyclicPointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
//- Destructor
virtual ~cyclicPointPatch();

View File

@ -73,6 +73,39 @@ public:
cyclicPointPatch(patch, bm)
{}
//- Construct given the original patch and a map
cyclicSlipPointPatch
(
const cyclicSlipPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
cyclicPointPatch(patch, bm, index, mapAddressing, reversePointMap)
{}
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<cyclicSlipPointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
//- Destructor
virtual ~cyclicSlipPointPatch() = default;

View File

@ -72,6 +72,39 @@ public:
facePointPatch(patch, bm)
{}
//- Construct given the original patch and a map
emptyPointPatch
(
const emptyPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
facePointPatch(patch, bm, index, mapAddressing, reversePointMap)
{}
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<emptyPointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
// Member Functions

View File

@ -73,6 +73,40 @@ public:
cyclicPointPatch(patch, bm)
{}
//- Construct given the original patch and a map
nonuniformTransformCyclicPointPatch
(
const nonuniformTransformCyclicPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
cyclicPointPatch(patch, bm, index, mapAddressing, reversePointMap)
{}
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::
NewFrom<nonuniformTransformCyclicPointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
// Destructor

View File

@ -117,4 +117,20 @@ Foam::processorPointPatch::processorPointPatch
{}
Foam::processorPointPatch::processorPointPatch
(
const processorPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
coupledFacePointPatch(patch, bm, index, mapAddressing, reversePointMap),
procPolyPatch_(refCast<const processorPolyPatch>(patch.patch()))
{
//? map reverseMeshPoints_ or leave demand-driven
}
// ************************************************************************* //

View File

@ -111,6 +111,36 @@ public:
const pointBoundaryMesh& bm
);
//- Construct given the original patch and a map
processorPointPatch
(
const processorPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
);
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<processorPointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
//- Destructor
virtual ~processorPointPatch() = default;

View File

@ -59,6 +59,20 @@ processorCyclicPointPatch::processorCyclicPointPatch
{}
Foam::processorCyclicPointPatch::processorCyclicPointPatch
(
const processorCyclicPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
processorPointPatch(patch, bm, index, mapAddressing, reversePointMap),
procCycPolyPatch_(refCast<const processorCyclicPolyPatch>(patch.patch()))
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
processorCyclicPointPatch::~processorCyclicPointPatch()

View File

@ -89,6 +89,36 @@ public:
const pointBoundaryMesh& bm
);
//- Construct given the original patch and a map
processorCyclicPointPatch
(
const processorCyclicPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
);
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<processorCyclicPointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
//- Destructor
virtual ~processorCyclicPointPatch();

View File

@ -75,6 +75,38 @@ public:
facePointPatch(patch, bm)
{}
//- Construct given the original patch and a map
symmetryPointPatch
(
const symmetryPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
):
facePointPatch(patch, bm, index, mapAddressing, reversePointMap)
{}
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<symmetryPointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
// Member Functions

View File

@ -58,6 +58,23 @@ Foam::symmetryPlanePointPatch::symmetryPlanePointPatch
{}
Foam::symmetryPlanePointPatch::symmetryPlanePointPatch
(
const symmetryPlanePointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
facePointPatch(patch, bm, index, mapAddressing, reversePointMap),
symmetryPlanePolyPatch_
(
refCast<const symmetryPlanePolyPatch>(patch.patch())
)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::symmetryPlanePointPatch::applyConstraint

View File

@ -74,6 +74,36 @@ public:
const pointBoundaryMesh& bm
);
//- Construct given the original patch and a map
symmetryPlanePointPatch
(
const symmetryPlanePointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
);
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<symmetryPlanePointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
// Member Functions

View File

@ -58,6 +58,20 @@ Foam::wedgePointPatch::wedgePointPatch
{}
Foam::wedgePointPatch::wedgePointPatch
(
const wedgePointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
facePointPatch(patch, bm, index, mapAddressing, reversePointMap),
wedgePolyPatch_(refCast<const wedgePolyPatch>(patch.patch()))
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::wedgePointPatch::applyConstraint

View File

@ -74,6 +74,36 @@ public:
const pointBoundaryMesh& bm
);
//- Construct given the original patch and a map
wedgePointPatch
(
const wedgePointPatch& pp,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
);
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<wedgePointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
// Member Functions

View File

@ -50,4 +50,19 @@ Foam::coupledFacePointPatch::coupledFacePointPatch
{}
Foam::coupledFacePointPatch::coupledFacePointPatch
(
const coupledFacePointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
facePointPatch(patch, bm, index, mapAddressing, reversePointMap),
coupledPointPatch(bm),
coupledPolyPatch_(refCast<const coupledPolyPatch>(patch.patch()))
{}
// ************************************************************************* //

View File

@ -91,6 +91,16 @@ public:
const pointBoundaryMesh& bm
);
//- Construct given the original patch and a map
coupledFacePointPatch
(
const coupledFacePointPatch& pp,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
);
//- Destructor
virtual ~coupledFacePointPatch() = default;

View File

@ -71,6 +71,39 @@ public:
:
facePointPatch(patch, bm)
{}
//- Construct given the original patch and a map
wallPointPatch
(
const wallPointPatch& patch,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
facePointPatch(patch, bm, index, mapAddressing, reversePointMap)
{}
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<wallPointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
};

View File

@ -84,9 +84,30 @@ Foam::facePointPatch::facePointPatch
const pointBoundaryMesh& bm
)
:
pointPatch(bm),
pointPatch(p.name(), p.index(), bm, p.physicalType(), p.inGroups()),
polyPatch_(p)
{}
Foam::facePointPatch::facePointPatch
(
const facePointPatch& pp,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
pointPatch
(
pp.name(),
index,
bm,
pp.physicalType(),
pp.inGroups()
),
polyPatch_(pp.patch())
{}
// ************************************************************************* //

View File

@ -128,6 +128,36 @@ public:
const pointBoundaryMesh& pm
);
//- Construct given the original patch and a map
facePointPatch
(
const facePointPatch& pp,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
);
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<facePointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
// Selectors

View File

@ -0,0 +1,235 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016 OpenFOAM Foundation
Copyright (C) 2024 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 "meshPointPatch.H"
#include "addToRunTimeSelectionTable.H"
#include "pointMesh.H"
#include "pointConstraint.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(meshPointPatch, 0);
//- Needs run-time selection table on pointPatch, not facePointPatch
addToRunTimeSelectionTable
(
pointPatch,
meshPointPatch,
dictionary
);
static List<pointConstraint> makeConstraints(const vectorField& normals)
{
List<pointConstraint> cs(normals.size());
forAll(cs, i)
{
cs[i].applyConstraint(normals[i]);
}
return cs;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::meshPointPatch::meshPointPatch
(
const word& name,
const labelUList& meshPoints,
const List<pointConstraint>& constraints,
const label index,
const pointBoundaryMesh& bm,
const word& patchType
)
:
pointPatch(name, index, bm, word::null, wordList()),
meshPoints_(meshPoints),
constraints_(constraints)
{
if (meshPoints_.size() != constraints_.size())
{
FatalErrorInFunction << "patch " << name
<< " size of meshPoints " << meshPoints_.size()
<< " differs from size of constraints " << constraints_.size()
<< exit(FatalError);
}
}
Foam::meshPointPatch::meshPointPatch
(
const word& name,
const labelUList& meshPoints,
const vectorField& pointNormals,
const label index,
const pointBoundaryMesh& bm,
const word& patchType
)
:
pointPatch(name, index, bm, word::null, wordList()),
meshPoints_(meshPoints),
constraints_(makeConstraints(pointNormals))
{
if (meshPoints_.size() != pointNormals.size())
{
FatalErrorInFunction << "patch " << name
<< " size of meshPoints " << meshPoints_.size()
<< " differs from size of pointNormals " << pointNormals.size()
<< exit(FatalError);
}
}
Foam::meshPointPatch::meshPointPatch
(
const word& name,
const dictionary& dict,
const label index,
const pointBoundaryMesh& bm,
const word& patchType
)
:
pointPatch(name, dict, index, bm),
meshPoints_(dict.get<labelList>("meshPoints")),
constraints_(dict.get<List<pointConstraint>>("constraints"))
{}
Foam::meshPointPatch::meshPointPatch
(
const meshPointPatch& pp,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
meshPointPatch
(
pp.name(),
labelList(reversePointMap, labelList(pp.meshPoints(), mapAddressing)),
List<pointConstraint>(pp.constraints(), mapAddressing),
index,
bm,
pp.type()
)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::meshPointPatch::movePoints(PstreamBuffers&, const pointField& p)
{
localPointsPtr_.reset(nullptr);
// Recalculate the point normals? Something like
//if (owner())
//{
// const SubList<face> subFaces
// (
// mesh.faces(),
// mesh.nBoundaryFaces(),
// mesh.nInternalFaces()
// );
// const primitivePatch pp(subFaces, mesh.points());
//
//
// for (const label pointi : meshPoints())
// {
// const auto fnd(pp.meshPointMap().find(pointi));
// if (fnd)
// {
// const label patchPointi = fnd();
// // Determine point patch equiv
//
// const auto& point
//
//
}
void Foam::meshPointPatch::updateMesh(PstreamBuffers&)
{
localPointsPtr_.reset(nullptr);
pointNormalsPtr_.reset(nullptr);
// Do what to constraints_? Don't know what the new mesh points are
}
const Foam::pointField& Foam::meshPointPatch::localPoints() const
{
if (!localPointsPtr_)
{
localPointsPtr_.reset
(
new pointField
(
boundaryMesh().mesh().mesh().points(),
meshPoints()
)
);
}
return localPointsPtr_();
}
const Foam::vectorField& Foam::meshPointPatch::pointNormals() const
{
if (!pointNormalsPtr_)
{
pointNormalsPtr_.reset(new vectorField(size()));
vectorField& pointNormals = pointNormalsPtr_();
forAll(constraints_, i)
{
pointNormals[i] = constraints_[i].second();
}
}
return pointNormalsPtr_();
}
void Foam::meshPointPatch::write(Ostream& os) const
{
pointPatch::write(os);
meshPoints().writeEntry("meshPoints", os);
constraints().writeEntry("constraints", os);
}
// ************************************************************************* //

View File

@ -0,0 +1,213 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016 OpenFOAM Foundation
Copyright (C) 2024 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::meshPointPatch
Description
pointPatch with explicitly provided points instead of using the points
of a polyPatch.
Note: does not constrain displacement - is not a constraint patch.
SourceFiles
meshPointPatch.C
\*---------------------------------------------------------------------------*/
#ifndef meshPointPatch_H
#define meshPointPatch_H
#include "pointPatch.H"
#include "polyPatch.H"
#include "autoPtr.H"
#include "patchIdentifier.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class meshPointPatch Declaration
\*---------------------------------------------------------------------------*/
class meshPointPatch
:
public pointPatch
{
private:
// Private Member Functions
//- No copy construct
meshPointPatch(const meshPointPatch&) = delete;
//- No copy assignment
void operator=(const meshPointPatch&) = delete;
protected:
// Protected Member Data
//- Explicit mesh points
const labelList meshPoints_;
const List<pointConstraint> constraints_;
//- Demand-driven local points
mutable autoPtr<pointField> localPointsPtr_;
//- Demand-driven local normals (assumes constructed with pointNormals
// or normal-only-constraint)
mutable autoPtr<pointField> pointNormalsPtr_;
// Protected Member Functions
//- Correct patches after moving points
virtual void movePoints(PstreamBuffers&, const pointField&);
//- Update of the patch topology
virtual void updateMesh(PstreamBuffers&);
public:
//- Runtime type information
TypeName("meshPoint");
// Constructors
//- Construct from components
meshPointPatch
(
const word& name,
const labelUList& meshPoints,
const List<pointConstraint>& constraints,
const label index,
const pointBoundaryMesh& bm,
const word& patchType
);
//- Construct from single-constraint (i.e. slip, provided normals)
meshPointPatch
(
const word& name,
const labelUList& meshPoints,
const vectorField& pointNormals,
const label index,
const pointBoundaryMesh& bm,
const word& patchType
);
//- Construct from dictionary
meshPointPatch
(
const word& name,
const dictionary& dict,
const label index,
const pointBoundaryMesh& bm,
const word& patchType
);
//- Construct given the original patch and a map
meshPointPatch
(
const meshPointPatch& pp,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
);
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const
{
return autoPtr<pointPatch>::NewFrom<meshPointPatch>
(
*this,
bm,
index,
mapAddressing,
reversePointMap
);
}
//- Destructor
virtual ~meshPointPatch() = default;
// Member Functions
//- Return size
virtual label size() const
{
return meshPoints().size();
}
//- Return mesh points
virtual const labelList& meshPoints() const
{
return meshPoints_;
}
//- Return constraints
virtual const List<pointConstraint>& constraints() const
{
return constraints_;
}
//- Return pointField of points in patch
virtual const pointField& localPoints() const;
//- Return point unit normals. Assumes single constraint
virtual const vectorField& pointNormals() const;
//- Write the pointPatch data as a dictionary
virtual void write(Ostream&) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
Copyright (C) 2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -31,7 +32,33 @@ License
namespace Foam
{
defineTypeNameAndDebug(pointPatch, 0);
defineTypeNameAndDebug(pointPatch, 0);
// int pointPatch::disallowGenericPointPatch
// (
// debug::debugSwitch("disallowGenericPointPatch", 0)
// );
defineRunTimeSelectionTable(pointPatch, dictionary);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::pointPatch::write(Ostream& os) const
{
os.writeKeyword("type") << type() << token::END_STATEMENT << nl;
patchIdentifier::write(os);
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const pointPatch& p)
{
p.write(os);
os.check("Ostream& operator<<(Ostream& os, const pointPatch& p");
return os;
}

View File

@ -38,6 +38,7 @@ SourceFiles
#ifndef Foam_pointPatch_H
#define Foam_pointPatch_H
#include "patchIdentifier.H"
#include "labelList.H"
#include "vectorField.H"
#include "pointField.H"
@ -54,6 +55,8 @@ class pointConstraint;
class pointPatch;
class PstreamBuffers;
Ostream& operator<<(Ostream&, const pointPatch&);
//- Store lists of pointPatch as a PtrList
typedef PtrList<pointPatch> pointPatchList;
@ -62,6 +65,8 @@ typedef PtrList<pointPatch> pointPatchList;
\*---------------------------------------------------------------------------*/
class pointPatch
:
public patchIdentifier
{
// Private Data
@ -114,14 +119,90 @@ public:
TypeName("basePatch");
// Declare run-time constructor selection tables
declareRunTimeSelectionTable
(
autoPtr,
pointPatch,
dictionary,
(
const word& name,
const dictionary& dict,
const label index,
const pointBoundaryMesh& bm,
const word& patchType
),
(name, dict, index, bm, patchType)
);
// Constructor
//- Construct from boundary mesh
explicit pointPatch(const pointBoundaryMesh& bm)
//- Construct from components
explicit pointPatch
(
const word& name,
const label index,
const pointBoundaryMesh& bm,
const word& physicalType,
const wordList& inGroups
)
:
patchIdentifier(name, index, physicalType, inGroups),
boundaryMesh_(bm)
{}
//- Construct from dictionary
explicit pointPatch
(
const word& name,
const dictionary& dict,
const label index,
const pointBoundaryMesh& bm
)
:
patchIdentifier(name, dict, index),
boundaryMesh_(bm)
{}
//- Construct given the original patch and a map
explicit pointPatch
(
const pointPatch& pp,
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
)
:
patchIdentifier(pp.name(), index, pp.physicalType(), pp.inGroups()),
boundaryMesh_(bm)
{}
//- Construct and return a subset clone,
//- resetting the point list and boundary mesh
virtual autoPtr<pointPatch> clone
(
const pointBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const labelUList& reversePointMap
) const = 0;
// Selectors
//- Return a pointer to a new patch created on freestore. Returns
//- null if not found
static autoPtr<pointPatch> New
(
const word& name,
const dictionary& dict,
const label index,
const pointBoundaryMesh&
);
//- Destructor
virtual ~pointPatch() = default;
@ -129,15 +210,9 @@ public:
// Member Functions
//- Return name
virtual const word& name() const = 0;
//- Return size
virtual label size() const = 0;
//- Return the index of this patch in the pointBoundaryMesh
virtual label index() const = 0;
//- Return boundaryMesh reference
const pointBoundaryMesh& boundaryMesh() const
{
@ -172,6 +247,14 @@ public:
pointConstraint&
) const
{}
//- Write the pointPatch data as a dictionary
virtual void write(Ostream&) const;
// Ostream Operator
friend Ostream& operator<<(Ostream&, const pointPatch&);
};

View File

@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "pointPatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::pointPatch> Foam::pointPatch::New
(
const word& name,
const dictionary& dict,
const label index,
const pointBoundaryMesh& bm
)
{
// Similar to polyPatchNew but no support for generic since we want it
// to fall through to the construct-from-polyPatch
DebugInFunction << "Constructing pointPatch" << endl;
const word patchType(dict.lookup("type"));
//dict.readIfPresent("geometricType", patchType);
auto* ctorPtr = dictionaryConstructorTable(patchType);
if (!ctorPtr)
{
return nullptr;
}
return autoPtr<pointPatch>(ctorPtr(name, dict, index, bm, patchType));
}
// ************************************************************************* //

View File

@ -1418,6 +1418,9 @@ void Foam::polyBoundaryMesh::reorder
patches[patchi].index() = patchi;
}
// Clear group-to-patch addressing. Note: could re-calculate
groupIDsPtr_.reset(nullptr);
if (validBoundary)
{
updateMesh();

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2013-2015 OpenFOAM Foundation
Copyright (C) 2022 OpenCFD Ltd.
Copyright (C) 2022,2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -49,8 +49,12 @@ void Foam::symmetryPlanePolyPatch::calcGeometry(PstreamBuffers&)
{
if (returnReduceOr(size()))
{
const vectorField& nf = faceNormals();
n_ = gAverage(nf);
// Instead of using the average unit-normal use an area weighted
// average instead. This avoids problem when adding zero-sized
// faces since these have a calculated area vector of (0 0 0)
const auto& areas = faceAreas();
n_ = gSum(areas).normalise(ROOTVSMALL);
if (debug)
{
@ -60,22 +64,30 @@ void Foam::symmetryPlanePolyPatch::calcGeometry(PstreamBuffers&)
// Check the symmetry plane is planar
forAll(nf, facei)
forAll(areas, facei)
{
if (magSqr(n_ - nf[facei]) > SMALL)
const scalar a = mag(areas[facei]);
// Calculate only if non-zero area
if (a > ROOTVSMALL)
{
FatalErrorInFunction
<< "Symmetry plane '" << name() << "' is not planar."
<< endl
<< "At local face at "
<< primitivePatch::faceCentres()[facei]
<< " the normal " << nf[facei]
<< " differs from the average normal " << n_
<< " by " << magSqr(n_ - nf[facei]) << endl
<< "Either split the patch into planar parts"
<< " or use the " << symmetryPolyPatch::typeName
<< " patch type"
<< exit(FatalError);
const vector nf(areas[facei]/a);
if (magSqr(n_ - nf) > SMALL)
{
FatalErrorInFunction
<< "Symmetry plane '" << name()
<< "' is not planar." << endl
<< "At local face at "
<< primitivePatch::faceCentres()[facei]
<< " the normal " << nf
<< " differs from the average normal " << n_
<< " by " << magSqr(n_ - nf) << endl
<< "Either split the patch into planar parts"
<< " or use the " << symmetryPolyPatch::typeName
<< " patch type"
<< exit(FatalError);
}
}
}
}

View File

@ -101,6 +101,7 @@ motionSolvers/displacement/displacement/displacementMotionSolver.C
motionSolvers/displacement/interpolation/displacementInterpolationMotionSolver.C
motionSolvers/displacement/layeredSolver/displacementLayeredMotionMotionSolver.C
motionSolvers/displacement/layeredSolver/pointEdgeStructuredWalk.C
motionSolvers/displacement/multiDisplacement/multiDisplacementMotionSolver.C
motionSolvers/componentDisplacement/componentDisplacementMotionSolver.C
motionSolvers/velocity/velocityMotionSolver.C
motionSolvers/velocity/velocityDisplacement/velocityDisplacementMotionSolver.C
@ -111,6 +112,23 @@ motionSolvers/displacement/codedPoints0/codedPoints0MotionSolver.C
motionSolvers/displacement/solidBody/pointPatchFields/derived/solidBodyMotionDisplacement/solidBodyMotionDisplacementPointPatchVectorField.C
pointSmoothing = motionSolvers/displacement/pointSmoothing
$(pointSmoothing)/displacementPointSmoothingMotionSolver.C
/*
$(pointSmoothing)/displacementPointSmoothingMotionSolver2.C
$(pointSmoothing)/displacementPointSmoothingMotionSolver3.C
*/
$(pointSmoothing)/hexMeshSmootherMotionSolver.C
$(pointSmoothing)/displacementSmartPointSmoothingMotionSolver.C
pointSmoothers = $(pointSmoothing)/pointSmoothers
$(pointSmoothers)/pointSmoother/pointSmoother.C
$(pointSmoothers)/equipotentialPointSmoother/equipotentialPointSmoother.C
$(pointSmoothers)/geometricElementTransformPointSmoother/geometricElementTransformPointSmoother.C
$(pointSmoothers)/geometricElementTransformPointSmoother/cellPointConnectivity/cellPointConnectivity.C
$(pointSmoothers)/laplacianPointSmoother/laplacianPointSmoother.C
$(pointSmoothers)/laplacianPointSmoother/laplacianConstraintPointSmoother.C
createShellMesh/createShellMesh.C
extrudePatchMesh/extrudePatchMesh.C

View File

@ -57,7 +57,7 @@ Foam::displacementMotionSolver::displacementMotionSolver
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
pointMesh::New(mesh)
pointMesh::New(mesh, Foam::IOobject::READ_IF_PRESENT)
)
{}

View File

@ -0,0 +1,271 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "multiDisplacementMotionSolver.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(multiDisplacementMotionSolver, 0);
addToRunTimeSelectionTable
(
motionSolver,
multiDisplacementMotionSolver,
dictionary
);
addToRunTimeSelectionTable
(
displacementMotionSolver,
multiDisplacementMotionSolver,
displacement
);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::multiDisplacementMotionSolver::multiDisplacementMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict
)
:
displacementMotionSolver(mesh, dict, typeName),
curPoints_(mesh.points())
{
// Make pointDisplacement is not registered since all lower levels
// have a pointDisplacement as well.
pointDisplacement().checkOut();
label i = 0;
const dictionary& solverDict = dict.subDict("solvers");
motionSolvers_.setSize(solverDict.size());
for (const entry& dEntry : solverDict)
{
if (dEntry.isDict())
{
IOobject io(dict);
io.readOpt(IOobject::NO_READ);
io.writeOpt(IOobject::AUTO_WRITE);
io.rename(dEntry.dict().dictName());
IOdictionary IOsolverDict
(
io,
dEntry.dict()
);
auto* msPtr = motionSolver::New(mesh, IOsolverDict).ptr();
motionSolvers_.set
(
i,
dynamic_cast<displacementMotionSolver*>(msPtr)
);
// Avoid conflicts with multiple registrations
motionSolvers_[i].pointDisplacement().checkOut();
i++;
}
}
motionSolvers_.setSize(i);
if (i == 0)
{
FatalErrorInFunction << "No displacementMotionSolvers in dictionary "
<< dict << exit(FatalError);
}
// Re-register so only our 'pointDisplacement' is on the database.
pointDisplacement().checkIn();
}
Foam::multiDisplacementMotionSolver::
multiDisplacementMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict,
const pointVectorField& pointDisplacement,
const pointIOField& points0
)
:
displacementMotionSolver(mesh, dict, pointDisplacement, points0, typeName),
curPoints_(mesh.points())
{
// Make pointDisplacement is not registered since all lower levels
// have a pointDisplacement as well.
this->pointDisplacement().checkOut();
label i = 0;
const dictionary& solverDict = dict.subDict("solvers");
motionSolvers_.setSize(solverDict.size());
for (const entry& dEntry : solverDict)
{
if (dEntry.isDict())
{
IOobject io(dict);
io.readOpt(IOobject::NO_READ);
io.writeOpt(IOobject::AUTO_WRITE);
io.rename(dEntry.dict().dictName());
IOdictionary IOsolverDict
(
io,
dEntry.dict()
);
auto msPtr = displacementMotionSolver::New
(
dEntry.keyword(),
mesh,
IOsolverDict,
pointDisplacement,
points0
);
// Avoid conflicts with multiple registrations
msPtr->pointDisplacement().checkOut();
motionSolvers_.set(i++, msPtr);
}
}
motionSolvers_.setSize(i);
if (i == 0)
{
FatalErrorInFunction << "No displacementMotionSolvers in dictionary "
<< dict << exit(FatalError);
}
// Re-register so only our 'pointDisplacement' is on the database.
this->pointDisplacement().checkIn();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::tmp<Foam::pointField>
Foam::multiDisplacementMotionSolver::curPoints() const
{
return curPoints_;
}
void Foam::multiDisplacementMotionSolver::solve()
{
if (!motionSolvers_.size())
{
return;
}
// Bit tricky:
// - make sure only one copy of pointDisplacement is registered. This is
// for if cellDisplacement tries to look up the pointDisplacement it
// looks up its version. Or maybe we always should use our own version
// only?
// - copy the last set of calculated points into our copy (curPoints_)
// - move the mesh to update the faceCentres, cellCentres etc. This assumes
// that we can call movePoints() multiple times inside a time step.
// (note that this is supported in pimpleFoam with the
// moveMeshOuterCorrectors option)
pointDisplacement().checkOut();
// Doing first motion solver
motionSolvers_[0].pointDisplacement().checkIn();
// Take over my bc values
motionSolvers_[0].pointDisplacement() == pointDisplacement();
motionSolvers_[0].solve();
motionSolvers_[0].pointDisplacement().checkOut();
// Update my values
curPoints_ = motionSolvers_[0].curPoints();
pointDisplacement() == motionSolvers_[0].pointDisplacement();
for (label i = 1; i < motionSolvers_.size(); i++)
{
// Doing other motion solvers using new locations/face/cellCentres etc.
const_cast<polyMesh&>(mesh()).movePoints(curPoints_);
motionSolvers_[i].pointDisplacement().checkIn();
// Take over my bc values
motionSolvers_[i].pointDisplacement() == pointDisplacement();
motionSolvers_[i].solve();
motionSolvers_[i].pointDisplacement().checkOut();
// Update my values
curPoints_ = motionSolvers_[i].curPoints();
pointDisplacement() == motionSolvers_[i].pointDisplacement();
}
pointDisplacement().checkIn();
// Push my pointDisplacement onto all motionSolvers
for (auto& ms : motionSolvers_)
{
ms.pointDisplacement() == pointDisplacement();
}
}
void Foam::multiDisplacementMotionSolver::movePoints
(
const pointField& newPoints
)
{
curPoints_ = newPoints;
for (auto& ms : motionSolvers_)
{
ms.movePoints(newPoints);
}
}
void Foam::multiDisplacementMotionSolver::updateMesh(const mapPolyMesh& mpm)
{
for (auto& ms : motionSolvers_)
{
ms.updateMesh(mpm);
}
}
// ************************************************************************* //

View File

@ -0,0 +1,170 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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::multiDisplacementMotionSolver
Group
grpMeshMotionSolvers
Description
Mesh motion solver for a polyMesh. Applies multiple (displacement) motion
solvers in order.
Not very efficient : all displacementMotionSolvers store a copy
of the initial points (points0) and the displacement (pointDisplacement
or also cellDisplacement).
Used to combine large-scale, implicit displacement smoothing (e.g.
displacementLaplacian) with point smoothing.
Usage
Example of the dynamicMeshDict specification:
\verbatim
motionSolver multiDisplacement;
solvers
{
// Solve finite volume laplacian to efficiently smooth displacement
// (not point locations)
displacementLaplacian
{
motionSolver displacementLaplacian;
diffusivity uniform;
}
// Apply few iterations of smoothing of point locations
displacementPointSmoothing
{
motionSolver displacementPointSmoothing;
pointSmoother laplacian;
nPointSmootherIter 10;
}
}
\endverbatim
Note
When using displacementLaplacian: the default behaviour for the
cellDisplacement is to apply fixed value boundary conditions (by averaging
point values) only to those pointDisplacement boundary conditions that
are fixed value. Quite a few point boundary conditions (e.g. surfaceSlip,
edgeSlip) are not so require an explicitly provided cellDisplacement
field with 'cellMotion' boundary conditions for those patches.
SourceFiles
isplacementMultiMotionSolver.C
\*----------------------------------------------------------------------------*/
#ifndef Foam_multiDisplacementMotionSolver_H
#define Foam_multiDisplacementMotionSolver_H
#include "displacementMotionSolver.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class multiDisplacementMotionSolver Declaration
\*---------------------------------------------------------------------------*/
class multiDisplacementMotionSolver
:
public displacementMotionSolver
{
// Private data
//- Current points
pointField curPoints_;
//- List of motion solvers
PtrList<displacementMotionSolver> motionSolvers_;
// Private Member Functions
//- No copy construct
multiDisplacementMotionSolver
(
const multiDisplacementMotionSolver&
) = delete;
//- No copy assignment
void operator=(const multiDisplacementMotionSolver&) = delete;
public:
//- Runtime type information
TypeName("multiDisplacement");
// Constructors
//- Construct from polyMesh and IOdictionary
multiDisplacementMotionSolver
(
const polyMesh&,
const IOdictionary&
);
//- Construct from components
multiDisplacementMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict,
const pointVectorField& pointDisplacement,
const pointIOField& points0
);
//- Destructor
~multiDisplacementMotionSolver() = default;
// Member Functions
//- Provide current points for motion
virtual tmp<pointField> curPoints() const;
//- Solve for motion
virtual void solve();
//- Update local data for geometry changes
virtual void movePoints(const pointField&);
//- Update local data for topology changes
virtual void updateMesh(const mapPolyMesh&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,434 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "displacementPointSmoothingMotionSolver.H"
#include "addToRunTimeSelectionTable.H"
#include "syncTools.H"
#include "pointConstraints.H"
#include "motionSmootherAlgo.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(displacementPointSmoothingMotionSolver, 0);
addToRunTimeSelectionTable
(
motionSolver,
displacementPointSmoothingMotionSolver,
dictionary
);
addToRunTimeSelectionTable
(
displacementMotionSolver,
displacementPointSmoothingMotionSolver,
displacement
);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::displacementPointSmoothingMotionSolver::markAffectedFaces
(
const labelHashSet& changedFaces,
labelHashSet& affectedFaces
)
{
PackedBoolList affectedPoints(mesh().nPoints(), false);
forAllConstIter(labelHashSet, changedFaces, iter)
{
const label faceI(iter.key());
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
affectedPoints[pointI] = true;
}
}
syncTools::syncPointList
(
mesh(),
affectedPoints,
orEqOp<unsigned int>(),
0U
);
forAll(affectedPoints, pointI)
{
if (affectedPoints[pointI])
{
const labelList& pCells(mesh().pointCells()[pointI]);
forAll(pCells, pointCellI)
{
const label cellI(pCells[pointCellI]);
const labelList& cFaces(mesh().cells()[cellI]);
affectedFaces.insert(cFaces);
}
}
}
}
bool Foam::displacementPointSmoothingMotionSolver::relax()
{
if
(
(relaxationFactors_.size() == 0)
|| (relaxationFactors_.size() == 1 && relaxationFactors_[0] == 1.0)
)
{
relaxedPoints_ = points0() + pointDisplacement().internalField();
return true;
}
const pointField oldRelaxedPoints(relaxedPoints_);
labelHashSet affectedFaces(facesToMove_);
// Create a list of relaxation levels
// -1 indicates a point which is not to be moved
// 0 is the starting value for a moving point
labelList relaxationLevel(mesh().nPoints(), -1);
forAllConstIter(labelHashSet, affectedFaces, iter)
{
const label faceI(iter.key());
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
relaxationLevel[pointI] = 0;
}
}
syncTools::syncPointList
(
mesh(),
relaxationLevel,
maxEqOp<label>(),
label(-1)
);
// Loop whilst relaxation levels are being incremented
bool complete(false);
while (!complete)
{
//scalar nAffectedFaces(affectedFaces.size());
//reduce(nAffectedFaces, sumOp<scalar>());
//Info << " Moving " << nAffectedFaces << " faces" << endl;
// Move the points
forAll(relaxationLevel, pointI)
{
if (relaxationLevel[pointI] >= 0)
{
const scalar x
(
relaxationFactors_[relaxationLevel[pointI]]
);
relaxedPoints_[pointI] =
(1 - x)*oldRelaxedPoints[pointI]
+ x*(points0()[pointI] + pointDisplacement()[pointI]);
}
}
// Get a list of changed faces
labelHashSet markedFaces;
markAffectedFaces(affectedFaces, markedFaces);
labelList markedFacesList(markedFaces.toc());
// Update the geometry
meshGeometry_.correct(relaxedPoints_, markedFacesList);
// Check the modified face quality
markedFaces.clear();
motionSmootherAlgo::checkMesh
(
false,
meshQualityDict_,
meshGeometry_,
relaxedPoints_,
markedFacesList,
markedFaces
);
// Mark the affected faces
affectedFaces.clear();
markAffectedFaces(markedFaces, affectedFaces);
// Increase relaxation and check convergence
PackedBoolList pointsToRelax(mesh().nPoints(), false);
complete = true;
forAllConstIter(labelHashSet, affectedFaces, iter)
{
const label faceI(iter.key());
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
pointsToRelax[pointI] = true;
}
}
forAll(pointsToRelax, pointI)
{
if
(
pointsToRelax[pointI]
&& (relaxationLevel[pointI] < relaxationFactors_.size() - 1)
)
{
++ relaxationLevel[pointI];
complete = false;
}
}
// Synchronise relaxation levels
syncTools::syncPointList
(
mesh(),
relaxationLevel,
maxEqOp<label>(),
label(0)
);
// Synchronise completion
reduce(complete, andOp<bool>());
}
// Check for convergence
bool converged(true);
forAll(mesh().faces(), faceI)
{
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
if (relaxationLevel[pointI] > 0)
{
facesToMove_.insert(faceI);
converged = false;
break;
}
}
}
// Syncronise convergence
reduce(converged, andOp<bool>());
//if (converged)
//{
// Info<< "... Converged" << endl << endl;
//}
//else
//{
// Info<< "... Not converged" << endl << endl;
//}
return converged;
}
void Foam::displacementPointSmoothingMotionSolver::setFacesToMove
(
const dictionary& dict
)
{
if (dict.getOrDefault<bool>("moveInternalFaces", true))
{
facesToMove_.resize(2*mesh().nFaces());
forAll(mesh().faces(), faceI)
{
facesToMove_.insert(faceI);
}
}
else
{
facesToMove_.resize(2*(mesh().nBoundaryFaces()));
for
(
label faceI = mesh().nInternalFaces();
faceI < mesh().nFaces();
++ faceI
)
{
facesToMove_.insert(faceI);
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::displacementPointSmoothingMotionSolver::
displacementPointSmoothingMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict
)
:
displacementMotionSolver(mesh, dict, typeName),
meshGeometry_(mesh),
pointSmoother_(pointSmoother::New(mesh, coeffDict())),
nPointSmootherIter_
(
readLabel(coeffDict().lookup("nPointSmootherIter"))
),
relaxedPoints_(mesh.points())
{
if (coeffDict().readIfPresent("relaxationFactors", relaxationFactors_))
{
meshQualityDict_ = coeffDict().subDict("meshQuality");
}
setFacesToMove(coeffDict());
}
Foam::displacementPointSmoothingMotionSolver::
displacementPointSmoothingMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict,
const pointVectorField& pointDisplacement,
const pointIOField& points0
)
:
displacementMotionSolver(mesh, dict, pointDisplacement, points0, typeName),
meshGeometry_(mesh),
pointSmoother_
(
pointSmoother::New
(
mesh,
coeffDict()
)
),
nPointSmootherIter_
(
readLabel(coeffDict().lookup("nPointSmootherIter"))
),
relaxedPoints_(mesh.points())
{
if (coeffDict().readIfPresent("relaxationFactors", relaxationFactors_))
{
meshQualityDict_ = coeffDict().subDict("meshQuality");
}
setFacesToMove(coeffDict());
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::tmp<Foam::pointField>
Foam::displacementPointSmoothingMotionSolver::curPoints() const
{
//Note: twoDCorrect already done by ::solve
return relaxedPoints_;
}
void Foam::displacementPointSmoothingMotionSolver::solve()
{
//Pout<< "time:" << mesh().time().timeName()
// << " mesh faceCentres:" << gAverage(mesh().faceCentres())
// << " mesh cellCentres:" << gAverage(mesh().cellCentres())
// << endl;
movePoints(curPoints());
// Update values on pointDisplacement
pointDisplacement().boundaryFieldRef().updateCoeffs();
// Extend: face-to-point-to-cell-to-faces
labelHashSet affectedFaces;
markAffectedFaces(facesToMove_, affectedFaces);
for(label i = 0; i < nPointSmootherIter_; i ++)
{
meshGeometry_.correct
(
points0() + pointDisplacement().internalField(),
affectedFaces.toc()
);
//Pout<< "iter:" << i
// << " faceCentres:" << gAverage(meshGeometry_.faceCentres())
// << " cellCentres:" << gAverage(meshGeometry_.cellCentres())
// << endl;
pointSmoother_->update
(
affectedFaces.toc(),
points0(),
points0() + pointDisplacement().internalField(),
meshGeometry_,
pointDisplacement()
);
}
relax();
twoDCorrectPoints(relaxedPoints_);
// Update pointDisplacement for actual relaxedPoints. Keep fixed-value
// bcs.
pointDisplacement().primitiveFieldRef() = relaxedPoints_-points0();
// Adhere to multi-point constraints
const pointConstraints& pcs =
pointConstraints::New(pointDisplacement().mesh());
pcs.constrainDisplacement(pointDisplacement(), false);
// Update relaxedPoints to take constraints into account
relaxedPoints_ = points0() + pointDisplacement().internalField();
}
// ************************************************************************* //

View File

@ -0,0 +1,149 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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::displacementPointSmoothingMotionSolver
Description
Quality-based under-relaxation for run-time selectable point smoothing.
SourceFiles
displacementPointSmoothingMotionSolver.C
\*---------------------------------------------------------------------------*/
#ifndef displacementPointSmoothingMotionSolver_H
#define displacementPointSmoothingMotionSolver_H
#include "displacementMotionSolver.H"
#include "pointSmoother.H"
#include "polyMeshGeometry.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class displacementPointSmoothingMotionSolver Declaration
\*---------------------------------------------------------------------------*/
class displacementPointSmoothingMotionSolver
:
public displacementMotionSolver
{
protected:
// Protected Data
//- Part-updatable mesh geometry
polyMeshGeometry meshGeometry_;
//- Point smoothing method
autoPtr<pointSmoother> pointSmoother_;
//- Number of point smoother iterations per timestep
const label nPointSmootherIter_;
// Mesh quality based relaxation of smoothed position
//- Relaxation factors to use in each iteration
scalarList relaxationFactors_;
//- Relaxed point field
pointField relaxedPoints_;
//- Set of the faces which are to be moved
labelHashSet facesToMove_;
//- Mesh quality dictionary
dictionary meshQualityDict_;
// Private Member Functions
//- Mark affected faces
void markAffectedFaces
(
const labelHashSet& changedFaces,
labelHashSet& affectedFaces
);
//- Relax the points
bool relax();
//- Set all the faces to be moved
void virtual setFacesToMove(const dictionary&);
public:
//- Runtime type information
TypeName("displacementPointSmoothing");
// Constructors
//- Construct from a polyMesh and an IOdictionary
displacementPointSmoothingMotionSolver
(
const polyMesh&,
const IOdictionary&
);
//- Construct from components
displacementPointSmoothingMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict,
const pointVectorField& pointDisplacement,
const pointIOField& points0
);
//- Destructor
virtual ~displacementPointSmoothingMotionSolver() = default;
// Member Functions
//- Return point location obtained from the current motion field
virtual tmp<pointField> curPoints() const;
//- Solve for motion
virtual void solve();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,746 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "displacementSmartPointSmoothingMotionSolver.H"
#include "addToRunTimeSelectionTable.H"
#include "syncTools.H"
#include "pointConstraints.H"
#include "motionSmootherAlgo.H"
//#include "fvMesh.H"
//#include "fvGeometryScheme.H"
#include "OBJstream.H"
#include "emptyPointPatchFields.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(displacementSmartPointSmoothingMotionSolver, 0);
addToRunTimeSelectionTable
(
motionSolver,
displacementSmartPointSmoothingMotionSolver,
dictionary
);
addToRunTimeSelectionTable
(
displacementMotionSolver,
displacementSmartPointSmoothingMotionSolver,
displacement
);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::displacementSmartPointSmoothingMotionSolver::markAffectedFaces
(
const labelHashSet& changedFaces,
labelHashSet& affectedFaces
)
{
PackedBoolList affectedPoints(mesh().nPoints(), false);
forAllConstIter(labelHashSet, changedFaces, iter)
{
const label faceI(iter.key());
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
affectedPoints[pointI] = true;
}
}
syncTools::syncPointList
(
mesh(),
affectedPoints,
orEqOp<unsigned int>(),
0U
);
forAll(affectedPoints, pointI)
{
if (affectedPoints[pointI])
{
const labelList& pCells(mesh().pointCells()[pointI]);
forAll(pCells, pointCellI)
{
const label cellI(pCells[pointCellI]);
const labelList& cFaces(mesh().cells()[cellI]);
affectedFaces.insert(cFaces);
}
}
}
}
bool Foam::displacementSmartPointSmoothingMotionSolver::relax()
{
if
(
(relaxationFactors_.size() == 0)
|| (relaxationFactors_.size() == 1 && relaxationFactors_[0] == 1.0)
)
{
relaxedPoints_ = points0() + pointDisplacement().internalField();
return true;
}
const pointField oldRelaxedPoints(relaxedPoints_);
labelHashSet affectedFaces(facesToMove_);
// Create a list of relaxation levels
// -1 indicates a point which is not to be moved
// 0 is the starting value for a moving point
labelList relaxationLevel(mesh().nPoints(), -1);
forAllConstIter(labelHashSet, affectedFaces, iter)
{
const label faceI(iter.key());
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
relaxationLevel[pointI] = 0;
}
}
syncTools::syncPointList
(
mesh(),
relaxationLevel,
maxEqOp<label>(),
label(-1)
);
// Loop whilst relaxation levels are being incremented
bool complete(false);
while (!complete)
{
//scalar nAffectedFaces(affectedFaces.size());
//reduce(nAffectedFaces, sumOp<scalar>());
//Info << " Moving " << nAffectedFaces << " faces" << endl;
// Move the points
forAll(relaxationLevel, pointI)
{
if (relaxationLevel[pointI] >= 0)
{
const scalar x
(
relaxationFactors_[relaxationLevel[pointI]]
);
relaxedPoints_[pointI] =
(1 - x)*oldRelaxedPoints[pointI]
+ x*(points0()[pointI] + pointDisplacement()[pointI]);
}
}
// Get a list of changed faces
labelHashSet markedFaces;
markAffectedFaces(affectedFaces, markedFaces);
labelList markedFacesList(markedFaces.toc());
// Update the geometry
meshGeometry_.correct(relaxedPoints_, markedFacesList);
// Check the modified face quality
if (false)
{
// Use snappyHexMesh compatible checks
markedFaces.clear();
motionSmootherAlgo::checkMesh
(
false,
meshQualityDict_,
meshGeometry_,
relaxedPoints_,
markedFacesList,
markedFaces
);
// Mark the affected faces
affectedFaces.clear();
markAffectedFaces(markedFaces, affectedFaces);
}
else
{
// Use pointSmoother specific
tmp<scalarField> tfaceQ
(
pointUntangler_->faceQuality
(
relaxedPoints_,
meshGeometry_.faceCentres(),
meshGeometry_.faceAreas(),
meshGeometry_.cellCentres(),
meshGeometry_.cellVolumes()
)
);
if (debug)
{
MinMax<scalar> range(gMinMax(tfaceQ()));
Pout<< " min:" << range.min() << nl
<< " max:" << range.max() << endl;
}
labelList order;
Foam::sortedOrder(tfaceQ(), order);
label nUntangle = 0;
forAll(order, i)
{
if (tfaceQ()[order[i]] > untangleQ_)
{
nUntangle = i;
break;
}
}
affectedFaces = labelList(SubList<label>(order, nUntangle));
}
// Increase relaxation and check convergence
PackedBoolList pointsToRelax(mesh().nPoints(), false);
complete = true;
forAllConstIter(labelHashSet, affectedFaces, iter)
{
const label faceI(iter.key());
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
pointsToRelax[pointI] = true;
}
}
forAll(pointsToRelax, pointI)
{
if
(
pointsToRelax[pointI]
&& (relaxationLevel[pointI] < relaxationFactors_.size() - 1)
)
{
++ relaxationLevel[pointI];
complete = false;
}
}
// Synchronise relaxation levels
syncTools::syncPointList
(
mesh(),
relaxationLevel,
maxEqOp<label>(),
label(0)
);
// Synchronise completion
reduce(complete, andOp<bool>());
}
// Check for convergence
bool converged(true);
forAll(mesh().faces(), faceI)
{
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
if (relaxationLevel[pointI] > 0)
{
facesToMove_.insert(faceI);
converged = false;
break;
}
}
}
// Syncronise convergence
reduce(converged, andOp<bool>());
//if (converged)
//{
// Info<< "... Converged" << endl << endl;
//}
//else
//{
// Info<< "... Not converged" << endl << endl;
//}
return converged;
}
void Foam::displacementSmartPointSmoothingMotionSolver::setFacesToMove
(
const dictionary& dict
)
{
if (dict.getOrDefault<bool>("moveInternalFaces", true))
{
facesToMove_.resize(2*mesh().nFaces());
forAll(mesh().faces(), faceI)
{
facesToMove_.insert(faceI);
}
}
else
{
facesToMove_.resize(2*(mesh().nBoundaryFaces()));
for
(
label faceI = mesh().nInternalFaces();
faceI < mesh().nFaces();
++ faceI
)
{
facesToMove_.insert(faceI);
}
}
}
void Foam::displacementSmartPointSmoothingMotionSolver::emptyCorrectPoints
(
pointVectorField& pointDisplacement
)
{
// Assume empty point patches are already in correct location
// so knock out any off-plane displacement.
auto& fld = pointDisplacement.primitiveFieldRef();
for (const auto& ppf : pointDisplacement.boundaryField())
{
if (isA<emptyPointPatchVectorField>(ppf))
{
const auto& mp = ppf.patch().meshPoints();
forAll(mp, i)
{
pointConstraint pc;
ppf.patch().applyConstraint(i, pc);
fld[mp[i]] = pc.constrainDisplacement(fld[mp[i]]);
}
}
}
pointField wantedPoints(points0() + fld);
twoDCorrectPoints(wantedPoints);
fld = wantedPoints-points0();
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::displacementSmartPointSmoothingMotionSolver::
displacementSmartPointSmoothingMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict
)
:
displacementMotionSolver(mesh, dict, typeName),
meshGeometry_(mesh),
pointUntangler_
(
pointSmoother::New
(
coeffDict().get<word>("untangler"),
mesh,
coeffDict()
)
),
untangleQ_(coeffDict().get<scalar>("untangleQ")),
minQ_(coeffDict().get<scalar>("minQ")),
pointSmoother_(pointSmoother::New(mesh, coeffDict())),
nPointSmootherIter_
(
readLabel(coeffDict().lookup("nPointSmootherIter"))
),
relaxedPoints_(mesh.points())
{
if (coeffDict().readIfPresent("relaxationFactors", relaxationFactors_))
{
meshQualityDict_ = coeffDict().subDict("meshQuality");
}
setFacesToMove(coeffDict());
}
Foam::displacementSmartPointSmoothingMotionSolver::
displacementSmartPointSmoothingMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict,
const pointVectorField& pointDisplacement,
const pointIOField& points0
)
:
displacementMotionSolver(mesh, dict, pointDisplacement, points0, typeName),
meshGeometry_(mesh),
pointUntangler_
(
pointSmoother::New
(
coeffDict().get<word>("untangler"),
mesh,
coeffDict()
)
),
untangleQ_(coeffDict().get<scalar>("untangleQ")),
minQ_(coeffDict().get<scalar>("minQ")),
pointSmoother_
(
pointSmoother::New
(
mesh,
coeffDict()
)
),
nPointSmootherIter_
(
readLabel(coeffDict().lookup("nPointSmootherIter"))
),
relaxedPoints_(mesh.points())
{
if (coeffDict().readIfPresent("relaxationFactors", relaxationFactors_))
{
meshQualityDict_ = coeffDict().subDict("meshQuality");
}
setFacesToMove(coeffDict());
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::tmp<Foam::pointField>
Foam::displacementSmartPointSmoothingMotionSolver::curPoints() const
{
//Note: twoDCorrect already done by ::solve
return relaxedPoints_;
}
void Foam::displacementSmartPointSmoothingMotionSolver::solve()
{
movePoints(curPoints());
// Update values on pointDisplacement. Note: should also evaluate? Since
// e.g. cellMotionBC uses pointDisplacement value.
pointDisplacement().boundaryFieldRef().updateCoeffs();
fileName debugDir;
if (debug & 2)
{
debugDir = mesh().time().timePath();
mkDir(debugDir);
OBJstream os(debugDir/"bc.obj");
const pointField wantedPoints
(
points0()
+ pointDisplacement().internalField()
);
const auto& pbm = pointDisplacement().mesh().boundary();
for (const auto& ppp : pbm)
{
if (!isA<emptyPointPatch>(ppp))
{
const auto& mp = ppp.meshPoints();
for (const label pointi : mp)
{
os.write
(
linePointRef
(
points0()[pointi],
wantedPoints[pointi]
)
);
}
}
}
Pout<< "Written " << os.nVertices() << " initial displacements to "
<< os.name() << endl;
}
// Extend: face-to-point-to-cell-to-faces
labelHashSet affectedFaces;
markAffectedFaces(facesToMove_, affectedFaces);
for(label i = 0; i < nPointSmootherIter_; i ++)
{
const pointField wantedPoints
(
points0()
+ pointDisplacement().internalField()
);
meshGeometry_.correct
(
wantedPoints,
affectedFaces.toc()
);
//{
// // Debugging: check meshGeometry consistent with fvGeometryScheme
// const auto& geom =
// reinterpret_cast<const fvMesh&>(mesh()).geometry();
// pointField faceCentres(mesh().nFaces());
// vectorField faceAreas(mesh().nFaces());
// pointField cellCentres(mesh().nCells());
// scalarField cellVolumes(mesh().nCells());
// geom.updateGeom
// (
// wantedPoints,
// mesh().points(), // old points
// faceCentres,
// faceAreas,
// cellCentres,
// cellVolumes
// );
// forAll(faceCentres, facei)
// {
// const point& meshFc = mesh().faceCentres()[facei];
// const point& meshGeomFc = meshGeometry_.faceCentres()[facei];
// const point& updatedFc = faceCentres[facei];
//
// if (updatedFc != meshGeomFc)
// {
// const face& f = mesh().faces()[facei];
//
// Pout<< "At face:" << facei << nl
// << " old :" << meshFc << nl
// << " new :" << updatedFc << nl
// << " polyMeshGeom:" << meshGeomFc << nl
// << " oldPoints :"
// << UIndirectList<point>(mesh().points(), f) << nl
// << " wantedPoints:"
// << UIndirectList<point>(wantedPoints, f) << nl
// << endl;
// }
// }
//}
// Get measure of face quality
tmp<scalarField> tfaceQ
(
pointUntangler_->faceQuality
(
wantedPoints,
meshGeometry_.faceCentres(),
meshGeometry_.faceAreas(),
meshGeometry_.cellCentres(),
meshGeometry_.cellVolumes()
)
);
if (debug)
{
MinMax<scalar> range(gMinMax(tfaceQ()));
Pout<< " min:" << range.min() << nl
<< " max:" << range.max() << endl;
}
labelList order;
Foam::sortedOrder(tfaceQ(), order);
label nUntangle = 0;
forAll(order, i)
{
if (tfaceQ()[order[i]] > untangleQ_)
{
nUntangle = i;
break;
}
}
label nLow = 0;
forAll(order, i)
{
if (tfaceQ()[order[i]] > minQ_)
{
nLow = i;
break;
}
}
if (debug)
{
Pout<< " nUntangle:" << returnReduce(nUntangle, sumOp<label>())
<< nl
<< " nLow :" << returnReduce(nLow, sumOp<label>())
<< nl;
}
if (returnReduce(nUntangle, sumOp<label>()))
{
// Start untangling
labelList lowQFaces(SubList<label>(order, nUntangle));
//{
// // Grow set (non parallel)
// bitSet isMarkedFace(mesh().nFaces());
// for (const label facei : lowQFaces)
// {
// for (const label pointi : mesh().faces()[facei])
// {
// isMarkedFace.set(mesh().pointFaces()[pointi]);
// }
// }
// lowQFaces = isMarkedFace.sortedToc();
//}
//Pout<< " untangling "
// << returnReduce(lowQFaces.size(), sumOp<label>())
// << " faces" << endl;
pointUntangler_->update
(
lowQFaces,
points0(),
wantedPoints,
meshGeometry_,
pointDisplacement()
//false // ! do NOT apply bcs, constraints
);
// Keep points on empty patches. Note: since pointConstraints
// does not implement constraints on emptyPointPatches and
// emptyPointPatchField does not either.
emptyCorrectPoints(pointDisplacement());
if (debug & 2)
{
OBJstream os(debugDir/"untangle_" + Foam::name(i) + ".obj");
const pointField wantedPoints
(
points0()
+ pointDisplacement().internalField()
);
forAll(wantedPoints, pointi)
{
os.write
(
linePointRef
(
points0()[pointi],
wantedPoints[pointi]
)
);
}
Pout<< "Written " << os.nVertices() << " wanted untangle to "
<< os.name() << endl;
}
}
else if (returnReduce(nLow, sumOp<label>()))
{
labelList lowQFaces(SubList<label>(order, nLow));
//{
// // Grow set (non parallel)
// bitSet isMarkedFace(mesh().nFaces());
// for (const label facei : lowQFaces)
// {
// for (const label pointi : mesh().faces()[facei])
// {
// isMarkedFace.set(mesh().pointFaces()[pointi]);
// }
// }
// lowQFaces = isMarkedFace.sortedToc();
//}
//Pout<< " smoothing "
// << returnReduce(lowQFaces.size(), sumOp<label>())
// << " faces" << endl;
pointSmoother_->update
(
lowQFaces,
points0(),
wantedPoints,
meshGeometry_,
pointDisplacement()
);
// Keep points on empty patches
emptyCorrectPoints(pointDisplacement());
}
else
{
//Pout<< "** converged" << endl;
break;
}
}
relax();
//relaxedPoints_ = points0() + pointDisplacement().internalField();
twoDCorrectPoints(relaxedPoints_);
// Update pointDisplacement for actual relaxedPoints. Keep fixed-value
// bcs.
pointDisplacement().primitiveFieldRef() = relaxedPoints_-points0();
// Adhere to multi-point constraints. Does correctBoundaryConditions +
// multi-patch issues.
const pointConstraints& pcs =
pointConstraints::New(pointDisplacement().mesh());
pcs.constrainDisplacement(pointDisplacement(), false);
}
// ************************************************************************* //

View File

@ -0,0 +1,193 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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::displacementSmartPointSmoothingMotionSolver
Description
Quality-based under-relaxation for run-time selectable point smoothing. WIP.
Usage
\table
Property | Description | Required | Default value
untangler | pointSmoother for untangling | yes |
untangleQ | quality below which untangling is applied | yes |
pointSmoother | pointSmoother in 'normal' mode | yes
minQ | quality below which pointSmoother is applied | yes
nPointSmootherIter | max number of iterations
\endtable
Example of the motion solver specification in dynamicMeshDict:
\verbatim
motionSolver displacementSmartPointSmoothing;
displacementSmartPointSmoothingCoeffs
{
//- Overall max number of smoothing iterations
nPointSmootherIter 10;
//- If any faces have quality below untangleQ apply untangler
untangleQ 0.001;
untangler laplacian;
//- If any faces have quality below minQ apply 'normal' smoother
minQ 0.9;
pointSmoother geometricElementTransform;
transformationParameter 0.667;
}
\endverbatim
SourceFiles
displacementSmartPointSmoothingMotionSolver.C
\*---------------------------------------------------------------------------*/
#ifndef displacementSmartPointSmoothingMotionSolver_H
#define displacementSmartPointSmoothingMotionSolver_H
#include "displacementMotionSolver.H"
#include "pointSmoother.H"
#include "polyMeshGeometry.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class displacementSmartPointSmoothingMotionSolver Declaration
\*---------------------------------------------------------------------------*/
class displacementSmartPointSmoothingMotionSolver
:
public displacementMotionSolver
{
protected:
// Protected Data
//- Part-updatable mesh geometry
polyMeshGeometry meshGeometry_;
//- Point untangler method
autoPtr<pointSmoother> pointUntangler_;
//- Minimum allowed quality
const scalar untangleQ_;
//- Minimum allowed quality
const scalar minQ_;
//- Point smoothing method
autoPtr<pointSmoother> pointSmoother_;
//- Number of point smoother iterations per timestep
const label nPointSmootherIter_;
// Mesh quality based relaxation of smoothed position
//- Relaxation factors to use in each iteration
scalarList relaxationFactors_;
//- Relaxed point field
pointField relaxedPoints_;
//- Set of the faces which are to be moved
labelHashSet facesToMove_;
//- Mesh quality dictionary
dictionary meshQualityDict_;
// Private Member Functions
//- Mark affected faces
void markAffectedFaces
(
const labelHashSet& changedFaces,
labelHashSet& affectedFaces
);
//- Relax the points
bool relax();
//- Set all the faces to be moved
void virtual setFacesToMove(const dictionary&);
//- Handle 2D & empty bcs. Assume in both cases the starting mesh
// - has all edges aligned with 3rd dimension
// - is on planes of the empty patches
void emptyCorrectPoints(pointVectorField& pointDisplacement);
public:
//- Runtime type information
TypeName("displacementSmartPointSmoothing");
// Constructors
//- Construct from a polyMesh and an IOdictionary
displacementSmartPointSmoothingMotionSolver
(
const polyMesh&,
const IOdictionary&
);
//- Construct from components
displacementSmartPointSmoothingMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict,
const pointVectorField& pointDisplacement,
const pointIOField& points0
);
//- Destructor
virtual ~displacementSmartPointSmoothingMotionSolver() = default;
// Member Functions
//- Return point location obtained from the current motion field
virtual tmp<pointField> curPoints() const;
//- Solve for motion
virtual void solve();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,258 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 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::hexMeshSmootherMotionSolver
Description
Implementation of hexMeshSmoother (part of extBlockMesh). WIP.
See https://github.com/Etudes-NG/extBlockMesh
extBlockMesh Copyright (C) 2014 Etudes-NG
Quality-based under-relaxation of point smoothing.
Usage
Example of the motion solver specification in dynamicMeshDict:
\verbatim
motionSolver hexMeshSmoother;
hexMeshSmootherCoeffs
{
//- Number of smoothing iterations
nPointSmootherIter 10;
//- Smoother to apply
pointSmoother geometricElementTransform;
//- Any smoother-specific settings
transformationParameter 0.667;
//- Underrelax boundary condition
snapScale table ((0 0.1) (10 1.0));
}
SourceFiles
hexMeshSmootherMotionSolver.C
\*---------------------------------------------------------------------------*/
#ifndef hexMeshSmootherMotionSolver_H
#define hexMeshSmootherMotionSolver_H
#include "displacementMotionSolver.H"
#include "Function1.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
//class searchableSurfaces;
class pointSmoother;
/*---------------------------------------------------------------------------*\
Class hexMeshSmootherMotionSolver Declaration
\*---------------------------------------------------------------------------*/
class hexMeshSmootherMotionSolver
:
public displacementMotionSolver
{
public:
// Public Data
//- Enumeration defining the type of attraction
enum pointType
{
INTERIOR = 0,
SURFACE = 1,
EDGE = 2,
POINT = 3
};
protected:
// Protected Data
//- Point smoothing method
autoPtr<pointSmoother> pointSmoother_;
//- Number of point smoother iterations per timestep
const label nPointSmootherIter_;
// Mesh quality based relaxation of smoothed position
//- Relaxation factors to use in each iteration
const scalarList relaxationFactors_;
//- Per mesh point (including internal) what type
labelList pointTypes_;
//- Per mesh point the last used relaxation factor
labelList relaxationLevel_;
//- Relaxed point field
pointField relaxedPoints_;
////- Patches that are to be snapped
//const labelList snapPatches_;
//
////- FaceZones that are to be snapped
//const labelList snapZones_;
//- Scaling for snapping
const autoPtr<Function1<scalar>> snapScale_;
//- Cached per-point coupled status. For guaranteeing contributions
// of coupled points only done once
const bitSet isMasterPoint_;
//- Create big primitivePatch for all outside and any features on it
const autoPtr<indirectPrimitivePatch> bnd0Ptr_;
// Private Member Functions
//- Collect all non-constraint (i.e. no processor, cyclic, empty etc)
//- patches
static labelList nonConstraintPatches(const polyMesh& mesh);
//- Create single patch of all supplied faces
static autoPtr<indirectPrimitivePatch> makePatch
(
const polyMesh& mesh,
const labelList& patchIDs,
const labelList& zoneIDs,
const pointField& points0
);
//- Check with current points
void checkMesh
(
const pointField& currentPoints,
const vectorField& fCtrs,
const vectorField& fAreas,
const vectorField& cellCtrs,
const scalarField& cellVols,
labelHashSet& markedFaces,
bitSet& markedPoints
) const;
//- Apply current constraints (from pointDisplacement) to supplied
// locations
void constrainDisplacement(pointField& points) const;
//- Relax the points (supplied in pointDisplacement)
bool relax
(
const scalarList& relaxationFactors,
const bitSet& pointsToRelax,
const pointField& initialPoints,
const pointField& wantedPoints,
pointField& relaxedPoints,
labelList& relaxationLevel
) const;
label countPos(const labelList& elems) const;
labelList countZeroOrPos(const label size, const labelList& lst) const;
//- Helper: set in bitSet all elements with a certain value
void select(const labelUList&, const label val, bitSet& isVal) const;
void laplaceSmooth
(
const label type,
const pointField& initialPoints,
pointField& newPoints
) const;
void featLaplaceSmooth
(
const indirectPrimitivePatch& pp,
const pointField& initialPoints,
pointField& newPoints
) const;
// Snap points using boundary evaluation ...
void snapBoundaryPoints
(
const scalar scale,
const pointField& initialPoints,
pointField& newPoints
) const;
//- Keep points on empty patches
void emptyCorrectPoints(pointVectorField& pointDisplacement) const;
public:
//- Runtime type information
TypeName("hexMeshSmoother");
// Constructors
//- Construct from a polyMesh and an IOdictionary
hexMeshSmootherMotionSolver
(
const polyMesh&,
const IOdictionary&
);
//- Construct from components
hexMeshSmootherMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict,
const pointVectorField& pointDisplacement,
const pointIOField& points0
);
//- Destructor
virtual ~hexMeshSmootherMotionSolver();
// Member Functions
//- Return point location obtained from the current motion field
virtual tmp<pointField> curPoints() const;
//- Solve for motion
virtual void solve();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,148 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "equipotentialPointSmoother.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace pointSmoothers
{
defineTypeNameAndDebug(equipotentialPointSmoother, 0);
addToRunTimeSelectionTable
(
pointSmoother,
equipotentialPointSmoother,
dictionary
);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::pointSmoothers::equipotentialPointSmoother::equipotentialPointSmoother
(
const polyMesh& mesh,
const dictionary& dict
)
:
pointSmoother(mesh, dict)
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
void Foam::pointSmoothers::equipotentialPointSmoother::calculate
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
vectorField& pointDisplacement
) const
{
// Number of points used in each average
scalarField weights(mesh().nPoints(), 0);
// Reset the displacements which are about to be calculated
reset(facesToMove, weights, pointDisplacement);
// Sum the non-internal face displacements
forAll(facesToMove, faceToMoveI)
{
const label faceI(facesToMove[faceToMoveI]);
if (!isInternalOrProcessorFace(faceI))
{
const face& fPoints(mesh().faces()[faceI]);
const scalar area(mag(mesh().faceAreas()[faceI]));
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
pointDisplacement[pointI] +=
area
*(
faceCentres[faceI]
- oldPoints[pointI]
);
weights[pointI] += area;
}
}
}
// Sum the internal face displacements
forAll(facesToMove, faceToMoveI)
{
const label faceI(facesToMove[faceToMoveI]);
if (isInternalOrProcessorFace(faceI))
{
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
if (weights[pointI] < SMALL)
{
const labelList& pCells(mesh().pointCells()[pointI]);
forAll(pCells, pCellI)
{
const label cellI(pCells[pCellI]);
const scalar volume(mesh().cellVolumes()[cellI]);
pointDisplacement[pointI] +=
volume
*(
cellCentres[cellI]
- oldPoints[pointI]
);
weights[pointI] += volume;
}
}
}
}
}
// Average
average(facesToMove, weights, pointDisplacement);
}
// ************************************************************************* //

View File

@ -0,0 +1,105 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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::equipotentialPointSmoother
Description
Equipotential point smoothing. Points are moved towards the centroid of the
surrounding cell volumes. This method tends to equilise cell volumes, and
can generate distorted cells around refinement patterns.
SourceFiles
equipotentialPointSmoother.C
\*---------------------------------------------------------------------------*/
#ifndef equipotentialPointSmoother_H
#define equipotentialPointSmoother_H
#include "pointSmoother.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace pointSmoothers
{
/*---------------------------------------------------------------------------*\
Class equipotentialPointSmoother Declaration
\*---------------------------------------------------------------------------*/
class equipotentialPointSmoother
:
public pointSmoother
{
public:
//- Runtime type information
TypeName("equipotential");
// Constructors
//- Construct from a dictionary and a polyMesh
equipotentialPointSmoother
(
const polyMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~equipotentialPointSmoother() = default;
// Member Functions
//- Calculate the point displacements
virtual void calculate
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
vectorField& pointDisplacement
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace pointSmoothers
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,292 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "cellPointConnectivity.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(cellPointConnectivity, 0);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::cellPointConnectivity::generateCellPointConnectivity(label cellI)
{
const cell& cFaceLabels(mesh_.cells()[cellI]);
const labelList cPointLabels(cFaceLabels.labels(mesh_.faces()));
const edgeList cEdges(cFaceLabels.edges(mesh_.faces()));
// Generate a sorted list of points and corresponding point indices
labelPairList pointLabelPointIndices(cPointLabels.size());
forAll(cPointLabels, pointI)
{
pointLabelPointIndices[pointI] =
labelPair(cPointLabels[pointI], pointI);
}
sort(pointLabelPointIndices);
// Generate a sorted list of edge labels and corresponding edge indices
// Negative values indicate an edge which runs in an opposite direction to
// the face node listing
labelListList edgeLabelsEdgeIndices
(
2*cEdges.size(),
labelList(3, label(-1))
);
forAll(cEdges, cEdgeI)
{
edgeLabelsEdgeIndices[2*cEdgeI][0] = cEdges[cEdgeI][0];
edgeLabelsEdgeIndices[2*cEdgeI][1] = cEdges[cEdgeI][1];
edgeLabelsEdgeIndices[2*cEdgeI][2] = cEdgeI;
edgeLabelsEdgeIndices[2*cEdgeI+1][0] = cEdges[cEdgeI][1];
edgeLabelsEdgeIndices[2*cEdgeI+1][1] = cEdges[cEdgeI][0];
edgeLabelsEdgeIndices[2*cEdgeI+1][2] = - cEdgeI - 1;
}
sort(edgeLabelsEdgeIndices);
// Generate a sorted list of edge labels and correspoinding face indices
labelListList edgeLabelsFaceIndices;
forAll(cFaceLabels, cFaceI)
{
const face& cFace(mesh_.faces()[cFaceLabels[cFaceI]]);
const bool owner(mesh_.faceOwner()[cFaceLabels[cFaceI]] == cellI);
const label cFaceNEdges(cFace.size());
forAll(cFace, cFaceEdgeI)
{
edgeLabelsFaceIndices.append(labelList(3, label(-1)));
edgeLabelsFaceIndices.last()[0] =
cFace[(cFaceEdgeI + owner) % cFaceNEdges];
edgeLabelsFaceIndices.last()[1] =
cFace[(cFaceEdgeI + !owner) % cFaceNEdges];
edgeLabelsFaceIndices.last()[2] = cFaceI;
}
}
sort(edgeLabelsFaceIndices);
// Assemble lists of edge-face and cell-face connectivities
// Negative values indicate an edge which runs in an opposite direction to
// the face node listing
labelListList edgeFaceIndices(cEdges.size());
labelListList faceEdgeIndices(cFaceLabels.size());
forAll(edgeLabelsFaceIndices, I)
{
const label edgeLabelsEdgeIndex(edgeLabelsEdgeIndices[I][2]);
const label absCellEdgeEdgeIndex
(
edgeLabelsEdgeIndex >= 0
? edgeLabelsEdgeIndex
: - edgeLabelsEdgeIndex - 1
);
const label absCellEdgeFaceIndex(edgeLabelsFaceIndices[I][2]);
const label edgeLabelsFaceIndex
(
edgeLabelsEdgeIndex >= 0
? absCellEdgeFaceIndex
: - absCellEdgeFaceIndex - 1
);
edgeFaceIndices[absCellEdgeEdgeIndex].append(edgeLabelsFaceIndex);
faceEdgeIndices[absCellEdgeFaceIndex].append(edgeLabelsEdgeIndex);
}
// Generate a list of point labels and face index pairs
labelListList pointLabelEdgeIndexFaceIndexPairs;
forAll(cEdges, edgeI)
{
const labelPair pointIndices(cEdges[edgeI]);
const labelPair faceIndices
(
edgeFaceIndices[edgeI][0],
edgeFaceIndices[edgeI][1]
);
const labelPair absFaceIndices
(
faceIndices[0] >= 0 ? faceIndices[0] : - faceIndices[0] - 1,
faceIndices[1] >= 0 ? faceIndices[1] : - faceIndices[1] - 1
);
const bool order(faceIndices[0] > faceIndices[1]);
pointLabelEdgeIndexFaceIndexPairs.append(labelList(4, label(-1)));
pointLabelEdgeIndexFaceIndexPairs.last()[0] = pointIndices[0];
pointLabelEdgeIndexFaceIndexPairs.last()[1] = edgeI;
pointLabelEdgeIndexFaceIndexPairs.last()[2] = absFaceIndices[order];
pointLabelEdgeIndexFaceIndexPairs.last()[3] = absFaceIndices[!order];
pointLabelEdgeIndexFaceIndexPairs.append(labelList(4, label(-1)));
pointLabelEdgeIndexFaceIndexPairs.last()[0] = pointIndices[1];
pointLabelEdgeIndexFaceIndexPairs.last()[1] = edgeI;
pointLabelEdgeIndexFaceIndexPairs.last()[2] = absFaceIndices[!order];
pointLabelEdgeIndexFaceIndexPairs.last()[3] = absFaceIndices[order];
}
sort(pointLabelEdgeIndexFaceIndexPairs);
// Assemble a list of point face pairs from the sorted lists
labelListList pointEdgeIndices(cPointLabels.size());
List<List<Pair<label> > > pointFaceIndexPairs(cPointLabels.size());
{
label I(0);
label pointLabelOld(pointLabelEdgeIndexFaceIndexPairs[0][0]);
forAll
(
pointLabelEdgeIndexFaceIndexPairs,
pointLabelEdgeIndexFaceIndexPairI
)
{
const labelList& pointLabelEdgeIndexFaceIndexPair
(
pointLabelEdgeIndexFaceIndexPairs
[
pointLabelEdgeIndexFaceIndexPairI
]
);
if (pointLabelOld != pointLabelEdgeIndexFaceIndexPair[0])
{
I ++;
pointLabelOld = pointLabelEdgeIndexFaceIndexPair[0];
}
const label pointI(pointLabelPointIndices[I][1]);
pointEdgeIndices[pointI].append
(
pointLabelEdgeIndexFaceIndexPair[1]
);
pointFaceIndexPairs[pointI].append
(
labelPair
(
pointLabelEdgeIndexFaceIndexPair[2],
pointLabelEdgeIndexFaceIndexPair[3]
)
);
}
}
// Order the point face pairs and assemble a list of point face indices
labelListList pointFaceIndices(cPointLabels.size());
forAll(pointFaceIndexPairs, pointI)
{
labelPairList& faceIndexPairs(pointFaceIndexPairs[pointI]);
pointFaceIndices[pointI].append(faceIndexPairs[0][0]);
for (label pairI = 1; pairI < faceIndexPairs.size(); pairI ++)
{
for (label pairJ = pairI; pairJ < faceIndexPairs.size(); ++ pairJ)
{
if (faceIndexPairs[pairI-1][1] == faceIndexPairs[pairJ][0])
{
Swap
(
pointEdgeIndices[pointI][pairI],
pointEdgeIndices[pointI][pairJ]
);
Swap
(
faceIndexPairs[pairI],
faceIndexPairs[pairJ]
);
break;
}
}
pointFaceIndices[pointI].append(faceIndexPairs[pairI][0]);
}
}
// convert to global indices
forAll(cPointLabels, pointI)
{
labelList& edgeIndices(pointEdgeIndices[pointI]);
labelList& faceIndices(pointFaceIndices[pointI]);
const label nPointFaces(faceIndices.size());
cellPointPoints_[cellI][pointI].resize(nPointFaces);
forAll(edgeIndices, edgeI)
{
cellPointPoints_[cellI][pointI][edgeI] =
cEdges[edgeIndices[edgeI]]
[
cEdges[edgeIndices[edgeI]][0] == cPointLabels[pointI]
];
}
cellPointFaces_[cellI][pointI].resize(nPointFaces);
forAll(faceIndices, faceI)
{
cellPointFaces_[cellI][pointI][faceI] =
cFaceLabels
[
faceIndices[faceI]
];
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::cellPointConnectivity::cellPointConnectivity(const polyMesh& mesh)
:
MoveableMeshObject<polyMesh>(typeName, mesh),
mesh_(mesh),
cellPointPoints_(mesh.nCells()),
cellPointFaces_(mesh.nCells())
{
forAll(mesh.cells(), cellI)
{
const label nPoints(mesh.cellPoints()[cellI].size());
cellPointPoints_[cellI].resize(nPoints);
cellPointFaces_[cellI].resize(nPoints);
generateCellPointConnectivity(cellI);
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::cellPointConnectivity::~cellPointConnectivity()
{}
// ************************************************************************* //

View File

@ -0,0 +1,139 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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::cellPointConnectivity
Description
This class provides ordered connectivity for each point of each cell. Lists
are available of the points and faces surrounding each point of a cell. The
lists are ordered so that the connected points describe a polygonal cone.
For a convex cell, any three sequantial cone edges form a positive basis.
SourceFiles
cellPointConnectivity.C
\*---------------------------------------------------------------------------*/
#ifndef cellPointConnectivity_H
#define cellPointConnectivity_H
#include "polyMesh.H"
#include "MeshObject.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class cellPointConnectivity Declaration
\*---------------------------------------------------------------------------*/
class cellPointConnectivity
:
public MoveableMeshObject<polyMesh>
{
// Private data
//- Reference to the polyMesh
const polyMesh& mesh_;
//- Lists of point-point connections
labelListListList cellPointPoints_;
//- Lists of point-face connections
labelListListList cellPointFaces_;
// Private Member Functions
//- Disallow default bitwise copy construct
cellPointConnectivity(const cellPointConnectivity&);
//- Disallow default bitwise assignment
void operator=(const cellPointConnectivity&);
//- Generate the connectivity
void generateCellPointConnectivity(label cellI);
public:
// Run-time type information
TypeName("cellPointConnectivity");
// Constructors
//- Construct an IOobject and a polymesh
cellPointConnectivity(const polyMesh&);
//- Destructor
~cellPointConnectivity();
// Member Functions
// Access
//- Access the point-point connections
const labelListListList& cellPointPoints() const
{
return cellPointPoints_;
}
//- Access the point-face connections
const labelListListList& cellPointFaces() const
{
return cellPointFaces_;
}
// Edit
//- No action required on move points
virtual bool movePoints()
{
return true;
}
//- Dummy write for regIOobject
virtual bool writeData(Ostream&) const
{
return true;
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,479 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "geometricElementTransformPointSmoother.H"
#include "cellPointConnectivity.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace pointSmoothers
{
defineTypeNameAndDebug(geometricElementTransformPointSmoother, 0);
addToRunTimeSelectionTable
(
pointSmoother,
geometricElementTransformPointSmoother,
dictionary
);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::scalar
Foam::pointSmoothers::geometricElementTransformPointSmoother::cellQuality
(
const polyMesh& mesh,
const pointField& currentPoints,
const cellPointConnectivity& connectivity,
const label celli
)
{
const cell& cFaces = mesh.cells()[celli];
const labelList cPoints(cFaces.labels(mesh.faces()));
// Calculate a transformed point for each cell point
scalar cellQ = 0.0;
label nTets = 0;
forAll(cPoints, cPointi)
{
const label pointi(cPoints[cPointi]);
const point& pt = currentPoints[pointi];
const labelList& pPoints
(
connectivity.cellPointPoints()[celli][cPointi]
);
if (pPoints.size() != 3)
{
WarningInFunction<< "Cell:" << celli
<< " point:" << pointi
<< " connected points:" << pPoints << endl;
}
else
{
const Tensor<scalar> mA
(
currentPoints[pPoints[0]] - pt,
currentPoints[pPoints[1]] - pt,
currentPoints[pPoints[2]] - pt
);
const scalar sigma(det(mA));
if (sigma < ROOTVSMALL)
{
return 0;
}
// 3 * pow(sigma, 2.0/3.0)/magSqr(mA)
const scalar tetQ =
scalar(3) * Foam::cbrt(Foam::sqr(sigma)) / magSqr(mA);
cellQ += tetQ;
nTets++;
}
}
return cellQ/nTets;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::pointSmoothers::geometricElementTransformPointSmoother::
geometricElementTransformPointSmoother
(
const polyMesh& mesh,
const dictionary& dict
)
:
pointSmoother(mesh, dict),
transformationParameter_
(
readScalar(dict.lookup("transformationParameter"))
)
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
void Foam::pointSmoothers::geometricElementTransformPointSmoother::calculate
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
vectorField& pointDisplacement
) const
{
// Lookup or generate the cell-point connectivity/
const cellPointConnectivity& connectivity =
MeshObject<polyMesh, MoveableMeshObject, cellPointConnectivity>::New
(
mesh()
);
// Number of points used in each average
labelField counts(mesh().nPoints(), -1);
// Reset the displacements which are about to be calculated
reset(facesToMove, counts, pointDisplacement);
// Identify the cells which are to be moved
labelHashSet cellsToMove(facesToMove.size()*2/3);
forAll(facesToMove, faceToMoveI)
{
const label faceI(facesToMove[faceToMoveI]);
cellsToMove.insert(mesh().faceOwner()[faceI]);
if (mesh().isInternalFace(faceI))
{
cellsToMove.insert(mesh().faceNeighbour()[faceI]);
}
}
// Transformed point field
pointField transformedPoints(currentPoints);
// Calculate the internal transformations
forAllConstIter(labelHashSet, cellsToMove, iter)
{
const label cellI(iter.key());
const cell& cFaces
(
mesh().cells()[cellI]
);
const labelList cPoints
(
cFaces.labels(mesh().faces())
);
const edgeList cEdges
(
cFaces.edges(mesh().faces())
);
// Calculate a transformed point for each cell point
forAll(cPoints, cPointI)
{
const label pointI(cPoints[cPointI]);
if (counts[pointI] == -1) continue;
const labelList& pPoints
(
connectivity.cellPointPoints()[cellI][cPointI]
);
const labelList& pFaces
(
connectivity.cellPointFaces()[cellI][cPointI]
);
const label nPPoints(pPoints.size());
// Initial guess of the dual face centre
vector dualAverage(vector::zero);
forAll(pPoints, pPointI)
{
dualAverage +=
currentPoints[pPoints[pPointI]]
+ faceCentres[pFaces[pPointI]];
}
dualAverage /= 2*nPPoints;
// Calculate the dual face centre and normal
vector dualNormal(vector::zero);
forAll(pPoints, pPointI)
{
const label nextPPointI((pPointI + 1) % nPPoints);
point edgeCentre
(
0.5
*(
currentPoints[pPoints[pPointI]]
+ currentPoints[pointI]
)
);
point nextFaceCentre
(
faceCentres[pFaces[nextPPointI]]
);
point nextEdgeCentre
(
0.5
*(
currentPoints[pPoints[nextPPointI]]
+ currentPoints[pointI]
)
);
dualNormal +=
(nextFaceCentre - edgeCentre)
^(edgeCentre - dualAverage);
dualNormal +=
(nextEdgeCentre - nextFaceCentre)
^(nextFaceCentre - dualAverage);
}
vector dualNormalHat(dualNormal/max(mag(dualNormal), ROOTVSMALL));
scalar sumA(0);
vector sumAc(vector::zero);
forAll(pPoints, pPointI)
{
const label nextPPointI((pPointI + 1) % nPPoints);
point edgeCentre
(
0.5
*(
currentPoints[pPoints[pPointI]]
+ currentPoints[pointI]
)
);
point nextFaceCentre
(
faceCentres[pFaces[nextPPointI]]
);
point nextEdgeCentre
(
0.5
*(
currentPoints[pPoints[nextPPointI]]
+ currentPoints[pointI]
)
);
vector c1 = edgeCentre + nextFaceCentre + dualAverage;
vector c2 = nextFaceCentre + nextEdgeCentre + dualAverage;
vector n1 =
(nextFaceCentre - edgeCentre)
^(edgeCentre - dualAverage);
vector n2 =
(nextEdgeCentre - nextFaceCentre)
^(nextFaceCentre - dualAverage);
scalar a1 = n1 & dualNormalHat;
scalar a2 = n2 & dualNormalHat;
sumA += a1 + a2;
sumAc += a1*c1 + a2*c2;
}
const vector dualCentre(sumAc/max(sumA, ROOTVSMALL)/3);
// Calculate the transformed point
transformedPoints[pointI] =
dualCentre
+ transformationParameter_
*dualNormal/sqrt(max(mag(dualNormal), ROOTVSMALL));
}
// Length scale
scalar lengthScale(0), transformedLengthScale(0);
forAll(cEdges, cEdgeI)
{
lengthScale +=
cEdges[cEdgeI].mag(currentPoints);
transformedLengthScale +=
cEdges[cEdgeI].mag(transformedPoints);
}
lengthScale /= cEdges.size();
transformedLengthScale /= cEdges.size();
const scalar lengthScaleRatio =
(
(transformedLengthScale > SMALL)
? lengthScale/transformedLengthScale
: scalar(0)
);
// Add the displacement to the average
forAll(cPoints, cPointI)
{
const label pointI(cPoints[cPointI]);
if (counts[pointI] == -1) continue;
const vector newPoint
(
cellCentres[cellI]
+ lengthScaleRatio
*(
transformedPoints[pointI]
- cellCentres[cellI]
)
);
++ counts[pointI];
pointDisplacement[pointI] += newPoint - oldPoints[pointI];
}
}
// Reset all the boundary faces
reset(facesToMove, counts, pointDisplacement, false);
// Calculate the boundary transformations
forAll(facesToMove, faceToMoveI)
{
const label faceI(facesToMove[faceToMoveI]);
if (!isInternalOrProcessorFace(faceI))
{
const labelList& fPoints(mesh().faces()[faceI]);
// Face normal
vector faceNormalHat(faceAreas[faceI]);
faceNormalHat /= max(SMALL, mag(faceNormalHat));
// Calculate a transformed point for each face point
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
const label fPointIPrev
(
(fPointI - 1 + fPoints.size()) % fPoints.size()
);
const label fPointINext
(
(fPointI + 1) % fPoints.size()
);
const vector dualCentre
(
currentPoints[pointI]/2
+ (
currentPoints[fPoints[fPointINext]]
+ currentPoints[fPoints[fPointIPrev]]
)/4
);
const vector dualNormal
(
(
currentPoints[fPoints[fPointINext]]
- currentPoints[fPoints[fPointIPrev]]
)/2
^faceNormalHat
);
transformedPoints[pointI] =
dualCentre
+ transformationParameter_
*dualNormal/sqrt(max(mag(dualNormal), ROOTVSMALL));
}
// Length scale
scalar lengthScale(0), transformedLengthScale(0);
forAll(fPoints, fPointI)
{
const label fPointINext((fPointI + 1)%fPoints.size());
const label pointI(fPoints[fPointI]);
const label pointINext(fPoints[fPointINext]);
lengthScale += mag
(
currentPoints[pointINext] - currentPoints[pointI]
);
transformedLengthScale += mag
(
transformedPoints[pointINext] - transformedPoints[pointI]
);
}
lengthScale /= fPoints.size();
transformedLengthScale /= fPoints.size();
const scalar lengthScaleRatio
(
(transformedLengthScale > SMALL)
? lengthScale/transformedLengthScale
: scalar(0)
);
// Add the displacement to the average
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
const vector newPoint
(
faceCentres[faceI]
+ lengthScaleRatio
*(
transformedPoints[pointI]
- faceCentres[faceI]
)
);
++ counts[pointI];
pointDisplacement[pointI] += newPoint - oldPoints[pointI];
}
}
}
// Average
average(facesToMove, counts, pointDisplacement);
}
Foam::tmp<Foam::scalarField>
Foam::pointSmoothers::geometricElementTransformPointSmoother::cellQuality
(
const polyMesh& mesh,
const pointField& currentPoints
)
{
const cellPointConnectivity& connectivity =
MeshObject<polyMesh, MoveableMeshObject, cellPointConnectivity>::New
(
mesh
);
tmp<scalarField> tfld(tmp<scalarField>::New(mesh.nCells()));
scalarField& fld = tfld.ref();
forAll(fld, celli)
{
fld[celli] = cellQuality(mesh, currentPoints, connectivity, celli);
}
return tfld;
}
// ************************************************************************* //

View File

@ -0,0 +1,149 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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::pointSmoothers::geometricElementTransformPointSmoother
Description
Geometric Element Transformation Method (GETMe) point smoother. Points are
moved in a direction normal to the face of the dual element. This tends to
orthogonalise elements. This method can "push" as well as "pull".
The original references for this method only formulate it for a limited
variety of specific polyhedra. This version is written for arbitrary
polyhedra, and most closely follows the following reference:
\verbatim
"Fast smoothing of mixed volume meshes based on the effective geometric
element transformation method"
Dimitris Vartziotis, Joachim Wipper,
Comput. Methods Appl. Mech. Engrg. 201-204 (2012) 65-81
\endverbatim
This implementation does not include the various specific measures employed
in the referred article to improve the quality of types of irregular
polyhedra. It also does not use the same quality criteria as these are only
suitable for cell vertices with exactly three connecting edges.
SourceFiles
geometricElementTransformPointSmoother.C
\*---------------------------------------------------------------------------*/
#ifndef geometricElementTransformPointSmoother_H
#define geometricElementTransformPointSmoother_H
#include "pointSmoother.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class cellPointConnectivity;
namespace pointSmoothers
{
/*---------------------------------------------------------------------------*\
Class geometricElementTransformPointSmoother Declaration
\*---------------------------------------------------------------------------*/
class geometricElementTransformPointSmoother
:
public pointSmoother
{
private:
// Private Data
//- Transformation parameter
const scalar transformationParameter_;
// Private Member Functions
static scalar cellQuality
(
const polyMesh& mesh,
const pointField& currentPoints,
const cellPointConnectivity& connectivity,
const label celli
);
public:
//- Runtime type information
TypeName("geometricElementTransform");
// Constructors
//- Construct from a dictionary and a mesh
geometricElementTransformPointSmoother
(
const polyMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~geometricElementTransformPointSmoother() = default;
// Member Functions
//- Calculate the point displacements
virtual void calculate
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
vectorField& pointDisplacement
) const;
static tmp<scalarField> cellQuality
(
const polyMesh& mesh,
const pointField& currentPoints
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace pointSmoothers
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

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) 2024 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 "laplacianConstraintPointSmoother.H"
#include "addToRunTimeSelectionTable.H"
#include "meshPointPatch.H"
#include "processorPointPatch.H"
#include "pointConstraint.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace pointSmoothers
{
defineTypeNameAndDebug(laplacianConstraintPointSmoother, 0);
addToRunTimeSelectionTable
(
pointSmoother,
laplacianConstraintPointSmoother,
dictionary
);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::pointSmoothers::laplacianConstraintPointSmoother::
laplacianConstraintPointSmoother
(
const polyMesh& mesh,
const dictionary& dict
)
:
pointSmoother(mesh, dict)
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
void Foam::pointSmoothers::laplacianConstraintPointSmoother::calculate
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
vectorField& pointDisplacement
) const
{
// Get pointMesh so we can get at the constraints
const auto& pMesh = pointMesh::New(mesh());
// Number of points used in each average
labelField counts(mesh().nPoints(), 0);
// Reset the displacements which are about to be calculated
reset(facesToMove, counts, pointDisplacement);
// Get affected points
const bitSet isMovingPoint(pointsToMove(facesToMove, true));
// Set constraints:
// - internal points : 0
// - normal boundary points : 1
// - meshPointPatch : 1 (surface)
// 2 (feat-edge)
// 3 (feat-point)
labelList nConstraints(mesh().nPoints(), Zero);
for (const auto& pp : pMesh.boundary())
{
const auto& mp = pp.meshPoints();
const auto* mppPtr = isA<meshPointPatch>(pp);
if (mppPtr)
{
const auto& pc = mppPtr->constraints();
forAll(mp, i)
{
nConstraints[mp[i]] = pc[i].first();
}
}
else //if (!isA<processorPointPatch>(pp)) // what about cyclic? AMI?
{
forAll(mp, i)
{
// Indirectly detect any constraint
pointConstraint pc;
pp.applyConstraint(i, pc);
nConstraints[mp[i]] = pc.first();
}
}
}
// Average from equally constrained points
const auto& edges = mesh().edges();
const auto& pointEdges = mesh().pointEdges();
forAll(pointEdges, pointi)
{
if (isMovingPoint[pointi])
{
const auto& pEdges = pointEdges[pointi];
for (const label edgei : pEdges)
{
const label otherPointi = edges[edgei].otherVertex(pointi);
if (nConstraints[otherPointi] >= nConstraints[pointi])
{
pointDisplacement[pointi] +=
currentPoints[otherPointi]
- oldPoints[pointi];
++ counts[pointi];
}
}
}
}
// Average
average(facesToMove, counts, pointDisplacement);
// Make sure to set any unconnected points (or boundary feature points)
// since otherwise they never see the effect of the boundary conditions
forAll(counts, pointi)
{
if (isMovingPoint[pointi] && !counts[pointi])
{
pointDisplacement[pointi] = currentPoints[pointi]-oldPoints[pointi];
}
}
}
// ************************************************************************* //

View File

@ -0,0 +1,105 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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::laplacianConstraintPointSmoother
Description
Laplacian point smoothing. Points are moved towards the average of the
surrounding points. In case of constraints (boundary points) only
use average of equal or higher constrained points.
SourceFiles
laplacianConstraintPointSmoother.C
\*---------------------------------------------------------------------------*/
#ifndef laplacianConstraintPointSmoother_H
#define laplacianConstraintPointSmoother_H
#include "pointSmoother.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace pointSmoothers
{
/*---------------------------------------------------------------------------*\
Class laplacianConstraintPointSmoother Declaration
\*---------------------------------------------------------------------------*/
class laplacianConstraintPointSmoother
:
public pointSmoother
{
public:
//- Runtime type information
TypeName("laplacianConstraint");
// Constructors
//- Construct from a dictionary and a polyMesh
laplacianConstraintPointSmoother
(
const polyMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~laplacianConstraintPointSmoother() = default;
// Member Functions
//- Calculate the point displacement
virtual void calculate
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
vectorField& pointDisplacement
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace pointSmoothers
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,139 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "laplacianPointSmoother.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace pointSmoothers
{
defineTypeNameAndDebug(laplacianPointSmoother, 0);
addToRunTimeSelectionTable
(
pointSmoother,
laplacianPointSmoother,
dictionary
);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::pointSmoothers::laplacianPointSmoother::laplacianPointSmoother
(
const polyMesh& mesh,
const dictionary& dict
)
:
pointSmoother(mesh, dict)
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
void Foam::pointSmoothers::laplacianPointSmoother::calculate
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
vectorField& pointDisplacement
) const
{
// Number of points used in each average
labelField counts(mesh().nPoints(), 0);
// Reset the displacements which are about to be calculated
reset(facesToMove, counts, pointDisplacement);
// Sum the non-internal face displacements
forAll(facesToMove, faceToMoveI)
{
const label faceI(facesToMove[faceToMoveI]);
if (!isInternalOrProcessorFace(faceI))
{
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
pointDisplacement[pointI] +=
faceCentres[faceI]
- oldPoints[pointI];
++ counts[pointI];
}
}
}
// Sum the internal face displacements
forAll(facesToMove, faceToMoveI)
{
const label faceI(facesToMove[faceToMoveI]);
if (isInternalOrProcessorFace(faceI))
{
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
if (counts[pointI] == 0)
{
const labelList& pCells(mesh().pointCells()[pointI]);
forAll(pCells, pCellI)
{
const label cellI(pCells[pCellI]);
pointDisplacement[pointI] +=
cellCentres[cellI]
- oldPoints[pointI];
++ counts[pointI];
}
}
}
}
}
// Average
average(facesToMove, counts, pointDisplacement);
}
// ************************************************************************* //

View File

@ -0,0 +1,105 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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::laplacianPointSmoother
Description
Laplacian point smoothing (or rather Lloyds). Points are moved towards
the average of the surrounding cell centres (or average of boundary
face centres for points on boundary)
SourceFiles
laplacianPointSmoother.C
\*---------------------------------------------------------------------------*/
#ifndef laplacianPointSmoother_H
#define laplacianPointSmoother_H
#include "pointSmoother.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace pointSmoothers
{
/*---------------------------------------------------------------------------*\
Class laplacianPointSmoother Declaration
\*---------------------------------------------------------------------------*/
class laplacianPointSmoother
:
public pointSmoother
{
public:
//- Runtime type information
TypeName("laplacian");
// Constructors
//- Construct from a dictionary and a polyMesh
laplacianPointSmoother
(
const polyMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~laplacianPointSmoother() = default;
// Member Functions
//- Calculate the point displacement
virtual void calculate
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
vectorField& pointDisplacement
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace pointSmoothers
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,300 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "pointSmoother.H"
#include "pointConstraints.H"
#include "polyMeshTools.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(pointSmoother, 0);
defineRunTimeSelectionTable(pointSmoother, dictionary);
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
bool Foam::pointSmoother::isInternalOrProcessorFace(const label faceI) const
{
if (mesh().isInternalFace(faceI))
{
return true;
}
if
(
processorPatchIDs_
[
mesh().boundaryMesh().patchID()
[
faceI - mesh().nInternalFaces()
]
]
)
{
return true;
}
return false;
}
Foam::autoPtr<Foam::PackedBoolList> Foam::pointSmoother::pointsToMove
(
const labelList& facesToMove,
const bool moveInternalFaces
) const
{
autoPtr<PackedBoolList> markerPtr
(
new PackedBoolList(mesh().nPoints(), false)
);
PackedBoolList& marker(markerPtr());
forAll(facesToMove, faceToMoveI)
{
const label faceI(facesToMove[faceToMoveI]);
if (moveInternalFaces || !isInternalOrProcessorFace(faceI))
{
const face& fPoints(mesh().faces()[faceI]);
forAll(fPoints, fPointI)
{
const label pointI(fPoints[fPointI]);
marker[pointI] = true;
}
}
}
syncTools::syncPointList
(
mesh(),
marker,
orEqOp<unsigned int>(),
0U
);
return markerPtr;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::pointSmoother::pointSmoother
(
const polyMesh& mesh,
const dictionary& dict
)
:
mesh_(mesh)
{
for (const auto& pp : mesh.boundaryMesh())
{
if (isA<processorPolyPatch>(pp))
{
processorPatchIDs_.insert(pp.index());
}
}
}
// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::pointSmoother>
Foam::pointSmoother::New
(
const word& pointSmootherType,
const polyMesh& mesh,
const dictionary& dict
)
{
Info<< "Selecting pointSmoother type " << pointSmootherType << endl;
auto cstrIter = dictionaryConstructorTablePtr_->find(pointSmootherType);
if (cstrIter == dictionaryConstructorTablePtr_->end())
{
FatalErrorIn("pointSmoother::New")
<< "Unknown " << typeName << " type "
<< pointSmootherType << endl << endl
<< "Valid " << typeName << " types are : " << endl
<< dictionaryConstructorTablePtr_->sortedToc()
<< exit(FatalError);
}
return cstrIter()(mesh, dict);
}
Foam::autoPtr<Foam::pointSmoother>
Foam::pointSmoother::New
(
const polyMesh& mesh,
const dictionary& dict
)
{
word pointSmootherType(dict.lookup(typeName));
return New(pointSmootherType, mesh, dict);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::pointSmoother::~pointSmoother()
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
void Foam::pointSmoother::update
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
pointVectorField& pointDisplacement,
const bool correctBCs
) const
{
// Apply point smoothing (without boundary conditions!)
calculate
(
facesToMove,
oldPoints,
currentPoints,
faceCentres,
faceAreas,
cellCentres,
cellVolumes,
pointDisplacement.ref()
);
// Note: do not want to apply boundary conditions whilst smoothing so
// disable for now
//// Take over boundary values
//for (auto& ppf : pointDisplacement.boundaryFieldRef())
//{
// ppf.operator==(ppf.patchInternalField());
//}
if (correctBCs)
{
// Apply (multi-)patch constraints
pointConstraints::New
(
pointDisplacement().mesh()
).constrainDisplacement(pointDisplacement);
}
}
Foam::tmp<Foam::scalarField> Foam::pointSmoother::faceQuality
(
const pointField& points,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes
) const
{
// See e.g.
// - src/functionObjects/field/stabilityBlendingFactor/
// stabilityBlendingFactor.H
// - maybe add function to motionSmootherCheck to return value instead
// of yes/no for invalid?
// - for now just look at non-ortho
tmp<scalarField> tortho
(
polyMeshTools::faceOrthogonality
(
mesh(),
faceAreas,
cellCentres
)
);
//return max(tortho, scalar(0.0));
return tortho;
}
Foam::tmp<Foam::scalarField> Foam::pointSmoother::cellQuality
(
const pointField& points,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes
) const
{
// Get face-based non-ortho
tmp<scalarField> tfaceOrtho
(
faceQuality
(
points,
faceCentres,
faceAreas,
cellCentres,
cellVolumes
)
);
const auto& faceOrtho = tfaceOrtho();
// Min over cells
tmp<scalarField> tortho(new scalarField(mesh().nCells(), GREAT));
auto& ortho = tortho.ref();
const auto& own = mesh().faceOwner();
const auto& nei = mesh().faceNeighbour();
forAll(own, facei)
{
auto& o = ortho[own[facei]];
o = min(o, faceOrtho[facei]);
}
for (label facei = 0; facei < mesh().nInternalFaces(); facei++)
{
auto& o = ortho[nei[facei]];
o = min(o, faceOrtho[facei]);
}
return tortho;
}
// ************************************************************************* //

View File

@ -0,0 +1,279 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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::pointSmoother
Description
Abstract base class for point smoothing methods. Handles parallel
communication via reset and average functions.
SourceFiles
pointSmoother.C
pointSmootherTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef pointSmoother_H
#define pointSmoother_H
#include "polyMeshGeometry.H"
#include "runTimeSelectionTables.H"
#include "PackedBoolList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class pointSmoother Declaration
\*---------------------------------------------------------------------------*/
class pointSmoother
{
private:
// Private data
//- Reference to the polyMesh
const polyMesh& mesh_;
//- Set of the processor patch indices
labelHashSet processorPatchIDs_;
// Private Member Functions
//- Disallow default bitwise copy construct
pointSmoother(const pointSmoother&);
//- Disallow default bitwise assignment
void operator=(const pointSmoother&);
protected:
// Protected Member Functions
//- Test if the given face is internal or on a processor boundary
bool isInternalOrProcessorFace(const label faceI) const;
//- Get a boolean list of the points to be moved
autoPtr<PackedBoolList> pointsToMove
(
const labelList& facesToMove,
const bool moveInternalFaces
) const;
//- Reset the relevant weights and displacements to zero
template <class weightType>
void reset
(
const labelList& facesToMove,
Field<weightType>& weights,
vectorField& pointDisplacement,
const bool resetInternalFaces = true
) const;
//- Average the displacements using the weights provided
template <class weightType>
void average
(
const labelList& facesToMove,
Field<weightType>& weights,
vectorField& pointDisplacement
) const;
public:
//- Runtime type information
TypeName("pointSmoother");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
pointSmoother,
dictionary,
(const polyMesh& mesh, const dictionary& dict),
(mesh, dict)
);
// Constructors
//- Construct from a dictionary and a point displacement field
pointSmoother(const polyMesh& mesh, const dictionary&);
// Selector
//- Construct given type
static autoPtr<pointSmoother> New
(
const word& pointSmootherType,
const polyMesh& mesh,
const dictionary& dict
);
//- Construct with type looked up from dictionary
static autoPtr<pointSmoother> New
(
const polyMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~pointSmoother();
// Member Functions
// Access the mesh
const polyMesh& mesh() const
{
return mesh_;
}
//- Update the point displacements and apply constraints
void update
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
pointVectorField& pointDisplacement,
const bool correctBCs = true
) const;
//- Update the point displacements and apply constraints
void update
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const polyMeshGeometry& meshGeometry,
pointVectorField& pointDisplacement,
const bool correctBCs = true
) const
{
update
(
facesToMove,
oldPoints,
currentPoints,
meshGeometry.faceCentres(),
meshGeometry.faceAreas(),
meshGeometry.cellCentres(),
meshGeometry.cellVolumes(),
pointDisplacement,
correctBCs
);
}
//- Calculate the point displacement
virtual void calculate
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes,
vectorField& pointDisplacement
) const = 0;
//- Update the point displacements
virtual void calculate
(
const labelList& facesToMove,
const pointField& oldPoints,
const pointField& currentPoints,
const polyMeshGeometry& meshGeometry,
vectorField& pointDisplacement
) const
{
calculate
(
facesToMove,
oldPoints,
currentPoints,
meshGeometry.faceCentres(),
meshGeometry.faceAreas(),
meshGeometry.cellCentres(),
meshGeometry.cellVolumes(),
pointDisplacement
);
}
//- Check element quality: 1 = best, 0 = invalid. (also negative?)
//- Topology from mesh, point locations supplied.
//- Move to motionSolver level?
virtual tmp<scalarField> faceQuality
(
const pointField& points,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes
) const;
//- Check element quality: 1 = best, 0 = invalid.
//- Topology from mesh, point locations supplied.
//- Move to motionSolver level?
virtual tmp<scalarField> cellQuality
(
const pointField& points,
const pointField& faceCentres,
const vectorField& faceAreas,
const pointField& cellCentres,
const scalarField& cellVolumes
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "pointSmootherTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,105 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "pointSmoother.H"
#include "syncTools.H"
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
template <class weightType>
void Foam::pointSmoother::reset
(
const labelList& facesToMove,
Field<weightType>& weights,
vectorField& pointDisplacement,
const bool resetInternalFaces
) const
{
autoPtr<PackedBoolList> resetPointsPtr
(
pointsToMove(facesToMove, resetInternalFaces)
);
const PackedBoolList& resetPoints(resetPointsPtr);
forAll(resetPoints, pointI)
{
if (resetPoints[pointI])
{
weights[pointI] = pTraits<weightType>::zero;
pointDisplacement[pointI] = vector::zero;
}
}
}
template <class weightType>
void Foam::pointSmoother::average
(
const labelList& facesToMove,
Field<weightType>& weights,
vectorField& pointDisplacement
) const
{
syncTools::syncPointList
(
mesh(),
weights,
plusEqOp<weightType>(),
pTraits<weightType>::zero
);
syncTools::syncPointList
(
mesh(),
pointDisplacement,
plusEqOp<vector>(),
vector::zero
);
autoPtr<PackedBoolList> averagePointsPtr
(
pointsToMove(facesToMove, true)
);
const PackedBoolList& averagePoints(averagePointsPtr);
forAll(averagePoints, pointI)
{
if
(
averagePoints[pointI]
&& weights[pointI] != pTraits<weightType>::zero
)
{
pointDisplacement[pointI] /= weights[pointI];
}
}
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
Copyright (C) 2020,2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -28,8 +28,8 @@ Class
Foam::addPatchCellLayer
Description
Adds layers of cells to outside of polyPatch. Can optionally create
stand-alone extruded mesh (addToMesh=false).
Adds layers of cells to outside (or inside) of polyMesh. Can optionally
create stand-alone extruded mesh (addToMesh=false).
Call setRefinement with offset vector for every patch point and number
of layers per patch face and number of layers per patch point.
@ -51,24 +51,47 @@ Description
\verbatim
Was:
a b <- patch of boundary face
+------+------+
| | | <- original cells
+------+------+
a b <- patch of boundary face
+------+------+
| | | <- original cells
+------+------+
Becomes:
Extrusion:
a b <- patch of boundary face
+------+------+
+ +------+
+------+------+
+------+------+
| | | <- original cells
+------+------+
added added
face cell
---- ----
a b <- patch of boundary face
+------+------+ 3
| | | 2
+ +------+ 2
| | | 1
+------+------+ 1
| | | 0
+------+------+ 0 <- original boundary faces
| | | <- original cells
+------+------+
Intrusion:
face cell
---- ----
a b <- patch of boundary face
+------+------+ 0
| | | 0
+------+------+ 1
| | | 1
+ +------+ 2
| | | 2
+------+------+ 3
| | | <- original cells
+------+------+
\endverbatim
- added faces get same patchID as face they are extruded from
- 'side' faces (i.e. on the edge of pp) get the patchID/zoneID of the
other patch/zone they are connected to (hopefully only 1)
@ -78,10 +101,15 @@ Description
\verbatim
a b b <- patch of boundary face
+------+------+------+
| | | |
| | | | <- cells
| | | |
+------+------+------+
(shown for extrusion mode only):
^ ^ <- wanted extrusion vector (none at far right)
a | b | b <- patch of boundary face
+------+------+------+
@ -123,7 +151,7 @@ class primitiveMesh;
class globalIndex;
/*---------------------------------------------------------------------------*\
Class addPatchCellLayer Declaration
Class addPatchCellLayer Declaration
\*---------------------------------------------------------------------------*/
class addPatchCellLayer
@ -136,15 +164,23 @@ class addPatchCellLayer
//- Add layers to existing mesh or create new mesh
const bool addToMesh_;
//- Add layers to outside of mesh or to inside
const bool extrude_;
//- For all patchpoints: list of added points (size 0 or nLayers)
// First point in list is one nearest to original point in patch,
// last one is the new point on the surface.
// last one is
// - extrude : the new point on the surface
// - intrude : the point connecting to the original cell.
labelListList addedPoints_;
//- For all patchfaces: list of layer faces.
// - empty if no face extruded
// - first face is original boundary face
// - last one is new boundary face.
// - first element is original patch face
// - last element is
// - extrude : the new boundary face
// - intrude : the new internal face to the original cell.
labelListList layerFaces_;
@ -226,25 +262,6 @@ class addPatchCellLayer
label& inflateFaceI
);
//- Find internal or boundary face to get extrude properties
// from. zoneFlip consistent with ppEdge ordering
static void findZoneFace
(
const bool useInternalFaces,
const bool useBoundaryFaces,
const polyMesh& mesh,
const indirectPrimitivePatch& pp,
const label ppEdgeI,
const labelUIndList& excludeFaces,
const labelList& meshFaces,
label& inflateFaceI,
label& patchI,
label& zoneI,
bool& zoneFlip
);
//- Mark internal and boundary edges of patch. In mesh edges
//- since processor might not have pp but does have edge.
static void markPatchEdges
@ -294,7 +311,12 @@ public:
// Constructors
//- Construct from mesh.
explicit addPatchCellLayer(const polyMesh&, const bool addToMesh=true);
explicit addPatchCellLayer
(
const polyMesh&,
const bool addToMesh=true,
const bool extrude=true
);
// Member Functions
@ -314,8 +336,13 @@ public:
}
//- Helper: get added cells per patch face.
// addedCells[patchFace] is list of cells added. Last element is
// the top cells (i.e. the boundary cell)
// addedCells[patchFace] is list of cells added.
// extrude :
// first element : next to original cell
// last element : is the top cell (i.e. the boundary cell)
// intrude :
// first element : top cell
// last element : next to original cell
static labelListList addedCells
(
const polyMesh&,
@ -328,6 +355,18 @@ public:
// Edit
//- Per patch edge the pp faces (in global indices) using it.
// Uses ListOps::uniqueEqOp to remove duplicates. On coupled
// faces only selects the one with the correct orientation/flip
// (assumes the orientation is opposite on a coupled face pair)
static labelListList globalEdgeFaces
(
const polyMesh&,
const globalIndex& globalFaces,
const indirectPrimitivePatch& pp,
const bitSet& orientation
);
//- Per patch edge the pp faces (in global indices) using it.
// Uses ListOps::uniqueEqOp to remove duplicates.
static labelListList globalEdgeFaces
@ -454,6 +493,28 @@ public:
const labelList& faceMap, // new to old patch faces
const labelList& pointMap // new to old patch points
);
//- Helper: given patch and points on patch that are extruded
// (to slave side or master side) find the affected
// points. Calculates by walking across faces which vertices on
// which face are affected. isDupMeshPoint:
// -1 : unaffected
// >=0 : should use local duplicate of point
// (though it does not tell us whether it should use
// slave side or master side)
static void findDuplicatedPoints
(
const polyMesh& mesh,
const indirectPrimitivePatch& pp,
const bitSet& ppFlip, // optional orientation on top of pp
const bitSet& isBlockedFace,// any mesh faces not to be
// traversed.Usually pp.addressing()
const bitSet& isDupPatchPoint,
const bool extrude, // which side to extrude
faceList& isDupMeshPoint
);
};

View File

@ -37,7 +37,7 @@ Usage
\table
Property | Description | Required | Default value
scale | Time varying scale | yes |
patch | patchField providing the raw patch value | yes |
refValue | patchField providing the raw patch value | yes |
\endtable
Example of the boundary condition specification to scale a reference

View File

@ -164,6 +164,23 @@ public:
//- Do what is necessary if the mesh has moved
virtual void movePoints();
//- Calculate geometry quantities using mesh topology and provided
//- points. If oldPoints provided only does local update. Returns
//- true if anything changed, false otherwise
virtual bool updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints, // optional old points
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const
{
NotImplemented;
return true;
}
};

View File

@ -29,6 +29,7 @@ License
#include "addToRunTimeSelectionTable.H"
#include "surfaceFields.H"
#include "volFields.H"
#include "primitiveMeshTools.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -390,4 +391,36 @@ Foam::basicFvGeometryScheme::nonOrthCorrectionVectors() const
}
bool Foam::basicFvGeometryScheme::updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints,
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const
{
primitiveMeshTools::makeFaceCentresAndAreas
(
mesh_,
points,
faceCentres,
faceAreas
);
primitiveMeshTools::makeCellCentresAndVols
(
mesh_,
faceCentres,
faceAreas,
cellCentres,
cellVolumes
);
// Assume something has changed
return true;
}
// ************************************************************************* //

View File

@ -93,6 +93,19 @@ public:
//- Return non-orthogonality correction vectors
virtual tmp<surfaceVectorField> nonOrthCorrectionVectors() const;
//- Calculate geometry quantities using mesh topology and provided
//- points. If oldPoints provided only does local update. Returns
//- true if anything changed, false otherwise
virtual bool updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints, // optional old points
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const;
};

View File

@ -160,6 +160,19 @@ public:
// const labelHashSet& patchIDs,
// const word& defaultPatchDistMethod
//) const = 0;
//- Calculate geometry quantities using mesh topology and provided
//- points. If oldPoints provided only does local update. Returns
//- true if anything changed, false otherwise
virtual bool updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints, // optional old points
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const = 0;
};

View File

@ -456,4 +456,46 @@ void Foam::highAspectRatioFvGeometryScheme::movePoints()
}
bool Foam::highAspectRatioFvGeometryScheme::updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints,
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const
{
// Basic
basicFvGeometryScheme::updateGeom
(
points,
oldPoints,
faceCentres,
faceAreas,
cellCentres,
cellVolumes
);
// Average opposite faces
pointField avgFaceCentres;
pointField avgCellCentres;
makeAverageCentres
(
mesh_,
points,
faceAreas,
mag(faceAreas),
avgFaceCentres,
avgCellCentres
);
faceCentres = std::move(avgFaceCentres);
cellCentres = std::move(avgCellCentres);
// Assume something has changed.
return true;
}
// ************************************************************************* //

View File

@ -123,6 +123,19 @@ public:
//- Do what is necessary if the mesh has moved
virtual void movePoints();
//- Calculate geometry quantities using mesh topology and provided
//- points. If oldPoints provided only does local update. Returns
//- true if anything changed, false otherwise
virtual bool updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints, // optional old points
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const;
};

View File

@ -47,6 +47,92 @@ namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::parallelFvGeometryScheme::adjustGeometry
(
pointField& faceCentres,
vectorField& faceAreas
) const
{
pointField syncedBCentres;
syncedBCentres = SubField<vector>
(
faceCentres,
mesh_.nBoundaryFaces(),
mesh_.nInternalFaces()
);
syncTools::swapBoundaryFaceList
(
mesh_,
syncedBCentres
);
vectorField syncedBAreas;
syncedBAreas = SubField<vector>
(
faceAreas,
mesh_.nBoundaryFaces(),
mesh_.nInternalFaces()
);
syncTools::syncBoundaryFaceList
(
mesh_,
syncedBAreas,
eqOp<vector>(),
transformOriented()
);
const auto& pbm = mesh_.boundaryMesh();
for (const auto& pp : pbm)
{
const auto* ppp = isA<coupledPolyPatch>(pp);
//if (ppp)
//{
// Pout<< "For patch:" << ppp->name()
// << " size:" << ppp->size()
// << endl;
// forAll(*ppp, i)
// {
// const label facei = ppp->start()+i;
// Pout<< " Face:" << facei << nl
// << " meshFc:" << faceCentres[facei] << nl
// << " meshFa:" << faceAreas[facei] << nl
// << endl;
// }
//}
if (ppp && !ppp->owner())
{
SubField<point> patchFc
(
faceCentres,
ppp->size(),
ppp->start()
);
patchFc = SubField<vector>
(
syncedBCentres,
ppp->size(),
ppp->offset()
);
SubField<vector> patchArea
(
faceAreas,
ppp->size(),
ppp->start()
);
patchArea = SubField<vector>
(
syncedBAreas,
ppp->size(),
ppp->offset()
);
}
}
}
void Foam::parallelFvGeometryScheme::adjustGeometry()
{
// Swap face centres and areas
@ -304,5 +390,38 @@ Foam::parallelFvGeometryScheme::nonOrthCorrectionVectors() const
}
bool Foam::parallelFvGeometryScheme::updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints,
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const
{
primitiveMeshTools::makeFaceCentresAndAreas
(
mesh_,
points,
faceCentres,
cellCentres
);
// Parallel consistency
adjustGeometry(faceCentres, faceAreas);
primitiveMeshTools::makeCellCentresAndVols
(
mesh_,
faceCentres,
faceAreas,
cellCentres,
cellVolumes
);
return true;
}
// ************************************************************************* //

View File

@ -102,6 +102,13 @@ private:
// Private Member Functions
//- Swap processor-face geometry
void adjustGeometry
(
pointField& faceCentres,
vectorField& faceAreas
) const;
//- Swap processor-face geometry
void adjustGeometry();
@ -181,6 +188,19 @@ public:
//- Return non-orthogonality correction vectors
virtual tmp<surfaceVectorField> nonOrthCorrectionVectors() const;
//- Calculate geometry quantities using mesh topology and provided
//- points. If oldPoints provided only does local update. Returns
//- true if anything changed, false otherwise
virtual bool updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints, // optional old points
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const;
};

View File

@ -45,6 +45,68 @@ namespace Foam
}
bool Foam::solidBodyFvGeometryScheme::markChanges
(
const pointField& oldPoints,
const pointField& currPoints,
bitSet& isChangedPoint,
bitSet& isChangedFace,
bitSet& isChangedCell
) const
{
isChangedPoint.setSize(oldPoints.size());
// Check for non-identical points
forAll(isChangedPoint, pointi)
{
isChangedPoint.set(pointi, oldPoints[pointi] != currPoints[pointi]);
}
DebugInfo
<< "SBM --- Changed points:"
<< returnReduce(isChangedPoint.count(), sumOp<label>())
<< endl;
// Quick return if no points have moved
if (returnReduceAnd(isChangedPoint.none()))
{
return false;
}
isChangedFace.setSize(mesh_.nFaces());
isChangedFace = false;
isChangedCell.setSize(mesh_.nCells());
isChangedCell = false;
const auto& pointFaces = mesh_.pointFaces();
const auto& own = mesh_.faceOwner();
const auto& nbr = mesh_.faceNeighbour();
// Identify faces and cells attached to moving points
for (const label pointi : isChangedPoint)
{
for (const auto facei : pointFaces[pointi])
{
isChangedFace.set(facei);
isChangedCell.set(own[facei]);
if (facei < mesh_.nInternalFaces())
{
isChangedCell.set(nbr[facei]);
}
}
}
DebugInfo
<< "SBM --- Changed cells:"
<< returnReduce(isChangedCell.count(), sumOp<label>())
<< endl;
return true;
}
void Foam::solidBodyFvGeometryScheme::setMeshMotionData()
{
if (!cacheInitialised_ || !cacheMotion_)
@ -67,64 +129,86 @@ void Foam::solidBodyFvGeometryScheme::setMeshMotionData()
<< abort(FatalError);
}
bitSet changedPoints(oldPoints.size());
//bitSet changedPoints(oldPoints.size());
//
//// Check for non-identical points
//forAll(changedPoints, pointi)
//{
// changedPoints.set
// (
// pointi,
// oldPoints[pointi] != currPoints[pointi]
// );
//}
//
//DebugInfo
// << "SBM --- Changed points:"
// << returnReduce(changedPoints.count(), sumOp<label>())
// << endl;
//
//// Quick return if no points have moved
//if (returnReduceAnd(changedPoints.none()))
//{
// return;
//}
//
//bitSet cellIDs(mesh_.nCells());
//bitSet faceIDs(mesh_.nFaces());
//
//const auto& pointFaces = mesh_.pointFaces();
//const auto& own = mesh_.faceOwner();
//const auto& nbr = mesh_.faceNeighbour();
//
//// Identify faces and cells attached to moving points
//for (const label pointi : changedPoints)
//{
// for (const auto facei : pointFaces[pointi])
// {
// faceIDs.set(facei);
//
// cellIDs.set(own[facei]);
// if (facei < mesh_.nInternalFaces())
// {
// cellIDs.set(nbr[facei]);
// }
// }
//}
//
//changedCellIDs_ = cellIDs.toc();
//
//DebugInfo
// << "SBM --- Changed cells:"
// << returnReduce(changedCellIDs_.size(), sumOp<label>())
// << endl;
// Check for non-identical points
forAll(changedPoints, pointi)
{
changedPoints.set(pointi, oldPoints[pointi] != currPoints[pointi]);
}
DebugInfo
<< "SBM --- Changed points:"
<< returnReduce(changedPoints.count(), sumOp<label>())
<< endl;
bitSet isChangedPoint;
bitSet isChangedFace;
bitSet isChangedCell;
const bool changed = markChanges
(
oldPoints,
currPoints,
isChangedPoint,
isChangedFace,
isChangedCell
);
// Quick return if no points have moved
if (returnReduceAnd(changedPoints.none()))
if (!changed)
{
return;
}
bitSet cellIDs(mesh_.nCells());
bitSet faceIDs(mesh_.nFaces());
const auto& pointFaces = mesh_.pointFaces();
const auto& own = mesh_.faceOwner();
const auto& nbr = mesh_.faceNeighbour();
// Identify faces and cells attached to moving points
for (const label pointi : changedPoints)
{
for (const auto facei : pointFaces[pointi])
{
faceIDs.set(facei);
cellIDs.set(own[facei]);
if (facei < mesh_.nInternalFaces())
{
cellIDs.set(nbr[facei]);
}
}
}
changedCellIDs_ = cellIDs.toc();
DebugInfo
<< "SBM --- Changed cells:"
<< returnReduce(changedCellIDs_.size(), sumOp<label>())
<< endl;
changedCellIDs_ = isChangedCell.toc();
// Construct face and patch ID info
const auto changedFaceFlag = faceIDs.values();
DynamicList<label> changedFaceIDs(faceIDs.count());
DynamicList<label> changedPatchIDs(faceIDs.count());
DynamicList<label> changedFaceIDs(isChangedFace.count());
DynamicList<label> changedPatchIDs(changedFaceIDs.capacity());
for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
{
if (changedFaceFlag[facei])
if (isChangedFace[facei])
{
changedFaceIDs.append(facei);
changedPatchIDs.append(-1);
@ -138,7 +222,7 @@ void Foam::solidBodyFvGeometryScheme::setMeshMotionData()
for (const label meshFacei : pp.range())
{
if (changedFaceFlag[meshFacei])
if (isChangedFace[meshFacei])
{
changedFaceIDs.append(meshFacei);
changedPatchIDs.append(patchi);
@ -343,4 +427,82 @@ void Foam::solidBodyFvGeometryScheme::updateMesh(const mapPolyMesh& mpm)
}
bool Foam::solidBodyFvGeometryScheme::updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints,
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const
{
if
(
(faceCentres.size() != mesh_.nFaces())
|| (faceAreas.size() != mesh_.nFaces())
|| (cellCentres.size() != mesh_.nCells())
|| (cellVolumes.size() != mesh_.nCells())
|| !oldPoints
)
{
// Do all
return basicFvGeometryScheme::updateGeom
(
points,
oldPoints,
faceCentres,
faceAreas,
cellCentres,
cellVolumes
);
}
else
{
// Since oldPoints provided assume that face & cell geometry is
// up to date with it
bitSet isChangedPoint;
bitSet isChangedFace;
bitSet isChangedCell;
const bool changed = markChanges
(
oldPoints(),
points,
isChangedPoint,
isChangedFace,
isChangedCell
);
if (!changed)
{
return false;
}
// Make face centres and areas consistent with new points
primitiveMeshTools::updateFaceCentresAndAreas
(
mesh_,
isChangedFace.toc(),
points,
faceCentres,
faceAreas
);
primitiveMeshTools::updateCellCentresAndVols
(
mesh_,
faceCentres,
faceAreas,
isChangedCell.toc(),
mesh_.cells(),
cellCentres,
cellVolumes
);
return true;
}
}
// ************************************************************************* //

View File

@ -94,6 +94,16 @@ class solidBodyFvGeometryScheme
// Private Member Functions
//- Detect what geometry has changed. Return true if anything has.
bool markChanges
(
const pointField& oldPoints,
const pointField& currPoints,
bitSet& isChangedPoint,
bitSet& isChangedFace,
bitSet& isChangedCell
) const;
//- Set the mesh motion data (point, face IDs)
void setMeshMotionData();
@ -127,6 +137,19 @@ public:
//- Update mesh for topology changes
virtual void updateMesh(const mapPolyMesh& mpm);
//- Calculate geometry quantities using mesh topology and provided
//- points. If oldPoints provided only does local update. Returns
//- true if anything changed, false otherwise
virtual bool updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints, // optional old points
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const;
};

View File

@ -208,4 +208,35 @@ void Foam::stabilisedFvGeometryScheme::movePoints()
}
bool Foam::stabilisedFvGeometryScheme::updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints,
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const
{
makeFaceCentresAndAreas
(
mesh_,
points,
faceCentres,
faceAreas
);
primitiveMeshTools::makeCellCentresAndVols
(
mesh_,
faceCentres,
faceAreas,
cellCentres,
cellVolumes
);
return true;
}
// ************************************************************************* //

View File

@ -112,6 +112,19 @@ public:
//- Do what is necessary if the mesh has moved
virtual void movePoints();
//- Calculate geometry quantities using mesh topology and provided
//- points. If oldPoints provided only does local update. Returns
//- true if anything changed, false otherwise
virtual bool updateGeom
(
const pointField& points,
const refPtr<pointField>& oldPoints, // optional old points
pointField& faceCentres,
vectorField& faceAreas,
pointField& cellCentres,
scalarField& cellVolumes
) const;
};

View File

@ -32,10 +32,16 @@ License
#include "cyclicPolyPatch.H"
#include "emptyPolyPatch.H"
#include "processorPolyPatch.H"
#include "meshPointPatch.H"
#include "processorPointPatch.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
Foam::word Foam::fvMeshSubset::exposedPatchName("oldInternalFaces");
namespace Foam
{
word fvMeshSubset::exposedPatchName("oldInternalFaces");
defineTypeNameAndDebug(fvMeshSubset, 0);
}
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
@ -522,6 +528,16 @@ void Foam::fvMeshSubset::reset
void Foam::fvMeshSubset::reset(const Foam::zero)
{
// Was old pointMesh present?
const auto* basePointMeshPtr =
baseMesh_.thisDb().cfindObject<pointMesh>(pointMesh::typeName);
if (basePointMeshPtr)
{
DebugPout<< "fvMeshSubset::reset(const Foam::zero) :"
<< " Detected pointMesh" << endl;
}
clear();
// Create zero-sized subMesh
@ -574,6 +590,46 @@ void Foam::fvMeshSubset::reset(const Foam::zero)
}
// Clone old additional point patches
if (basePointMeshPtr)
{
DebugPout<< "Subsetting pointMesh" << endl;
const auto& basePointMesh = *basePointMeshPtr;
const auto& oldPointBoundary = basePointMesh.boundary();
// 1. Generate pointBoundaryMesh from polyBoundaryMesh (so ignoring
// any additional patches
const auto& newSubPointMesh = pointMesh::New(newSubMesh);
auto& newBoundary =
const_cast<pointBoundaryMesh&>(newSubPointMesh.boundary());
// Start off from (poly)patch map
pointPatchMap_ = patchMap_;
// 2. Explicitly add subsetted meshPointPatches
for (const auto& oldPointPatch : oldPointBoundary)
{
const auto* mppPtr = isA<meshPointPatch>(oldPointPatch);
if (mppPtr && (newBoundary.findPatchID(mppPtr->name()) == -1))
{
newBoundary.push_back
(
mppPtr->clone
(
newBoundary,
newBoundary.size(),
labelList::null(), // map
labelList::null() // map
)
);
}
}
// Extend patchMap with -1
pointPatchMap_.setSize(newBoundary.size(), -1);
}
// Add the zones
subsetZones();
}
@ -586,6 +642,16 @@ void Foam::fvMeshSubset::reset
const bool syncPar
)
{
// Was old pointMesh present?
const auto* basePointMeshPtr =
baseMesh_.thisDb().cfindObject<pointMesh>(pointMesh::typeName);
if (basePointMeshPtr)
{
DebugPout<< "fvMeshSubset::reset(const bitSet&) :"
<< " Detected pointMesh" << endl;
}
// Clear all old maps and pointers
clear();
@ -1126,6 +1192,8 @@ void Foam::fvMeshSubset::reset
// Inserted patch
label newInternalPatchID = -1;
if (wantedPatchID == -1)
{
label oldInternalSize = boundaryPatchSizes[oldInternalPatchID];
@ -1159,6 +1227,7 @@ void Foam::fvMeshSubset::reset
// the internal faces
patchStart += boundaryPatchSizes[oldInternalPatchID];
patchMap_[nNewPatches] = -1;
newInternalPatchID = nNewPatches;
++nNewPatches;
}
}
@ -1233,6 +1302,98 @@ void Foam::fvMeshSubset::reset
// Subset and add any zones
subsetZones();
if (basePointMeshPtr)
{
DebugPout<< "Subsetting pointMesh" << endl;
const auto& basePointMesh = *basePointMeshPtr;
const auto& oldPointBoundary = basePointMesh.boundary();
// 1. Generate pointBoundaryMesh from polyBoundaryMesh (so ignoring
// any additional patches
const auto& newSubPointMesh = pointMesh::New(subMeshPtr_());
pointPatchMap_ = patchMap_;
auto& newBoundary =
const_cast<pointBoundaryMesh&>(newSubPointMesh.boundary());
// 2. Explicitly add subsetted meshPointPatches
labelList oldToNewPoints(baseMesh_.nPoints(), -1);
forAll(pointMap_, i)
{
oldToNewPoints[pointMap_[i]] = i;
}
// Add meshPointPatches
pointPatchMap_.setSize(newBoundary.size(), -1);
for (const auto& oldPointPatch : oldPointBoundary)
{
const auto* mppPtr = isA<meshPointPatch>(oldPointPatch);
if (mppPtr && (newBoundary.findPatchID(mppPtr->name()) == -1))
{
const auto& mp = mppPtr->meshPoints();
DynamicList<label> subPointMap(mp.size());
forAll(mp, i)
{
const label newPointi = oldToNewPoints[mp[i]];
if (newPointi != -1)
{
subPointMap.append(i);
}
}
pointPatchMap_.push_back(mppPtr->index());
newBoundary.push_back
(
mppPtr->clone
(
newBoundary,
newBoundary.size(),
subPointMap, // map
oldToNewPoints
)
);
}
}
// 3. rotate into place:
// - global patches (including meshPointPatches)
// - optional 'internalFaces' patch
// - processor patches
labelList oldToNew(newBoundary.size());
label newPatchi = 0;
forAll(newBoundary, patchi)
{
if
(
patchi != newInternalPatchID
&& !isA<processorPointPatch>(newBoundary[patchi])
)
{
oldToNew[patchi] = newPatchi++;
}
}
if (newInternalPatchID != -1)
{
oldToNew[newInternalPatchID] = newPatchi++;
}
forAll(newBoundary, patchi)
{
if (isA<processorPointPatch>(newBoundary[patchi]))
{
oldToNew[patchi] = newPatchi++;
}
}
newBoundary.reorder(oldToNew, true);
inplaceReorder(oldToNew, pointPatchMap_);
}
}

View File

@ -102,6 +102,9 @@ class fvMeshSubset
//- Patch mapping array
labelList patchMap_;
//- PointPatch mapping array
labelList pointPatchMap_;
// Private Member Functions
@ -135,6 +138,10 @@ protected:
public:
// Declare name of the class and its debug switch
ClassName("fvMeshSubset");
// Static Data Members
//- Name for exposed internal faces (default: oldInternalFaces)
@ -225,6 +232,10 @@ public:
//- Return patch map
inline const labelList& patchMap() const;
//- Return point-patch map. Usually identical to patchMap except if
//- additional patches are added to the pointMesh.
inline const labelList& pointPatchMap() const;
// Edit

Some files were not shown because too many files have changed in this diff Show More