/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
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 .
\*---------------------------------------------------------------------------*/
#include "mapDistributeBase.H"
#include "bitSet.H"
#include "ListOps.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Setup array of element masks to match maps sizes
//
// \param[out] masks Sized for each position in the maps
// \param maps The element maps
static void blankElementMasks(List& masks, const labelListList& maps)
{
// If base container not already sized
if (masks.empty())
{
masks.resize(maps.size());
}
forAll(masks, proci)
{
masks[proci].reset(); // zero all bits
masks[proci].resize(maps[proci].size());
}
}
// Calculate the element mask correspondig to allowedElems in the maps
//
// \param allowedElems Permissible mapped elements (true/false)
// \param[out] masks True/false for each position within the maps
// \param maps The element maps
// \param hasFlip Map has flip indexing
//
// \return the max index used.
static label calcElementMasks
(
const bitSet& allowedElems,
List& masks, // [out] - often presized before calling
const labelListList& maps,
const bool hasFlip
)
{
// Index after flipping
const auto unflippedIndex =
(
hasFlip
? [](label idx) -> label { return mag(idx)-1; }
: [](label idx) -> label { return idx; }
);
// If not already sized
if (masks.empty())
{
masks.resize(maps.size());
}
label maxIndex = -1;
forAll(masks, proci)
{
bitSet& mask = masks[proci];
const labelList& map = maps[proci];
mask.reset(); // zero all bits
mask.resize(map.size());
forAll(map, i)
{
// Element is used (or not)
const label index = unflippedIndex(map[i]);
if (allowedElems.test(index))
{
mask.set(i);
maxIndex = max(maxIndex, index);
}
}
}
return maxIndex;
}
} // End namespace Foam
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
void Foam::mapDistributeBase::exchangeMasks
(
const UList& sendMasks,
UList& recvMasks,
const int tag,
const label comm
)
{
// Require properly sized mask buffers.
// The information *is* known from the maps, so always use that
// instead having a needless all-to-all for the sizes.
if (sendMasks.size() != recvMasks.size())
{
FatalErrorInFunction
<< "Mismatched mask sizes: "
<< sendMasks.size() << " != "
<< recvMasks.size() << nl
<< Foam::abort(FatalError);
}
const label myRank = UPstream::myProcNo(comm);
if (UPstream::parRun())
{
#ifdef FULLDEBUG
if (sendMasks.size() > UPstream::nProcs(comm))
{
FatalErrorInFunction
<< "Mask sizes (" << sendMasks.size()
<< ") are larger than number of procs:"
<< UPstream::nProcs(comm) << nl
<< Foam::abort(FatalError);
}
#endif
const label startOfRequests = UPstream::nRequests();
forAll(recvMasks, proci)
{
if (proci != myRank && recvMasks[proci].size())
{
UIPstream::read
(
UPstream::commsTypes::nonBlocking,
proci,
recvMasks[proci].data_bytes(),
recvMasks[proci].size_bytes(),
tag,
comm
);
}
}
forAll(sendMasks, proci)
{
if (proci != myRank && sendMasks[proci].size())
{
UOPstream::write
(
UPstream::commsTypes::nonBlocking,
proci,
sendMasks[proci].cdata_bytes(),
sendMasks[proci].size_bytes(),
tag,
comm
);
}
}
// Wait for outstanding requests
UPstream::waitRequests(startOfRequests);
}
// Receiving myself is just a copy
recvMasks[myRank] = sendMasks[myRank];
}
void Foam::mapDistributeBase::unionCombineMasks
(
UList& sendMasks,
UList& recvMasks,
const int tag,
const label comm
)
{
// Require properly sized mask buffers.
// The information *is* known from the maps, so always use that
// instead having a needless all-to-all for the sizes.
if (sendMasks.size() != recvMasks.size())
{
FatalErrorInFunction
<< "Mismatched mask sizes: "
<< sendMasks.size() << " != "
<< recvMasks.size() << nl
<< Foam::abort(FatalError);
}
if (UPstream::parRun())
{
// Scratch buffers for union operations
List scratch(recvMasks.size());
// Size for receives
forAll(scratch, proci)
{
scratch[proci].resize(recvMasks[proci].size());
}
// Exchange: from sendMasks -> scratch (intermediate receive)
exchangeMasks(sendMasks, scratch, tag, comm);
// Update recvMasks (as union)
forAll(recvMasks, proci)
{
recvMasks[proci] &= scratch[proci];
}
// Size for sends
forAll(scratch, proci)
{
scratch[proci].resize(sendMasks[proci].size());
}
// Exchange: from recvMasks -> scratch (intermediate send)
exchangeMasks(recvMasks, scratch, tag, comm);
// Final synchronization
forAll(sendMasks, proci)
{
sendMasks[proci] &= scratch[proci];
}
}
else
{
// Non-parallel: 'synchronize' myself
const label myRank = UPstream::myProcNo(comm);
recvMasks[myRank] &= sendMasks[myRank];
sendMasks[myRank] = recvMasks[myRank];
}
// Done with parallel exchanges so can shrink the masks to
// the min-size actually needed.
for (auto& mask : sendMasks)
{
mask.resize_last();
}
for (auto& mask : recvMasks)
{
mask.resize_last();
}
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::label Foam::mapDistributeBase::renumberMap
(
labelListList& mapElements,
const labelUList& oldToNew,
const bool hasFlip
)
{
label maxIndex = -1;
// Transcribe the map
if (hasFlip)
{
for (labelList& map : mapElements)
{
for (label& val : map)
{
// Unflip indexed value
const label index = oldToNew[mag(val)-1];
if (index >= 0) // Not certain this check is needed
{
maxIndex = max(maxIndex, index);
// Retain flip information from original
val = (val < 0 ? (-index-1) : (index+1));
}
}
}
}
else
{
for (labelList& map : mapElements)
{
for (label& val : map)
{
// Get indexed value (no flipping)
const label index = oldToNew[val];
if (index >= 0) // Not certain this check is needed
{
maxIndex = max(maxIndex, index);
val = index;
}
}
}
}
return (maxIndex+1);
}
Foam::label Foam::mapDistributeBase::renumberMap
(
labelList& map,
const label localSize,
const label offset,
const Map