Comms update on GGI AMG interface

This commit is contained in:
Hrvoje Jasak 2016-08-10 14:08:15 +01:00
parent 5f5860e3c4
commit 07de8431c1
11 changed files with 322 additions and 258 deletions

View file

@ -258,6 +258,12 @@ bool Foam::ggiFvPatch::localParallel() const
}
const Foam::mapDistribute& Foam::ggiFvPatch::map() const
{
return ggiPolyPatch_.map();
}
const Foam::scalarListList& Foam::ggiFvPatch::weights() const
{
if (ggiPolyPatch_.master())

View file

@ -171,6 +171,9 @@ public:
//- Is the patch localised on a single processor
virtual bool localParallel() const;
//- Return mapDistribute
virtual const mapDistribute& map() const;
//- Return weights. Master side returns own weights and
// slave side returns weights from master
virtual const scalarListList& weights() const;

View file

@ -34,6 +34,7 @@ Author
#include "fvMesh.H"
#include "fvBoundaryMesh.H"
#include "foamTime.H"
#include "mapDistribute.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -302,6 +303,12 @@ bool Foam::regionCoupleFvPatch::localParallel() const
}
const Foam::mapDistribute& Foam::regionCoupleFvPatch::map() const
{
return rcPolyPatch_.map();
}
const Foam::scalarListList& Foam::regionCoupleFvPatch::weights() const
{
if (rcPolyPatch_.master())

View file

@ -180,6 +180,9 @@ public:
//- Is the patch localised on a single processor
virtual bool localParallel() const;
//- Return mapDistribute
const mapDistribute& map() const;
//- Return weights. Master side returns own weights and
// slave side returns weights from master
virtual const scalarListList& weights() const;

View file

@ -46,6 +46,10 @@ SourceFiles
namespace Foam
{
// Forward declaration of classes
class mapDistribute;
/*---------------------------------------------------------------------------*\
Class ggiLduInterface Declaration
\*---------------------------------------------------------------------------*/
@ -111,6 +115,9 @@ public:
//- Is the patch localised on a single processor
virtual bool localParallel() const = 0;
//- Return mapDistribute
virtual const mapDistribute& map() const = 0;
//- Return weights
virtual const scalarListList& weights() const = 0;

View file

@ -839,30 +839,67 @@ Foam::ggiAMGInterface::ggiAMGInterface
// Re-pack singly linked list of processor master faces
// and pass to other processors
// First index: master proc
// Second index: slave proc
// List contents: global faces in order
labelListListList crissCrossList(Pstream::nProcs());
labelListList& crissList = crissCrossList[Pstream::myProcNo()];
crissList.setSize(Pstream::nProcs());
forAll (crissList, procI)
{
crissList[procI] = procMasterFacesLL[procI];
}
Pstream::gatherList(crissCrossList);
Pstream::scatterList(crissCrossList);
procMasterFaces_.setSize(Pstream::nProcs());
forAll (procMasterFaces_, procI)
// Copy self
procMasterFaces_[Pstream::myProcNo()] =
procMasterFacesLL[Pstream::myProcNo()];
if (Pstream::parRun())
{
procMasterFaces_[procI] =
crissCrossList[procI][Pstream::myProcNo()];
const List<labelPair> schedule =
fineGgiInterface_.map().schedule();
// Do the comms
forAll (schedule, i)
{
const label sendProc = schedule[i].first();
const label recvProc = schedule[i].second();
if (Pstream::myProcNo() == sendProc)
{
OPstream toNbr(Pstream::scheduled, recvProc);
toNbr << labelList(procMasterFacesLL[recvProc]);
}
else if (Pstream::myProcNo() == recvProc)
{
IPstream fromNbr(Pstream::scheduled, sendProc);
procMasterFaces_[sendProc] = labelList(fromNbr);
}
else
{
FatalErrorIn("...")
<< "My proc number " << Pstream::myProcNo()
<< " is neither a sender nor a receiver: "
<< schedule[i]
<< abort(FatalError);
}
}
}
// // First index: master proc
// // Second index: slave proc
// // List contents: global faces in order
// labelListListList crissCrossList(Pstream::nProcs());
// labelListList& crissList = crissCrossList[Pstream::myProcNo()];
// crissList.setSize(Pstream::nProcs());
// forAll (crissList, procI)
// {
// crissList[procI] = procMasterFacesLL[procI];
// }
// Pstream::gatherList(crissCrossList);
// Pstream::scatterList(crissCrossList);
// forAll (procMasterFaces_, procI)
// {
// procMasterFaces_[procI] =
// crissCrossList[procI][Pstream::myProcNo()];
// }
}
// Agglomerate slave
else

View file

@ -509,17 +509,6 @@ void Foam::ggiPolyPatch::calcSendReceive() const
}
const Foam::mapDistribute& Foam::ggiPolyPatch::map() const
{
if (!mapPtr_)
{
calcSendReceive();
}
return *mapPtr_;
}
void Foam::ggiPolyPatch::clearGeom() const
{
deleteDemandDrivenData(reconFaceCellCentresPtr_);
@ -530,6 +519,10 @@ void Foam::ggiPolyPatch::clearGeom() const
// HJ, 23/Jun/2011
deleteDemandDrivenData(remoteZoneAddressingPtr_);
// localParallel depends on geometry - must be cleared!
// HR, 11/Jul/2013
deleteDemandDrivenData(localParallelPtr_);
deleteDemandDrivenData(mapPtr_);
}
@ -543,7 +536,6 @@ void Foam::ggiPolyPatch::clearOut() const
deleteDemandDrivenData(zoneAddressingPtr_);
deleteDemandDrivenData(patchToPatchPtr_);
deleteDemandDrivenData(localParallelPtr_);
}
@ -826,6 +818,17 @@ const Foam::ggiZoneInterpolation& Foam::ggiPolyPatch::patchToPatch() const
}
const Foam::mapDistribute& Foam::ggiPolyPatch::map() const
{
if (!mapPtr_)
{
calcSendReceive();
}
return *mapPtr_;
}
const Foam::vectorField& Foam::ggiPolyPatch::reconFaceCellCentres() const
{
if (!reconFaceCellCentresPtr_)

View file

@ -138,9 +138,6 @@ class ggiPolyPatch
//- Calculate send and receive addressing
void calcSendReceive() const;
//- Return mapDistribute
const mapDistribute& map() const;
// Memory management
@ -335,6 +332,9 @@ public:
//- Is the patch localised on a single processor
bool localParallel() const;
//- Return mapDistribute
const mapDistribute& map() const;
//- Return reference to patch-to-patch interpolation
// Used only for addressing
const ggiZoneInterpolation& patchToPatch() const;

View file

@ -226,7 +226,7 @@ void Foam::regionCouplePolyPatch::calcPatchToPatch() const
SMALL, // Non-overlapping face tolerances
SMALL,
true, // Rescale weighting factors
ggiInterpolation::BB_OCTREE // Octree search, MB.
reject_ // Quick rejection algorithm, default BB_OCTREE
);
// Abort immediately if uncovered faces are present and the option
@ -378,7 +378,7 @@ void Foam::regionCouplePolyPatch::calcSendReceive() const
// (of the calc-call) they will be set to zero-sized array
// HJ, 4/Jun/2011
if (receiveAddrPtr_ || sendAddrPtr_)
if (mapPtr_)
{
FatalErrorIn("void regionCouplePolyPatch::calcSendReceive() const")
<< "Send-receive addressing already calculated"
@ -399,74 +399,129 @@ void Foam::regionCouplePolyPatch::calcSendReceive() const
<< abort(FatalError);
}
// Master will receive and store the maps
if (Pstream::master())
{
receiveAddrPtr_ = new labelListList(Pstream::nProcs());
labelListList& rAddr = *receiveAddrPtr_;
// Gather send and receive addressing (to master)
sendAddrPtr_ = new labelListList(Pstream::nProcs());
labelListList& sAddr = *sendAddrPtr_;
// Insert master
rAddr[0] = zoneAddressing();
for (label procI = 1; procI < Pstream::nProcs(); procI++)
{
// Note: must use normal comms because the size of the
// communicated lists is unknown on the receiving side
// HJ, 4/Jun/2011
// Opt: reconsider mode of communication
IPstream ip(Pstream::scheduled, procI);
rAddr[procI] = labelList(ip);
sAddr[procI] = labelList(ip);
}
}
else
{
// Create dummy pointers: only master processor stores maps
receiveAddrPtr_ = new labelListList();
sendAddrPtr_ = new labelListList();
// Send information to master
// Get patch-to-zone addressing
const labelList& za = zoneAddressing();
const labelList& ra = remoteZoneAddressing();
// Note: must use normal comms because the size of the
// communicated lists is unknown on the receiving side
// HJ, 4/Jun/2011
// Make a zone-sized field and fill it in with proc markings for processor
// that holds and requires the data
labelField zoneProcID(zone().size(), -1);
// Opt: reconsider mode of communication
OPstream op(Pstream::scheduled, Pstream::masterNo());
// Send local and remote addressing to master
op << za << ra;
}
}
const Foam::labelListList& Foam::regionCouplePolyPatch::receiveAddr() const
{
if (!receiveAddrPtr_)
forAll (za, zaI)
{
calcSendReceive();
zoneProcID[za[zaI]] = Pstream::myProcNo();
}
return *receiveAddrPtr_;
}
reduce(zoneProcID, maxOp<labelField>());
const labelList& shadowRza = shadow().remoteZoneAddressing();
const Foam::labelListList& Foam::regionCouplePolyPatch::sendAddr() const
{
if (!sendAddrPtr_)
// Find out where my zone data is coming from
labelList nRecv(Pstream::nProcs(), 0);
// Note: only visit the data from the local zone
forAll (shadowRza, shadowRzaI)
{
calcSendReceive();
nRecv[zoneProcID[shadowRza[shadowRzaI]]]++;
}
return *sendAddrPtr_;
// Make a receiving sub-map
// It tells me which data I will receive from which processor and
// where I need to put it into the remoteZone data before the mapping
labelListList constructMap(Pstream::nProcs());
// Size the receiving list
forAll (nRecv, procI)
{
constructMap[procI].setSize(nRecv[procI]);
}
// Reset counters for processors
nRecv = 0;
forAll (shadowRza, shadowRzaI)
{
label recvProc = zoneProcID[shadowRza[shadowRzaI]];
constructMap[recvProc][nRecv[recvProc]] = shadowRza[shadowRzaI];
nRecv[recvProc]++;
}
// Make the sending sub-map
// It tells me which data is required from me to be sent to which
// processor
// Algorithm
// - expand the local zone faces with indices into a size of local zone
// - go through remote zone addressing on all processors
// - find out who hits my faces
labelList localZoneIndices(zone().size(), -1);
forAll (za, zaI)
{
localZoneIndices[za[zaI]] = zaI;
}
labelListList shadowToReceiveAddr(Pstream::nProcs());
// Get the list of what my shadow needs to receive from my zone
// on all other processors
shadowToReceiveAddr[Pstream::myProcNo()] = shadowRza;
Pstream::gatherList(shadowToReceiveAddr);
Pstream::scatterList(shadowToReceiveAddr);
// Now local zone indices contain the index of a local face that will
// provide the data. For faces that are not local, the index will be -1
// Find out where my zone data is going to
// Make a sending sub-map
// It tells me which data I will send to which processor
labelListList sendMap(Pstream::nProcs());
// Collect local labels to be sent to each processor
forAll (shadowToReceiveAddr, procI)
{
const labelList& curProcSend = shadowToReceiveAddr[procI];
// Find out how much of my data is going to this processor
label nProcSend = 0;
forAll (curProcSend, sendI)
{
if (localZoneIndices[curProcSend[sendI]] > -1)
{
nProcSend++;
}
}
if (nProcSend > 0)
{
// Collect the indices
labelList& curSendMap = sendMap[procI];
curSendMap.setSize(nProcSend);
// Reset counter
nProcSend = 0;
forAll (curProcSend, sendI)
{
if (localZoneIndices[curProcSend[sendI]] > -1)
{
curSendMap[nProcSend] =
localZoneIndices[curProcSend[sendI]];
nProcSend++;
}
}
}
}
// Map will return the object of the size of remote zone
// HJ, 9/May/2016
mapPtr_ = new mapDistribute(zone().size(), sendMap, constructMap);
}
@ -492,18 +547,19 @@ void Foam::regionCouplePolyPatch::clearGeom() const
{
clearDeltas();
deleteDemandDrivenData(reconFaceCellCentresPtr_);
// Remote addressing and send-receive maps depend on the local
// position. Therefore, it needs to be recalculated at mesh motion.
// Local zone addressing does not change with mesh motion
// HJ, 23/Jun/2011
deleteDemandDrivenData(remoteZoneAddressingPtr_);
deleteDemandDrivenData(receiveAddrPtr_);
deleteDemandDrivenData(sendAddrPtr_);
// localParallel depends on geometry - must be cleared!
// HR, 11/Jul/2013
deleteDemandDrivenData(localParallelPtr_);
deleteDemandDrivenData(mapPtr_);
}
@ -511,6 +567,9 @@ void Foam::regionCouplePolyPatch::clearOut() const
{
clearGeom();
shadowIndex_ = -1;
zoneIndex_ = -1;
deleteDemandDrivenData(zoneAddressingPtr_);
deleteDemandDrivenData(patchToPatchPtr_);
}
@ -535,6 +594,7 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
master_(false),
isWall_(false),
bridgeOverlap_(false),
reject_(ggiZoneInterpolation::BB_OCTREE),
shadowIndex_(-1),
zoneIndex_(-1),
patchToPatchPtr_(NULL),
@ -542,8 +602,7 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
remoteZoneAddressingPtr_(NULL),
reconFaceCellCentresPtr_(NULL),
localParallelPtr_(NULL),
receiveAddrPtr_(NULL),
sendAddrPtr_(NULL)
mapPtr_(NULL)
{}
@ -560,7 +619,8 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
const bool attached,
const bool master,
const bool isWall,
const bool bridgeOverlap
const bool bridgeOverlap,
const ggiZoneInterpolation::quickReject reject
)
:
coupledPolyPatch(name, size, start, index, bm),
@ -571,6 +631,7 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
master_(master),
isWall_(isWall),
bridgeOverlap_(bridgeOverlap),
reject_(reject),
shadowIndex_(-1),
zoneIndex_(-1),
patchToPatchPtr_(NULL),
@ -578,8 +639,7 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
remoteZoneAddressingPtr_(NULL),
reconFaceCellCentresPtr_(NULL),
localParallelPtr_(NULL),
receiveAddrPtr_(NULL),
sendAddrPtr_(NULL)
mapPtr_(NULL)
{}
@ -599,6 +659,7 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
master_(dict.lookup("master")),
isWall_(dict.lookup("isWall")),
bridgeOverlap_(dict.lookup("bridgeOverlap")),
reject_(ggiZoneInterpolation::BB_OCTREE),
shadowIndex_(-1),
zoneIndex_(-1),
patchToPatchPtr_(NULL),
@ -606,9 +667,16 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
remoteZoneAddressingPtr_(NULL),
reconFaceCellCentresPtr_(NULL),
localParallelPtr_(NULL),
receiveAddrPtr_(NULL),
sendAddrPtr_(NULL)
{}
mapPtr_(NULL)
{
if (dict.found("quickReject"))
{
reject_ = ggiZoneInterpolation::quickRejectNames_.read
(
dict.lookup("quickReject")
);
}
}
Foam::regionCouplePolyPatch::regionCouplePolyPatch
@ -624,6 +692,8 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
attached_(pp.attached_),
master_(pp.master_),
isWall_(pp.isWall_),
bridgeOverlap_(pp.bridgeOverlap_),
reject_(pp.reject_),
shadowIndex_(-1),
zoneIndex_(-1),
patchToPatchPtr_(NULL),
@ -631,8 +701,7 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
remoteZoneAddressingPtr_(NULL),
reconFaceCellCentresPtr_(NULL),
localParallelPtr_(NULL),
receiveAddrPtr_(NULL),
sendAddrPtr_(NULL)
mapPtr_(NULL)
{}
@ -652,6 +721,8 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
attached_(pp.attached_),
master_(pp.master_),
isWall_(pp.isWall_),
bridgeOverlap_(pp.bridgeOverlap_),
reject_(pp.reject_),
shadowIndex_(-1),
zoneIndex_(-1),
patchToPatchPtr_(NULL),
@ -659,8 +730,7 @@ Foam::regionCouplePolyPatch::regionCouplePolyPatch
remoteZoneAddressingPtr_(NULL),
reconFaceCellCentresPtr_(NULL),
localParallelPtr_(NULL),
receiveAddrPtr_(NULL),
sendAddrPtr_(NULL)
mapPtr_(NULL)
{}
@ -911,6 +981,17 @@ Foam::regionCouplePolyPatch::patchToPatch() const
}
const Foam::mapDistribute& Foam::regionCouplePolyPatch::map() const
{
if (!mapPtr_)
{
calcSendReceive();
}
return *mapPtr_;
}
const Foam::vectorField&
Foam::regionCouplePolyPatch::reconFaceCellCentres() const
{
@ -940,6 +1021,11 @@ void Foam::regionCouplePolyPatch::initAddressing()
// Calculate transforms for correct GGI cut
calcTransforms();
if (master())
{
shadow().calcTransforms();
}
// Force zone addressing and remote zone addressing
// (uses GGI interpolator)
zoneAddressing();
@ -949,7 +1035,7 @@ void Foam::regionCouplePolyPatch::initAddressing()
if (Pstream::parRun() && !localParallel())
{
// Calculate send addressing
sendAddr();
map();
}
}
@ -1019,7 +1105,7 @@ void Foam::regionCouplePolyPatch::initMovePoints(const pointField& p)
if (Pstream::parRun() && !localParallel())
{
// Calculate send addressing
sendAddr();
map();
}
}

