/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2012-2017 OpenFOAM Foundation Copyright (C) 2015-2022 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 "meshToMesh.H" #include "OFstream.H" #include "Time.H" #include "globalIndex.H" #include "mergePoints.H" #include "processorPolyPatch.H" #include "SubField.H" #include "AABBTree.H" #include "cellBox.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // Foam::label Foam::meshToMesh::calcDistribution ( const polyMesh& src, const polyMesh& tgt ) const { label proci = 0; if (Pstream::parRun()) { const bitSet hasMesh ( UPstream::listGatherValues ( src.nCells() > 0 || tgt.nCells() > 0 ) ); const auto nHaveMesh = hasMesh.count(); if (nHaveMesh == 1) { proci = hasMesh.find_first(); DebugInFunction << "Meshes local to processor" << proci << endl; } else if (nHaveMesh > 1) { proci = -1; DebugInFunction << "Meshes split across multiple processors" << endl; } Pstream::broadcast(proci); } return proci; } Foam::label Foam::meshToMesh::calcOverlappingProcs ( const List& procBb, const boundBox& bb, boolList& overlaps ) const { overlaps = false; label nOverlaps = 0; forAll(procBb, proci) { const treeBoundBoxList& bbp = procBb[proci]; for (const treeBoundBox& b : bbp) { if (b.overlaps(bb)) { overlaps[proci] = true; ++nOverlaps; break; } } } return nOverlaps; } Foam::autoPtr Foam::meshToMesh::calcProcMap ( const polyMesh& src, const polyMesh& tgt ) const { switch (procMapMethod_) { case procMapMethod::pmLOD: { Info<< "meshToMesh: Using processorLOD method" << endl; // Create processor map of overlapping faces. This map gets // (possibly remote) cells from the tgt mesh such that they // (together) cover all of the src mesh const label nGlobalSrcCells = src.globalData().nTotalCells(); // Note: minimum content has to be > 1 since otherwise // would keep on splitting. 16 is fairly random choice. const label cellsPerBox = max(16, 0.001*nGlobalSrcCells); typename processorLODs::cellBox boxLOD ( src.cells(), src.faces(), src.points(), tgt.cells(), tgt.faces(), tgt.points(), cellsPerBox, src.nCells() ); return boxLOD.map(); break; } default: { Info<< "meshToMesh: Using AABBTree method" << endl; // get decomposition of cells on src mesh List procBb(Pstream::nProcs()); if (src.nCells() > 0) { procBb[Pstream::myProcNo()] = AABBTree ( src.cellPoints(), src.points(), false ).boundBoxes(); } else { procBb[Pstream::myProcNo()] = treeBoundBoxList(); } Pstream::allGatherList(procBb); if (debug) { InfoInFunction << "Determining extent of src mesh per processor:" << nl << "\tproc\tbb" << endl; forAll(procBb, proci) { Info<< '\t' << proci << '\t' << procBb[proci] << endl; } } // determine which cells of tgt mesh overlaps src mesh per proc const cellList& cells = tgt.cells(); const faceList& faces = tgt.faces(); const pointField& points = tgt.points(); labelListList sendMap; { // per processor indices into all segments to send List> dynSendMap(Pstream::nProcs()); label iniSize = floor(tgt.nCells()/Pstream::nProcs()); forAll(dynSendMap, proci) { dynSendMap[proci].setCapacity(iniSize); } // work array - whether src processor bb overlaps the tgt cell // bounds boolList procBbOverlaps(Pstream::nProcs()); forAll(cells, celli) { const cell& c = cells[celli]; // determine bounding box of tgt cell boundBox cellBb(boundBox::invertedBox); forAll(c, facei) { const face& f = faces[c[facei]]; forAll(f, fp) { cellBb.add(points, f); } } // find the overlapping tgt cells on each src processor (void)calcOverlappingProcs(procBb, cellBb, procBbOverlaps); forAll(procBbOverlaps, proci) { if (procBbOverlaps[proci]) { dynSendMap[proci].append(celli); } } } // convert dynamicList to labelList sendMap.setSize(Pstream::nProcs()); forAll(sendMap, proci) { sendMap[proci].transfer(dynSendMap[proci]); } } // debug printing if (debug) { Pout<< "Of my " << cells.size() << " target cells I need to send to:" << nl << "\tproc\tcells" << endl; forAll(sendMap, proci) { Pout<< '\t' << proci << '\t' << sendMap[proci].size() << endl; } } // send over how many tgt cells I need to receive from each // processor labelListList sendSizes(Pstream::nProcs()); sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs()); forAll(sendMap, proci) { sendSizes[Pstream::myProcNo()][proci] = sendMap[proci].size(); } Pstream::allGatherList(sendSizes); // determine order of receiving labelListList constructMap(Pstream::nProcs()); label segmentI = 0; forAll(constructMap, proci) { // what I need to receive is what other processor is sending // to me label nRecv = sendSizes[proci][Pstream::myProcNo()]; constructMap[proci].setSize(nRecv); for (label i = 0; i < nRecv; i++) { constructMap[proci][i] = segmentI++; } } return autoPtr::New ( segmentI, // size after construction std::move(sendMap), std::move(constructMap) ); break; } } } void Foam::meshToMesh::distributeCells ( const mapDistribute& map, const polyMesh& tgtMesh, const globalIndex& globalI, List& points, List