ENH: improve flexibilty of globalIndex

- construct or reset from a list of local sizes. It is generally
  easier and safer to assemble sizes and let globalIndex determine the
  corresponding offsets, when working with raw values.

- Can use reset() from sizes or fine-tune offsets with setLocalSize()
  instead of using the potentially more fragile non-const access to
  the offsets.

- add globalIndex const_iterator to iterate across the access ranges.
  This is makes it simpler to use with the List slice() method to
  access or operate on a sub-section of list.

  For example,
      scalarField allValues = ...;
      globalIndex procAccess = ...;

      for (const labelRange& range : procAccess)
      {
          someOutput(allValues.slice(range));
      }
This commit is contained in:
Mark Olesen
2021-10-15 14:42:21 +02:00
parent b8a4b7e80d
commit 609fb366e3
4 changed files with 577 additions and 65 deletions

View File

@ -27,6 +27,84 @@ License
\*---------------------------------------------------------------------------*/
#include "globalIndex.H"
#include "labelRange.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::labelList
Foam::globalIndex::calcOffsets
(
const labelUList& localSizes,
const bool checkOverflow
)
{
labelList values;
const label len = localSizes.size();
if (len)
{
values.resize(len+1);
label start = 0;
for (label i = 0; i < len; ++i)
{
values[i] = start;
start += localSizes[i];
if (checkOverflow && start < values[i])
{
FatalErrorInFunction
<< "Overflow : sum of sizes exceeds labelMax ("
<< labelMax << ") after index " << i << " of "
<< flatOutput(localSizes) << nl
<< "Please recompile with larger datatype for label." << nl
<< exit(FatalError);
}
}
values[len] = start;
}
return values;
}
Foam::List<Foam::labelRange>
Foam::globalIndex::calcRanges
(
const labelUList& localSizes,
const bool checkOverflow
)
{
List<labelRange> values;
const label len = localSizes.size();
if (len)
{
values.resize(len);
label start = 0;
for (label i = 0; i < len; ++i)
{
values[i].reset(start, localSizes[i]);
start += localSizes[i];
if (checkOverflow && start < values[i].start())
{
FatalErrorInFunction
<< "Overflow : sum of sizes exceeds labelMax ("
<< labelMax << ") after index " << i << " of "
<< flatOutput(localSizes) << nl
<< "Please recompile with larger datatype for label." << nl
<< exit(FatalError);
}
}
}
return values;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
@ -52,8 +130,8 @@ void Foam::globalIndex::bin
bins.m() = UIndirectList<label>(globalIds, order);
labelList& binOffsets = bins.offsets();
binOffsets.setSize(offsets.size());
binOffsets = 0;
binOffsets.resize_nocopy(offsets.size());
binOffsets = Zero;
validBins.clear();
@ -106,9 +184,12 @@ void Foam::globalIndex::reset
const bool parallel
)
{
offsets_.resize(Pstream::nProcs(comm)+1);
const label len = Pstream::nProcs(comm);
labelList localSizes(Pstream::nProcs(comm), Zero);
if (len)
{
// Seed with localSize, zero elsewhere (for non-parallel branch)
labelList localSizes(len, Zero);
localSizes[Pstream::myProcNo(comm)] = localSize;
if (parallel)
@ -117,22 +198,66 @@ void Foam::globalIndex::reset
Pstream::scatterList(localSizes, tag, comm);
}
label offset = 0;
offsets_[0] = 0;
for (const int proci : Pstream::allProcs(comm))
reset(localSizes, true); // checkOverflow = true
}
else
{
const label oldOffset = offset;
offset += localSizes[proci];
offsets_.clear();
}
}
if (offset < oldOffset)
void Foam::globalIndex::reset
(
const labelUList& localSizes,
const bool checkOverflow
)
{
const label len = localSizes.size();
if (len)
{
offsets_.resize_nocopy(len+1);
label start = 0;
for (label i = 0; i < len; ++i)
{
offsets_[i] = start;
start += localSizes[i];
if (checkOverflow && start < offsets_[i])
{
FatalErrorInFunction
<< "Overflow : sum of sizes " << localSizes
<< " exceeds capability of label (" << labelMax
<< "). Please recompile with larger datatype for label."
<< "Overflow : sum of sizes exceeds labelMax ("
<< labelMax << ") after index " << i << " of "
<< flatOutput(localSizes) << nl
<< "Please recompile with larger datatype for label." << nl
<< exit(FatalError);
}
offsets_[proci+1] = offset;
}
offsets_[len] = start;
}
else
{
offsets_.clear();
}
}
void Foam::globalIndex::setLocalSize(const label proci, const label len)
{
if (proci >= 0 && proci+1 < offsets_.size() && len >= 0)
{
const label delta = (len - (offsets_[proci+1] - offsets_[proci]));
// TBD: additional overflow check
if (delta)
{
for (label i = proci+1; i < offsets_.size(); ++i)
{
offsets_[i] += delta;
}
}
}
}
@ -159,6 +284,33 @@ Foam::labelList Foam::globalIndex::sizes() const
}
Foam::List<Foam::labelRange>
Foam::globalIndex::ranges() const
{
List<labelRange> values;
const label len = (offsets_.size() - 1);
if (len < 1)
{
return values;
}
values.resize(len);
for (label proci=0; proci < len; ++proci)
{
values[proci].reset
(
offsets_[proci],
(offsets_[proci+1] - offsets_[proci])
);
}
return values;
}
Foam::label Foam::globalIndex::maxNonLocalSize(const label proci) const
{
const label len = (offsets_.size() - 1);

View File

@ -68,6 +68,12 @@ Ostream& operator<<(Ostream& os, const globalIndex& gi);
class globalIndex
{
// Private Data
//- Start of proci. Size is nProcs()+1. (so like CompactListList)
labelList offsets_;
// Private Member Functions
//- Sort and bin. validBins contains bins with non-zero size.
@ -80,26 +86,42 @@ class globalIndex
DynamicList<label>& validBins
);
// Private Data
//- Start of proci. Size is nProcs()+1. (so like CompactListList)
labelList offsets_;
public:
// Public Data Types
//- Disambiguation tag (list construction dispatch)
enum accessType : char { OFFSETS, SIZES };
// Constructors
//- Default construct
globalIndex() = default;
//- Construct from local max size.
// Does communication with default communicator and message tag.
//- Copy construct from a list of offsets.
//- No communication required
inline explicit globalIndex(const labelUList& listOffsets);
//- Move construct from a list of offsets.
//- No communication required
inline explicit globalIndex(labelList&& listOffsets);
//- Copy construct from a list of offsets or sizes.
//- No communication required
inline globalIndex
(
const labelUList& offsetsOrSizes,
enum accessType accType
);
//- Construct from local size.
// Communication with default communicator and message tag.
inline explicit globalIndex(const label localSize);
//- Construct from local max size.
// Does communication with given communicator and message tag
//- Construct from local size.
// Communication with given communicator and message tag,
// unless parallel == false
inline globalIndex
(
const label localSize,
@ -108,13 +130,8 @@ public:
const bool parallel //!< use parallel comms
);
//- Copy construct from list of labels
inline explicit globalIndex(const labelUList& offsets);
//- Move construct from list of labels
inline explicit globalIndex(labelList&& offsets);
//- Construct from Istream
//- Construct from Istream.
//- No communication required
explicit globalIndex(Istream& is);
@ -123,9 +140,6 @@ public:
//- Check for default constructed or global sum == 0
inline bool empty() const;
//- The number of processors covered by the offsets
inline label nProcs() const noexcept;
//- Global sum of localSizes
inline label size() const;
@ -142,6 +156,18 @@ public:
inline const labelList& offsets() const noexcept;
// Dimensions
//- The number of processors covered by the offsets
inline label nProcs() const noexcept;
//- Range of process indices for all addressed offsets (processes)
inline labelRange allProcs() const noexcept;
//- Range of process indices for addressed sub-offsets (processes)
inline labelRange subProcs() const noexcept;
// Edit
//- Write-access to the offsets, for changing after construction
@ -152,7 +178,8 @@ public:
inline void reset(const label localSize);
//- Reset from local size.
// Does communication with given communicator and message tag
// Does communication with given communicator and message tag,
// unless parallel == false
void reset
(
const label localSize,
@ -161,6 +188,18 @@ public:
const bool parallel //!< use parallel comms
);
//- Reset from list of local sizes,
//- with optional check for label overflow.
//- No communication required
void reset
(
const labelUList& sizes,
const bool checkOverflow = false
);
//- Alter local size for given processor
void setLocalSize(const label proci, const label len);
// Queries
@ -178,6 +217,9 @@ public:
//- Return start/size range of local processor data
inline labelRange range() const;
//- Return start/size ranges for all data
List<labelRange> ranges() const;
//- Is on local processor
inline bool isLocal(const label i) const;
@ -240,6 +282,99 @@ public:
inline label whichProcID(const label i) const;
// Iteration
//- Forward input iterator with const access
class const_iterator
{
//- The parent class for which this is an iterator
const globalIndex* parent_;
//- The index into the parent
label proci_;
public:
// Constructors
//- Construct from globalIndex list at given index
explicit const_iterator
(
const globalIndex* globalIdx,
const label proci = 0
) noexcept;
// Member Operators
//- The associated local proc
inline label proci() const noexcept;
//- The local start
inline label start() const;
//- The local size
inline label size() const;
//- The local range
inline labelRange range() const;
//- The local range
inline labelRange operator*() const;
inline const_iterator& operator++();
inline const_iterator operator++(int);
inline const_iterator& operator--();
inline const_iterator operator--(int);
inline bool operator==(const const_iterator& iter) const noexcept;
inline bool operator!=(const const_iterator& iter) const noexcept;
};
//- A const_iterator set to the beginning
inline const_iterator cbegin() const noexcept;
//- A const_iterator set to beyond the end
inline const const_iterator cend() const noexcept;
//- A const_iterator set to the beginning
inline const_iterator begin() const noexcept;
//- A const_iterator set to beyond the end
inline const const_iterator end() const noexcept;
// Helper Functions
//- Calculate offsets from a list of local sizes,
//- with optional check for label overflow
static labelList calcOffsets
(
const labelUList& localSizes,
const bool checkOverflow = false
);
//- Calculate offsets from list of lists,
//- with optional check for label overflow
template<class SubListType>
static labelList calcListOffsets
(
const List<SubListType>& lists,
const bool checkOverflow = false
);
//- Calculate ranges (offset/size) from a list of local sizes,
//- with optional check for label overflow
static List<labelRange> calcRanges
(
const labelUList& localSizes,
const bool checkOverflow = false
);
// Other
//- Collect data in processor order on master (== procIDs[0]).

View File

@ -31,9 +31,53 @@ License
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::globalIndex::globalIndex
(
const labelUList& listOffsets
)
{
if (listOffsets.size() > 1)
{
offsets_ = listOffsets;
}
}
inline Foam::globalIndex::globalIndex
(
labelList&& listOffsets
)
{
if (listOffsets.size() > 1)
{
offsets_.transfer(listOffsets);
}
else
{
listOffsets.clear();
}
}
inline Foam::globalIndex::globalIndex
(
const labelUList& offsetsOrSizes,
enum globalIndex::accessType accType
)
{
if (accType == accessType::SIZES)
{
reset(offsetsOrSizes);
}
else if (offsetsOrSizes.size() > 1)
{
// accessType::OFFSETS
offsets_ = offsetsOrSizes;
}
}
inline Foam::globalIndex::globalIndex(const label localSize)
:
globalIndex()
{
reset(localSize);
}
@ -46,25 +90,11 @@ inline Foam::globalIndex::globalIndex
const label comm,
const bool parallel
)
:
globalIndex()
{
reset(localSize, tag, comm, parallel);
}
inline Foam::globalIndex::globalIndex(const labelUList& offsets)
:
offsets_(offsets)
{}
inline Foam::globalIndex::globalIndex(labelList&& offsets)
:
offsets_(std::move(offsets))
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool Foam::globalIndex::empty() const
@ -76,7 +106,23 @@ inline bool Foam::globalIndex::empty() const
inline Foam::label Foam::globalIndex::nProcs() const noexcept
{
const label len = (offsets_.size() - 1);
return (len < 1) ? 0 : len;
return (len < 1) ? static_cast<label>(0) : len;
}
inline Foam::labelRange Foam::globalIndex::allProcs() const noexcept
{
// Proc 0 -> nProcs
const label len = (offsets_.size() - 1);
return (len < 1) ? labelRange() : labelRange(0, len);
}
inline Foam::labelRange Foam::globalIndex::subProcs() const noexcept
{
// Proc 1 -> nProcs
const label len = (offsets_.size() - 2);
return (len < 1) ? labelRange() : labelRange(1, len);
}
@ -104,7 +150,7 @@ inline const Foam::labelUList Foam::globalIndex::localStarts() const
inline Foam::label Foam::globalIndex::size() const
{
return offsets_.empty() ? 0 : offsets_.last();
return offsets_.empty() ? static_cast<label>(0) : offsets_.last();
}
@ -276,4 +322,143 @@ inline Foam::label Foam::globalIndex::whichProcID(const label i) const
}
// * * * * * * * * * * * * * * * * Iterators * * * * * * * * * * * * * * * * //
inline Foam::globalIndex::const_iterator::
const_iterator
(
const globalIndex* globalIdx,
const label i
) noexcept
:
parent_(globalIdx),
proci_(i)
{}
inline Foam::label Foam::globalIndex::const_iterator::
proci() const noexcept
{
return proci_;
}
inline Foam::label Foam::globalIndex::const_iterator::
start() const
{
return (*parent_).localStart(proci_);
}
inline Foam::label Foam::globalIndex::const_iterator::
size() const
{
return (*parent_).localSize(proci_);
}
inline Foam::labelRange Foam::globalIndex::const_iterator::
range() const
{
return (*parent_).range(proci_);
}
inline Foam::labelRange Foam::globalIndex::const_iterator::
operator*() const
{
return this->range();
}
inline Foam::globalIndex::const_iterator&
Foam::globalIndex::const_iterator::
operator++()
{
++proci_;
return *this;
}
inline Foam::globalIndex::const_iterator
Foam::globalIndex::const_iterator::
operator++(int)
{
const_iterator old(*this);
++proci_;
return old;
}
inline Foam::globalIndex::const_iterator&
Foam::globalIndex::const_iterator::
operator--()
{
--proci_;
return *this;
}
inline Foam::globalIndex::const_iterator
Foam::globalIndex::const_iterator::
operator--(int)
{
const_iterator old(*this);
--proci_;
return old;
}
inline bool
Foam::globalIndex::const_iterator::
operator==
(
const const_iterator& iter
) const noexcept
{
return (proci_ == iter.proci_);
}
inline bool
Foam::globalIndex::const_iterator::
operator!=
(
const const_iterator& iter
) const noexcept
{
return (proci_ != iter.proci_);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline Foam::globalIndex::const_iterator
Foam::globalIndex::cbegin() const noexcept
{
return const_iterator(this);
}
inline const Foam::globalIndex::const_iterator
Foam::globalIndex::cend() const noexcept
{
return const_iterator(this, this->nProcs());
}
inline Foam::globalIndex::const_iterator
Foam::globalIndex::begin() const noexcept
{
return const_iterator(this);
}
inline const Foam::globalIndex::const_iterator
Foam::globalIndex::end() const noexcept
{
return const_iterator(this, this->nProcs());
}
// ************************************************************************* //

View File

@ -28,6 +28,46 @@ License
#include "globalIndex.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
template<class SubListType>
Foam::labelList
Foam::globalIndex::calcListOffsets
(
const List<SubListType>& lists,
const bool checkOverflow
)
{
labelList values;
const label len = lists.size();
if (len)
{
values.resize(len+1);
label start = 0;
for (label i = 0; i < len; ++i)
{
values[i] = start;
start += lists[i].size();
if (checkOverflow && start < values[i])
{
FatalErrorInFunction
<< "Overflow : sum of sizes exceeds labelMax ("
<< labelMax << ") after index " << i << nl
<< "Please recompile with larger datatype for label." << nl
<< exit(FatalError);
}
}
values[len] = start;
}
return values;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Container, class Type>