View file

@ -42,6 +42,7 @@ SourceFiles
#include "ggiInterpolation.H"
#include "faceZone.H"
#include "Switch.H"
#include "mapDistribute.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -81,6 +82,12 @@ class regionCouplePolyPatch
//- Use bridging to fix overlap error in interpolation
Switch bridgeOverlap_;
//- Quick reject algorithm
ggiZoneInterpolation::quickReject reject_;
// Demand-driven data
//- Shadow patch index. Delayed evaluation for construction
mutable label shadowIndex_;
@ -108,11 +115,8 @@ class regionCouplePolyPatch
// Used for parallel optimisation
mutable bool* localParallelPtr_;
//- List of zone faces indices received from each processor
mutable labelListList* receiveAddrPtr_;
//- List of zone faces indices to send to each processor
mutable labelListList* sendAddrPtr_;
//- Map-distribute comms tool
mutable mapDistribute* mapPtr_;
// Private member functions
@ -145,13 +149,6 @@ class regionCouplePolyPatch
void calcSendReceive() const;
//- Return receive addressing
const labelListList& receiveAddr() const;
//- Return send addressing
const labelListList& sendAddr() const;
// Memory management
//- Clear delta coefficients
@ -232,7 +229,9 @@ public:
const bool attached,
const bool master,
const bool isWall,
const bool bridgeOverlap
const bool bridgeOverlap,
const ggiZoneInterpolation::quickReject
reject = ggiZoneInterpolation::BB_OCTREE
);
//- Construct from dictionary
@ -292,8 +291,7 @@ public:
}
// Destructor
//-Destructor
virtual ~regionCouplePolyPatch();
@ -382,6 +380,9 @@ public:
//- Is the patch localised on a single processor
bool localParallel() const;
//- Return mapDistribute
const mapDistribute& map() const;
//- Return reference to patch-to-patch interpolation
const ggiZoneInterpolation& patchToPatch() const;

