30#include "../code_config.hpp"
31#include "../containers/C2DContainer.hpp"
32#include "../parallelization/omp_structure.hpp"
58template <
typename Index_t>
60 static_assert(std::is_integral<Index_t>::value);
93 template <
class Iterator>
95 const auto size = outerPtrEnd - outerPtrBegin;
98 for (
auto it = outerPtrBegin; it != outerPtrEnd; ++it) m_outerPtr(k++) = *it;
100 m_innerIdx.
resize(m_outerPtr(size - 1)) = defaultInnerIdx;
112 assert(m_innerIdx.
size() == m_outerPtr(m_outerPtr.
size() - 1));
130 assert(m_innerIdx.
size() == m_outerPtr(m_outerPtr.
size() - 1));
139 m_outerPtr.
resize(lil.size() + 1);
141 for (Index_t i = 1; i < Index_t(m_outerPtr.
size()); ++i) m_outerPtr(i) = m_outerPtr(i - 1) + lil[i - 1].
size();
143 m_innerIdx.
resize(m_outerPtr(lil.size()));
145 for (Index_t i = 0; i < Index_t(lil.size()); ++i)
146 for (Index_t j = 0; j < Index_t(lil[i].size()); ++j) m_innerIdx(k++) = lil[i][j];
153 if (!m_diagPtr.
empty())
return;
166 if (!m_innerIdxTransp.
empty())
return;
172 for (Index_t k = m_outerPtr(i); k < m_outerPtr(i + 1); ++k) {
173 auto j = m_innerIdx(k);
175 assert(m_innerIdxTransp(k) != m_innerIdx.
size() &&
"The pattern is not symmetric.");
200 inline Index_t
getNumNonZeros(Index_t iOuterIdx)
const {
return m_outerPtr(iOuterIdx + 1) - m_outerPtr(iOuterIdx); }
207 inline Index_t
getInnerIdx(Index_t iOuterIdx, Index_t iNonZero)
const {
209 return m_innerIdx(m_outerPtr(iOuterIdx) + iNonZero);
217 inline Index_t&
getInnerIdx(Index_t iOuterIdx, Index_t iNonZero) {
219 return m_innerIdx(m_outerPtr(iOuterIdx) + iNonZero);
227 return CInnerIter(m_innerIdx.
data() + m_outerPtr(iOuterIdx), m_innerIdx.
data() + m_outerPtr(iOuterIdx + 1));
236 inline Index_t
findInnerIdx(Index_t iOuterIdx, Index_t iInnerIdx)
const {
237 for (Index_t k = m_outerPtr(iOuterIdx); k < m_outerPtr(iOuterIdx + 1); ++k)
238 if (m_innerIdx(k) == iInnerIdx)
return k;
239 return m_innerIdx.
size();
247 inline bool isNonZero(Index_t iOuterIdx, Index_t iInnerIdx)
const {
258 assert(
isNonZero(iOuterIdx, iInnerIdx) &&
"Error, j does not belong to NZ(i).");
259 Index_t k = m_outerPtr(iOuterIdx);
260 while (m_innerIdx(k) != iInnerIdx) ++k;
268 inline Index_t
getDiagPtr(Index_t iDiagIdx)
const {
return m_diagPtr(iDiagIdx); }
274 assert(!
empty() &&
"Sparse pattern has not been built.");
275 return m_outerPtr.
data();
282 assert(!
empty() &&
"Sparse pattern has not been built.");
283 return m_innerIdx.
data();
289 inline const Index_t*
innerIdx(Index_t iOuterIdx)
const {
290 assert(!
empty() &&
"Sparse pattern has not been built.");
291 return m_innerIdx.
data() + m_outerPtr(iOuterIdx);
298 assert(!m_diagPtr.
empty() &&
"Diagonal map has not been built.");
299 return m_diagPtr.
data();
306 assert(!m_innerIdxTransp.
empty() &&
"Transpose map has not been built.");
307 return m_innerIdxTransp;
314 Index_t idx = std::numeric_limits<Index_t>::max();
315 for (Index_t k = 0; k < m_innerIdx.
size(); ++k) idx = std::min(idx, m_innerIdx(k));
323 Index_t idx = std::numeric_limits<Index_t>::min();
324 for (Index_t k = 0; k < m_innerIdx.
size(); ++k) idx = std::max(idx, m_innerIdx(k));
334template <
typename Index_t>
354template <
class Geometry_t,
typename Index_t>
356 Index_t nPoint = geometry.GetnPoint();
358 std::vector<Index_t> outerPtr(nPoint + 1);
359 std::vector<Index_t> innerIdx;
360 innerIdx.reserve(nPoint);
362 for (Index_t iPoint = 0; iPoint < nPoint; ++iPoint) {
364 outerPtr[iPoint] = innerIdx.size();
367 std::set<Index_t> neighbors;
370 neighbors.insert(iPoint);
373 std::set<Index_t> addedNeighbors(neighbors);
375 for (Index_t iLevel = 0;; ++iLevel) {
377 std::set<Index_t> newNeighbors;
381 for (
auto jPoint : addedNeighbors) {
384 for (Index_t kPoint : geometry.nodes->GetPoints(jPoint))
385 if (neighbors.count(kPoint) == 0)
386 newNeighbors.insert(kPoint);
390 for (
auto iElem : geometry.nodes->GetElems(jPoint)) {
391 auto elem = geometry.elem[iElem];
393 for (
unsigned short iNode = 0; iNode < elem->GetnNodes(); ++iNode) {
394 Index_t kPoint = elem->GetNode(iNode);
396 if (neighbors.count(kPoint) == 0)
397 newNeighbors.insert(kPoint);
403 neighbors.insert(newNeighbors.begin(), newNeighbors.end());
405 if (iLevel >= fillLvl)
break;
408 addedNeighbors = newNeighbors;
412 innerIdx.insert(innerIdx.end(), neighbors.begin(), neighbors.end());
414 outerPtr.back() = innerIdx.size();
426template <
typename Index_t>
428 assert(!csr.
empty());
430 const auto* outerPtr = csr.
outerPtr();
431 const auto* innerIdx = csr.
innerIdx();
432 const auto* diagPtr = csr.
diagPtr();
436 for (
auto i = 0ul; i < nPoint; ++i) outerPtrL(i + 1) = outerPtrL(i) + static_cast<Index_t>(diagPtr[i] - outerPtr[i]);
440 for (
auto i = 0ul; i < nPoint; ++i)
441 for (
auto p = outerPtr[i]; p < diagPtr[i]; ++p) innerIdxL(k++) = innerIdx[p];
452template <
typename Index_t>
454 assert(!csr.
empty());
456 const auto* outerPtr = csr.
outerPtr();
457 const auto* innerIdx = csr.
innerIdx();
458 const auto* diagPtr = csr.
diagPtr();
462 for (
auto i = 0ul; i < nPoint; ++i)
463 outerPtrU(i + 1) = outerPtrU(i) +
static_cast<Index_t
>(outerPtr[i + 1] - diagPtr[i] - 1);
467 for (
auto i = 0ul; i < nPoint; ++i)
468 for (
auto p = diagPtr[i] + 1; p < outerPtr[i + 1]; ++p) innerIdxU(k++) = innerIdx[p];
482template <
typename Index_t>
488 assert(nnz_l == nnz_u &&
"L and U must have the same NNZ (symmetric pattern).");
493 for (Index_t i = 0; i < pattern_l.
getOuterSize(); ++i) {
494 for (Index_t k_l = pattern_l.
outerPtr()[i]; k_l < pattern_l.
outerPtr()[i + 1]; ++k_l) {
495 const Index_t j = pattern_l.
innerIdx()[k_l];
510template <
class T = CCompressedSparsePatternUL,
class Index_t =
typename T::IndexType>
515 outerPtr(1) = numInnerIndexes;
519 std::iota(innerIdx.
data(), innerIdx.
data() + numInnerIndexes, 0);
521 return T(std::move(outerPtr), std::move(innerIdx));
547template <
typename Color_t =
unsigned char,
size_t MaxColors = 255,
size_t MaxMB = 128,
class T>
548T
colorSparsePattern(
const T& pattern,
size_t groupSize = 1,
bool includeOuterIdx =
false,
bool balanceColors =
false,
549 std::vector<Color_t>* indexColor =
nullptr) {
550 static_assert(std::is_integral<Color_t>::value);
551 static_assert(std::numeric_limits<Color_t>::max() >= MaxColors);
553 using Index_t =
typename T::IndexType;
555 const Index_t grpSz = groupSize;
556 const Index_t nOuter = pattern.getOuterSize();
561 const Index_t minIdx = pattern.getMinInnerIdx();
562 const Index_t nInner = pattern.getMaxInnerIdx() + 1 - minIdx;
565 if (
size_t(nInner) > (MaxMB << 23))
return T();
568 std::vector<Color_t> idxColor(nOuter);
571 std::vector<Index_t> colorSize(1, 0);
576 std::vector<std::vector<bool>> innerInColor;
577 innerInColor.emplace_back(nInner,
false);
580 std::vector<Color_t> searchOrder(MaxColors);
582 auto outerPtr = pattern.outerPtr();
583 auto innerIdx = pattern.innerIdx();
585 for (Index_t iOuter = 0; iOuter < nOuter; iOuter += grpSz) {
586 Index_t grpEnd = std::min(iOuter + grpSz, nOuter);
588 searchOrder.resize(nColor);
589 std::iota(searchOrder.begin(), searchOrder.end(), 0);
593 std::sort(searchOrder.begin(), searchOrder.end(),
594 [&colorSize](Color_t a, Color_t b) { return colorSize[a] < colorSize[b]; });
597 auto it = searchOrder.begin();
599 for (; it != searchOrder.end(); ++it) {
601 if (includeOuterIdx) {
602 for (Index_t k = iOuter; k < grpEnd && free; ++k) {
603 free = !innerInColor[*it][k];
607 for (Index_t k = outerPtr[iOuter]; k < outerPtr[grpEnd] && free; ++k) {
608 free = !innerInColor[*it][innerIdx[k] - minIdx];
617 if (it != searchOrder.end()) {
623 if (nColor == MaxColors)
return T();
624 colorSize.push_back(0);
625 innerInColor.emplace_back(nInner,
false);
629 for (Index_t k = iOuter; k < grpEnd; ++k) idxColor[k] = color;
632 for (Index_t k = outerPtr[iOuter]; k < outerPtr[grpEnd]; ++k) {
633 innerInColor[color][innerIdx[k] - minIdx] =
true;
637 colorSize[color] += grpEnd - iOuter;
648 for (Color_t color = 0; color < nColor; ++color) {
649 colorPtr(color + 1) = colorPtr(color) + colorSize[color];
651 for (Index_t iOuter = 0; iOuter < nOuter; ++iOuter)
652 if (idxColor[iOuter] == color) outerIdx(k++) = iOuter;
656 if (indexColor) *indexColor = std::move(idxColor);
659 return T(std::move(colorPtr), std::move(outerIdx));
665template <
typename T = su2u
int>
667 static_assert(std::is_integral<T>::value);
683template <
typename T = su2u
int>
685 static_assert(std::is_integral<T>::value);
689 inline T operator[](T i)
const {
return i; }
717template <
class SparsePattern>
719 using Index_t =
typename SparsePattern::IndexType;
726 for (Index_t color = 0; color < coloring.getOuterSize(); ++color)
727 real += chunkSize *
roundUpDiv(
roundUpDiv(coloring.getNumNonZeros(color), chunkSize), numThreads);
738 using Index =
typename T::IndexType;
740 std::vector<std::vector<Index>> levels;
742 const auto n = pattern.getOuterSize();
744 for (Index i = 0; i < n; ++i) {
746 for (
const auto j : pattern.getInnerIter(i)) {
747 if (j >= i)
continue;
748 level(i) = std::max(level(i), level(j) + 1);
750 if (
static_cast<std::size_t
>(level(i) + 1) > levels.size()) {
751 levels.emplace_back();
753 levels[level(i)].push_back(i);
A templated matrix/vector-like object.
Definition C2DContainer.hpp:374
C2DContainer & resize(const Index_t size1, const Index_t size2=1) noexcept
Request a change of size.
Definition C2DContainer.hpp:541
size_t size() const noexcept
Definition C2DContainer.hpp:222
A simple class to store adjacency information in a compressed format suitable for sparse matrix opera...
Definition graph_toolbox.hpp:59
CCompressedSparsePattern(const T &outerPtr, const T &innerIdx)
Construct from vector-like objects of any type with methods "size()" and "data()" (returning a pointe...
Definition graph_toolbox.hpp:122
bool empty() const
Definition graph_toolbox.hpp:184
const Index_t * diagPtr() const
Definition graph_toolbox.hpp:297
Index_t & getInnerIdx(Index_t iOuterIdx, Index_t iNonZero)
Definition graph_toolbox.hpp:217
Index_t getOuterSize() const
Definition graph_toolbox.hpp:189
const Index_t * innerIdx() const
Definition graph_toolbox.hpp:281
Index_t getMaxInnerIdx() const
Definition graph_toolbox.hpp:322
CInnerIter getInnerIter(Index_t iOuterIdx) const
Definition graph_toolbox.hpp:226
CCompressedSparsePattern(su2vector< Index_t > &&outerPtr, su2vector< Index_t > &&innerIdx)
Construct from rvalue refs.
Definition graph_toolbox.hpp:109
Index_t getInnerIdx(Index_t iOuterIdx, Index_t iNonZero) const
Definition graph_toolbox.hpp:207
Index_t findInnerIdx(Index_t iOuterIdx, Index_t iInnerIdx) const
Definition graph_toolbox.hpp:236
Index_t IndexType
Definition graph_toolbox.hpp:69
bool isNonZero(Index_t iOuterIdx, Index_t iInnerIdx) const
Definition graph_toolbox.hpp:247
Index_t getNumNonZeros() const
Definition graph_toolbox.hpp:194
const Index_t * innerIdx(Index_t iOuterIdx) const
Definition graph_toolbox.hpp:289
Index_t getMinInnerIdx() const
Definition graph_toolbox.hpp:313
CCompressedSparsePattern(const T &lil)
Build from a "list of lists" type object.
Definition graph_toolbox.hpp:138
Index_t quickFindInnerIdx(Index_t iOuterIdx, Index_t iInnerIdx) const
Definition graph_toolbox.hpp:257
Index_t getNumNonZeros(Index_t iOuterIdx) const
Definition graph_toolbox.hpp:200
CCompressedSparsePattern()=default
Default construction.
const su2vector< Index_t > & transposePtr() const
Definition graph_toolbox.hpp:305
void buildDiagPtr()
Build a list of pointers to the diagonal entries of the pattern.
Definition graph_toolbox.hpp:152
CCompressedSparsePattern(Iterator outerPtrBegin, Iterator outerPtrEnd, Index_t defaultInnerIdx)
Construct with default inner indices.
Definition graph_toolbox.hpp:94
Index_t getDiagPtr(Index_t iDiagIdx) const
Definition graph_toolbox.hpp:268
void buildTransposePtr()
Build a list of pointers to the transpose entries of the pattern, requires symmetry.
Definition graph_toolbox.hpp:165
const Index_t * outerPtr() const
Definition graph_toolbox.hpp:273
Scalar_t * data() noexcept
Definition C2DContainer.hpp:222
bool empty() const noexcept
Definition C2DContainer.hpp:222
passivedouble su2double
Definition code_config.hpp:181
void buildLUTransposeMaps(const CCompressedSparsePattern< Index_t > &pattern_l, const CCompressedSparsePattern< Index_t > &pattern_u, su2vector< Index_t > &l_to_u, su2vector< Index_t > &u_to_l)
Build bijective maps between strictly-lower (L) and strictly-upper (U) non-zero entries that are each...
Definition graph_toolbox.hpp:483
CCompressedSparsePattern< Index_t > buildUpperPattern(const CCompressedSparsePattern< Index_t > &csr)
Extract the strictly-upper part of a symmetric compressed sparse pattern. For each row i,...
Definition graph_toolbox.hpp:453
ConnectivityType
In FVM points are connected by the edges (faces) of the grid. In FEM, two points are connected if the...
Definition graph_toolbox.hpp:49
CCompressedSparsePattern< Index_t > buildCSRPattern(Geometry_t &geometry, ConnectivityType type, Index_t fillLvl)
Build a sparse pattern from geometry information, of type FVM or FEM, for a given fill-level....
Definition graph_toolbox.hpp:355
T colorSparsePattern(const T &pattern, size_t groupSize=1, bool includeOuterIdx=false, bool balanceColors=false, std::vector< Color_t > *indexColor=nullptr)
Color contiguous groups of outer indices of a sparse pattern such that within each color,...
Definition graph_toolbox.hpp:548
T computeLevels(const T &pattern)
Compute the levels for the lower part of a sparse pattern. For example, corresponding to the dependen...
Definition graph_toolbox.hpp:737
T createNaturalColoring(Index_t numInnerIndexes)
Create the natural coloring (equivalent to the normal sequential loop order) for a given number of in...
Definition graph_toolbox.hpp:511
su2double coloringEfficiency(const SparsePattern &coloring, int numThreads, int chunkSize)
Computes the efficiency of a grid coloring for given number of threads and chunk size.
Definition graph_toolbox.hpp:718
CCompressedSparsePattern< Index_t > buildLowerPattern(const CCompressedSparsePattern< Index_t > &csr)
Extract the strictly-lower part of a symmetric compressed sparse pattern. For each row i,...
Definition graph_toolbox.hpp:427
#define END_SU2_OMP_PARALLEL
Definition omp_structure.hpp:157
constexpr size_t roundUpDiv(size_t numerator, size_t denominator)
Integer division rounding up.
Definition omp_structure.hpp:204
constexpr int omp_get_max_threads()
Maximum number of threads available.
Definition omp_structure.hpp:70
#define SU2_OMP_PARALLEL_(ARGS)
Definition omp_structure.hpp:146
Type to allow range for loops over inner indices.
Definition graph_toolbox.hpp:74
const IndexType * begin() const
Definition graph_toolbox.hpp:78
CInnerIter(const IndexType *first, const IndexType *last)
Definition graph_toolbox.hpp:77
const IndexType * end() const
Definition graph_toolbox.hpp:79
const IndexType *const m_first
Definition graph_toolbox.hpp:75
const IndexType *const m_last
Definition graph_toolbox.hpp:76
Definition graph_toolbox.hpp:694
T i
Definition graph_toolbox.hpp:695
T operator->() const
Definition graph_toolbox.hpp:706
IteratorLikeInt(T pos=0)
Definition graph_toolbox.hpp:696
IteratorLikeInt & operator++()
Definition graph_toolbox.hpp:697
bool operator==(const IteratorLikeInt &other) const
Definition graph_toolbox.hpp:707
bool operator!=(const IteratorLikeInt &other) const
Definition graph_toolbox.hpp:708
IteratorLikeInt operator++(int)
Definition graph_toolbox.hpp:701
T operator*() const
Definition graph_toolbox.hpp:705
A way to represent natural coloring {0,1,2,...,size-1} with zero overhead (behaves like looping with ...
Definition graph_toolbox.hpp:684
struct DummyGridColor::@83 indices
IteratorLikeInt end() const
Definition graph_toolbox.hpp:711
T size
Definition graph_toolbox.hpp:687
DummyGridColor(T sz=0)
Definition graph_toolbox.hpp:692
IteratorLikeInt begin() const
Definition graph_toolbox.hpp:710
A way to represent one grid color that allows range-for syntax.
Definition graph_toolbox.hpp:666
T groupSize
Definition graph_toolbox.hpp:670
const T size
Definition graph_toolbox.hpp:669
const T * end() const
Definition graph_toolbox.hpp:676
const T *const indices
Definition graph_toolbox.hpp:671
GridColor(const T *idx=nullptr, T sz=0, T grp=0)
Definition graph_toolbox.hpp:673
const T * begin() const
Definition graph_toolbox.hpp:675