reconstructParMesh, fvMeshDistribute: Removed all geometric point merging
Geometric point merging has an inherent chance of failure that occurs
when a mesh contains valid distinct points that are closer together than
the supplied tolerance. It is beneficial to avoid such merging whenever
possible.
reconstructParMesh does not need explicit point merging any more. Points
may be duplicated temporarily when processor meshes are combined which
share points and edges but not faces. Ultimately, however,
reconstructParMesh reconstructs the entire mesh so everything eventually
gets face-connected and all point duplications get resolved.
fvMeshDistribute requires point-merging, as the entire mesh is not
constructed. However, since 5d4c8f5d, this process has been purely
topological and has not relied on any of the geometric merging processes
triggered by utilised code.
As such, all geometric point merging operations and tolerances have been
removed from these two implementations, as well as in lower level code
in faceCoupleInfo and polyMeshAdder. faceCoupleInfo has also had support
for face and edge splits removed as this was not being used. This change
will have improved the robustness of both reconstruction and
redistributuon and has greatly reduced the total amount of code
involved.
The only geometric tolerance-based matching still being performed by
either of these processes is as a result of coupled patch ordering in
fvMeshDistribute. It is possible that this is not necessary either
(though at present coupled patch ordering is certainly needed
elsewhere). This warrants further investigation.
This commit is contained in:
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -405,7 +405,7 @@ void Foam::backgroundMeshDecomposition::initialRefinement()
|
||||
icellWeights
|
||||
);
|
||||
|
||||
fvMeshDistribute distributor(mesh_, mergeDist_);
|
||||
fvMeshDistribute distributor(mesh_);
|
||||
|
||||
autoPtr<mapDistributePolyMesh> mapDist = distributor.distribute
|
||||
(
|
||||
@ -813,7 +813,6 @@ Foam::backgroundMeshDecomposition::backgroundMeshDecomposition
|
||||
)
|
||||
),
|
||||
decomposerPtr_(decompositionMethod::New(decomposeDict_)),
|
||||
mergeDist_(1e-6*mesh_.bounds().mag()),
|
||||
spanScale_(coeffsDict.lookup<scalar>("spanScale")),
|
||||
minCellSizeLimit_
|
||||
(
|
||||
@ -998,7 +997,7 @@ Foam::backgroundMeshDecomposition::distribute
|
||||
|
||||
Info<< " Redistributing background mesh cells" << endl;
|
||||
|
||||
fvMeshDistribute distributor(mesh_, mergeDist_);
|
||||
fvMeshDistribute distributor(mesh_);
|
||||
|
||||
autoPtr<mapDistributePolyMesh> mapDist = distributor.distribute(newDecomp);
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -1247,7 +1247,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// Mesh distribution engine (uses tolerance to reconstruct meshes)
|
||||
fvMeshDistribute distributor(mesh, mergeDist);
|
||||
fvMeshDistribute distributor(mesh);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -25,17 +25,11 @@ Application
|
||||
reconstructParMesh
|
||||
|
||||
Description
|
||||
Reconstructs a mesh using geometric information only.
|
||||
Reconstructs a mesh.
|
||||
|
||||
Writes point/face/cell procAddressing so afterwards reconstructPar can be
|
||||
used to reconstruct fields.
|
||||
|
||||
Note:
|
||||
- uses geometric matching tolerance (set with -mergeTol (at your option)
|
||||
|
||||
If the parallel case does not have correct procBoundaries use the
|
||||
-fullMatch option which will check all boundary faces (bit slower).
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
@ -56,160 +50,95 @@ using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Tolerance (as fraction of the bounding box). Needs to be fairly lax since
|
||||
// usually meshes get written with limited precision (6 digits)
|
||||
static const scalar defaultMergeTol = 1e-7;
|
||||
|
||||
|
||||
static void renumber
|
||||
(
|
||||
const labelList& map,
|
||||
labelList& elems
|
||||
)
|
||||
{
|
||||
forAll(elems, i)
|
||||
{
|
||||
if (elems[i] >= 0)
|
||||
{
|
||||
elems[i] = map[elems[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Determine which faces are coupled. Uses geometric merge distance.
|
||||
// Looks either at all boundaryFaces (fullMatch) or only at the
|
||||
// procBoundaries for proci. Assumes that masterMesh contains already merged
|
||||
// all the processors < proci.
|
||||
autoPtr<faceCoupleInfo> determineCoupledFaces
|
||||
(
|
||||
const bool fullMatch,
|
||||
const label masterMeshProcStart,
|
||||
const label masterMeshProcEnd,
|
||||
const polyMesh& masterMesh,
|
||||
const label meshToAddProcStart,
|
||||
const label meshToAddProcEnd,
|
||||
const polyMesh& meshToAdd,
|
||||
const scalar mergeDist
|
||||
const polyMesh& meshToAdd
|
||||
)
|
||||
{
|
||||
if (fullMatch || masterMesh.nCells() == 0)
|
||||
{
|
||||
return autoPtr<faceCoupleInfo>
|
||||
(
|
||||
new faceCoupleInfo
|
||||
(
|
||||
masterMesh,
|
||||
meshToAdd,
|
||||
mergeDist, // Absolute merging distance
|
||||
true // Matching faces identical
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pick up all patches on masterMesh ending in "toDDD" where DDD is
|
||||
// the processor number proci.
|
||||
|
||||
const polyBoundaryMesh& masterPatches = masterMesh.boundaryMesh();
|
||||
|
||||
const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh();
|
||||
|
||||
DynamicList<label> masterFaces
|
||||
(
|
||||
masterMesh.nFaces()
|
||||
- masterMesh.nInternalFaces()
|
||||
masterMesh.nFaces() - masterMesh.nInternalFaces()
|
||||
);
|
||||
|
||||
|
||||
forAll(masterPatches, patchi)
|
||||
{
|
||||
const polyPatch& pp = masterPatches[patchi];
|
||||
|
||||
if (isA<processorPolyPatch>(pp))
|
||||
{
|
||||
for
|
||||
(
|
||||
label proci=meshToAddProcStart;
|
||||
proci<meshToAddProcEnd;
|
||||
proci++
|
||||
)
|
||||
{
|
||||
const string toProcString("to" + name(proci));
|
||||
if (
|
||||
pp.name().rfind(toProcString)
|
||||
== (pp.name().size()-toProcString.size())
|
||||
)
|
||||
{
|
||||
label meshFacei = pp.start();
|
||||
forAll(pp, i)
|
||||
{
|
||||
masterFaces.append(meshFacei++);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
masterFaces.shrink();
|
||||
|
||||
|
||||
// Pick up all patches on meshToAdd ending in "procBoundaryDDDtoYYY"
|
||||
// where DDD is the processor number proci and YYY is < proci.
|
||||
|
||||
const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh();
|
||||
|
||||
DynamicList<label> addFaces
|
||||
(
|
||||
meshToAdd.nFaces()
|
||||
- meshToAdd.nInternalFaces()
|
||||
meshToAdd.nFaces() - meshToAdd.nInternalFaces()
|
||||
);
|
||||
|
||||
forAll(addPatches, patchi)
|
||||
{
|
||||
const polyPatch& pp = addPatches[patchi];
|
||||
|
||||
if (isA<processorPolyPatch>(pp))
|
||||
{
|
||||
bool isConnected = false;
|
||||
|
||||
for
|
||||
(
|
||||
label mergedProci=masterMeshProcStart;
|
||||
!isConnected && (mergedProci < masterMeshProcEnd);
|
||||
mergedProci++
|
||||
label masterProci = masterMeshProcStart;
|
||||
masterProci < masterMeshProcEnd;
|
||||
masterProci++
|
||||
)
|
||||
{
|
||||
for
|
||||
(
|
||||
label proci = meshToAddProcStart;
|
||||
proci < meshToAddProcEnd;
|
||||
proci++
|
||||
label addProci = meshToAddProcStart;
|
||||
addProci < meshToAddProcEnd;
|
||||
addProci++
|
||||
)
|
||||
{
|
||||
const word fromProcString
|
||||
const word masterToAddName
|
||||
(
|
||||
processorPolyPatch::newName(proci, mergedProci)
|
||||
"procBoundary" + name(masterProci) + "to" + name(addProci)
|
||||
);
|
||||
const word addToMasterName
|
||||
(
|
||||
"procBoundary" + name(addProci) + "to" + name(masterProci)
|
||||
);
|
||||
|
||||
if (pp.name() == fromProcString)
|
||||
const label masterToAddID =
|
||||
masterPatches.findPatchID(masterToAddName);
|
||||
const label addToMasterID =
|
||||
addPatches.findPatchID(addToMasterName);
|
||||
|
||||
if (masterToAddID != -1 && addToMasterID != -1)
|
||||
{
|
||||
isConnected = true;
|
||||
break;
|
||||
const polyPatch& masterPp = masterPatches[masterToAddID];
|
||||
|
||||
forAll(masterPp, i)
|
||||
{
|
||||
masterFaces.append(masterPp.start() + i);
|
||||
}
|
||||
|
||||
const polyPatch& addPp = addPatches[addToMasterID];
|
||||
|
||||
forAll(addPp, i)
|
||||
{
|
||||
addFaces.append(addPp.start() + i);
|
||||
}
|
||||
}
|
||||
|
||||
if ((masterToAddID != -1) != (addToMasterID != -1))
|
||||
{
|
||||
const label foundProci =
|
||||
masterToAddID != -1 ? masterProci : addProci;
|
||||
const word& foundName =
|
||||
masterToAddID != -1 ? masterToAddName : addToMasterName;
|
||||
|
||||
const label missingProci =
|
||||
masterToAddID != -1 ? addProci : masterProci;
|
||||
const word& missingName =
|
||||
masterToAddID != -1 ? addToMasterName : masterToAddName;
|
||||
|
||||
FatalErrorInFunction
|
||||
<< "Patch " << foundName << " found on processor "
|
||||
<< foundProci << " but corresponding patch "
|
||||
<< missingName << " missing on processor "
|
||||
<< missingProci << exit(FatalError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isConnected)
|
||||
{
|
||||
label meshFacei = pp.start();
|
||||
forAll(pp, i)
|
||||
{
|
||||
addFaces.append(meshFacei++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
masterFaces.shrink();
|
||||
addFaces.shrink();
|
||||
|
||||
return autoPtr<faceCoupleInfo>
|
||||
@ -219,157 +148,13 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
|
||||
masterMesh,
|
||||
masterFaces,
|
||||
meshToAdd,
|
||||
addFaces,
|
||||
mergeDist, // Absolute merging distance
|
||||
true, // Matching faces identical?
|
||||
false, // If perfect match are faces already ordered
|
||||
// (e.g. processor patches)
|
||||
false // are faces each on separate patch?
|
||||
addFaces
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
autoPtr<mapPolyMesh> mergeSharedPoints
|
||||
(
|
||||
const scalar mergeDist,
|
||||
polyMesh& mesh,
|
||||
labelListList& pointProcAddressing
|
||||
)
|
||||
{
|
||||
// Find out which sets of points get merged and create a map from
|
||||
// mesh point to unique point.
|
||||
Map<label> pointToMaster
|
||||
(
|
||||
fvMeshAdder::findSharedPoints
|
||||
(
|
||||
mesh,
|
||||
mergeDist
|
||||
)
|
||||
);
|
||||
|
||||
Info<< "mergeSharedPoints : detected " << pointToMaster.size()
|
||||
<< " points that are to be merged." << endl;
|
||||
|
||||
if (returnReduce(pointToMaster.size(), sumOp<label>()) == 0)
|
||||
{
|
||||
return autoPtr<mapPolyMesh>(nullptr);
|
||||
}
|
||||
|
||||
polyTopoChange meshMod(mesh);
|
||||
|
||||
fvMeshAdder::mergePoints(mesh, pointToMaster, meshMod);
|
||||
|
||||
// Change the mesh (no inflation). Note: parallel comms allowed.
|
||||
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
|
||||
|
||||
// Update fields. No inflation, parallel sync.
|
||||
mesh.updateMesh(map);
|
||||
|
||||
// pointProcAddressing give indices into the master mesh so adapt them
|
||||
// for changed point numbering.
|
||||
|
||||
// Adapt constructMaps for merged points.
|
||||
forAll(pointProcAddressing, proci)
|
||||
{
|
||||
labelList& constructMap = pointProcAddressing[proci];
|
||||
|
||||
forAll(constructMap, i)
|
||||
{
|
||||
label oldPointi = constructMap[i];
|
||||
|
||||
// New label of point after changeMesh.
|
||||
label newPointi = map().reversePointMap()[oldPointi];
|
||||
|
||||
if (newPointi < -1)
|
||||
{
|
||||
constructMap[i] = -newPointi-2;
|
||||
}
|
||||
else if (newPointi >= 0)
|
||||
{
|
||||
constructMap[i] = newPointi;
|
||||
}
|
||||
else
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Problem. oldPointi:" << oldPointi
|
||||
<< " newPointi:" << newPointi << abort(FatalError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
boundBox procBounds
|
||||
(
|
||||
const argList& args,
|
||||
const PtrList<Time>& databases,
|
||||
const word& regionDir
|
||||
)
|
||||
{
|
||||
boundBox bb = boundBox::invertedBox;
|
||||
|
||||
forAll(databases, proci)
|
||||
{
|
||||
fileName pointsInstance
|
||||
(
|
||||
databases[proci].findInstance
|
||||
(
|
||||
regionDir/polyMesh::meshSubDir,
|
||||
"points"
|
||||
)
|
||||
);
|
||||
|
||||
if (pointsInstance != databases[proci].timeName())
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Your time was specified as " << databases[proci].timeName()
|
||||
<< " but there is no polyMesh/points in that time." << endl
|
||||
<< "(there is a points file in " << pointsInstance
|
||||
<< ")" << endl
|
||||
<< "Please rerun with the correct time specified"
|
||||
<< " (through the -constant, -time or -latestTime "
|
||||
<< "(at your option)."
|
||||
<< endl << exit(FatalError);
|
||||
}
|
||||
|
||||
Info<< "Reading points from "
|
||||
<< databases[proci].caseName()
|
||||
<< " for time = " << databases[proci].timeName()
|
||||
<< nl << endl;
|
||||
|
||||
pointIOField points
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"points",
|
||||
databases[proci].findInstance
|
||||
(
|
||||
regionDir/polyMesh::meshSubDir,
|
||||
"points"
|
||||
),
|
||||
regionDir/polyMesh::meshSubDir,
|
||||
databases[proci],
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
boundBox domainBb(points, false);
|
||||
|
||||
bb.min() = min(bb.min(), domainBb.min());
|
||||
bb.max() = max(bb.max(), domainBb.max());
|
||||
}
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
||||
void writeCellDistance
|
||||
void writeCellDistribution
|
||||
(
|
||||
Time& runTime,
|
||||
const fvMesh& masterMesh,
|
||||
@ -451,27 +236,9 @@ void writeCellDistance
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"reconstruct a mesh using geometric information only"
|
||||
);
|
||||
|
||||
// Enable -constant ... if someone really wants it
|
||||
// Enable -withZero to prevent accidentally trashing the initial fields
|
||||
argList::addNote("reconstruct a mesh");
|
||||
timeSelector::addOptions(true, true);
|
||||
argList::noParallel();
|
||||
argList::addOption
|
||||
(
|
||||
"mergeTol",
|
||||
"scalar",
|
||||
"specify the merge distance relative to the bounding box size "
|
||||
"(default 1e-7)"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"fullMatch",
|
||||
"do (slower) geometric matching on all boundary faces"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"cellDist",
|
||||
@ -484,22 +251,6 @@ int main(int argc, char *argv[])
|
||||
#include "setRootCase.H"
|
||||
#include "createTime.H"
|
||||
|
||||
Info<< "This is an experimental tool which tries to merge"
|
||||
<< " individual processor" << nl
|
||||
<< "meshes back into one master mesh. Use it if the original"
|
||||
<< " master mesh has" << nl
|
||||
<< "been deleted or if the processor meshes have been modified"
|
||||
<< " (topology change)." << nl
|
||||
<< "This tool will write the resulting mesh to a new time step"
|
||||
<< " and construct" << nl
|
||||
<< "xxxxProcAddressing files in the processor meshes so"
|
||||
<< " reconstructPar can be" << nl
|
||||
<< "used to regenerate the fields on the master mesh." << nl
|
||||
<< nl
|
||||
<< "Not well tested & use at your own risk!" << nl
|
||||
<< endl;
|
||||
|
||||
|
||||
const wordList regionNames(selectRegionNames(args, runTime));
|
||||
if (regionNames.size() > 1)
|
||||
{
|
||||
@ -515,52 +266,11 @@ int main(int argc, char *argv[])
|
||||
Info<< "Operating on region " << regionNames[0] << nl << endl;
|
||||
}
|
||||
|
||||
|
||||
scalar mergeTol = defaultMergeTol;
|
||||
args.optionReadIfPresent("mergeTol", mergeTol);
|
||||
|
||||
scalar writeTol = Foam::pow(10.0, -scalar(IOstream::defaultPrecision()));
|
||||
|
||||
Info<< "Merge tolerance : " << mergeTol << nl
|
||||
<< "Write tolerance : " << writeTol << endl;
|
||||
|
||||
if (runTime.writeFormat() == IOstream::ASCII && mergeTol < writeTol)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Your current settings specify ASCII writing with "
|
||||
<< IOstream::defaultPrecision() << " digits precision." << endl
|
||||
<< "Your merging tolerance (" << mergeTol << ") is finer than this."
|
||||
<< endl
|
||||
<< "Please change your writeFormat to binary"
|
||||
<< " or increase the writePrecision" << endl
|
||||
<< "or adjust the merge tolerance (-mergeTol)."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
|
||||
const bool fullMatch = args.optionFound("fullMatch");
|
||||
|
||||
if (fullMatch)
|
||||
{
|
||||
Info<< "Doing geometric matching on all boundary faces." << nl << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Doing geometric matching on correct procBoundaries only."
|
||||
<< nl << "This assumes a correct decomposition." << endl;
|
||||
}
|
||||
|
||||
bool writeCellDist = args.optionFound("cellDist");
|
||||
|
||||
|
||||
label nProcs = fileHandler().nProcs(args.path());
|
||||
|
||||
Info<< "Found " << nProcs << " processor directories" << nl << endl;
|
||||
|
||||
|
||||
// Read all time databases
|
||||
PtrList<Time> databases(nProcs);
|
||||
|
||||
forAll(databases, proci)
|
||||
{
|
||||
Info<< "Reading database "
|
||||
@ -630,18 +340,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
// Read point on individual processors to determine merge tolerance
|
||||
// (otherwise single cell domains might give problems)
|
||||
|
||||
const boundBox bb = procBounds(args, databases, regionDir);
|
||||
const scalar mergeDist = mergeTol*bb.mag();
|
||||
|
||||
Info<< "Overall mesh bounding box : " << bb << nl
|
||||
<< "Relative tolerance : " << mergeTol << nl
|
||||
<< "Absolute matching distance : " << mergeDist << nl
|
||||
<< endl;
|
||||
|
||||
|
||||
// Addressing from processor to reconstructed case
|
||||
labelListList cellProcAddressing(nProcs);
|
||||
labelListList faceProcAddressing(nProcs);
|
||||
@ -656,9 +354,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
{
|
||||
// Construct empty mesh.
|
||||
// fvMesh** masterMesh = new fvMesh*[nProcs];
|
||||
PtrList<fvMesh> masterMesh(nProcs);
|
||||
|
||||
// Read all the meshes
|
||||
for (label proci=0; proci<nProcs; proci++)
|
||||
{
|
||||
masterMesh.set
|
||||
@ -696,17 +394,15 @@ int main(int argc, char *argv[])
|
||||
boundaryProcAddressing[proci] =
|
||||
identity(meshToAdd.boundaryMesh().size());
|
||||
|
||||
// Find geometrically shared points/faces.
|
||||
// Find shared points/faces
|
||||
autoPtr<faceCoupleInfo> couples = determineCoupledFaces
|
||||
(
|
||||
fullMatch,
|
||||
proci,
|
||||
proci,
|
||||
masterMesh[proci],
|
||||
proci,
|
||||
proci,
|
||||
meshToAdd,
|
||||
mergeDist
|
||||
meshToAdd
|
||||
);
|
||||
|
||||
// Add elements to mesh
|
||||
@ -718,15 +414,29 @@ int main(int argc, char *argv[])
|
||||
);
|
||||
|
||||
// Added processor
|
||||
renumber(map().addedCellMap(), cellProcAddressing[proci]);
|
||||
renumber(map().addedFaceMap(), faceProcAddressing[proci]);
|
||||
renumber(map().addedPointMap(), pointProcAddressing[proci]);
|
||||
renumber
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedCellMap(),
|
||||
cellProcAddressing[proci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedFaceMap(),
|
||||
faceProcAddressing[proci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedPointMap(),
|
||||
pointProcAddressing[proci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedPatchMap(),
|
||||
boundaryProcAddressing[proci]
|
||||
);
|
||||
}
|
||||
|
||||
// Merge the meshes
|
||||
for (label step=2; step<nProcs*2; step*=2)
|
||||
{
|
||||
for (label proci=0; proci<nProcs; proci+=step)
|
||||
@ -740,17 +450,15 @@ int main(int argc, char *argv[])
|
||||
Info<< "Merging mesh " << proci << " with " << next
|
||||
<< endl;
|
||||
|
||||
// Find geometrically shared points/faces.
|
||||
// Find shared points/faces
|
||||
autoPtr<faceCoupleInfo> couples = determineCoupledFaces
|
||||
(
|
||||
fullMatch,
|
||||
proci,
|
||||
next,
|
||||
masterMesh[proci],
|
||||
next,
|
||||
proci+step,
|
||||
masterMesh[next],
|
||||
mergeDist
|
||||
masterMesh[next]
|
||||
);
|
||||
|
||||
// Add elements to mesh
|
||||
@ -764,26 +472,22 @@ int main(int argc, char *argv[])
|
||||
// Processors that were already in masterMesh
|
||||
for (label mergedI=proci; mergedI<next; mergedI++)
|
||||
{
|
||||
renumber
|
||||
inplaceRenumber
|
||||
(
|
||||
map().oldCellMap(),
|
||||
cellProcAddressing[mergedI]
|
||||
);
|
||||
|
||||
renumber
|
||||
inplaceRenumber
|
||||
(
|
||||
map().oldFaceMap(),
|
||||
faceProcAddressing[mergedI]
|
||||
);
|
||||
|
||||
renumber
|
||||
inplaceRenumber
|
||||
(
|
||||
map().oldPointMap(),
|
||||
pointProcAddressing[mergedI]
|
||||
);
|
||||
|
||||
// Note: boundary is special since can contain -1.
|
||||
renumber
|
||||
inplaceRenumber
|
||||
(
|
||||
map().oldPatchMap(),
|
||||
boundaryProcAddressing[mergedI]
|
||||
@ -798,25 +502,22 @@ int main(int argc, char *argv[])
|
||||
addedI++
|
||||
)
|
||||
{
|
||||
renumber
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedCellMap(),
|
||||
cellProcAddressing[addedI]
|
||||
);
|
||||
|
||||
renumber
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedFaceMap(),
|
||||
faceProcAddressing[addedI]
|
||||
);
|
||||
|
||||
renumber
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedPointMap(),
|
||||
pointProcAddressing[addedI]
|
||||
);
|
||||
|
||||
renumber
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedPatchMap(),
|
||||
boundaryProcAddressing[addedI]
|
||||
@ -835,14 +536,6 @@ int main(int argc, char *argv[])
|
||||
<< nl << nl << endl;
|
||||
}
|
||||
|
||||
// See if any points on the mastermesh have become connected
|
||||
// because of connections through processor meshes.
|
||||
mergeSharedPoints
|
||||
(
|
||||
mergeDist,
|
||||
masterMesh[0],
|
||||
pointProcAddressing
|
||||
);
|
||||
|
||||
// Save some properties on the reconstructed mesh
|
||||
masterInternalFaces = masterMesh[0].nInternalFaces();
|
||||
@ -860,9 +553,9 @@ int main(int argc, char *argv[])
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
if (writeCellDist)
|
||||
if (args.optionFound("cellDist"))
|
||||
{
|
||||
writeCellDistance
|
||||
writeCellDistribution
|
||||
(
|
||||
runTime,
|
||||
masterMesh[0],
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -58,65 +58,6 @@ Description
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Tolerance (as fraction of the bounding box). Needs to be fairly lax since
|
||||
// usually meshes get written with limited precision (6 digits)
|
||||
static const scalar defaultMergeTol = 1e-6;
|
||||
|
||||
|
||||
// Get merging distance when matching face centres
|
||||
scalar getMergeDistance
|
||||
(
|
||||
const argList& args,
|
||||
const Time& runTime,
|
||||
const boundBox& bb
|
||||
)
|
||||
{
|
||||
scalar mergeTol = defaultMergeTol;
|
||||
args.optionReadIfPresent("mergeTol", mergeTol);
|
||||
|
||||
scalar writeTol =
|
||||
Foam::pow(scalar(10.0), -scalar(IOstream::defaultPrecision()));
|
||||
|
||||
Info<< "Merge tolerance : " << mergeTol << nl
|
||||
<< "Write tolerance : " << writeTol << endl;
|
||||
|
||||
if (runTime.writeFormat() == IOstream::ASCII && mergeTol < writeTol)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Your current settings specify ASCII writing with "
|
||||
<< IOstream::defaultPrecision() << " digits precision." << endl
|
||||
<< "Your merging tolerance (" << mergeTol << ") is finer than this."
|
||||
<< endl
|
||||
<< "Please change your writeFormat to binary"
|
||||
<< " or increase the writePrecision" << endl
|
||||
<< "or adjust the merge tolerance (-mergeTol)."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
scalar mergeDist = mergeTol * bb.mag();
|
||||
|
||||
Info<< "Overall meshes bounding box : " << bb << nl
|
||||
<< "Relative tolerance : " << mergeTol << nl
|
||||
<< "Absolute matching distance : " << mergeDist << nl
|
||||
<< endl;
|
||||
|
||||
return mergeDist;
|
||||
}
|
||||
|
||||
|
||||
//void printMeshData(Ostream& os, const polyMesh& mesh)
|
||||
//{
|
||||
// os << "Number of points: " << mesh.points().size() << nl
|
||||
// << " faces: " << mesh.faces().size() << nl
|
||||
// << " internal faces: " << mesh.faceNeighbour().size() << nl
|
||||
// << " cells: " << mesh.cells().size() << nl
|
||||
// << " boundary patches: " << mesh.boundaryMesh().size() << nl
|
||||
// << " point zones: " << mesh.pointZones().size() << nl
|
||||
// << " face zones: " << mesh.faceZones().size() << nl
|
||||
// << " cell zones: " << mesh.cellZones().size() << nl;
|
||||
//}
|
||||
|
||||
|
||||
void printMeshData(const polyMesh& mesh)
|
||||
{
|
||||
// Collect all data on master
|
||||
@ -365,72 +306,11 @@ void readFields
|
||||
}
|
||||
|
||||
|
||||
// Debugging: compare two fields.
|
||||
void compareFields
|
||||
(
|
||||
const scalar tolDim,
|
||||
const volVectorField& a,
|
||||
const volVectorField& b
|
||||
)
|
||||
{
|
||||
forAll(a, celli)
|
||||
{
|
||||
if (mag(b[celli] - a[celli]) > tolDim)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Did not map volVectorField correctly:" << nl
|
||||
<< "cell:" << celli
|
||||
<< " transfer b:" << b[celli]
|
||||
<< " real cc:" << a[celli]
|
||||
<< abort(FatalError);
|
||||
}
|
||||
}
|
||||
forAll(a.boundaryField(), patchi)
|
||||
{
|
||||
// We have real mesh cellcentre and
|
||||
// mapped original cell centre.
|
||||
|
||||
const fvPatchVectorField& aBoundary =
|
||||
a.boundaryField()[patchi];
|
||||
|
||||
const fvPatchVectorField& bBoundary =
|
||||
b.boundaryField()[patchi];
|
||||
|
||||
if (!bBoundary.coupled())
|
||||
{
|
||||
forAll(aBoundary, i)
|
||||
{
|
||||
if (mag(aBoundary[i] - bBoundary[i]) > tolDim)
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Did not map volVectorField correctly:"
|
||||
<< endl
|
||||
<< "patch:" << patchi << " patchFace:" << i
|
||||
<< " cc:" << endl
|
||||
<< " real :" << aBoundary[i] << endl
|
||||
<< " mapped :" << bBoundary[i] << endl
|
||||
<< "This might be just a precision entry"
|
||||
<< " on writing the mesh." << endl;
|
||||
//<< abort(FatalError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#include "addRegionOption.H"
|
||||
#include "addOverwriteOption.H"
|
||||
argList::addOption
|
||||
(
|
||||
"mergeTol",
|
||||
"scalar",
|
||||
"specify the merge distance relative to the bounding box size "
|
||||
"(default 1e-6)"
|
||||
);
|
||||
|
||||
// Include explicit constant options, have zero from time range
|
||||
timeSelector::addOptions();
|
||||
|
||||
@ -781,16 +661,8 @@ int main(int argc, char *argv[])
|
||||
// Used to test correctness of mapping
|
||||
// volVectorField mapCc("mapCc", 1*mesh.C());
|
||||
|
||||
// Global matching tolerance
|
||||
const scalar tolDim = getMergeDistance
|
||||
(
|
||||
args,
|
||||
runTime,
|
||||
mesh.bounds()
|
||||
);
|
||||
|
||||
// Mesh distribution engine
|
||||
fvMeshDistribute distributor(mesh, tolDim);
|
||||
fvMeshDistribute distributor(mesh);
|
||||
|
||||
// Pout<< "Wanted distribution:"
|
||||
// << distributor.countCells(finalDecomp) << nl << endl;
|
||||
@ -819,9 +691,6 @@ int main(int argc, char *argv[])
|
||||
mesh.write();
|
||||
|
||||
|
||||
// Debugging: test mapped cellcentre field.
|
||||
// compareFields(tolDim, mesh.C(), mapCc);
|
||||
|
||||
// Print nice message
|
||||
// ~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -656,10 +656,95 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::fvMeshDistribute::mergeSharedPoints
|
||||
return autoPtr<mapPolyMesh>(nullptr);
|
||||
}
|
||||
|
||||
|
||||
// Create the mesh change engine to merge the points
|
||||
polyTopoChange meshMod(mesh_);
|
||||
{
|
||||
// Remove all non-master points.
|
||||
forAll(mesh_.points(), pointi)
|
||||
{
|
||||
Map<label>::const_iterator iter = pointToMaster.find(pointi);
|
||||
|
||||
fvMeshAdder::mergePoints(mesh_, pointToMaster, meshMod);
|
||||
if (iter != pointToMaster.end())
|
||||
{
|
||||
if (iter() != pointi)
|
||||
{
|
||||
meshMod.removePoint(pointi, iter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modify faces for points. Note: could use pointFaces here but want to
|
||||
// avoid addressing calculation.
|
||||
const faceList& faces = mesh_.faces();
|
||||
|
||||
forAll(faces, facei)
|
||||
{
|
||||
const face& f = faces[facei];
|
||||
|
||||
bool hasMerged = false;
|
||||
|
||||
forAll(f, fp)
|
||||
{
|
||||
label pointi = f[fp];
|
||||
|
||||
Map<label>::const_iterator iter = pointToMaster.find(pointi);
|
||||
|
||||
if (iter != pointToMaster.end())
|
||||
{
|
||||
if (iter() != pointi)
|
||||
{
|
||||
hasMerged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMerged)
|
||||
{
|
||||
face newF(f);
|
||||
|
||||
forAll(f, fp)
|
||||
{
|
||||
label pointi = f[fp];
|
||||
|
||||
Map<label>::const_iterator iter =
|
||||
pointToMaster.find(pointi);
|
||||
|
||||
if (iter != pointToMaster.end())
|
||||
{
|
||||
newF[fp] = iter();
|
||||
}
|
||||
}
|
||||
|
||||
label patchID = mesh_.boundaryMesh().whichPatch(facei);
|
||||
label nei = (patchID == -1 ? mesh_.faceNeighbour()[facei] : -1);
|
||||
label zoneID = mesh_.faceZones().whichZone(facei);
|
||||
bool zoneFlip = false;
|
||||
|
||||
if (zoneID >= 0)
|
||||
{
|
||||
const faceZone& fZone = mesh_.faceZones()[zoneID];
|
||||
zoneFlip = fZone.flipMap()[fZone.whichFace(facei)];
|
||||
}
|
||||
|
||||
meshMod.setAction
|
||||
(
|
||||
polyModifyFace
|
||||
(
|
||||
newF, // modified face
|
||||
facei, // label of face
|
||||
mesh_.faceOwner()[facei], // owner
|
||||
nei, // neighbour
|
||||
false, // face flip
|
||||
patchID, // patch for face
|
||||
false, // remove from zone
|
||||
zoneID, // zone for face
|
||||
zoneFlip // face flip in zone
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change the mesh (no inflation). Note: parallel comms allowed.
|
||||
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
|
||||
@ -1624,10 +1709,9 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshDistribute::receiveMesh
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
// Construct from components
|
||||
Foam::fvMeshDistribute::fvMeshDistribute(fvMesh& mesh, const scalar mergeTol)
|
||||
Foam::fvMeshDistribute::fvMeshDistribute(fvMesh& mesh)
|
||||
:
|
||||
mesh_(mesh),
|
||||
mergeTol_(mergeTol)
|
||||
mesh_(mesh)
|
||||
{}
|
||||
|
||||
|
||||
@ -2676,11 +2760,7 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
|
||||
mesh_,
|
||||
masterCoupledFaces,
|
||||
domainMesh,
|
||||
slaveCoupledFaces,
|
||||
mergeTol_, // merge tolerance
|
||||
true, // faces align
|
||||
true, // couples are ordered already
|
||||
false
|
||||
slaveCoupledFaces
|
||||
);
|
||||
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -75,10 +75,6 @@ class fvMeshDistribute
|
||||
//- Underlying fvMesh
|
||||
fvMesh& mesh_;
|
||||
|
||||
//- Absolute merging tolerance (constructing meshes gets done using
|
||||
// geometric matching)
|
||||
const scalar mergeTol_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
@ -344,8 +340,8 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from mesh and absolute merge tolerance
|
||||
fvMeshDistribute(fvMesh& mesh, const scalar mergeTol);
|
||||
//- Construct from mesh
|
||||
fvMeshDistribute(fvMesh& mesh);
|
||||
|
||||
//- Disallow default bitwise copy construction
|
||||
fvMeshDistribute(const fvMeshDistribute&) = delete;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -26,108 +26,12 @@ Class
|
||||
|
||||
Description
|
||||
Container for information needed to couple to meshes. When constructed
|
||||
from two meshes and a geometric tolerance finds the corresponding
|
||||
boundary faces.
|
||||
|
||||
The information it keeps is the set of faces&points (cutFaces,
|
||||
cutPoints) that should replace a set of faces on the master
|
||||
(masterPatch) and a set of faces on the slave (slavePatch)
|
||||
|
||||
|
||||
Uses same tolerance to match faces and points on matched faces since
|
||||
they both originate from the same points and the tolerance usually
|
||||
comes from writing these points with limited precision (6 by default)
|
||||
|
||||
-# Perfect match:
|
||||
- one-to-one match for faces and points.
|
||||
- the cut is always the 'most connected' of the master and slave so
|
||||
multiple master or slave points might point to the same cut point.
|
||||
|
||||
\verbatim
|
||||
e.g. master:
|
||||
|
||||
+--+
|
||||
| |
|
||||
| |
|
||||
+--+
|
||||
+--+
|
||||
| |
|
||||
| |
|
||||
+--+
|
||||
slave:
|
||||
+--+
|
||||
| |
|
||||
| |
|
||||
+--+
|
||||
+--+
|
||||
| |
|
||||
| |
|
||||
+--+
|
||||
\endverbatim
|
||||
adding both together creates a singly connected 2x2 cavity so suddenly
|
||||
the duplicate master points and the duplicate slave points all become
|
||||
a single cut point.
|
||||
|
||||
|
||||
-# Subdivision match:
|
||||
- Can be constructed from slave being subdivision of master with the
|
||||
polyPatch constructor.
|
||||
- Does not include above shared-point detection!
|
||||
|
||||
Notes on multiple slave faces per master:
|
||||
|
||||
As long as
|
||||
- all master edges are present in slave
|
||||
- slave can have extra edges/points/faces BUT all subfaces have to have
|
||||
at least one point on a maste face.
|
||||
|
||||
\verbatim
|
||||
So master:
|
||||
+-------+
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
+-------+
|
||||
|
||||
slave:
|
||||
+---+---+
|
||||
|\ | /|
|
||||
| \ | / |
|
||||
| \|/ |
|
||||
+---+---+
|
||||
| /|\ |
|
||||
| / | \ |
|
||||
|/ | \|
|
||||
+---+---+
|
||||
is ok.
|
||||
\endverbatim
|
||||
|
||||
For this kind of matching the order is:
|
||||
- match cutpoint to masterpoint
|
||||
- find those cutEdges that align with a master edge. This gives two sets
|
||||
of cut edges: those that have a master equivalent ('border edges') and
|
||||
those that don't ('internal edges'). The border edges now divide the
|
||||
cutFaces into regions with the same masterFace correspondence.
|
||||
- find cutFaces that are fully determined by the border edges they use.
|
||||
- all cutFaces that are connected through an internal edge have the same
|
||||
master face.
|
||||
|
||||
|
||||
Note: matching refined faces onto master is a bit dodgy and will probably
|
||||
only work for unwarped faces. Also it will fail if e.g. face is split
|
||||
into 3x3 since then middle face has no point/edge in common with master.
|
||||
(problem is in face matching (findSlavesCoveringMaster), probably
|
||||
point/edge matching might just work)
|
||||
|
||||
from two meshes and a list of coupled faces returns the mapping between
|
||||
points.
|
||||
|
||||
SourceFiles
|
||||
faceCoupleInfo.C
|
||||
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef faceCoupleInfo_H
|
||||
@ -135,20 +39,13 @@ SourceFiles
|
||||
|
||||
#include "pointField.H"
|
||||
#include "indirectPrimitivePatch.H"
|
||||
#include "primitiveFacePatch.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
typedef HashTable<labelList, edge, Hash<edge>> edgeLookup;
|
||||
|
||||
|
||||
// Forward declaration of classes
|
||||
class face;
|
||||
class primitiveMesh;
|
||||
class polyPatch;
|
||||
class polyMesh;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
@ -159,49 +56,20 @@ class faceCoupleInfo
|
||||
{
|
||||
// Private Data
|
||||
|
||||
//- Angle matching tolerance.
|
||||
static const scalar angleTol_;
|
||||
|
||||
//- Master patch
|
||||
autoPtr<indirectPrimitivePatch> masterPatchPtr_;
|
||||
|
||||
//- Slave patch
|
||||
autoPtr<indirectPrimitivePatch> slavePatchPtr_;
|
||||
|
||||
//- The number of coupled points
|
||||
label nCouplePoints_;
|
||||
|
||||
//- Description of cut.
|
||||
// - Cut is the matching area between the slave
|
||||
// and the master.
|
||||
// - cut is the finest of master and slave. It can never be
|
||||
// coarser than either one of them. (so face addressing we keep is
|
||||
// cut-to-master and cut-to-slave)
|
||||
// - multiple master or slave points can end up becoming one cut point
|
||||
// (so point addressing we keep is master-to-cut and slave-to-cut)
|
||||
//- Master-to-couple point addressing
|
||||
labelList masterToCouplePoints_;
|
||||
|
||||
// Cut consists of faces and points (note: could be expressed as some
|
||||
// kind of PrimitivePatch which holds points instead of reference to
|
||||
// them)
|
||||
// Orientation of cutFaces should be same as masterFaces!
|
||||
pointField cutPoints_;
|
||||
autoPtr<primitiveFacePatch> cutFacesPtr_;
|
||||
|
||||
//- Additional point coupling information. Is between points on
|
||||
// boundary of both meshes.
|
||||
|
||||
// Addressing to/from cut
|
||||
|
||||
//- master
|
||||
labelList cutToMasterFaces_;
|
||||
labelList masterToCutPoints_;
|
||||
|
||||
//- slave
|
||||
labelList cutToSlaveFaces_;
|
||||
labelList slaveToCutPoints_;
|
||||
|
||||
//- For edges originating from splitting of edges:
|
||||
// given the two endpoints of the unsplit edge give the list
|
||||
// of in between vertices
|
||||
edgeLookup cutEdgeToPoints_;
|
||||
//- Slave-to-couple point addressing
|
||||
labelList slaveToCouplePoints_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
@ -233,8 +101,7 @@ class faceCoupleInfo
|
||||
(
|
||||
const fileName& fName,
|
||||
const edgeList& edges,
|
||||
const pointField& points,
|
||||
const bool compact = true
|
||||
const pointField& points
|
||||
);
|
||||
|
||||
//- Write edges
|
||||
@ -249,136 +116,6 @@ class faceCoupleInfo
|
||||
// as .obj files.
|
||||
void writePointsFaces() const;
|
||||
|
||||
//- Write connections between corresponding edges as .obj files.
|
||||
void writeEdges(const labelList&, const labelList&) const;
|
||||
|
||||
|
||||
// Edge handling/matching
|
||||
|
||||
//- Find corresponding edges on patch when having only a map for
|
||||
// the points.
|
||||
labelList findMappedEdges
|
||||
(
|
||||
const edgeList& edges,
|
||||
const labelList& pointMap,
|
||||
const indirectPrimitivePatch&
|
||||
);
|
||||
|
||||
//- Check if edge on slavePatch corresponds to an edge between faces
|
||||
// in two different polyPatches on the mesh.
|
||||
bool regionEdge(const polyMesh&, const label slaveEdgeI) const;
|
||||
|
||||
//- Finds edge connected to point most aligned with master edge.
|
||||
label mostAlignedCutEdge
|
||||
(
|
||||
const bool report,
|
||||
const polyMesh& slaveMesh,
|
||||
const bool patchDivision,
|
||||
const labelList& cutToMasterEdges,
|
||||
const labelList& cutToSlaveEdges,
|
||||
const label pointi,
|
||||
const label edgeStart,
|
||||
const label edgeEnd
|
||||
) const;
|
||||
|
||||
//- From (many-to-one) map of cut edges to master edges determine
|
||||
// points in between. I.e. just string up the edges. Stores this
|
||||
// all on cutEdgeToPoints_
|
||||
void setCutEdgeToPoints(const labelList& cutToMasterEdges);
|
||||
|
||||
// Face matching
|
||||
|
||||
//- Matches two faces.
|
||||
// Determines rotation for f1 to match up with f0,
|
||||
// i.e. the index in f0 of the first point of f1.
|
||||
static label matchFaces
|
||||
(
|
||||
const scalar absTol,
|
||||
const pointField& points0,
|
||||
const face& f0,
|
||||
const pointField& points1,
|
||||
const face& f1,
|
||||
const bool sameOrientation
|
||||
);
|
||||
|
||||
//- Matches points on patch to points on cut.
|
||||
static bool matchPointsThroughFaces
|
||||
(
|
||||
const scalar absTol,
|
||||
const pointField& cutPoints,
|
||||
const faceList& cutFaces,
|
||||
const pointField& patchPoints,
|
||||
const faceList& patchFaces,
|
||||
const bool sameOrientation,
|
||||
|
||||
labelList& patchToCutPoints,// patch to (uncompacted) cut points
|
||||
labelList& cutToCompact, // compaction list
|
||||
labelList& compactToCut // compaction list
|
||||
);
|
||||
|
||||
//- Returns max distance to masterF of any point on cutF.
|
||||
static scalar maxDistance
|
||||
(
|
||||
const face& cutF,
|
||||
const pointField& cutPoints,
|
||||
const face& masterF,
|
||||
const pointField& masterPoints
|
||||
);
|
||||
|
||||
//- Finds matching (boundary)face centres.
|
||||
// Since faces identical uses geometric match on face centres.
|
||||
static void findPerfectMatchingFaces
|
||||
(
|
||||
const primitiveMesh& mesh0,
|
||||
const primitiveMesh& mesh1,
|
||||
const scalar absTol,
|
||||
|
||||
labelList& mesh0Faces,
|
||||
labelList& mesh1Faces
|
||||
);
|
||||
|
||||
//- Find matching (boundary)faces. Matching if slave is on top of
|
||||
// master face (slaves is subdivision of master)
|
||||
static void findSlavesCoveringMaster
|
||||
(
|
||||
const primitiveMesh& mesh0,
|
||||
const primitiveMesh& mesh1,
|
||||
const scalar absTol,
|
||||
|
||||
labelList& mesh0Faces,
|
||||
labelList& mesh1Faces
|
||||
);
|
||||
|
||||
//- Grow cutToMasterFace across 'internal' edges.
|
||||
label growCutFaces(const labelList&, Map<labelList>&);
|
||||
|
||||
void checkMatch(const labelList& cutToMasterEdges) const;
|
||||
|
||||
//- Gets a list of cutFaces (that use a master edge) and the
|
||||
// candidate master faces.
|
||||
// Checks among these master faces if there is only one remaining
|
||||
// unmatched one.
|
||||
label matchEdgeFaces(const labelList&, Map<labelList>& candidates);
|
||||
|
||||
//- Gets a list of cutFaces (that use a master edge) and the
|
||||
// candidate master faces.
|
||||
// Finds most aligned master face.
|
||||
label geometricMatchEdgeFaces(Map<labelList>& candidates);
|
||||
|
||||
//- Find point and edge correspondence for perfect matching faces
|
||||
void perfectOrderedPointMatch();
|
||||
|
||||
//- Find point and edge correspondence for perfect matching faces
|
||||
void perfectPointMatch(const scalar absTol);
|
||||
|
||||
//- Find point and edge correspondence for slaves being subdivision of
|
||||
// master.
|
||||
void subDivisionMatch
|
||||
(
|
||||
const polyMesh& slaveMesh,
|
||||
const bool patchDivision,
|
||||
const scalar absTol
|
||||
);
|
||||
|
||||
public:
|
||||
|
||||
@ -388,43 +125,16 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from two meshes and absolute tolerance.
|
||||
// Finds out matches geometrically. No checking for nonsense match.
|
||||
// Tolerance is absolute one so use with care.
|
||||
// perfectMatch : each point/edge/face has corresponding point on other
|
||||
// side
|
||||
// if this is false then assumes slave is subdivision.
|
||||
// Matching then will work only for non-warped faces
|
||||
// since does nearest-to-face comparison with absTol.
|
||||
faceCoupleInfo
|
||||
(
|
||||
const polyMesh& mesh0,
|
||||
const polyMesh& mesh1,
|
||||
const scalar absTol,
|
||||
const bool perfectMatch
|
||||
);
|
||||
|
||||
//- Construct from meshes and subset of mesh faces
|
||||
// (i.e. indirectPrimitivePatch addressing)
|
||||
// All faces in patch are considered matched (but don't have to be
|
||||
// ordered)
|
||||
// perfectMatch : each point/edge/face has corresponding point on other
|
||||
// side
|
||||
// orderedFaces : faces in patch are ordered (so masterAddressing[i]
|
||||
// matches slaveAddressing[i])
|
||||
// patchDivision: faces in slave mesh that originate from the
|
||||
// same master face have the same patch. Used by some triangulation
|
||||
// methods.
|
||||
//- Construct from meshes and subset of mesh faces (i.e.,
|
||||
// indirectPrimitivePatch addressing). Faces should be supplied in
|
||||
// order and the points within them should be ordered (i.e., coupled
|
||||
// faces should have the same zero-point and opposite orientations).
|
||||
faceCoupleInfo
|
||||
(
|
||||
const polyMesh& masterMesh,
|
||||
const labelList& masterAddressing,
|
||||
const polyMesh& slaveMesh,
|
||||
const labelList& slaveAddressing,
|
||||
const scalar absTol,
|
||||
const bool perfectMatch,
|
||||
const bool orderedFaces,
|
||||
const bool patchDivision
|
||||
const labelList& slaveAddressing
|
||||
);
|
||||
|
||||
|
||||
@ -432,19 +142,8 @@ public:
|
||||
~faceCoupleInfo();
|
||||
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Utility functions
|
||||
|
||||
//- Get patch face labels
|
||||
static labelList faceLabels(const polyPatch&);
|
||||
|
||||
//- Create Map from List
|
||||
static Map<label> makeMap(const labelList&);
|
||||
static Map<labelList> makeMap(const labelListList&);
|
||||
|
||||
|
||||
// Access
|
||||
|
||||
//- Addressing engine for coupled faces on mesh0
|
||||
@ -459,49 +158,40 @@ public:
|
||||
return slavePatchPtr_();
|
||||
}
|
||||
|
||||
//- Addressing engine for combined set of faces.
|
||||
const primitiveFacePatch& cutFaces() const
|
||||
//- Access master-to-couple point addressing
|
||||
const labelList& masterToCouplePoints() const
|
||||
{
|
||||
return cutFacesPtr_();
|
||||
return masterToCouplePoints_;
|
||||
}
|
||||
|
||||
//- Points for combined set of faces.
|
||||
const pointField& cutPoints() const
|
||||
//- Access slave-to-couple point addressing
|
||||
const labelList& slaveToCouplePoints() const
|
||||
{
|
||||
return cutPoints_;
|
||||
return slaveToCouplePoints_;
|
||||
}
|
||||
|
||||
|
||||
// Addressing from meshes to cut and vice versa.
|
||||
|
||||
//- Master face for every face on cut. Will always be at least
|
||||
// one but there might be multiple cut faces pointing to the same
|
||||
// master
|
||||
const labelList& cutToMasterFaces() const
|
||||
//- Generate couple-to-master point addressing
|
||||
labelListList coupleToMasterPoints() const
|
||||
{
|
||||
return cutToMasterFaces_;
|
||||
}
|
||||
const labelList& masterToCutPoints() const
|
||||
{
|
||||
return masterToCutPoints_;
|
||||
return invertOneToMany(nCouplePoints_, masterToCouplePoints_);
|
||||
}
|
||||
|
||||
const labelList& cutToSlaveFaces() const
|
||||
//- Generate couple-to-slave point addressing
|
||||
labelListList coupleToSlavePoints() const
|
||||
{
|
||||
return cutToSlaveFaces_;
|
||||
}
|
||||
const labelList& slaveToCutPoints() const
|
||||
{
|
||||
return slaveToCutPoints_;
|
||||
return invertOneToMany(nCouplePoints_, slaveToCouplePoints_);
|
||||
}
|
||||
|
||||
//- From two cut points (original edge) to list of inserted
|
||||
// points
|
||||
const edgeLookup& cutEdgeToPoints() const
|
||||
//- Return a coupled face
|
||||
const face coupleFace(const label coupleFacei) const
|
||||
{
|
||||
return cutEdgeToPoints_;
|
||||
return
|
||||
renumber
|
||||
(
|
||||
masterToCouplePoints(),
|
||||
masterPatch().localFaces()[coupleFacei]
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -31,7 +31,6 @@ License
|
||||
#include "SortableList.H"
|
||||
#include "Time.H"
|
||||
#include "globalMeshData.H"
|
||||
#include "mergePoints.H"
|
||||
#include "polyModifyFace.H"
|
||||
#include "polyRemovePoint.H"
|
||||
#include "polyTopoChange.H"
|
||||
@ -395,81 +394,6 @@ Foam::labelList Foam::polyMeshAdder::getFaceOrder
|
||||
}
|
||||
|
||||
|
||||
// Extends face f with split points. cutEdgeToPoints gives for every
|
||||
// edge the points introduced in between the endpoints.
|
||||
void Foam::polyMeshAdder::insertVertices
|
||||
(
|
||||
const edgeLookup& cutEdgeToPoints,
|
||||
const Map<label>& meshToMaster,
|
||||
const labelList& masterToCutPoints,
|
||||
const face& masterF,
|
||||
|
||||
DynamicList<label>& workFace,
|
||||
face& allF
|
||||
)
|
||||
{
|
||||
workFace.clear();
|
||||
|
||||
// Check any edge for being cut (check on the cut so takes account
|
||||
// for any point merging on the cut)
|
||||
|
||||
forAll(masterF, fp)
|
||||
{
|
||||
label v0 = masterF[fp];
|
||||
label v1 = masterF.nextLabel(fp);
|
||||
|
||||
// Copy existing face point
|
||||
workFace.append(allF[fp]);
|
||||
|
||||
// See if any edge between v0,v1
|
||||
|
||||
Map<label>::const_iterator v0Fnd = meshToMaster.find(v0);
|
||||
if (v0Fnd != meshToMaster.end())
|
||||
{
|
||||
Map<label>::const_iterator v1Fnd = meshToMaster.find(v1);
|
||||
if (v1Fnd != meshToMaster.end())
|
||||
{
|
||||
// Get edge in cutPoint numbering
|
||||
edge cutEdge
|
||||
(
|
||||
masterToCutPoints[v0Fnd()],
|
||||
masterToCutPoints[v1Fnd()]
|
||||
);
|
||||
|
||||
edgeLookup::const_iterator iter = cutEdgeToPoints.find(cutEdge);
|
||||
|
||||
if (iter != cutEdgeToPoints.end())
|
||||
{
|
||||
const edge& e = iter.key();
|
||||
const labelList& addedPoints = iter();
|
||||
|
||||
// cutPoints first in allPoints so no need for renumbering
|
||||
if (e[0] == cutEdge[0])
|
||||
{
|
||||
forAll(addedPoints, i)
|
||||
{
|
||||
workFace.append(addedPoints[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
forAllReverse(addedPoints, i)
|
||||
{
|
||||
workFace.append(addedPoints[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (workFace.size() != allF.size())
|
||||
{
|
||||
allF.transfer(workFace);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Adds primitives (cells, faces, points)
|
||||
// Cells:
|
||||
// - all of mesh0
|
||||
@ -511,7 +435,6 @@ void Foam::polyMeshAdder::mergePrimitives
|
||||
const polyBoundaryMesh& patches0 = mesh0.boundaryMesh();
|
||||
const polyBoundaryMesh& patches1 = mesh1.boundaryMesh();
|
||||
|
||||
const primitiveFacePatch& cutFaces = coupleInfo.cutFaces();
|
||||
const indirectPrimitivePatch& masterPatch = coupleInfo.masterPatch();
|
||||
const indirectPrimitivePatch& slavePatch = coupleInfo.slavePatch();
|
||||
|
||||
@ -528,53 +451,37 @@ void Foam::polyMeshAdder::mergePrimitives
|
||||
from1ToAllPoints.setSize(mesh1.nPoints());
|
||||
from1ToAllPoints = -1;
|
||||
|
||||
// Copy coupled points (on cut)
|
||||
// Copy coupled points
|
||||
{
|
||||
const pointField& cutPoints = coupleInfo.cutPoints();
|
||||
|
||||
// const labelListList& cutToMasterPoints =
|
||||
// coupleInfo.cutToMasterPoints();
|
||||
labelListList cutToMasterPoints
|
||||
const labelListList coupleToMasterPoints
|
||||
(
|
||||
invertOneToMany
|
||||
coupleInfo.coupleToMasterPoints()
|
||||
);
|
||||
const labelListList coupleToSlavePoints
|
||||
(
|
||||
cutPoints.size(),
|
||||
coupleInfo.masterToCutPoints()
|
||||
)
|
||||
coupleInfo.coupleToSlavePoints()
|
||||
);
|
||||
|
||||
// const labelListList& cutToSlavePoints =
|
||||
// coupleInfo.cutToSlavePoints();
|
||||
labelListList cutToSlavePoints
|
||||
(
|
||||
invertOneToMany
|
||||
(
|
||||
cutPoints.size(),
|
||||
coupleInfo.slaveToCutPoints()
|
||||
)
|
||||
);
|
||||
|
||||
forAll(cutPoints, i)
|
||||
forAll(coupleToMasterPoints, couplePointi)
|
||||
{
|
||||
allPoints[allPointi] = cutPoints[i];
|
||||
|
||||
// Mark all master and slave points referring to this point.
|
||||
|
||||
const labelList& masterPoints = cutToMasterPoints[i];
|
||||
const labelList& masterPoints = coupleToMasterPoints[couplePointi];
|
||||
|
||||
forAll(masterPoints, j)
|
||||
{
|
||||
label mesh0Pointi = masterPatch.meshPoints()[masterPoints[j]];
|
||||
from0ToAllPoints[mesh0Pointi] = allPointi;
|
||||
allPoints[allPointi] = mesh0.points()[mesh0Pointi];
|
||||
}
|
||||
|
||||
const labelList& slavePoints = cutToSlavePoints[i];
|
||||
const labelList& slavePoints = coupleToSlavePoints[couplePointi];
|
||||
|
||||
forAll(slavePoints, j)
|
||||
{
|
||||
label mesh1Pointi = slavePatch.meshPoints()[slavePoints[j]];
|
||||
from1ToAllPoints[mesh1Pointi] = allPointi;
|
||||
allPoints[allPointi] = mesh1.points()[mesh1Pointi];
|
||||
}
|
||||
|
||||
allPointi++;
|
||||
}
|
||||
}
|
||||
@ -635,14 +542,9 @@ void Foam::polyMeshAdder::mergePrimitives
|
||||
|
||||
// Copy coupled faces. Every coupled face has an equivalent master and
|
||||
// slave. Also uncount as boundary faces all the newly coupled faces.
|
||||
const labelList& cutToMasterFaces = coupleInfo.cutToMasterFaces();
|
||||
const labelList& cutToSlaveFaces = coupleInfo.cutToSlaveFaces();
|
||||
|
||||
forAll(cutFaces, i)
|
||||
forAll(masterPatch, coupleFacei)
|
||||
{
|
||||
label masterFacei = cutToMasterFaces[i];
|
||||
|
||||
label mesh0Facei = masterPatch.addressing()[masterFacei];
|
||||
const label mesh0Facei = masterPatch.addressing()[coupleFacei];
|
||||
|
||||
if (from0ToAllFaces[mesh0Facei] == -1)
|
||||
{
|
||||
@ -654,9 +556,7 @@ void Foam::polyMeshAdder::mergePrimitives
|
||||
nFacesPerPatch[patch0]--;
|
||||
}
|
||||
|
||||
label slaveFacei = cutToSlaveFaces[i];
|
||||
|
||||
label mesh1Facei = slavePatch.addressing()[slaveFacei];
|
||||
const label mesh1Facei = slavePatch.addressing()[coupleFacei];
|
||||
|
||||
if (from1ToAllFaces[mesh1Facei] == -1)
|
||||
{
|
||||
@ -668,7 +568,7 @@ void Foam::polyMeshAdder::mergePrimitives
|
||||
|
||||
// Copy cut face (since cutPoints are copied first no renumbering
|
||||
// necessary)
|
||||
allFaces[allFacei] = cutFaces[i];
|
||||
allFaces[allFacei] = coupleInfo.coupleFace(coupleFacei);
|
||||
allOwner[allFacei] = mesh0.faceOwner()[mesh0Facei];
|
||||
allNeighbour[allFacei] = mesh1.faceOwner()[mesh1Facei] + mesh0.nCells();
|
||||
|
||||
@ -750,85 +650,6 @@ void Foam::polyMeshAdder::mergePrimitives
|
||||
allOwner.setSize(allFacei);
|
||||
allNeighbour.setSize(allFacei);
|
||||
|
||||
|
||||
// So now we have all ok for one-to-one mapping.
|
||||
// For split slace faces:
|
||||
// - mesh consistent with slave side
|
||||
// - mesh not consistent with owner side. It is not zipped up, the
|
||||
// original faces need edges split.
|
||||
|
||||
// Use brute force to prevent having to calculate addressing:
|
||||
// - get map from master edge to split edges.
|
||||
// - check all faces to find any edge that is split.
|
||||
{
|
||||
// From two cut-points to labels of cut-points in between.
|
||||
// (in order: from e[0] to e[1]
|
||||
const edgeLookup& cutEdgeToPoints = coupleInfo.cutEdgeToPoints();
|
||||
|
||||
// Get map of master face (in mesh labels) that are in cut. These faces
|
||||
// do not need to be renumbered.
|
||||
labelHashSet masterCutFaces(cutToMasterFaces.size());
|
||||
forAll(cutToMasterFaces, i)
|
||||
{
|
||||
label meshFacei = masterPatch.addressing()[cutToMasterFaces[i]];
|
||||
|
||||
masterCutFaces.insert(meshFacei);
|
||||
}
|
||||
|
||||
DynamicList<label> workFace(100);
|
||||
|
||||
forAll(from0ToAllFaces, face0)
|
||||
{
|
||||
if (!masterCutFaces.found(face0))
|
||||
{
|
||||
label allFacei = from0ToAllFaces[face0];
|
||||
|
||||
insertVertices
|
||||
(
|
||||
cutEdgeToPoints,
|
||||
masterPatch.meshPointMap(),
|
||||
coupleInfo.masterToCutPoints(),
|
||||
mesh0.faces()[face0],
|
||||
|
||||
workFace,
|
||||
allFaces[allFacei]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Same for slave face
|
||||
|
||||
labelHashSet slaveCutFaces(cutToSlaveFaces.size());
|
||||
forAll(cutToSlaveFaces, i)
|
||||
{
|
||||
label meshFacei = slavePatch.addressing()[cutToSlaveFaces[i]];
|
||||
|
||||
slaveCutFaces.insert(meshFacei);
|
||||
}
|
||||
|
||||
forAll(from1ToAllFaces, face1)
|
||||
{
|
||||
if (!slaveCutFaces.found(face1))
|
||||
{
|
||||
label allFacei = from1ToAllFaces[face1];
|
||||
|
||||
insertVertices
|
||||
(
|
||||
cutEdgeToPoints,
|
||||
slavePatch.meshPointMap(),
|
||||
coupleInfo.slaveToCutPoints(),
|
||||
mesh1.faces()[face1],
|
||||
|
||||
workFace,
|
||||
allFaces[allFacei]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now we have a full facelist and owner/neighbour addressing.
|
||||
|
||||
|
||||
// Cells
|
||||
// ~~~~~
|
||||
|
||||
@ -1603,7 +1424,7 @@ Foam::autoPtr<Foam::polyMesh> Foam::polyMeshAdder::add
|
||||
fromAllTo1Patches,
|
||||
mesh0.nInternalFaces()
|
||||
+ mesh1.nInternalFaces()
|
||||
+ coupleInfo.cutFaces().size(),
|
||||
+ coupleInfo.masterPatch().size(),
|
||||
nFaces,
|
||||
|
||||
from0ToAllPatches,
|
||||
@ -1998,310 +1819,4 @@ Foam::autoPtr<Foam::mapAddedPolyMesh> Foam::polyMeshAdder::add
|
||||
}
|
||||
|
||||
|
||||
Foam::Map<Foam::label> Foam::polyMeshAdder::findSharedPoints
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const scalar mergeDist
|
||||
)
|
||||
{
|
||||
const labelList& sharedPointLabels = mesh.globalData().sharedPointLabels();
|
||||
const labelList& sharedPointAddr = mesh.globalData().sharedPointAddr();
|
||||
|
||||
// Because of adding the missing pieces e.g. when redistributing a mesh
|
||||
// it can be that there are multiple points on the same processor that
|
||||
// refer to the same shared point.
|
||||
|
||||
// Invert point-to-shared addressing
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Map<labelList> sharedToMesh(sharedPointLabels.size());
|
||||
|
||||
label nMultiple = 0;
|
||||
|
||||
forAll(sharedPointLabels, i)
|
||||
{
|
||||
label pointi = sharedPointLabels[i];
|
||||
|
||||
label sharedI = sharedPointAddr[i];
|
||||
|
||||
Map<labelList>::iterator iter = sharedToMesh.find(sharedI);
|
||||
|
||||
if (iter != sharedToMesh.end())
|
||||
{
|
||||
// sharedI already used by other point. Add this one.
|
||||
|
||||
nMultiple++;
|
||||
|
||||
labelList& connectedPointLabels = iter();
|
||||
|
||||
label sz = connectedPointLabels.size();
|
||||
|
||||
// Check just to make sure.
|
||||
if (findIndex(connectedPointLabels, pointi) != -1)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Duplicate point in sharedPoint addressing." << endl
|
||||
<< "When trying to add point " << pointi << " on shared "
|
||||
<< sharedI << " with connected points "
|
||||
<< connectedPointLabels
|
||||
<< abort(FatalError);
|
||||
}
|
||||
|
||||
connectedPointLabels.setSize(sz+1);
|
||||
connectedPointLabels[sz] = pointi;
|
||||
}
|
||||
else
|
||||
{
|
||||
sharedToMesh.insert(sharedI, labelList(1, pointi));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Assign single master for every shared with multiple geometric points
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Map<label> pointToMaster(nMultiple);
|
||||
|
||||
forAllConstIter(Map<labelList>, sharedToMesh, iter)
|
||||
{
|
||||
const labelList& connectedPointLabels = iter();
|
||||
|
||||
// Pout<< "For shared:" << iter.key()
|
||||
// << " found points:" << connectedPointLabels
|
||||
// << " at coords:"
|
||||
// << pointField(mesh.points(), connectedPointLabels) << endl;
|
||||
|
||||
if (connectedPointLabels.size() > 1)
|
||||
{
|
||||
const pointField connectedPoints
|
||||
(
|
||||
mesh.points(),
|
||||
connectedPointLabels
|
||||
);
|
||||
|
||||
labelList toMergedPoints;
|
||||
label nUnique = Foam::mergePoints
|
||||
(
|
||||
connectedPoints,
|
||||
mergeDist,
|
||||
false,
|
||||
toMergedPoints
|
||||
);
|
||||
|
||||
if (nUnique < connectedPoints.size())
|
||||
{
|
||||
// Invert toMergedPoints
|
||||
const labelListList mergeSets
|
||||
(
|
||||
invertOneToMany
|
||||
(
|
||||
nUnique,
|
||||
toMergedPoints
|
||||
)
|
||||
);
|
||||
|
||||
// Find master for valid merges
|
||||
forAll(mergeSets, setI)
|
||||
{
|
||||
const labelList& mergeSet = mergeSets[setI];
|
||||
|
||||
if (mergeSet.size() > 1)
|
||||
{
|
||||
// Pick lowest numbered point
|
||||
label masterPointi = labelMax;
|
||||
|
||||
forAll(mergeSet, i)
|
||||
{
|
||||
label pointi = connectedPointLabels[mergeSet[i]];
|
||||
|
||||
masterPointi = min(masterPointi, pointi);
|
||||
}
|
||||
|
||||
forAll(mergeSet, i)
|
||||
{
|
||||
label pointi = connectedPointLabels[mergeSet[i]];
|
||||
|
||||
// Pout<< "Merging point " << pointi
|
||||
// << " at " << mesh.points()[pointi]
|
||||
// << " into master point "
|
||||
// << masterPointi
|
||||
// << " at " << mesh.points()[masterPointi]
|
||||
// << endl;
|
||||
|
||||
pointToMaster.insert(pointi, masterPointi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- Old: geometric merging. Causes problems for two close shared points.
|
||||
// labelList sharedToMerged;
|
||||
// label nUnique = Foam::mergePoints
|
||||
//(
|
||||
// pointField
|
||||
// (
|
||||
// mesh.points(),
|
||||
// sharedPointLabels
|
||||
// ),
|
||||
// mergeDist,
|
||||
// false,
|
||||
// sharedToMerged
|
||||
//);
|
||||
//
|
||||
//// Find out which sets of points get merged and create a map from
|
||||
//// mesh point to unique point.
|
||||
//
|
||||
// Map<label> pointToMaster(10*sharedToMerged.size());
|
||||
//
|
||||
// if (nUnique < sharedPointLabels.size())
|
||||
//{
|
||||
// labelListList mergeSets
|
||||
// (
|
||||
// invertOneToMany
|
||||
// (
|
||||
// sharedToMerged.size(),
|
||||
// sharedToMerged
|
||||
// )
|
||||
// );
|
||||
//
|
||||
// label nMergeSets = 0;
|
||||
//
|
||||
// forAll(mergeSets, setI)
|
||||
// {
|
||||
// const labelList& mergeSet = mergeSets[setI];
|
||||
//
|
||||
// if (mergeSet.size() > 1)
|
||||
// {
|
||||
// // Take as master the shared point with the lowest mesh
|
||||
// // point label. (rather arbitrarily - could use max or
|
||||
// // any other one of the points)
|
||||
//
|
||||
// nMergeSets++;
|
||||
//
|
||||
// label masterI = labelMax;
|
||||
//
|
||||
// forAll(mergeSet, i)
|
||||
// {
|
||||
// label sharedI = mergeSet[i];
|
||||
//
|
||||
// masterI = min(masterI, sharedPointLabels[sharedI]);
|
||||
// }
|
||||
//
|
||||
// forAll(mergeSet, i)
|
||||
// {
|
||||
// label sharedI = mergeSet[i];
|
||||
//
|
||||
// pointToMaster.insert(sharedPointLabels[sharedI], masterI);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // if (debug)
|
||||
// //{
|
||||
// // Pout<< "polyMeshAdder : merging:"
|
||||
// // << pointToMaster.size() << " into " << nMergeSets
|
||||
// // << " sets." << endl;
|
||||
// //}
|
||||
//}
|
||||
|
||||
return pointToMaster;
|
||||
}
|
||||
|
||||
|
||||
void Foam::polyMeshAdder::mergePoints
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const Map<label>& pointToMaster,
|
||||
polyTopoChange& meshMod
|
||||
)
|
||||
{
|
||||
// Remove all non-master points.
|
||||
forAll(mesh.points(), pointi)
|
||||
{
|
||||
Map<label>::const_iterator iter = pointToMaster.find(pointi);
|
||||
|
||||
if (iter != pointToMaster.end())
|
||||
{
|
||||
if (iter() != pointi)
|
||||
{
|
||||
meshMod.removePoint(pointi, iter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modify faces for points. Note: could use pointFaces here but want to
|
||||
// avoid addressing calculation.
|
||||
const faceList& faces = mesh.faces();
|
||||
|
||||
forAll(faces, facei)
|
||||
{
|
||||
const face& f = faces[facei];
|
||||
|
||||
bool hasMerged = false;
|
||||
|
||||
forAll(f, fp)
|
||||
{
|
||||
label pointi = f[fp];
|
||||
|
||||
Map<label>::const_iterator iter = pointToMaster.find(pointi);
|
||||
|
||||
if (iter != pointToMaster.end())
|
||||
{
|
||||
if (iter() != pointi)
|
||||
{
|
||||
hasMerged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMerged)
|
||||
{
|
||||
face newF(f);
|
||||
|
||||
forAll(f, fp)
|
||||
{
|
||||
label pointi = f[fp];
|
||||
|
||||
Map<label>::const_iterator iter = pointToMaster.find(pointi);
|
||||
|
||||
if (iter != pointToMaster.end())
|
||||
{
|
||||
newF[fp] = iter();
|
||||
}
|
||||
}
|
||||
|
||||
label patchID = mesh.boundaryMesh().whichPatch(facei);
|
||||
label nei = (patchID == -1 ? mesh.faceNeighbour()[facei] : -1);
|
||||
label zoneID = mesh.faceZones().whichZone(facei);
|
||||
bool zoneFlip = false;
|
||||
|
||||
if (zoneID >= 0)
|
||||
{
|
||||
const faceZone& fZone = mesh.faceZones()[zoneID];
|
||||
zoneFlip = fZone.flipMap()[fZone.whichFace(facei)];
|
||||
}
|
||||
|
||||
meshMod.setAction
|
||||
(
|
||||
polyModifyFace
|
||||
(
|
||||
newF, // modified face
|
||||
facei, // label of face
|
||||
mesh.faceOwner()[facei], // owner
|
||||
nei, // neighbour
|
||||
false, // face flip
|
||||
patchID, // patch for face
|
||||
false, // remove from zone
|
||||
zoneID, // zone for face
|
||||
zoneFlip // face flip in zone
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -59,7 +59,6 @@ class polyTopoChange;
|
||||
|
||||
class polyMeshAdder
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
// Private Member Functions
|
||||
@ -89,6 +88,7 @@ private:
|
||||
|
||||
//- Get starts of patches
|
||||
static labelList getPatchStarts(const polyBoundaryMesh&);
|
||||
|
||||
//- Get sizes of patches
|
||||
static labelList getPatchSizes(const polyBoundaryMesh&);
|
||||
|
||||
@ -117,19 +117,6 @@ private:
|
||||
const labelList& neighbour
|
||||
);
|
||||
|
||||
//- Extends face f with split points. cutEdgeToPoints gives for every
|
||||
// edge the points introduced in between the endpoints.
|
||||
static void insertVertices
|
||||
(
|
||||
const edgeLookup& cutEdgeToPoints,
|
||||
const Map<label>& meshToMaster,
|
||||
const labelList& masterToCutPoints,
|
||||
const face& masterFace,
|
||||
|
||||
DynamicList<label>& workFace,
|
||||
face& f
|
||||
);
|
||||
|
||||
//- Merges primitives of two meshes.
|
||||
static void mergePrimitives
|
||||
(
|
||||
@ -250,7 +237,6 @@ public:
|
||||
|
||||
// Member Functions
|
||||
|
||||
|
||||
//- Add two polyMeshes. Returns new polyMesh and map construct.
|
||||
static autoPtr<polyMesh> add
|
||||
(
|
||||
@ -269,32 +255,6 @@ public:
|
||||
const faceCoupleInfo& coupleInfo,
|
||||
const bool validBoundary = true
|
||||
);
|
||||
|
||||
// Point merging
|
||||
|
||||
//- Find topologically and geometrically shared points.
|
||||
//
|
||||
// - should only be called for parallel correct mesh
|
||||
// (since uses mesh.globalData)
|
||||
// - returns Map from point to master point (all in mesh point
|
||||
// labels) for any sets of points that need to be merged.
|
||||
static Map<label> findSharedPoints
|
||||
(
|
||||
const polyMesh&,
|
||||
const scalar mergeTol
|
||||
);
|
||||
|
||||
//- Helper: Merge points.
|
||||
//
|
||||
// - Gets map from point to destination point
|
||||
// - Removes all points that don't map to themselves
|
||||
// - Modifies all faces that use the points to be removed.
|
||||
static void mergePoints
|
||||
(
|
||||
const polyMesh&,
|
||||
const Map<label>& pointToMaster,
|
||||
polyTopoChange& meshMod
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user