View file

@ -39,22 +39,6 @@ Foam::tmp<Foam::Field<Type> > Foam::regionCouplePolyPatch::fastExpand
{
// Check and expand the field from patch size to zone size
// with communication
// Algorithm:
// 1) Master processor holds maps of all zone addressing (data provided)
// and all remote zone addressing (data required)
// 2) Each processor will send the locally active data to the master
// 3) Master assembles all the data
// 4) Master sends to all processors the data they need to receive
//
// Notes:
// A) If the size of zone addressing is zero, data is not sent
// B) Communicated data on each processor has the size of live faces
// C) Expanded data will be equal to actual data from other processors
// only for the faces marked in remote; for other faces, it will be
// equal to zero
// D) On processor zero, complete data is available
// HJ, 4/Jun/2011
if (ff.size() != size())
{
FatalErrorIn
@ -80,127 +64,54 @@ Foam::tmp<Foam::Field<Type> > Foam::regionCouplePolyPatch::fastExpand
<< abort(FatalError);
}
// Replaced old comms algorithm. HJ, 31/May/2016
// HJ, 4/Jun/2011
// This function requires send-receive-addressing, but usage is not
// symmetric across processors. Hence trigger re-calculate at this point
// HR, 10/Jul/2013
if (Pstream::parRun() && !localParallel())
{
receiveAddr();
shadow().receiveAddr();
map();
shadow().map();
}
// Expand the field to zone size
// New version: mapDistribute
if (Pstream::parRun())
{
// Optimised mapDistribute
// Prepare return field: expand the field to zone size
tmp<Field<Type> > texpandField
(
new Field<Type>(zone().size(), pTraits<Type>::zero)
new Field<Type>(ff)
);
Field<Type>& expandField = texpandField();
if (Pstream::master())
{
// Insert master processor
const labelList& za = zoneAddressing();
map().distribute(expandField);
forAll (za, i)
{
expandField[za[i]] = ff[i];
}
// Master receives and inserts data from all processors for which
// receiveAddr contains entries
for (label procI = 1; procI < Pstream::nProcs(); procI++)
{
const labelList& curRAddr = receiveAddr()[procI];
if (!curRAddr.empty())
{
Field<Type> receiveBuf(curRAddr.size());
// Opt: reconsider mode of communication
IPstream::read
(
Pstream::blocking,
procI,
reinterpret_cast<char*>(receiveBuf.begin()),
receiveBuf.byteSize()
);
// Insert received information
forAll (curRAddr, i)
{
expandField[curRAddr[i]] = receiveBuf[i];
}
}
}
// Expanded field complete, send required data to other processors
for (label procI = 1; procI < Pstream::nProcs(); procI++)
{
const labelList& curSAddr = shadow().sendAddr()[procI];
if (!curSAddr.empty())
{
Field<Type> sendBuf(curSAddr.size());
forAll (curSAddr, i)
{
sendBuf[i] = expandField[curSAddr[i]];
}
// Opt: reconsider mode of communication
OPstream::write
(
Pstream::blocking,
procI,
reinterpret_cast<const char*>(sendBuf.begin()),
sendBuf.byteSize()
);
}
}
return texpandField;
}
else
{
// Send local data to master and receive remote data
// If patch is empty, communication is avoided
// HJ, 4/Jun/2011
if (size())
{
// Opt: reconsider mode of communication
OPstream::write
// Serial. Expand the field to zone size
tmp<Field<Type> > texpandField
(
Pstream::blocking,
Pstream::masterNo(),
reinterpret_cast<const char*>(ff.begin()),
ff.byteSize()
new Field<Type>(zone().size()) // filled with nans
);
}
Field<Type>& expandField = texpandField();
// Prepare to receive remote data
const labelList& rza = shadow().remoteZoneAddressing();
const labelList& zAddr = zoneAddressing();
if (!rza.empty())
forAll (zAddr, i)
{
Field<Type> receiveBuf(rza.size());
// Opt: reconsider mode of communication
IPstream::read
(
Pstream::blocking,
Pstream::masterNo(),
reinterpret_cast<char*>(receiveBuf.begin()),
receiveBuf.byteSize()
);
// Insert the data into expanded field
forAll (rza, i)
{
expandField[rza[i]] = receiveBuf[i];
}
}
expandField[zAddr[i]] = ff[i];
}
return texpandField;
}
}