mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: splitMeshRegions: support automatic patching. Fixes #2251
This commit is contained in:
@ -43,8 +43,9 @@ Description
|
||||
- volScalarField with regions as different scalars (-detectOnly)
|
||||
or
|
||||
- mesh with multiple regions and mapped patches. These patches
|
||||
either cover the whole interface between two region (default) or
|
||||
only part according to faceZones (-useFaceZones)
|
||||
either cover the whole interface between two region (default),
|
||||
only part according to faceZones (-useFaceZones) or be auto-generated
|
||||
according to an AMI method (see below)
|
||||
or
|
||||
- mesh with cells put into cellZones (-makeCellZones)
|
||||
|
||||
@ -98,6 +99,14 @@ Description
|
||||
- boundaryRegionAddressing : for every patch in this region the
|
||||
patch in the original mesh (or -1 if added patch)
|
||||
|
||||
- auto-generate patches using AMI area-overlap detection. This requires a
|
||||
patchSet to apply it to and an optional AMIMethod (default is
|
||||
faceAreaWeightAMI2D).
|
||||
-autoPatch '("solid*")'
|
||||
-AMIMethod faceAreaWeightAMI2D
|
||||
Any mapped patch thus generated should probably use the
|
||||
nearestPatchFaceAMI sampling method.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
@ -116,6 +125,7 @@ Description
|
||||
#include "fvMeshTools.H"
|
||||
#include "zeroGradientFvPatchFields.H"
|
||||
#include "processorMeshes.H"
|
||||
#include "faceAreaWeightAMI2D.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
@ -317,12 +327,115 @@ void addToInterface
|
||||
}
|
||||
|
||||
|
||||
labelList getMinBoundaryValue
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const word& AMIMethod,
|
||||
const labelList& matchPatchIDs,
|
||||
const labelList& cellRegion
|
||||
)
|
||||
{
|
||||
// Neighbour cellRegion.
|
||||
labelList coupledRegion(mesh.nBoundaryFaces());
|
||||
|
||||
forAll(coupledRegion, i)
|
||||
{
|
||||
label celli = mesh.faceOwner()[i+mesh.nInternalFaces()];
|
||||
coupledRegion[i] = cellRegion[celli];
|
||||
}
|
||||
syncTools::swapBoundaryFaceList(mesh, coupledRegion);
|
||||
|
||||
// Add approximate matches
|
||||
forAll(matchPatchIDs, i)
|
||||
{
|
||||
const label patchi = matchPatchIDs[i];
|
||||
const auto& pp = mesh.boundaryMesh()[patchi];
|
||||
|
||||
for (label j = i+1; j < matchPatchIDs.size(); ++j)
|
||||
{
|
||||
const label nbrPatchi = matchPatchIDs[j];
|
||||
const auto& nbrPp = mesh.boundaryMesh()[nbrPatchi];
|
||||
|
||||
// Use AMI to try and find matches
|
||||
auto AMPtr(AMIInterpolation::New(AMIMethod));
|
||||
|
||||
AMPtr->calculate(pp, nbrPp, nullptr);
|
||||
if
|
||||
(
|
||||
gAverage(AMPtr->tgtWeightsSum()) > SMALL
|
||||
|| gAverage(AMPtr->srcWeightsSum()) > SMALL
|
||||
)
|
||||
{
|
||||
// Pull remote data local
|
||||
labelList thisDecomp(pp.size(), labelMax);
|
||||
AMPtr->interpolateToSource
|
||||
(
|
||||
labelList(cellRegion, nbrPp.faceCells()),
|
||||
[]
|
||||
(
|
||||
label& res,
|
||||
const label facei,
|
||||
const label& fld,
|
||||
const scalar& w
|
||||
)
|
||||
{
|
||||
res = min(res, fld);
|
||||
},
|
||||
thisDecomp,
|
||||
thisDecomp // used in case of low-weight-corr
|
||||
);
|
||||
|
||||
// Put thisDecomp into coupledRegion. Check for unmatched faces.
|
||||
forAll(thisDecomp, i)
|
||||
{
|
||||
if (thisDecomp[i] != labelMax)
|
||||
{
|
||||
coupledRegion[pp.offset()+i] = thisDecomp[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
labelList nbrDecomp(nbrPp.size(), labelMax);
|
||||
AMPtr->interpolateToTarget
|
||||
(
|
||||
labelList(cellRegion, pp.faceCells()), //thisDecomp,
|
||||
[]
|
||||
(
|
||||
label& res,
|
||||
const label facei,
|
||||
const label& fld,
|
||||
const scalar& w
|
||||
)
|
||||
{
|
||||
res = min(res, fld);
|
||||
},
|
||||
nbrDecomp,
|
||||
nbrDecomp // used in case of low-weight-corr
|
||||
);
|
||||
|
||||
// Put nbrDecomp into coupledRegion. Check for unmatched faces/
|
||||
forAll(nbrDecomp, i)
|
||||
{
|
||||
if (nbrDecomp[i] != labelMax)
|
||||
{
|
||||
coupledRegion[nbrPp.offset()+i] = nbrDecomp[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return coupledRegion;
|
||||
}
|
||||
|
||||
|
||||
// Get region-region interface name and sizes.
|
||||
// Returns interfaces as straight list for looping in identical order.
|
||||
void getInterfaceSizes
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const bool useFaceZones,
|
||||
const word& AMIMethod,
|
||||
const labelList& matchPatchIDs,
|
||||
const labelList& cellRegion,
|
||||
const wordList& regionNames,
|
||||
|
||||
@ -361,15 +474,16 @@ void getInterfaceSizes
|
||||
// Boundary faces
|
||||
// ~~~~~~~~~~~~~~
|
||||
|
||||
// Neighbour cellRegion.
|
||||
labelList coupledRegion(mesh.nBoundaryFaces());
|
||||
|
||||
forAll(coupledRegion, i)
|
||||
{
|
||||
label celli = mesh.faceOwner()[i+mesh.nInternalFaces()];
|
||||
coupledRegion[i] = cellRegion[celli];
|
||||
}
|
||||
syncTools::swapBoundaryFaceList(mesh, coupledRegion);
|
||||
const labelList coupledRegion
|
||||
(
|
||||
getMinBoundaryValue
|
||||
(
|
||||
mesh,
|
||||
AMIMethod,
|
||||
matchPatchIDs,
|
||||
cellRegion
|
||||
)
|
||||
);
|
||||
|
||||
forAll(coupledRegion, i)
|
||||
{
|
||||
@ -583,6 +697,8 @@ autoPtr<mapPolyMesh> createRegionMesh
|
||||
const labelList& cellRegion,
|
||||
const label regionI,
|
||||
const word& regionName,
|
||||
const word& AMIMethod,
|
||||
const labelList& matchPatchIDs,
|
||||
// Interface info
|
||||
const labelList& interfacePatches,
|
||||
const labelList& faceToInterface,
|
||||
@ -594,15 +710,16 @@ autoPtr<mapPolyMesh> createRegionMesh
|
||||
fvMeshTools::createDummyFvMeshFiles(mesh, regionName, true);
|
||||
|
||||
// Neighbour cellRegion.
|
||||
labelList coupledRegion(mesh.nBoundaryFaces());
|
||||
|
||||
forAll(coupledRegion, i)
|
||||
{
|
||||
label celli = mesh.faceOwner()[i+mesh.nInternalFaces()];
|
||||
coupledRegion[i] = cellRegion[celli];
|
||||
}
|
||||
syncTools::swapBoundaryFaceList(mesh, coupledRegion);
|
||||
|
||||
const labelList coupledRegion
|
||||
(
|
||||
getMinBoundaryValue
|
||||
(
|
||||
mesh,
|
||||
AMIMethod,
|
||||
matchPatchIDs,
|
||||
cellRegion
|
||||
)
|
||||
);
|
||||
|
||||
// Topology change container. Start off from existing mesh.
|
||||
polyTopoChange meshMod(mesh);
|
||||
@ -621,20 +738,16 @@ autoPtr<mapPolyMesh> createRegionMesh
|
||||
labelList exposedPatchIDs(exposedFaces.size());
|
||||
forAll(exposedFaces, i)
|
||||
{
|
||||
label facei = exposedFaces[i];
|
||||
label interfacei = faceToInterface[facei];
|
||||
const label facei = exposedFaces[i];
|
||||
const label interfacei = faceToInterface[facei];
|
||||
|
||||
label ownRegion = cellRegion[mesh.faceOwner()[facei]];
|
||||
label neiRegion = -1;
|
||||
|
||||
if (mesh.isInternalFace(facei))
|
||||
{
|
||||
neiRegion = cellRegion[mesh.faceNeighbour()[facei]];
|
||||
}
|
||||
else
|
||||
{
|
||||
neiRegion = coupledRegion[facei-mesh.nInternalFaces()];
|
||||
}
|
||||
const label ownRegion = cellRegion[mesh.faceOwner()[facei]];
|
||||
const label neiRegion
|
||||
(
|
||||
mesh.isInternalFace(facei)
|
||||
? cellRegion[mesh.faceNeighbour()[facei]]
|
||||
: coupledRegion[facei-mesh.nInternalFaces()]
|
||||
);
|
||||
|
||||
|
||||
// Check which side is being kept - determines which of the two
|
||||
@ -681,6 +794,62 @@ autoPtr<mapPolyMesh> createRegionMesh
|
||||
meshMod
|
||||
);
|
||||
|
||||
|
||||
// Do re-patching on non-removed cells ourselves. These are not exposed
|
||||
// faces but are boundary faces
|
||||
for (label bFacei = 0; bFacei < mesh.nBoundaryFaces(); bFacei++)
|
||||
{
|
||||
const label facei = mesh.nInternalFaces()+bFacei;
|
||||
|
||||
if (!meshMod.faceRemoved(facei))
|
||||
{
|
||||
const label interfacei = faceToInterface[facei];
|
||||
const label ownRegion = cellRegion[mesh.faceOwner()[facei]];
|
||||
const label neiRegion = coupledRegion[bFacei];
|
||||
|
||||
label exposedPatchID = -1;
|
||||
if (ownRegion == regionI)
|
||||
{
|
||||
if (regionI < neiRegion)
|
||||
{
|
||||
exposedPatchID = interfacePatches[interfacei];
|
||||
}
|
||||
else if (regionI > neiRegion)
|
||||
{
|
||||
exposedPatchID = interfacePatches[interfacei]+1;
|
||||
}
|
||||
}
|
||||
else if (neiRegion == regionI)
|
||||
{
|
||||
if (regionI < ownRegion)
|
||||
{
|
||||
exposedPatchID = interfacePatches[interfacei];
|
||||
}
|
||||
else if (regionI > ownRegion)
|
||||
{
|
||||
exposedPatchID = interfacePatches[interfacei]+1;
|
||||
}
|
||||
}
|
||||
|
||||
if (exposedPatchID != -1)
|
||||
{
|
||||
// In-place modify the patch
|
||||
DynamicList<label>& patchID =
|
||||
const_cast<DynamicList<label>&>(meshMod.region());
|
||||
|
||||
//Pout<< "For face:" << facei
|
||||
// << " on interface:" << interfacei
|
||||
// << " modifying from own:" << meshMod.faceOwner()[facei]
|
||||
// << " nei:" << meshMod.faceNeighbour()[facei]
|
||||
// << " verts:" << meshMod.faces()[facei]
|
||||
// << " patch " << patchID[facei]
|
||||
// << " to " << exposedPatchID << endl;
|
||||
patchID[facei] = exposedPatchID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
autoPtr<mapPolyMesh> map = meshMod.makeMesh
|
||||
(
|
||||
newMesh,
|
||||
@ -705,6 +874,8 @@ void createAndWriteRegion
|
||||
const labelList& cellRegion,
|
||||
const wordList& regionNames,
|
||||
const bool prefixRegion,
|
||||
const word& AMIMethod,
|
||||
const labelList& matchPatchIDs,
|
||||
const labelList& faceToInterface,
|
||||
const labelList& interfacePatches,
|
||||
const label regionI,
|
||||
@ -721,6 +892,8 @@ void createAndWriteRegion
|
||||
cellRegion,
|
||||
regionI,
|
||||
regionNames[regionI],
|
||||
AMIMethod,
|
||||
matchPatchIDs,
|
||||
interfacePatches,
|
||||
faceToInterface,
|
||||
newMesh
|
||||
@ -1019,6 +1192,7 @@ labelList addRegionPatches
|
||||
const wordList& regionNames,
|
||||
const edgeList& interfaces,
|
||||
const List<Pair<word>>& interfaceNames
|
||||
//const List<mappedPatchBase::sampleMode>& interfaceModes
|
||||
)
|
||||
{
|
||||
Info<< nl << "Adding patches" << nl << endl;
|
||||
@ -1042,7 +1216,7 @@ labelList addRegionPatches
|
||||
0, // overridden
|
||||
0, // overridden
|
||||
regionNames[e[1]], // sampleRegion
|
||||
mappedPatchBase::NEARESTPATCHFACE,
|
||||
mappedPatchBase::NEARESTPATCHFACE, //interfaceModes[interI]
|
||||
names[1], // samplePatch
|
||||
point::zero, // offset
|
||||
mesh.boundaryMesh()
|
||||
@ -1064,7 +1238,7 @@ labelList addRegionPatches
|
||||
0,
|
||||
0,
|
||||
regionNames[e[0]], // sampleRegion
|
||||
mappedPatchBase::NEARESTPATCHFACE,
|
||||
mappedPatchBase::NEARESTPATCHFACE, //interfaceModes[interI]
|
||||
names[0],
|
||||
point::zero, // offset
|
||||
mesh.boundaryMesh()
|
||||
@ -1521,6 +1695,18 @@ int main(int argc, char *argv[])
|
||||
"useFaceZones",
|
||||
"Use faceZones to patch inter-region faces instead of single patch"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"autoPatch",
|
||||
"lists of patches",
|
||||
"Find overlapping faces to auto-generate interface patches"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"AMIMethod",
|
||||
"word",
|
||||
"type of AMI matching method"
|
||||
);
|
||||
argList::addBoolOption
|
||||
(
|
||||
"prefixRegion",
|
||||
@ -1556,6 +1742,16 @@ int main(int argc, char *argv[])
|
||||
const bool useFaceZones = args.found("useFaceZones");
|
||||
const bool prefixRegion = args.found("prefixRegion");
|
||||
|
||||
labelList matchPatchIDs;
|
||||
word AMIMethod(faceAreaWeightAMI2D::typeName);
|
||||
if (args.found("autoPatch"))
|
||||
{
|
||||
const wordRes patchNames(args.getList<wordRe>("autoPatch"));
|
||||
//v2112: matchPatchIDs = mesh.boundaryMesh().indices(patchNames);
|
||||
//v2106:
|
||||
matchPatchIDs = mesh.boundaryMesh().patchSet(patchNames).sortedToc();
|
||||
args.readIfPresent("AMIMethod", AMIMethod);
|
||||
}
|
||||
|
||||
if
|
||||
(
|
||||
@ -1585,6 +1781,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
if (matchPatchIDs.size())
|
||||
{
|
||||
Info<< "Auto-detecting matching faces out of patches "
|
||||
<< UIndirectList<word>(mesh.boundaryMesh().names(), matchPatchIDs)
|
||||
<< nl << endl;
|
||||
}
|
||||
|
||||
|
||||
if (insidePoint && largestOnly)
|
||||
{
|
||||
@ -1968,6 +2171,8 @@ int main(int argc, char *argv[])
|
||||
(
|
||||
mesh,
|
||||
useFaceZones,
|
||||
AMIMethod,
|
||||
matchPatchIDs,
|
||||
cellRegion,
|
||||
regionNames,
|
||||
|
||||
@ -2147,6 +2352,7 @@ int main(int argc, char *argv[])
|
||||
regionNames,
|
||||
interfaces,
|
||||
interfaceNames
|
||||
//interfaceModes
|
||||
)
|
||||
);
|
||||
|
||||
@ -2199,6 +2405,8 @@ int main(int argc, char *argv[])
|
||||
cellRegion,
|
||||
regionNames,
|
||||
prefixRegion,
|
||||
AMIMethod,
|
||||
matchPatchIDs,
|
||||
faceToInterface,
|
||||
interfacePatches,
|
||||
regionI,
|
||||
@ -2220,6 +2428,8 @@ int main(int argc, char *argv[])
|
||||
cellRegion,
|
||||
regionNames,
|
||||
prefixRegion,
|
||||
AMIMethod,
|
||||
matchPatchIDs,
|
||||
faceToInterface,
|
||||
interfacePatches,
|
||||
regionI,
|
||||
@ -2241,6 +2451,8 @@ int main(int argc, char *argv[])
|
||||
cellRegion,
|
||||
regionNames,
|
||||
prefixRegion,
|
||||
AMIMethod,
|
||||
matchPatchIDs,
|
||||
faceToInterface,
|
||||
interfacePatches,
|
||||
regionI,
|
||||
|
||||
Reference in New Issue
Block a user