mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
- bundles frequently used 'gather/scatter' patterns more consistently. - combineAllGather -> combineGather + broadcast - listCombineAllGather -> listCombineGather + broadcast - mapCombineAllGather -> mapCombineGather + broadcast - allGatherList -> gatherList + scatterList - reduce -> gather + broadcast (ie, allreduce) - The allGatherList currently wraps gatherList/scatterList, but may be replaced with a different algorithm in the future. STYLE: PstreamCombineReduceOps.H is mostly unneeded now
274 lines
7.5 KiB
C
274 lines
7.5 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration |
|
|
\\ / A nd | www.openfoam.com
|
|
\\/ M anipulation |
|
|
-------------------------------------------------------------------------------
|
|
Copyright (C) 2011-2017 OpenFOAM Foundation
|
|
Copyright (C) 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 <http://www.gnu.org/licenses/>.
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#include "ProcessorTopology.H"
|
|
#include "ListOps.H"
|
|
#include "Pstream.H"
|
|
#include "commSchedule.H"
|
|
|
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
|
|
template<class Container, class ProcPatch>
|
|
Foam::labelList Foam::ProcessorTopology<Container, ProcPatch>::procNeighbours
|
|
(
|
|
const label nProcs,
|
|
const Container& patches
|
|
)
|
|
{
|
|
// Determine number of processor neighbours and max neighbour id.
|
|
|
|
label nNeighbours = 0;
|
|
|
|
label maxNb = 0;
|
|
|
|
boolList isNeighbourProc(nProcs, false);
|
|
|
|
forAll(patches, patchi)
|
|
{
|
|
const auto* cpp = isA<ProcPatch>(patches[patchi]);
|
|
if (cpp)
|
|
{
|
|
const label nbrProci = cpp->neighbProcNo();
|
|
|
|
if (!isNeighbourProc[nbrProci])
|
|
{
|
|
isNeighbourProc[nbrProci] = true;
|
|
maxNb = max(maxNb, nbrProci);
|
|
++nNeighbours;
|
|
}
|
|
}
|
|
}
|
|
|
|
labelList neighbours(nNeighbours, -1);
|
|
|
|
nNeighbours = 0;
|
|
|
|
forAll(isNeighbourProc, proci)
|
|
{
|
|
if (isNeighbourProc[proci])
|
|
{
|
|
neighbours[nNeighbours++] = proci;
|
|
}
|
|
}
|
|
|
|
procPatchMap_.setSize(maxNb + 1);
|
|
procPatchMap_ = -1;
|
|
|
|
forAll(patches, patchi)
|
|
{
|
|
const auto* cpp = isA<ProcPatch>(patches[patchi]);
|
|
if (cpp)
|
|
{
|
|
const label nbrProci = cpp->neighbProcNo();
|
|
|
|
// Reverse map
|
|
procPatchMap_[nbrProci] = patchi;
|
|
}
|
|
}
|
|
|
|
return neighbours;
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
|
|
|
template<class Container, class ProcPatch>
|
|
Foam::ProcessorTopology<Container, ProcPatch>::ProcessorTopology
|
|
(
|
|
const Container& patches,
|
|
const label comm
|
|
)
|
|
:
|
|
labelListList(Pstream::nProcs(comm)),
|
|
patchSchedule_()
|
|
{
|
|
if (Pstream::parRun())
|
|
{
|
|
// Fill my 'slot' with my neighbours
|
|
operator[](Pstream::myProcNo(comm)) =
|
|
procNeighbours(this->size(), patches);
|
|
|
|
// Distribute to all processors
|
|
Pstream::allGatherList(*this, Pstream::msgType(), comm);
|
|
}
|
|
|
|
if
|
|
(
|
|
Pstream::parRun()
|
|
&& Pstream::defaultCommsType == Pstream::commsTypes::scheduled
|
|
)
|
|
{
|
|
patchSchedule_.resize(2*patches.size());
|
|
|
|
label patchEvali = 0;
|
|
|
|
// 1. All non-processor patches
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
forAll(patches, patchi)
|
|
{
|
|
if (!isA<ProcPatch>(patches[patchi]))
|
|
{
|
|
patchSchedule_[patchEvali].patch = patchi;
|
|
patchSchedule_[patchEvali++].init = true;
|
|
patchSchedule_[patchEvali].patch = patchi;
|
|
patchSchedule_[patchEvali++].init = false;
|
|
}
|
|
}
|
|
|
|
// 2. All processor patches
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
// Determine the schedule for all. Insert processor pair once
|
|
// to determine the schedule. Each processor pair stands for both
|
|
// send and receive.
|
|
label nComms = 0;
|
|
for (const labelList& neighbours : *this)
|
|
{
|
|
nComms += neighbours.size();
|
|
}
|
|
DynamicList<labelPair> comms(nComms);
|
|
|
|
forAll(*this, proci)
|
|
{
|
|
const labelList& neighbours = operator[](proci);
|
|
|
|
for (const label nbrProci : neighbours)
|
|
{
|
|
if (proci < nbrProci)
|
|
{
|
|
comms.append(labelPair(proci, nbrProci));
|
|
}
|
|
}
|
|
}
|
|
comms.shrink();
|
|
|
|
// Determine a schedule.
|
|
labelList mySchedule
|
|
(
|
|
commSchedule
|
|
(
|
|
Pstream::nProcs(comm),
|
|
comms
|
|
).procSchedule()[Pstream::myProcNo(comm)]
|
|
);
|
|
|
|
for (const label commI : mySchedule)
|
|
{
|
|
// Get the other processor
|
|
label nb = comms[commI][0];
|
|
if (nb == Pstream::myProcNo(comm))
|
|
{
|
|
nb = comms[commI][1];
|
|
}
|
|
label patchi = procPatchMap_[nb];
|
|
|
|
if (Pstream::myProcNo(comm) > nb)
|
|
{
|
|
patchSchedule_[patchEvali].patch = patchi;
|
|
patchSchedule_[patchEvali++].init = true;
|
|
patchSchedule_[patchEvali].patch = patchi;
|
|
patchSchedule_[patchEvali++].init = false;
|
|
}
|
|
else
|
|
{
|
|
patchSchedule_[patchEvali].patch = patchi;
|
|
patchSchedule_[patchEvali++].init = false;
|
|
patchSchedule_[patchEvali].patch = patchi;
|
|
patchSchedule_[patchEvali++].init = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
patchSchedule_ = nonBlockingSchedule(patches);
|
|
}
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
|
|
|
template<class Container, class ProcPatch>
|
|
Foam::lduSchedule
|
|
Foam::ProcessorTopology<Container, ProcPatch>::nonBlockingSchedule
|
|
(
|
|
const Container& patches
|
|
)
|
|
{
|
|
lduSchedule patchSchedule(2*patches.size());
|
|
|
|
label patchEvali = 0;
|
|
|
|
// 1. All non-processor patches
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
// Have evaluate directly after initEvaluate. Could have them separated
|
|
// as long as they're not intermingled with processor patches since
|
|
// then e.g. any reduce parallel traffic would interfere with the
|
|
// processor swaps.
|
|
|
|
forAll(patches, patchi)
|
|
{
|
|
if (!isA<ProcPatch>(patches[patchi]))
|
|
{
|
|
patchSchedule[patchEvali].patch = patchi;
|
|
patchSchedule[patchEvali++].init = true;
|
|
patchSchedule[patchEvali].patch = patchi;
|
|
patchSchedule[patchEvali++].init = false;
|
|
}
|
|
}
|
|
|
|
// 2. All processor patches
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
// 2a. initEvaluate
|
|
forAll(patches, patchi)
|
|
{
|
|
if (isA<ProcPatch>(patches[patchi]))
|
|
{
|
|
patchSchedule[patchEvali].patch = patchi;
|
|
patchSchedule[patchEvali++].init = true;
|
|
}
|
|
}
|
|
|
|
// 2b. evaluate
|
|
forAll(patches, patchi)
|
|
{
|
|
if (isA<ProcPatch>(patches[patchi]))
|
|
{
|
|
patchSchedule[patchEvali].patch = patchi;
|
|
patchSchedule[patchEvali++].init = false;
|
|
}
|
|
}
|
|
|
|
return patchSchedule;
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|