ENH: splitMeshRegions: support automatic patching. Fixes #2251

This commit is contained in:
mattijs
2021-10-25 19:20:38 +01:00
parent eb2b9b2823
commit 25ff1d7d6f

View File

@ -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,