diff --git a/applications/utilities/parallelProcessing/reconstructParMesh/Make/options b/applications/utilities/parallelProcessing/reconstructParMesh/Make/options index 792a51bf7fce4e4db070d172f67aac88e26b0fc4..943d00d5f36b3ae38612c028bb06b2c334b82c5e 100644 --- a/applications/utilities/parallelProcessing/reconstructParMesh/Make/options +++ b/applications/utilities/parallelProcessing/reconstructParMesh/Make/options @@ -1,9 +1,12 @@ EXE_INC = \ -I$(LIB_SRC)/finiteVolume/lnInclude \ -I$(LIB_SRC)/meshTools/lnInclude \ + -I$(LIB_SRC)/finiteArea/lnInclude \ -I$(LIB_SRC)/dynamicMesh/lnInclude EXE_LIBS = \ -lfiniteVolume \ -lmeshTools \ + -lfiniteArea \ + -lfaReconstruct \ -ldynamicMesh diff --git a/applications/utilities/parallelProcessing/reconstructParMesh/reconstructParMesh.C b/applications/utilities/parallelProcessing/reconstructParMesh/reconstructParMesh.C index c77a2742a22609f9ae1313edd1a42ffa6abe997b..d5b9c2ef9c906b2ce3d2694580abebd81f01a1d7 100644 --- a/applications/utilities/parallelProcessing/reconstructParMesh/reconstructParMesh.C +++ b/applications/utilities/parallelProcessing/reconstructParMesh/reconstructParMesh.C @@ -73,6 +73,9 @@ Usage #include "regionProperties.H" #include "fvMeshTools.H" +#include "faMeshReconstructor.H" +#include "ignoreFaPatch.H" + using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -573,6 +576,160 @@ void printWarning() } +// Used to determine the correspondence between the edges. +// See faMeshReconstructor::calcAddressing +void determineFaEdgeMapping +( + const uindirectPrimitivePatch& onePatch,// reconstructed faMesh patch + const PtrList<faMesh>& procFaMeshes, // individual faMeshes + const labelListList& pointProcAddressing, // procPolyMesh to reconstructed + + labelListList& faEdgeProcAddressing +) +{ + // Determines ordering from faMesh to onePatch (= recsontructed faMesh) + + // From two polyMesh points to patch-edge label + EdgeMap<label> pointsToOnePatchEdge(onePatch.nEdges()); + { + const edgeList& edges = onePatch.edges(); + const labelList& mp = onePatch.meshPoints(); + + forAll(edges, edgei) + { + const edge meshE(mp, edges[edgei]); + pointsToOnePatchEdge.insert(meshE, edgei); + } + } + + // Now we can create the mapping from patch-edge on processor + // to patch-edge on onePatch + + faEdgeProcAddressing.resize_nocopy(procFaMeshes.size()); + forAll(procFaMeshes, proci) + { + const auto& procPatch = procFaMeshes[proci].patch(); + const auto& edges = procPatch.edges(); + const auto& mp = procPatch.meshPoints(); + const auto& ppAddressing = pointProcAddressing[proci]; + + labelList& edgeProcAddr = faEdgeProcAddressing[proci]; + edgeProcAddr.resize_nocopy(edges.size()); + + label edgei = 0; + for + ( + ; + edgei < procPatch.nEdges(); //procPatch.nInternalEdges(); + edgei++ + ) + { + const edge meshE(mp, edges[edgei]); + const edge onePatchE(ppAddressing, meshE); + + edgeProcAddr[edgei] = pointsToOnePatchEdge[onePatchE]; + } + } +} + + +void sortFaEdgeMapping +( + const uindirectPrimitivePatch& onePatch,// reconstructed faMesh patch + const PtrList<faMesh>& procFaMeshes, // individual faMeshes + const labelListList& pointProcAddressing, // procPolyMesh to reconstructed + + labelListList& faEdgeProcAddressing, // per proc the map to the master + labelListList& singlePatchEdgeLabels // per patch the map to the master +) +{ + // From faMeshReconstructor.C - edge shuffling on patches + + Map<label> remapGlobal(2*onePatch.nEdges()); + for (label edgei = 0; edgei < onePatch.nInternalEdges(); ++edgei) + { + remapGlobal.insert(edgei, remapGlobal.size()); + } + + + const faMesh& procMesh0 = procFaMeshes[0]; + const label nNonProcessor = procMesh0.boundary().nNonProcessor(); + + singlePatchEdgeLabels.resize_nocopy(nNonProcessor); + + forAll(singlePatchEdgeLabels, patchi) + { + if (isA<ignoreFaPatch>(procMesh0.boundary()[patchi])) + { + // These are not real edges + continue; + } + + forAll(procFaMeshes, proci) + { + const faMesh& procMesh = procFaMeshes[proci]; + const faPatch& fap = procMesh.boundary()[patchi]; + + labelList patchEdgeLabels(fap.edgeLabels()); + + // Renumber from local edges to global edges (natural order) + for (label& edgeId : patchEdgeLabels) + { + edgeId = faEdgeProcAddressing[proci][edgeId]; + } + + // Combine from all processors + singlePatchEdgeLabels[patchi].append(patchEdgeLabels); + } + + // Sorted order will be the original non-decomposed order + Foam::sort(singlePatchEdgeLabels[patchi]); + + for (const label sortedEdgei : singlePatchEdgeLabels[patchi]) + { + remapGlobal.insert(sortedEdgei, remapGlobal.size()); + } + } + + { + // Use the map to rewrite the local faEdgeProcAddressing + + labelListList newEdgeProcAddr(faEdgeProcAddressing); + + forAll(procFaMeshes, proci) + { + const faMesh& procMesh = procFaMeshes[proci]; + + label edgei = procMesh.nInternalEdges(); + + for (const faPatch& fap : procMesh.boundary()) + { + for (const label patchEdgei : fap.edgeLabels()) + { + const label globalEdgei = + faEdgeProcAddressing[proci][patchEdgei]; + + const auto fnd = remapGlobal.cfind(globalEdgei); + if (fnd.good()) + { + newEdgeProcAddr[proci][edgei] = fnd.val(); + ++edgei; + } + else + { + FatalErrorInFunction + << "Failed to find edge " << globalEdgei + << " this indicates a programming error" << nl + << exit(FatalError); + } + } + } + } + faEdgeProcAddressing = std::move(newEdgeProcAddr); + } +} + + int main(int argc, char *argv[]) { argList::addNote @@ -614,6 +771,12 @@ int main(int argc, char *argv[]) "Write cell distribution as a labelList - for use with 'manual' " "decomposition method or as a volScalarField for post-processing." ); + argList::addBoolOption + ( + "no-finite-area", + "Suppress finiteArea mesh reconstruction", + true // Advanced option + ); #include "addAllRegionOptions.H" @@ -625,7 +788,7 @@ int main(int argc, char *argv[]) const bool fullMatch = args.found("fullMatch"); const bool procMatch = args.found("procMatch"); const bool writeCellDist = args.found("cellDist"); - + const bool doFiniteArea = !args.found("no-finite-area"); const bool writeAddrOnly = args.found("addressing-only"); const scalar mergeTol = @@ -1234,21 +1397,31 @@ int main(int argc, char *argv[]) Info<< "Reconstructing addressing from processor meshes" << " to the newly reconstructed mesh" << nl << endl; + + // Read finite-area + PtrList<faMesh> procFaMeshes(databases.size()); + PtrList<polyMesh> procMeshes(databases.size()); + forAll(databases, proci) { Info<< "Processor " << proci << nl << "Read processor mesh: " << (databases[proci].caseName()/regionDir) << endl; - polyMesh procMesh + procMeshes.set ( - IOobject + proci, + new polyMesh ( - regionName, - databases[proci].timeName(), - databases[proci] + IOobject + ( + regionName, + databases[proci].timeName(), + databases[proci] + ) ) ); + const polyMesh& procMesh = procMeshes[proci]; writeMaps ( @@ -1260,6 +1433,255 @@ int main(int argc, char *argv[]) pointProcAddressing[proci], boundProcAddressing[proci] ); + + + if (doFiniteArea) + { + const word boundaryInst = + procMesh.time().findInstance + ( + procMesh.meshDir(), + "boundary" + ); + + IOobject io + ( + "faBoundary", + boundaryInst, + faMesh::meshDir(procMesh, word::null), + procMesh.time(), + IOobject::READ_IF_PRESENT, + IOobject::NO_WRITE, + IOobject::NO_REGISTER + ); + + if (io.typeHeaderOk<faBoundaryMesh>(true)) + { + // Always based on the volume decomposition! + procFaMeshes.set(proci, new faMesh(procMesh)); + } + } + } + + + // Finite-area mapping + if (doFiniteArea) + { + // Addressing from processor to reconstructed case + labelListList faFaceProcAddressing(nProcs); + labelListList faEdgeProcAddressing(nProcs); + labelListList faPointProcAddressing(nProcs); + labelListList faBoundProcAddressing(nProcs); + + + // boundProcAddressing + // ~~~~~~~~~~~~~~~~~~~ + + forAll(procFaMeshes, proci) + { + const auto& procMesh = procFaMeshes[proci]; + const auto& bm = procMesh.boundary(); + + faBoundProcAddressing[proci] = identity(bm.size()); + // Mark processor patches + for + ( + label patchi = bm.nNonProcessor(); + patchi < bm.size(); + ++patchi + ) + { + faBoundProcAddressing[proci][patchi] = -1; + } + } + + + // Re-read reconstructed polyMesh. Note: could probably be avoided + // by merging into loops above. + const polyMesh masterMesh + ( + IOobject + ( + regionName, + runTime.timeName(), + runTime + ), + true + ); + + + // faceProcAddressing + // ~~~~~~~~~~~~~~~~~~ + + DynamicList<label> masterFaceLabels; + label nPatchFaces = 0; + forAll(procFaMeshes, proci) + { + const auto& procMesh = procFaMeshes[proci]; + const auto& procPolyFaces = procMesh.faceLabels(); + const auto& fpa = faceProcAddressing[proci]; + + labelList& faceAddr = faFaceProcAddressing[proci]; + faceAddr.resize_nocopy(procPolyFaces.size()); + + // Map to masterPolyMesh faces + forAll(procPolyFaces, i) + { + const label facei = procPolyFaces[i]; + masterFaceLabels.append(fpa[facei]); + faceAddr[i] = nPatchFaces++; + } + } + + + // faMesh itself + // ~~~~~~~~~~~~~ + + // Set up to read-if-present + IOobject io(masterMesh); + io.readOpt(IOobject::READ_IF_PRESENT); + + // Construct without patches + faMesh masterFaMesh + ( + masterMesh, + std::move(masterFaceLabels), + io + ); + + const uindirectPrimitivePatch& masterPatch = + masterFaMesh.patch(); + + + // pointProcAddressing + // ~~~~~~~~~~~~~~~~~~~ + + const auto& mpm = masterPatch.meshPointMap(); + forAll(procFaMeshes, proci) + { + const auto& procPatch = procFaMeshes[proci].patch(); + const auto& mp = procPatch.meshPoints(); + + labelList& pointAddr = faPointProcAddressing[proci]; + pointAddr.resize_nocopy(mp.size()); + + forAll(mp, i) + { + pointAddr[i] = mpm[pointProcAddressing[proci][mp[i]]]; + } + } + + + // edgeProcAddressing + // ~~~~~~~~~~~~~~~~~~ + // 1. straight mapping from proc faMesh back to reconstructed + // faMesh + determineFaEdgeMapping + ( + masterPatch, // reconstructed faMesh patch + procFaMeshes, // individual faMeshes + pointProcAddressing, // procPolyMesh to reconstructed + + faEdgeProcAddressing + ); + + + // Per patch all edges on the masterPatch + labelListList singlePatchEdgeLabels; + + // 2. edgeProcAddressing : fix ordering on patches + sortFaEdgeMapping + ( + masterPatch, // reconstructed faMesh patch + procFaMeshes, // individual faMeshes + pointProcAddressing, // procPolyMesh to reconstructed + + faEdgeProcAddressing, // per proc the map to the master + singlePatchEdgeLabels // per patch the map to the master + ); + + + const faMesh& procMesh0 = procFaMeshes[0]; + + + // Add faPatches + // ~~~~~~~~~~~~~ + + faPatchList completePatches(singlePatchEdgeLabels.size()); + label nPatches = 0; + forAll(completePatches, patchi) + { + const labelList& patchEdgeLabels = + singlePatchEdgeLabels[patchi]; + + const faPatch& fap = procMesh0.boundary()[patchi]; + + if (isA<ignoreFaPatch>(fap)) + { + // These are not real edges + continue; + } + + const label neiPolyPatchId = fap.ngbPolyPatchIndex(); + + completePatches.set + ( + nPatches, + fap.clone + ( + masterFaMesh.boundary(), + patchEdgeLabels, + nPatches, // index + neiPolyPatchId + ) + ); + + ++nPatches; + } + + completePatches.resize(nPatches); + + // Serial mesh - no parallel communication + + const bool oldParRun = Pstream::parRun(false); + + masterFaMesh.addFaPatches(completePatches); + + Pstream::parRun(oldParRun); // Restore parallel state + + + // Write mesh & individual addressing + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + faMeshReconstructor::writeMesh + ( + masterMesh.time().timeName(), + masterFaMesh, + masterFaMesh.faceLabels() + ); + + forAll(procFaMeshes, proci) + { + const faMesh& procMesh = procFaMeshes[proci]; + + faMeshReconstructor::writeAddressing + ( + IOobject + ( + "procAddressing", + masterMesh.time().timeName(), + faMesh::meshSubDir, + procMesh.thisDb(), + IOobject::NO_READ, + IOobject::NO_WRITE, + IOobject::NO_REGISTER + ), + faBoundProcAddressing[proci], + faFaceProcAddressing[proci], + faPointProcAddressing[proci], + faEdgeProcAddressing[proci] + ); + } } } } diff --git a/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.C b/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.C index 71b7584fb4ea33384785dee018ad3c2c164c12ae..4f6002839daaa65b878d04f1c45097cf39da0a39 100644 --- a/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.C +++ b/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2021-2023 OpenCFD Ltd. + Copyright (C) 2021-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -678,36 +678,60 @@ void Foam::faMeshReconstructor::writeAddressing() const } -void Foam::faMeshReconstructor::writeAddressing(const word& timeName) const +void Foam::faMeshReconstructor::writeAddressing +( + const IOobject& io, + const labelList& faBoundaryProcAddr, + const labelList& faFaceProcAddr, + const labelList& faPointProcAddr, + const labelList& faEdgeProcAddr +) { // Write copies - IOobject ioAddr - ( - "procAddressing", - timeName, - faMesh::meshSubDir, - procMesh_.thisDb(), - IOobject::NO_READ, - IOobject::NO_WRITE, - IOobject::NO_REGISTER - ); + IOobject ioAddr(io); // boundaryProcAddressing ioAddr.rename("boundaryProcAddressing"); - IOListRef<label>(ioAddr, faBoundaryProcAddr_).write(); + IOListRef<label>(ioAddr, faBoundaryProcAddr).write(); // faceProcAddressing ioAddr.rename("faceProcAddressing"); - IOListRef<label>(ioAddr, faFaceProcAddr_).write(); + IOListRef<label>(ioAddr, faFaceProcAddr).write(); // pointProcAddressing ioAddr.rename("pointProcAddressing"); - IOListRef<label>(ioAddr, faPointProcAddr_).write(); + IOListRef<label>(ioAddr, faPointProcAddr).write(); // edgeProcAddressing ioAddr.rename("edgeProcAddressing"); - IOListRef<label>(ioAddr, faEdgeProcAddr_).write(); + IOListRef<label>(ioAddr, faEdgeProcAddr).write(); +} + + +void Foam::faMeshReconstructor::writeAddressing(const word& timeName) const +{ + // Write copies + + IOobject ioAddr + ( + "procAddressing", + timeName, + faMesh::meshSubDir, + procMesh_.thisDb(), + IOobject::NO_READ, + IOobject::NO_WRITE, + IOobject::NO_REGISTER + ); + + writeAddressing + ( + ioAddr, + faBoundaryProcAddr_, + faFaceProcAddr_, + faPointProcAddr_, + faEdgeProcAddr_ + ); } @@ -717,10 +741,13 @@ void Foam::faMeshReconstructor::writeMesh() const } -void Foam::faMeshReconstructor::writeMesh(const word& timeName) const +void Foam::faMeshReconstructor::writeMesh +( + const word& timeName, + const faMesh& fullMesh, + const labelUList& singlePatchFaceLabels +) { - const faMesh& fullMesh = this->mesh(); - refPtr<fileOperation> writeHandler(fileOperation::NewUncollated()); auto oldHandler = fileOperation::fileHandler(writeHandler); @@ -733,7 +760,7 @@ void Foam::faMeshReconstructor::writeMesh(const word& timeName) const IOobject io(fullMesh.boundary()); io.rename("faceLabels"); - IOListRef<label>(io, singlePatchFaceLabels_).write(); + IOListRef<label>(io, singlePatchFaceLabels).write(); fullMesh.boundary().write(); @@ -746,4 +773,10 @@ void Foam::faMeshReconstructor::writeMesh(const word& timeName) const } +void Foam::faMeshReconstructor::writeMesh(const word& timeName) const +{ + writeMesh(timeName, this->mesh(), singlePatchFaceLabels_); +} + + // ************************************************************************* // diff --git a/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.H b/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.H index 9ffc7400033229dffa29043c31e68c2dc0839fbf..02253daa179afae10ec50d740399fd4e4ece6702 100644 --- a/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.H +++ b/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2021-2022 OpenCFD Ltd. + Copyright (C) 2021-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -210,12 +210,30 @@ public: // Write + //- Write proc addressing + static void writeAddressing + ( + const IOobject& io, + const labelList& faBoundaryProcAddr, + const labelList& faFaceProcAddr, + const labelList& faPointProcAddr, + const labelList& faEdgeProcAddr + ); + //- Write proc addressing at the polyMesh faceInstances time void writeAddressing() const; //- Write proc addressing at the given time void writeAddressing(const word& timeName) const; + //- Write mesh information + static void writeMesh + ( + const word& timeName, + const faMesh& fullMesh, + const labelUList& singlePatchFaceLabels + ); + //- Write equivalent mesh information at the polyMesh faceInstances time void writeMesh() const;