10#include <boost/graph/adjacency_list.hpp>
11#include <boost/graph/graph_utility.hpp>
12#include <boost/graph/minimum_degree_ordering.hpp>
13#include <boost/graph/cuthill_mckee_ordering.hpp>
14#include <boost/graph/properties.hpp>
15#include <boost/graph/bandwidth.hpp>
32 tLocalMatStruct::const_iterator mat_begin, tLocalMatStruct::const_iterator mat_end,
int nPart,
34 std::string metisType =
"KWAY",
int metisNcuts = 3,
int metisUfactor = 5,
int metisSeed = 0)
36 idx_t
nCell = METIS::indexToIdx(size_t_to_signed<index>(mat_end - mat_begin));
38 std::array<idx_t, METIS_NOPTIONS> options{};
39 METIS_SetDefaultOptions(options.data());
41 options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
42 options[METIS_OPTION_CTYPE] = METIS_CTYPE_SHEM;
43 options[METIS_OPTION_IPTYPE] = METIS_IPTYPE_GROW;
44 options[METIS_OPTION_RTYPE] = METIS_RTYPE_FM;
46 options[METIS_OPTION_NCUTS] = std::max(metisNcuts, 1);
47 options[METIS_OPTION_NITER] = 10;
49 options[METIS_OPTION_UFACTOR] = metisUfactor;
50 options[METIS_OPTION_MINCONN] = 1;
51 options[METIS_OPTION_CONTIG] = 1;
52 options[METIS_OPTION_SEED] = metisSeed;
53 options[METIS_OPTION_NUMBERING] = 0;
57 auto &cell2cellFaceV = mat_begin;
61 std::vector<idx_t> adjncy, xadj;
62 xadj.resize(
nCell + 1);
64 for (idx_t iC = 0; iC <
nCell; iC++)
67 for (
auto iCOther : cell2cellFaceV[iC])
69 index iLocal = iCOther - ind_offset;
70 if (iLocal >= 0 && iLocal <
nCell)
73 xadj[iC + 1] = xadj[iC] + count;
75 adjncy.resize(xadj.back());
76 for (idx_t iC = 0; iC <
nCell; iC++)
79 for (
auto iCOther : cell2cellFaceV[iC])
81 index iLocal = iCOther - ind_offset;
82 if (iLocal >= 0 && iLocal <
nCell)
83 adjncy[pos++] = METIS::indexToIdx(iLocal);
88 std::vector<idx_t> partOut(
nCell);
91 if (metisType ==
"RB")
92 ret = METIS_PartGraphRecursive(
93 &
nCell, &nCon, xadj.data(), adjncy.data(),
nullptr,
nullptr,
nullptr,
94 &nPart,
nullptr,
nullptr, options.data(), &objval, partOut.data());
95 else if (metisType ==
"KWAY")
96 ret = METIS_PartGraphKway(
97 &
nCell, &nCon, xadj.data(), adjncy.data(),
nullptr,
nullptr,
nullptr,
98 &nPart,
nullptr,
nullptr, options.data(), &objval, partOut.data());
100 DNDS_assert_info(ret == METIS_OK, fmt::format(
"Metis return not ok, [{}]", ret));
107 idx_t
nCell = METIS::indexToIdx(size_t_to_signed<index>(mat.size()));
109 std::array<idx_t, METIS_NOPTIONS> options{};
110 METIS_SetDefaultOptions(options.data());
112 options[METIS_OPTION_CTYPE] = METIS_CTYPE_SHEM;
113 options[METIS_OPTION_RTYPE] = METIS_RTYPE_FM;
114 options[METIS_OPTION_IPTYPE] = METIS_IPTYPE_EDGE;
115 options[METIS_OPTION_RTYPE] = METIS_RTYPE_SEP1SIDED;
116 options[METIS_OPTION_NSEPS] = 1;
117 options[METIS_OPTION_NITER] = 10;
118 options[METIS_OPTION_UFACTOR] = 30;
119 options[METIS_OPTION_COMPRESS] = 0;
121 options[METIS_OPTION_SEED] = 0;
122 options[METIS_OPTION_PFACTOR] = 0;
123 options[METIS_OPTION_NUMBERING] = 0;
126 const std::vector<std::vector<index>> &cell2cellFaceV = mat;
127 std::vector<idx_t> adjncy, xadj, perm, iPerm;
128 xadj.resize(
nCell + 1);
130 for (idx_t iC = 0; iC <
nCell; iC++)
131 xadj[iC + 1] = signedIntSafeAdd<idx_t>(xadj[iC], size_t_to_signed<idx_t>(cell2cellFaceV[iC].size()));
132 adjncy.resize(xadj.back());
133 for (idx_t iC = 0; iC <
nCell; iC++)
134 std::copy(cell2cellFaceV[iC].begin(), cell2cellFaceV[iC].end(), adjncy.begin() + xadj[iC]);
138 int ret = METIS_NodeND(&
nCell, xadj.data(), adjncy.data(),
nullptr, options.data(), perm.data(), iPerm.data());
139 DNDS_assert_info(ret == METIS_OK, fmt::format(
"Metis return not ok, [{}]", ret));
141 std::vector<index> localFillOrderingNew2Old, localFillOrderingOld2New;
143 localFillOrderingNew2Old.resize(
nCell);
144 localFillOrderingOld2New.resize(
nCell);
147 localFillOrderingNew2Old[
i] = perm[
i];
148 localFillOrderingOld2New[
i] = iPerm[
i];
151 return {localFillOrderingNew2Old, localFillOrderingOld2New};
156 std::vector<index> localFillOrderingNew2Old, localFillOrderingOld2New;
157 using namespace boost;
158 using Graph = adjacency_list<vecS, vecS, directedS>;
159 Graph cell2cellG(mat.size());
160 const std::vector<std::vector<index>> &cell2cellFaceV = mat;
161 for (
index iCell = 0; iCell < size_t_to_signed<index>(mat.size()); iCell++)
162 for (
auto iCOther : cell2cellFaceV[iCell])
163 add_edge(iCell, iCOther, cell2cellG);
164 std::vector<index> supernodeSizes(mat.size(), 1), degree(mat.size(), 0);
165 localFillOrderingNew2Old.resize(mat.size(), 0);
166 localFillOrderingOld2New.resize(mat.size(), 0);
167 boost::property_map<Graph, vertex_index_t>::type
id = get(vertex_index, cell2cellG);
168 minimum_degree_ordering(
170 make_iterator_property_map(degree.data(),
id, degree[0]),
171 localFillOrderingOld2New.data(),
172 localFillOrderingNew2Old.data(),
173 make_iterator_property_map(supernodeSizes.data(),
id, supernodeSizes[0]),
176 return {localFillOrderingNew2Old, localFillOrderingOld2New};
181 std::vector<index> localFillOrderingNew2Old, localFillOrderingOld2New;
182 using namespace boost;
183 using Graph = adjacency_list<vecS, vecS, undirectedS, property<vertex_color_t, default_color_type, property<vertex_degree_t, int>>>;
184 using Vertex = graph_traits<Graph>::vertex_descriptor;
186 Graph cell2cellG(mat.size());
187 const std::vector<std::vector<index>> &cell2cellFaceV = mat;
189 for (
index iCell = 0; iCell < size_t_to_signed<index>(mat.size()); iCell++)
190 for (
auto iCOther : cell2cellFaceV[iCell])
191 add_edge(iCell, iCOther, cell2cellG), bandWidthOld = std::max(bandWidthOld, std::abs(iCell - iCOther));
192 localFillOrderingNew2Old.resize(mat.size(), 0);
193 localFillOrderingOld2New.resize(mat.size(), 0);
194 Vertex startVert = vertex(0, cell2cellG);
195 cuthill_mckee_ordering(cell2cellG, startVert, localFillOrderingNew2Old.rbegin(),
196 get(vertex_color, cell2cellG), get(vertex_degree, cell2cellG));
197 std::unordered_set<index> _checkOrder;
198 for (
auto v : localFillOrderingNew2Old)
200 DNDS_assert_info(_checkOrder.size() == localFillOrderingNew2Old.size(),
"The output of boost::cuthill_mckee_ordering is invalid!");
202 for (
index iCell = 0; iCell < size_t_to_signed<index>(mat.size()); iCell++)
203 localFillOrderingOld2New[localFillOrderingNew2Old[iCell]] = iCell;
204 for (
auto v : localFillOrderingOld2New)
205 DNDS_assert(
v < size_t_to_signed<index>(mat.size()) &&
v >= 0);
207 for (
index iCell = 0; iCell < size_t_to_signed<index>(mat.size()); iCell++)
208 for (
auto iCOther : cell2cellFaceV[iCell])
209 bandWidthNew = std::max(bandWidthNew, std::abs(localFillOrderingOld2New[iCell] - localFillOrderingOld2New[iCOther]));
211 return {localFillOrderingNew2Old, localFillOrderingOld2New};
232 return *ptr_ + offset_;
252 return ptr_ == other.ptr_;
257 return !(*
this == other);
270 OffsetRange(
typename std::vector<T>::const_iterator
b,
typename std::vector<T>::const_iterator e, T offset)
271 : begin_(std::addressof(*
b)), end_(std::addressof(*e)), offset_(offset) {}
275 : begin_(vec.data()), end_(vec.data() + vec.
size()), offset_(offset) {}
279 [[nodiscard]] ptrdiff_t
size()
const {
return end_ - begin_; }
283 tLocalMatStruct::const_iterator mat_begin, tLocalMatStruct::const_iterator mat_end,
287 std::vector<index> localFillOrderingNew2Old, localFillOrderingOld2New;
300 index mat_size = mat_end - mat_begin;
302 for (
index iCell = 0; iCell < size_t_to_signed<index>(mat_size); iCell++)
303 for (
auto iCOther : mat_begin[iCell])
304 bandWidthOld = std::max(bandWidthOld, std::abs(iCell + offset - iCOther));
306 localFillOrderingNew2Old.resize(mat_size, 0);
307 localFillOrderingOld2New.resize(mat_size, 0);
308 auto graphFunctor = [&](
index i)
314 int ret = graph.CheckAdj();
319 return localFillOrderingOld2New.at(
i);
322 for (
auto &
v : localFillOrderingOld2New)
323 v = localFillOrderingOld2New.size() - 1 -
v;
325 std::unordered_set<index>
327 for (
auto v : localFillOrderingOld2New)
328 DNDS_assert(
v < size_t_to_signed<index>(mat_size) &&
v >= 0), _checkOrder.insert(
v);
329 DNDS_check_throw_info(_checkOrder.size() == localFillOrderingOld2New.size(),
"The output of CorrectRCM::CuthillMcKeeOrdering is invalid!");
331 for (
index iCell = 0; iCell < size_t_to_signed<index>(mat_size); iCell++)
332 localFillOrderingNew2Old[localFillOrderingOld2New[iCell]] = iCell;
333 for (
auto v : localFillOrderingNew2Old)
334 DNDS_assert(
v < size_t_to_signed<index>(mat_size) &&
v >= 0);
336 for (
index iCell = 0; iCell < size_t_to_signed<index>(mat_size); iCell++)
337 for (
auto iCOther : mat_begin[iCell])
338 bandWidthNew = std::max(bandWidthNew, std::abs(localFillOrderingOld2New[iCell] - localFillOrderingOld2New.at(iCOther - offset)));
340 return {localFillOrderingNew2Old, localFillOrderingOld2New};
351 tLocalMatStruct::iterator mat_begin, tLocalMatStruct::iterator mat_end,
352 std::vector<index>::iterator i_new2old_begin, std::vector<index>::iterator i_new2old_end,
357 tLocalMatStruct::iterator full_mat_begin = tLocalMatStruct::iterator{},
358 index full_n_elem = 0);
#define DNDS_assert_info(expr, info)
Debug-only assertion with an extra std::string info message.
#define DNDS_assert(expr)
Debug-only assertion (compiled out when DNDS_NDEBUG is defined). Prints the expression + file/line + ...
#define DNDS_check_throw_info(expr, info)
Same as DNDS_check_throw but attaches a user-supplied info message to the thrown std::runtime_error.
bool operator==(const OffsetIterator &other) const
OffsetIterator operator++(int)
bool operator!=(const OffsetIterator &other) const
OffsetIterator & operator++()
std::input_iterator_tag iterator_category
std::ptrdiff_t difference_type
OffsetIterator(const T *p, T off)
OffsetRange(typename std::vector< T >::const_iterator b, typename std::vector< T >::const_iterator e, T offset)
OffsetIterator< T > begin() const
OffsetRange(const std::vector< const T > &vec, T offset)
OffsetIterator< T > end() const
void CuthillMcKeeOrdering(TGraph &&G, TFFiller &&FFiller, TIndex &&root, std::optional< std::reference_wrapper< std::ostream > > os={})
std::pair< std::vector< index >, std::vector< index > > ReorderSerialAdj_BoostRCM(const tLocalMatStruct &mat, index &bandWidthOld, index &bandWidthNew)
std::pair< std::vector< index >, std::vector< index > > ReorderSerialAdj_Metis(const tLocalMatStruct &mat)
std::pair< std::vector< index >, std::vector< index > > ReorderSerialAdj_BoostMMD(const tLocalMatStruct &mat)
std::pair< std::vector< index >, std::vector< index > > ReorderSerialAdj_CorrectRCM(tLocalMatStruct::const_iterator mat_begin, tLocalMatStruct::const_iterator mat_end, index &bandWidthOld, index &bandWidthNew, index offset=0)
std::vector< index > ReorderSerialAdj_PartitionMetisC(tLocalMatStruct::iterator mat_begin, tLocalMatStruct::iterator mat_end, std::vector< index >::iterator i_new2old_begin, std::vector< index >::iterator i_new2old_end, int nParts, index ind_offset, bool do_rcm, index &bwOldM, index &bwNewM, tLocalMatStruct::iterator full_mat_begin, index full_n_elem)
Partition a sub-graph into nParts and optionally apply RCM reordering within each part.
auto PartitionSerialAdj_Metis(tLocalMatStruct::const_iterator mat_begin, tLocalMatStruct::const_iterator mat_end, int nPart, index ind_offset=0, std::string metisType="KWAY", int metisNcuts=3, int metisUfactor=5, int metisSeed=0)
Partition a (sub-)graph using Metis.
std::vector< std::vector< index > > tLocalMatStruct
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Eigen::Matrix< real, 5, 1 > v
const tPoint const tPoint const tPoint & p