From 02bf8928cbe1e8d96b98beab2f9572593266c922 Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Wed, 12 May 2021 22:55:57 +0200 Subject: [PATCH] ENH: faMeshReconstructor for reconstructing equivalent serial faMesh (#2084) - A bare-bones reconstructor for finiteArea meshes when processor meshes are available (in parallel) but an equivalent serial faMesh is needed for reconstruction or decomposition. In these situations, a serial version of the faMesh is needed, but preferably without reconstructing the entire volume mesh. It uses the finiteVolume faceProcAddressing in addition to the geometric information available from the underlying polyMesh. The resulting equivalent faMesh can be used for basic operations, but caution should be exercised before attempting large operations. --- .../reconstruct/faReconstruct/Make/files | 1 + .../faReconstruct/faMeshReconstructor.C | 637 ++++++++++++++++++ .../faReconstruct/faMeshReconstructor.H | 222 ++++++ 3 files changed, 860 insertions(+) create mode 100644 src/parallel/reconstruct/faReconstruct/faMeshReconstructor.C create mode 100644 src/parallel/reconstruct/faReconstruct/faMeshReconstructor.H diff --git a/src/parallel/reconstruct/faReconstruct/Make/files b/src/parallel/reconstruct/faReconstruct/Make/files index 4d7028d13c..c0f15e7ecd 100644 --- a/src/parallel/reconstruct/faReconstruct/Make/files +++ b/src/parallel/reconstruct/faReconstruct/Make/files @@ -1,4 +1,5 @@ processorFaMeshes.C faFieldReconstructor.C +faMeshReconstructor.C LIB = $(FOAM_LIBBIN)/libfaReconstruct diff --git a/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.C b/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.C new file mode 100644 index 0000000000..0f85a81d5e --- /dev/null +++ b/src/parallel/reconstruct/faReconstruct/faMeshReconstructor.C @@ -0,0 +1,637 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2021 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see . + +\*---------------------------------------------------------------------------*/ + +#include "faMeshReconstructor.H" +#include "globalIndex.H" +#include "globalMeshData.H" +#include "edgeHashes.H" +#include "Time.H" +#include "PstreamCombineReduceOps.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +int Foam::faMeshReconstructor::debug = 0; + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::faMeshReconstructor::calcAddressing +( + const labelUList& fvFaceProcAddr +) +{ + const globalIndex globalFaceNum(procMesh_.nFaces()); + + // ---------------------- + // boundaryProcAddressing + // + // Trivial since non-processor boundary ordering is identical + + const label nPatches = procMesh_.boundary().size(); + + faBoundaryProcAddr_ = identity(nPatches); + + // Mark processor patches + for + ( + label patchi = procMesh_.boundary().nNonProcessor(); + patchi < nPatches; + ++patchi + ) + { + faBoundaryProcAddr_[patchi] = -1; + } + + + // ------------------ + // faceProcAddressing + // + // Transcribe/rewrite based on finiteVolume faceProcAddressing + + faFaceProcAddr_ = procMesh_.faceLabels(); + + // From local faceLabels to proc values + for (label& facei : faFaceProcAddr_) + { + // Use finiteVolume info, ignoring face flips + facei = mag(fvFaceProcAddr[facei] - 1); + } + + + // Make global consistent. + // Starting at '0', without gaps in numbering etc. + // - the sorted order is the obvious solution + { + globalFaceNum.gather(faFaceProcAddr_, singlePatchFaceLabels_); + + labelList order(Foam::sortedOrder(singlePatchFaceLabels_)); + + singlePatchFaceLabels_ = labelList(singlePatchFaceLabels_, order); + + globalFaceNum.scatter(order, faFaceProcAddr_); + } + + // Broadcast the same information everywhere + Pstream::scatter(singlePatchFaceLabels_); + + + // ------------------ + // edgeProcAddressing + // + // This is more complicated. + + // Create a single (serial) patch of the finiteArea mesh without a + // corresponding volume mesh, otherwise it would be the same as + // reconstructPar on the volume mesh (big, slow, etc). + // + // Do manual point-merge and relabeling to avoid dependency on + // finiteVolume pointProcAddressing + + faPointProcAddr_.clear(); // Final size == procMesh_.nPoints() + + // 1. + // - Topological point merge of the area meshes + // - use the local patch faces and points + + // 2. + // - build a single (serial) patch of the finiteArea mesh only + // without any point support from the volume mesh + // - it may be possible to skip this step, but not obvious how + + // The collected faces are contiguous per processor, which gives us + // the possibility to easily identify their source by using the + // global face indexing (if needed). + // The ultimate face locations are handled with a separate ordering + // list. + + const uindirectPrimitivePatch& procPatch = procMesh_.patch(); + + + { + faceList singlePatchProcFaces; // [proc0faces, proc1faces ...] + labelList uniqueMeshPointLabels; + + // Local face points to compact merged point index + labelList pointToGlobal; + + autoPtr globalPointsPtr = + procMesh_.mesh().globalData().mergePoints + ( + procPatch.meshPoints(), + procPatch.meshPointMap(), // unused + pointToGlobal, + uniqueMeshPointLabels + ); + + // Gather faces, renumbered for the *merged* points + faceList tmpFaces(globalFaceNum.localSize()); + + forAll(tmpFaces, facei) + { + tmpFaces[facei] = + face(pointToGlobal, procPatch.localFaces()[facei]); + } + + globalFaceNum.gather + ( + tmpFaces, + singlePatchProcFaces, + UPstream::msgType(), + Pstream::commsTypes::scheduled + ); + + globalPointsPtr().gather + ( + UIndirectList + ( + procPatch.points(), // NB: mesh points (non-local) + uniqueMeshPointLabels + ), + singlePatchPoints_ + ); + + // Transcribe into final assembled order + singlePatchFaces_.resize(singlePatchProcFaces.size()); + + // Target face ordering + labelList singlePatchProcAddr; + globalFaceNum.gather(faFaceProcAddr_, singlePatchProcAddr); + + forAll(singlePatchProcAddr, facei) + { + const label targetFacei = singlePatchProcAddr[facei]; + singlePatchFaces_[targetFacei] = singlePatchProcFaces[facei]; + } + + // Use initial equivalent "global" (serial) patch + // to establish the correct point and face walking order + // + // - only meaningful on master + const primitivePatch initialPatch + ( + SubList(singlePatchFaces_), + singlePatchPoints_ + ); + + // Grab the faces/points in local point ordering + tmpFaces = initialPatch.localFaces(); + pointField tmpPoints(initialPatch.localPoints()); + + // The meshPointMap is contiguous, so flatten as linear list + /// Map