/*---------------------------------------------------------------------------*\
========= |
\\ / 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