mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: extend bitSet functionality
- num_blocks(), test_set() as per boost - broadcast(), reduceAnd(), reduceOr() to simplify parallel operations - matrix-like output for PackedList::writeList() BUG: Pstream::broadcastList() missing resize on sub-ranks - latent bug since it was unused in any OpenFOAM code
This commit is contained in:
@ -1,3 +1,3 @@
|
||||
Test-PackedList.C
|
||||
Test-PackedList.cxx
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-PackedList
|
||||
|
||||
@ -142,6 +142,9 @@ int main(int argc, char *argv[])
|
||||
Info<< "got: " << bset1 << nl
|
||||
<< "and: " << bset2 << nl
|
||||
<< "and: " << bset3 << nl;
|
||||
|
||||
Info<< "==";
|
||||
bset3.writeList(Info, 10) << nl; // matrix-like output
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -137,11 +137,11 @@ inline bool compare
|
||||
const std::string& expected
|
||||
)
|
||||
{
|
||||
const List<unsigned int>& store = bitset.storage();
|
||||
const auto& store = bitset.storage();
|
||||
|
||||
std::string has;
|
||||
|
||||
for (label blocki=0; blocki < bitset.nBlocks(); ++blocki)
|
||||
for (label blocki=0; blocki < bitset.num_blocks(); ++blocki)
|
||||
{
|
||||
has += toString(store[blocki]);
|
||||
}
|
||||
|
||||
@ -185,9 +185,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
broadcast_chunks<labelList, label>(input1);
|
||||
|
||||
Pstream::maxCommsSize = 33;
|
||||
UPstream::maxCommsSize = 33;
|
||||
|
||||
args.readIfPresent("comms-size", Pstream::maxCommsSize);
|
||||
args.readIfPresent("comms-size", UPstream::maxCommsSize);
|
||||
|
||||
broadcast_chunks<labelList, label>(input1);
|
||||
|
||||
@ -197,11 +197,11 @@ int main(int argc, char *argv[])
|
||||
PstreamBuffers pBufs;
|
||||
|
||||
labelList sendData;
|
||||
if (Pstream::master())
|
||||
if (UPstream::master())
|
||||
{
|
||||
sendData = identity(500);
|
||||
|
||||
for (const int proci : Pstream::subProcs())
|
||||
for (const int proci : UPstream::subProcs())
|
||||
{
|
||||
UOPstream os(proci, pBufs);
|
||||
os << sendData;
|
||||
@ -211,7 +211,7 @@ int main(int argc, char *argv[])
|
||||
Info<< "call finishedSends()" << endl;
|
||||
pBufs.finishedScatters();
|
||||
|
||||
if (!Pstream::master())
|
||||
if (UPstream::is_subrank())
|
||||
{
|
||||
UIPstream is(UPstream::masterNo(), pBufs);
|
||||
is >> sendData;
|
||||
@ -225,11 +225,11 @@ int main(int argc, char *argv[])
|
||||
labelListList recvBufs(UPstream::nProcs());
|
||||
labelList recvSizes;
|
||||
|
||||
if (Pstream::master())
|
||||
if (UPstream::master())
|
||||
{
|
||||
for (const int proci : Pstream::allProcs())
|
||||
for (const int proci : UPstream::allProcs())
|
||||
{
|
||||
if (proci != Pstream::myProcNo())
|
||||
if (proci != UPstream::myProcNo())
|
||||
{
|
||||
sendBufs[proci] = identity(500);
|
||||
}
|
||||
@ -253,11 +253,11 @@ int main(int argc, char *argv[])
|
||||
Map<labelList> recvBufs;
|
||||
Map<label> recvSizes;
|
||||
|
||||
if (Pstream::master())
|
||||
if (UPstream::master())
|
||||
{
|
||||
for (const int proci : Pstream::allProcs())
|
||||
for (const int proci : UPstream::allProcs())
|
||||
{
|
||||
if (proci != Pstream::myProcNo())
|
||||
if (proci != UPstream::myProcNo())
|
||||
{
|
||||
sendBufs(proci) = identity(500);
|
||||
}
|
||||
|
||||
@ -110,21 +110,25 @@ int main(int argc, char *argv[])
|
||||
<< " (self) reduced " << selfVal << nl;
|
||||
|
||||
// Identical size on all procs
|
||||
bitSet procUsed(nProcs);
|
||||
|
||||
if ((myRank % 4) == 0)
|
||||
{
|
||||
procUsed.set(myRank);
|
||||
bitSet localUsed(nProcs);
|
||||
localUsed.set(myRank, ((myRank % 4) == 0));
|
||||
|
||||
Pout<< "local procUsed " << localUsed << nl;
|
||||
localUsed.reduceOr(UPstream::worldComm, false);
|
||||
Pout<< "reduce procUsed " << localUsed << nl;
|
||||
}
|
||||
|
||||
// With allGather
|
||||
{
|
||||
bitSet procUsed
|
||||
(
|
||||
bitSet::allGather((myRank % 4) == 0)
|
||||
);
|
||||
|
||||
Pout<< "allGather: " << procUsed << nl;
|
||||
}
|
||||
|
||||
Pout<< "local procUsed " << procUsed << nl;
|
||||
reduce
|
||||
(
|
||||
procUsed.data(),
|
||||
procUsed.size_data(),
|
||||
bitOrOp<unsigned int>()
|
||||
);
|
||||
Pout<< "reduce procUsed " << procUsed << nl;
|
||||
|
||||
// Identical size on all procs
|
||||
// encode as 0:empty, 1:uniform, 2:nonuniform, 3:mixed
|
||||
@ -147,12 +151,26 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
Pout<< "local uniform " << uniformity << nl;
|
||||
reduce
|
||||
// reduce with op<..>()
|
||||
#if 1
|
||||
Foam::reduce
|
||||
(
|
||||
uniformity.data(),
|
||||
uniformity.size_data(),
|
||||
bitOrOp<unsigned int>()
|
||||
uniformity.num_blocks(),
|
||||
bitOrOp<unsigned int>(),
|
||||
UPstream::msgType(), // ignored
|
||||
UPstream::worldComm
|
||||
);
|
||||
#else
|
||||
// Direct call to MPI_Allreduce
|
||||
UPstream::mpiAllReduce
|
||||
(
|
||||
uniformity.data(),
|
||||
uniformity.num_blocks(),
|
||||
UPstream::opCodes::op_bit_or,
|
||||
UPstream::worldComm
|
||||
);
|
||||
#endif
|
||||
Pout<< "reduce uniform " << uniformity << nl;
|
||||
}
|
||||
|
||||
@ -160,8 +178,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
Pair<label> val
|
||||
(
|
||||
Pstream::myProcNo(UPstream::commWorld()),
|
||||
Pstream::myProcNo(UPstream::commWorld())
|
||||
UPstream::myProcNo(UPstream::commWorld()),
|
||||
UPstream::myProcNo(UPstream::commWorld())
|
||||
);
|
||||
|
||||
Pair<label> worldVal = val;
|
||||
|
||||
@ -79,7 +79,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
#include "setRootCase.H"
|
||||
|
||||
if (!Pstream::parRun())
|
||||
if (!UPstream::parRun())
|
||||
{
|
||||
Info<< "\nWarning: not parallel - skipping further tests\n" << endl;
|
||||
return 0;
|
||||
@ -97,7 +97,7 @@ int main(int argc, char *argv[])
|
||||
DynamicList<MPI_Request> recvRequests(10);
|
||||
|
||||
|
||||
if (!Pstream::master())
|
||||
if (UPstream::is_subrank())
|
||||
{
|
||||
// Send some random length to master
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
#include "setRootCase.H"
|
||||
|
||||
if (!Pstream::parRun())
|
||||
if (!UPstream::parRun())
|
||||
{
|
||||
Info<< "\nWarning: not parallel - skipping further tests\n" << endl;
|
||||
return 0;
|
||||
@ -96,7 +96,7 @@ int main(int argc, char *argv[])
|
||||
// Map request indices to procs
|
||||
Map<label> recvFromProc(20);
|
||||
|
||||
if (!Pstream::master())
|
||||
if (UPstream::is_subrank())
|
||||
{
|
||||
// Send some random length to master
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
const bool optNonBlocking = args.found("non-blocking");
|
||||
|
||||
if (!Pstream::parRun())
|
||||
if (!UPstream::parRun())
|
||||
{
|
||||
Info<< "\nWarning: not parallel - skipping further tests\n" << endl;
|
||||
return 0;
|
||||
@ -73,7 +73,7 @@ int main(int argc, char *argv[])
|
||||
DynamicList<UPstream::Request> sendRequests(10);
|
||||
DynamicList<UPstream::Request> recvRequests(10);
|
||||
|
||||
if (!Pstream::master())
|
||||
if (UPstream::is_subrank())
|
||||
{
|
||||
// Send some random length to master
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2017-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2017-2025 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -422,20 +422,20 @@ public:
|
||||
// Low-level access
|
||||
|
||||
//- The number of internal storage blocks
|
||||
inline label nBlocks() const;
|
||||
inline label num_blocks() const noexcept;
|
||||
|
||||
//- Return the underlying storage blocks
|
||||
inline const List<unsigned int>& storage() const;
|
||||
const List<block_type>& storage() const noexcept { return blocks_; }
|
||||
|
||||
//- Return the underlying storage blocks
|
||||
// Manipulate with utmost caution
|
||||
inline List<unsigned int>& storage();
|
||||
List<block_type>& storage() noexcept { return blocks_; }
|
||||
|
||||
//- A const pointer to the raw storage
|
||||
inline const unsigned int* cdata() const noexcept;
|
||||
const block_type* cdata() const noexcept { return blocks_.cdata(); }
|
||||
|
||||
//- A pointer to the raw storage
|
||||
inline unsigned int* data() noexcept;
|
||||
block_type* data() noexcept { return blocks_.data(); }
|
||||
|
||||
//- A const pointer to the raw storage, reinterpreted as byte data
|
||||
inline const char* cdata_bytes() const noexcept;
|
||||
@ -443,15 +443,15 @@ public:
|
||||
//- A pointer to the raw storage, reinterpreted as byte data
|
||||
inline char* data_bytes() noexcept;
|
||||
|
||||
//- The number of integer blocks addressed in the raw storage
|
||||
//- The number of integer blocks addressed in the raw storage.
|
||||
//- Same as num_blocks().
|
||||
inline std::streamsize size_data() const noexcept;
|
||||
|
||||
//- The number of bytes used in the raw storage
|
||||
//- including any unused padding.
|
||||
//- The number of bytes addressed in the raw storage
|
||||
//- including any padding.
|
||||
inline std::streamsize size_bytes() const noexcept;
|
||||
|
||||
//- The number of bytes used in the raw storage
|
||||
//- including any unused padding.
|
||||
//- Same as size_bytes()
|
||||
inline std::streamsize byteSize() const noexcept;
|
||||
|
||||
|
||||
@ -465,7 +465,7 @@ public:
|
||||
|
||||
//- Write List, with line-breaks in ASCII when length exceeds shortLen.
|
||||
// Using '0' suppresses line-breaks entirely.
|
||||
Ostream& writeList(Ostream& os, const label shortLen=0) const;
|
||||
Ostream& writeList(Ostream& os, label shortLen=0) const;
|
||||
|
||||
//- Write as a dictionary entry with keyword
|
||||
void writeEntry(const word& keyword, Ostream& os) const;
|
||||
@ -529,10 +529,10 @@ public:
|
||||
public:
|
||||
|
||||
//- Copy construct
|
||||
reference(const reference&) = default;
|
||||
reference(const reference&) noexcept = default;
|
||||
|
||||
//- Move construct
|
||||
reference(reference&&) = default;
|
||||
reference(reference&&) noexcept = default;
|
||||
|
||||
//- Value assignment
|
||||
inline void operator=(const reference& other);
|
||||
|
||||
@ -609,40 +609,12 @@ inline void Foam::PackedList<Width>::shrink_to_fit()
|
||||
|
||||
|
||||
template<unsigned Width>
|
||||
inline Foam::List<unsigned int>& Foam::PackedList<Width>::storage()
|
||||
{
|
||||
return blocks_;
|
||||
}
|
||||
|
||||
|
||||
template<unsigned Width>
|
||||
inline const Foam::List<unsigned int>& Foam::PackedList<Width>::storage() const
|
||||
{
|
||||
return blocks_;
|
||||
}
|
||||
|
||||
|
||||
template<unsigned Width>
|
||||
inline Foam::label Foam::PackedList<Width>::nBlocks() const
|
||||
inline Foam::label Foam::PackedList<Width>::num_blocks() const noexcept
|
||||
{
|
||||
return num_blocks(size());
|
||||
}
|
||||
|
||||
|
||||
template<unsigned Width>
|
||||
inline const unsigned int* Foam::PackedList<Width>::cdata() const noexcept
|
||||
{
|
||||
return blocks_.cdata();
|
||||
}
|
||||
|
||||
|
||||
template<unsigned Width>
|
||||
inline unsigned int* Foam::PackedList<Width>::data() noexcept
|
||||
{
|
||||
return blocks_.data();
|
||||
}
|
||||
|
||||
|
||||
template<unsigned Width>
|
||||
inline const char* Foam::PackedList<Width>::cdata_bytes() const noexcept
|
||||
{
|
||||
@ -667,7 +639,7 @@ inline std::streamsize Foam::PackedList<Width>::size_data() const noexcept
|
||||
template<unsigned Width>
|
||||
inline std::streamsize Foam::PackedList<Width>::size_bytes() const noexcept
|
||||
{
|
||||
return size_data() * sizeof(block_type);
|
||||
return num_blocks(size()) * sizeof(block_type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2018-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2025 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -178,12 +178,14 @@ template<unsigned Width>
|
||||
Foam::Ostream& Foam::PackedList<Width>::writeList
|
||||
(
|
||||
Ostream& os,
|
||||
const label shortLen
|
||||
label shortLen
|
||||
) const
|
||||
{
|
||||
const PackedList<Width>& list = *this;
|
||||
const label len = list.size();
|
||||
|
||||
if (shortLen < 0) shortLen = 1; // <- sanity
|
||||
|
||||
if (os.format() == IOstreamOption::BINARY)
|
||||
{
|
||||
// Binary (always contiguous)
|
||||
@ -209,7 +211,7 @@ Foam::Ostream& Foam::PackedList<Width>::writeList
|
||||
os << len << token::BEGIN_LIST;
|
||||
|
||||
// Contents
|
||||
for (label i=0; i < len; ++i)
|
||||
for (label i = 0; i < len; ++i)
|
||||
{
|
||||
if (i) os << token::SPACE;
|
||||
os << label(list.get(i));
|
||||
@ -226,9 +228,33 @@ Foam::Ostream& Foam::PackedList<Width>::writeList
|
||||
os << nl << len << nl << token::BEGIN_LIST << nl;
|
||||
|
||||
// Contents
|
||||
for (label i=0; i < len; ++i)
|
||||
if (shortLen <= 1)
|
||||
{
|
||||
os << label(list.get(i)) << nl;
|
||||
// simple multi-line
|
||||
for (label i = 0; i < len; ++i)
|
||||
{
|
||||
os << label(list.get(i)) << nl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 'matrix' of values
|
||||
label line = 0;
|
||||
|
||||
for (label i = 0; i < len; ++i, ++line)
|
||||
{
|
||||
if (line == shortLen)
|
||||
{
|
||||
os << nl;
|
||||
line = 0;
|
||||
}
|
||||
else if (line)
|
||||
{
|
||||
os << token::SPACE;
|
||||
}
|
||||
os << label(list.get(i));
|
||||
}
|
||||
if (line) os << nl;
|
||||
}
|
||||
|
||||
// End delimiter
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2018-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2025 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -28,14 +28,19 @@ License
|
||||
#include "bitSet.H"
|
||||
#include "labelRange.H"
|
||||
#include "IOstreams.H"
|
||||
#include "UPstream.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
defineTypeNameAndDebug(bitSet, 0);
|
||||
}
|
||||
|
||||
// TBD: add IO support of compound type?
|
||||
// defineNamedCompoundTypeName(bitSet, List<1>);
|
||||
// addNamedCompoundToRunTimeSelectionTable(bitSet, bitSet, List<1>);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
||||
|
||||
@ -76,7 +81,7 @@ Foam::bitSet& Foam::bitSet::minusEq(const bitSet& other)
|
||||
|
||||
Foam::bitSet& Foam::bitSet::andEq(const bitSet& other)
|
||||
{
|
||||
if (&other == this)
|
||||
if (FOAM_UNLIKELY(&other == this))
|
||||
{
|
||||
// Self '&=' : no-op
|
||||
|
||||
@ -273,19 +278,24 @@ Foam::bitSet::bitSet(const labelRange& range)
|
||||
|
||||
void Foam::bitSet::assign(const UList<bool>& bools)
|
||||
{
|
||||
const label len = bools.size();
|
||||
fill(false);
|
||||
resize(bools.size());
|
||||
|
||||
clear();
|
||||
resize(len);
|
||||
unsigned bitIdx = 0u;
|
||||
auto* packed = blocks_.data();
|
||||
|
||||
// Could also handle block-wise (in the future?)
|
||||
|
||||
// Set according to indices that are true.
|
||||
for (label i = 0; i < len; ++i)
|
||||
// Set according to indices that are true
|
||||
for (const auto b : bools)
|
||||
{
|
||||
if (bools[i])
|
||||
if (b)
|
||||
{
|
||||
set(i);
|
||||
*packed |= (1u << bitIdx);
|
||||
}
|
||||
|
||||
if (++bitIdx >= PackedList<1>::elem_per_block)
|
||||
{
|
||||
bitIdx = 0u;
|
||||
++packed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -540,4 +550,209 @@ Foam::List<bool> Foam::bitSet::values() const
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * Parallel Functions * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::bitSet::broadcast(int communicator, bool syncSizes)
|
||||
{
|
||||
if (communicator < 0)
|
||||
{
|
||||
communicator = UPstream::worldComm;
|
||||
}
|
||||
|
||||
if (!UPstream::is_parallel(communicator))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t len(size());
|
||||
|
||||
if (syncSizes)
|
||||
{
|
||||
UPstream::broadcast(&len, 1, communicator);
|
||||
|
||||
if (UPstream::is_subrank(communicator))
|
||||
{
|
||||
fill(false);
|
||||
resize(len);
|
||||
}
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
// Only broadcast non-empty
|
||||
UPstream::broadcast(this->data(), this->num_blocks(), communicator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::bitSet::reduceAnd(int communicator, bool syncSizes)
|
||||
{
|
||||
if (communicator < 0)
|
||||
{
|
||||
communicator = UPstream::worldComm;
|
||||
}
|
||||
|
||||
if (!UPstream::is_parallel(communicator))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const label origSize(size());
|
||||
|
||||
if (syncSizes)
|
||||
{
|
||||
// Operation is an intersection
|
||||
// - common size may be smaller than the original size
|
||||
int64_t commonSize(size());
|
||||
|
||||
UPstream::mpiAllReduce
|
||||
(
|
||||
&commonSize,
|
||||
1,
|
||||
UPstream::opCodes::op_min,
|
||||
communicator
|
||||
);
|
||||
resize(commonSize);
|
||||
}
|
||||
|
||||
if (!empty())
|
||||
{
|
||||
UPstream::mpiAllReduce
|
||||
(
|
||||
this->data(),
|
||||
this->num_blocks(),
|
||||
UPstream::opCodes::op_bit_and,
|
||||
communicator
|
||||
);
|
||||
|
||||
clear_trailing_bits(); // safety
|
||||
}
|
||||
|
||||
// Undo side effects from the reduction
|
||||
if (syncSizes)
|
||||
{
|
||||
resize(origSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::bitSet::reduceOr(int communicator, bool syncSizes)
|
||||
{
|
||||
if (communicator < 0)
|
||||
{
|
||||
communicator = UPstream::worldComm;
|
||||
}
|
||||
|
||||
if (!UPstream::is_parallel(communicator))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// const label origSize(size());
|
||||
|
||||
if (syncSizes)
|
||||
{
|
||||
// Operation can increase the addressed size
|
||||
|
||||
// Extend size based on the addressed length.
|
||||
// This is greedy, but produces consistent sizing
|
||||
int64_t commonSize(size());
|
||||
|
||||
// Alternative: Extend size based on the bits used.
|
||||
// - tighter, but inconsistent sizes result
|
||||
// // label commonSize(find_last()+1);
|
||||
|
||||
UPstream::mpiAllReduce
|
||||
(
|
||||
&commonSize,
|
||||
1,
|
||||
UPstream::opCodes::op_max,
|
||||
communicator
|
||||
);
|
||||
|
||||
extend(commonSize);
|
||||
}
|
||||
|
||||
if (!empty())
|
||||
{
|
||||
UPstream::mpiAllReduce
|
||||
(
|
||||
this->data(),
|
||||
this->num_blocks(),
|
||||
UPstream::opCodes::op_bit_or,
|
||||
communicator
|
||||
);
|
||||
|
||||
clear_trailing_bits(); // safety
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::bitSet Foam::bitSet::gatherValues(bool localValue, int communicator)
|
||||
{
|
||||
if (communicator < 0)
|
||||
{
|
||||
communicator = UPstream::worldComm;
|
||||
}
|
||||
|
||||
bitSet allValues;
|
||||
|
||||
if (!UPstream::is_parallel(communicator))
|
||||
{
|
||||
// non-parallel: return own value
|
||||
// TBD: only when UPstream::is_rank(communicator) as well?
|
||||
allValues.resize(1);
|
||||
allValues.set(0, localValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<bool> bools;
|
||||
if (UPstream::master(communicator))
|
||||
{
|
||||
bools.resize(UPstream::nProcs(communicator), false);
|
||||
}
|
||||
|
||||
UPstream::mpiGather
|
||||
(
|
||||
&localValue, // Send
|
||||
bools.data(), // Recv
|
||||
1, // Num send/recv data per rank
|
||||
communicator
|
||||
);
|
||||
|
||||
// Transcribe to bitSet (on master)
|
||||
allValues.assign(bools);
|
||||
}
|
||||
|
||||
return allValues;
|
||||
}
|
||||
|
||||
|
||||
// Note that for allGather()
|
||||
// - MPI_Gather of individual bool values and broadcast the packed result
|
||||
// - this avoids bit_or on 32bit values everywhere, since we know a priori
|
||||
// that each rank only contributes 1bit of info
|
||||
|
||||
Foam::bitSet Foam::bitSet::allGather(bool localValue, int communicator)
|
||||
{
|
||||
if (communicator < 0)
|
||||
{
|
||||
communicator = UPstream::worldComm;
|
||||
}
|
||||
|
||||
bitSet allValues(bitSet::gatherValues(localValue, communicator));
|
||||
|
||||
if (UPstream::is_parallel(communicator))
|
||||
{
|
||||
// Identical size on all ranks
|
||||
allValues.resize(UPstream::nProcs(communicator));
|
||||
|
||||
// Sizes are consistent - broadcast without resizing
|
||||
allValues.broadcast(communicator, false);
|
||||
}
|
||||
|
||||
return allValues;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2018-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2025 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -46,7 +46,6 @@ See also
|
||||
#ifndef Foam_bitSet_H
|
||||
#define Foam_bitSet_H
|
||||
|
||||
#include "className.H"
|
||||
#include "PackedList.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
@ -111,7 +110,11 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
// Forward declaration of access classes
|
||||
//- A bitSet acts like a packed boolList
|
||||
typedef bool value_type;
|
||||
|
||||
|
||||
// Forward Declarations
|
||||
|
||||
class reference;
|
||||
class const_iterator;
|
||||
@ -331,6 +334,13 @@ public:
|
||||
// set(pos) on individual bits.
|
||||
void set(const labelRange& range);
|
||||
|
||||
//- Test for \em True value at specified position
|
||||
//- and change the value at that position.
|
||||
// Does auto-vivify for non-existent, non-zero entries.
|
||||
//
|
||||
// \note Method name compatibility with std::bitset
|
||||
bool test_set(const label i, const bool val = true);
|
||||
|
||||
|
||||
// Unsetting single or multiple values
|
||||
|
||||
@ -475,10 +485,10 @@ public:
|
||||
public:
|
||||
|
||||
//- Copy construct
|
||||
reference(const reference&) = default;
|
||||
reference(const reference&) noexcept = default;
|
||||
|
||||
//- Move construct
|
||||
reference(reference&&) = default;
|
||||
reference(reference&&) noexcept = default;
|
||||
|
||||
//- Flip the bit at the position, no range-checking
|
||||
inline void flip();
|
||||
@ -605,6 +615,61 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// Parallel Operations
|
||||
|
||||
//- Broadcast the contents
|
||||
void broadcast
|
||||
(
|
||||
//! The UPstream communicator (default is worldComm)
|
||||
int communicator = -1,
|
||||
//! False: sizes already consistent. True: adjust sizes.
|
||||
bool syncSizes = true
|
||||
);
|
||||
|
||||
//- Inplace \c bit_and parallel reduction
|
||||
void reduceAnd
|
||||
(
|
||||
//! The UPstream communicator (default is worldComm)
|
||||
int communicator = -1,
|
||||
//! False: sizes already consistent. True: adjust (shrink) sizes.
|
||||
bool syncSizes = true
|
||||
);
|
||||
|
||||
//- Inplace \c bit_or parallel reduction
|
||||
void reduceOr
|
||||
(
|
||||
//! The UPstream communicator (default is worldComm)
|
||||
int communicator = -1,
|
||||
//! False: sizes already consistent. True: adjust (extend) sizes.
|
||||
bool syncSizes = true
|
||||
);
|
||||
|
||||
//- Gather individual values into bitSet locations.
|
||||
// On master, the resulting bitSet has size == nProcs,
|
||||
// otherwise zero length.
|
||||
// \n
|
||||
// For \b non-parallel :
|
||||
// the length of the returned set is 1 with localValue.
|
||||
static bitSet gatherValues
|
||||
(
|
||||
//! The processor-local value
|
||||
bool localValue,
|
||||
//! The UPstream communicator (default is worldComm)
|
||||
int communicator = -1
|
||||
);
|
||||
|
||||
//- Allgather individual values into bitSet locations.
|
||||
// The resulting bitSet has size nProcs, identical on all ranks.
|
||||
// Behaves like Pstream::allGatherValues() but returning a bitSet.
|
||||
static bitSet allGather
|
||||
(
|
||||
//! The processor-local value
|
||||
bool localValue,
|
||||
//! The UPstream communicator (default is worldComm)
|
||||
int communicator = -1
|
||||
);
|
||||
|
||||
|
||||
// Housekeeping
|
||||
|
||||
//- Same as contains()
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2018-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2025 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -482,23 +482,27 @@ inline void Foam::bitSet::fill(const bool val)
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
return; // Trivial case
|
||||
return;
|
||||
}
|
||||
|
||||
const label nblocks = num_blocks(size());
|
||||
|
||||
// Fill value for complete blocks
|
||||
const unsigned int blockval = (val ? ~0u : 0u);
|
||||
|
||||
for (label blocki=0; blocki < nblocks; ++blocki)
|
||||
{
|
||||
blocks_[blocki] = blockval;
|
||||
}
|
||||
|
||||
if (val)
|
||||
else if (val)
|
||||
{
|
||||
std::fill_n(blocks_.data(), num_blocks(), ~0u);
|
||||
clear_trailing_bits();
|
||||
}
|
||||
else
|
||||
{
|
||||
// or: PackedList<1>::reset();
|
||||
// or: blocks_ = 0u;
|
||||
std::fill_n(blocks_.data(), num_blocks(), 0u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::bitSet::test_set(const label i, const bool val)
|
||||
{
|
||||
bool old = test(i);
|
||||
PackedList<1>::set(i, val);
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -51,6 +51,9 @@ SourceFiles
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Forward Declarations
|
||||
class bitSet;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class Pstream Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -149,6 +149,11 @@ void Foam::Pstream::broadcastList
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if constexpr (std::is_same_v<bitSet, ListType>)
|
||||
{
|
||||
// Specialized handling implemented within bitSet itself
|
||||
list.broadcast(communicator);
|
||||
}
|
||||
else if constexpr (is_contiguous_v<typename ListType::value_type>)
|
||||
{
|
||||
// List data are contiguous
|
||||
@ -166,6 +171,11 @@ void Foam::Pstream::broadcastList
|
||||
communicator
|
||||
);
|
||||
|
||||
if (UPstream::is_subrank(communicator))
|
||||
{
|
||||
list.resize_nocopy(len);
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
// Only broadcast non-empty content
|
||||
|
||||
Reference in New Issue
Block a user