diff --git a/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C b/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C index 01f2d864c1..82b9fcaf64 100644 --- a/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C +++ b/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C @@ -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" @@ -115,6 +124,7 @@ Description #include "mappedWallPolyPatch.H" #include "fvMeshTools.H" #include "processorMeshes.H" +#include "faceAreaWeightAMI2D.H" using namespace Foam; @@ -296,12 +306,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, @@ -340,15 +453,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) { @@ -540,6 +654,8 @@ autoPtr createRegionMesh const labelList& cellRegion, const label regionI, const word& regionName, + const word& AMIMethod, + const labelList& matchPatchIDs, // Interface info const labelList& interfacePatches, const labelList& faceToInterface, @@ -551,15 +667,16 @@ autoPtr 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); @@ -578,20 +695,16 @@ autoPtr 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 @@ -638,6 +751,62 @@ autoPtr 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