DNDSR 0.2.1
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
Mesh_Serial_Partition.cpp
Go to the documentation of this file.
1#include "Mesh.hpp"
2#include "Solver/Direct.hpp"
3#include "Geom/Metis.hpp"
5
6#include <array>
7
8namespace DNDS::Geom
9{
12 {
13 if (mesh->getMPI().rank == mRank)
14 DNDS::log() << "UnstructuredMeshSerialRW === Doing MeshPartitionCell2Cell" << std::endl;
15 //! preset hyper config, should be optional in the future
16 bool isSerial = true;
17 idx_t nPart = mesh->getMPI().size;
18 cnPart = nPart;
19
20 //! assuming all adj point to local numbers now
21 // * Tend to local-global issues putting into
22 // cell2cellSerial->Compress();
23 // cell2cellSerial->AssertConsistent();
24 // cell2cellSerial->createGlobalMapping();
25 cell2cellSerialFacial->Compress();
26 cell2cellSerialFacial->AssertConsistent();
27 cell2cellSerialFacial->createGlobalMapping();
28
29 std::vector<idx_t> vtxdist(mesh->getMPI().size + 1);
30#ifdef DNDS_USE_OMP
31# pragma omp parallel for
32#endif
33 for (DNDS::MPI_int r = 0; r <= mesh->getMPI().size; r++)
34 vtxdist[r] = METIS::indexToIdx(cell2cellSerialFacial->pLGlobalMapping->ROffsets().at(r));
35 std::vector<idx_t> xadj(cell2cellSerialFacial->Size() + 1);
36#ifdef DNDS_USE_OMP
37# pragma omp parallel for
38#endif
39 for (DNDS::index iCell = 0; iCell < xadj.size(); iCell++)
40 xadj[iCell] = METIS::indexToIdx(cell2cellSerialFacial->rowPtr(iCell) - cell2cellSerialFacial->rowPtr(0));
41 std::vector<idx_t> adjncy(xadj.back());
42 std::vector<idx_t> adjncyWeights;
43 DNDS_assert(cell2cellSerialFacial->DataSize() == xadj.back());
44#ifdef DNDS_USE_OMP
45# pragma omp parallel for
46#endif
47 for (DNDS::index iAdj = 0; iAdj < xadj.back(); iAdj++)
48 adjncy[iAdj] = METIS::indexToIdx(cell2cellSerialFacial->data()[iAdj]);
49 if (c_options.edgeWeightMethod == 1)
50 {
51 adjncyWeights.reserve(xadj.back());
52 std::vector<real> adjncyWeightsR;
53 adjncyWeightsR.reserve(xadj.back());
54
55 real maxDistMax{0};
56 for (index iCell = 0; iCell < cell2cellSerialFacial->Size(); iCell++)
57 {
58 tSmallCoords coordsC;
59 GetCoordsOnCellSerial(iCell, coordsC, coordSerial);
60 std::vector<index> cell2nodeCV = cell2nodeSerial->operator[](iCell);
61 std::sort(cell2nodeCV.begin(), cell2nodeCV.end());
62 for (auto iCellOther : cell2cellSerialFacial->operator[](iCell))
63 {
64 std::vector<index> cell2nodeCVOther = cell2nodeSerial->operator[](iCellOther);
65 std::sort(cell2nodeCVOther.begin(), cell2nodeCVOther.end());
66 std::vector<index> faceFound;
67 faceFound.reserve(9);
68 std::set_intersection(cell2nodeCV.begin(), cell2nodeCV.end(), cell2nodeCVOther.begin(), cell2nodeCVOther.end(), std::back_inserter(faceFound));
69 DNDS_assert(faceFound.size() >= 2);
70 std::vector<int> faceFoundC2F;
71 faceFoundC2F.reserve(faceFound.size());
72 for (auto iN : faceFound)
73 for (int i = 0; i < cell2nodeSerial->operator[](iCell).size(); i++)
74 if (cell2nodeSerial->operator[](iCell)[i] == iN)
75 faceFoundC2F.push_back(i);
76 DNDS_assert(faceFoundC2F.size() == faceFound.size());
77 tSmallCoords coordsF = coordsC(EigenAll, faceFoundC2F);
78 real maxDist{0};
79 for (int i = 0; i < coordsF.cols(); i++)
80 for (int j = 0; j < coordsF.cols(); j++)
81 if (i != j)
82 maxDist = std::max(maxDist, (coordsF(EigenAll, i) - coordsF(EigenAll, j)).norm());
83 adjncyWeightsR.push_back(maxDist);
84 maxDistMax = std::max(maxDist, maxDistMax);
85 }
86 }
87 auto weightMapping = [](real x) -> real
88 { return std::pow(x, 1); };
89 for (auto d : adjncyWeightsR)
90 adjncyWeights.push_back(weightMapping(d / maxDistMax) * (INT_MAX - 1) + 1.);
91 }
92 if (adjncy.empty())
93 adjncy.resize(1, -1); //*coping with zero sized data
94
95 idx_t nCell = METIS::indexToIdx(cell2cellSerialFacial->Size());
96 idx_t nCon{1};
97 std::array<idx_t, METIS_NOPTIONS> options{};
98 METIS_SetDefaultOptions(options.data());
99 {
100 options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
101 options[METIS_OPTION_CTYPE] = METIS_CTYPE_SHEM; //? could try shem?
102 options[METIS_OPTION_IPTYPE] = METIS_IPTYPE_GROW;
103 options[METIS_OPTION_RTYPE] = METIS_RTYPE_FM;
104 // options[METIS_OPTION_NO2HOP] = 0; // only available in metis 5.1.0
105 options[METIS_OPTION_NCUTS] = std::max(c_options.metisNcuts, 1);
106 options[METIS_OPTION_NITER] = 10;
107 // options[METIS_OPTION_UFACTOR] = 30; // load imbalance factor, fow k-way
108 options[METIS_OPTION_UFACTOR] = c_options.metisUfactor;
109 options[METIS_OPTION_MINCONN] = 1;
110 options[METIS_OPTION_CONTIG] = 1; // ! forcing contigious partition now ? necessary?
111 options[METIS_OPTION_SEED] = c_options.metisSeed; // ! seeding 0 for determined result
112 options[METIS_OPTION_NUMBERING] = 0;
113 // options[METIS_OPTION_DBGLVL] = METIS_DBG_TIME | METIS_DBG_IPART;
114 options[METIS_OPTION_DBGLVL] = METIS_DBG_TIME;
115 }
116 std::vector<idx_t> partOut(nCell);
117 if (nCell == 0)
118 partOut.resize(1, -1); //*coping with zero sized data
119 if (nPart > 1)
120 {
121 if (mesh->getMPI().size == 1 || (isSerial && mesh->getMPI().rank == mRank))
122 {
123 idx_t objval;
124 DNDS_assert_info(c_options.metisType == std::string("KWAY") or c_options.metisType == std::string("RB"), "metisType must be KWAY or RB!");
125 int ret = c_options.metisType == std::string("KWAY")
126 ? METIS_PartGraphKway(
127 &nCell, &nCon, xadj.data(), adjncy.data(), nullptr, nullptr, c_options.edgeWeightMethod ? adjncyWeights.data() : nullptr,
128 &nPart, nullptr, nullptr, options.data(), &objval, partOut.data())
129 : METIS_PartGraphRecursive(
130 &nCell, &nCon, xadj.data(), adjncy.data(), nullptr, nullptr, c_options.edgeWeightMethod ? adjncyWeights.data() : nullptr,
131 &nPart, nullptr, nullptr, options.data(), &objval, partOut.data());
132 if (ret != METIS_OK)
133 {
134 DNDS::log() << "METIS returned not OK: [" << ret << "]" << std::endl;
135 DNDS_assert(false);
136 }
137 }
138 else if (mesh->getMPI().size != 1 && (!isSerial))
139 {
140 ///@todo //TODO: parmetis needs testing!
141 for (int i = 0; i < vtxdist.size() - 1; i++)
142 DNDS_assert_info(vtxdist[i + 1] - vtxdist[i] > 0, "need more than zero cells on each proc!");
143 std::vector<real_t> tpWeights(static_cast<index>(nPart) * nCon, 1.0 / nPart); //! assuming homogenous
144 std::array<real_t, 1> ubVec{1.05};
145 DNDS_assert(nCon == 1);
146 std::array<idx_t, 3> optsC{};
147 idx_t wgtflag{0}, numflag{0};
148 optsC[0] = 1;
149 optsC[1] = 1;
150 optsC[2] = 0;
151 idx_t objval;
152 int ret = ParMETIS_V3_PartKway(
153 vtxdist.data(), xadj.data(), adjncy.data(), nullptr, nullptr, &wgtflag, &numflag,
154 &nCon, &nPart, tpWeights.data(), ubVec.data(), optsC.data(), &objval, partOut.data(),
155 &mesh->getMPI().comm);
156 if (ret != METIS_OK)
157 {
158 DNDS::log() << "METIS returned not OK: [" << ret << "]" << std::endl;
159 DNDS_assert(false);
160 }
161 }
162 }
163 else
164 {
165 partOut.assign(partOut.size(), 0);
166 }
167 cellPartition.resize(cell2cellSerialFacial->Size());
168 for (DNDS::index i = 0; i < cellPartition.size(); i++)
169 cellPartition[i] = partOut[i];
170 if (mesh->getMPI().rank == mRank)
171 {
172 std::vector<index> partCellCnt(nPart, 0);
173 for (auto p : cellPartition)
174 partCellCnt.at(p)++;
175 auto [min, max] = std::minmax_element(partCellCnt.begin(), partCellCnt.end());
176 log() << "UnstructuredMeshSerialRW === Done MeshPartitionCell2Cell "
177 << fmt::format("ave [{}], min [{}], max [{}], ", real(cellPartition.size()) / nPart, *min, *max)
178 << fmt::format("ratio [{:.4f}] ", real(*min) / *max) << std::endl;
179 }
180 }
181
183 {
184 // if (onLocalPartition)
185 // DNDS_assert(this->localPartitionStarts.size() >= 2);
187 DNDS_assert(cell2node.isLocal() && bnd2node.isLocal());
188 std::vector<std::vector<index>> cell2cellFaceV;
189 cell2cellFaceV.resize(this->NumCell());
190 if (this->adjFacialState == Adj_PointToLocal && this->face2cell.isBuilt())
191 {
192 for (int iPart = 0; iPart < this->NLocalParts(); iPart++)
193 for (index iCell = this->LocalPartStart(iPart); iCell < this->LocalPartEnd(iPart); iCell++)
194 {
195 cell2cellFaceV[iCell].reserve(cell2face.RowSize(iCell)); // do not preserve the diagonal
196 for (auto iFace : cell2face[iCell])
197 {
199 if (iCellOther != UnInitIndex && iCellOther < this->NumCell()) //! must be local not ghost ptrs
200 {
203 continue;
204 cell2cellFaceV[iCell].push_back(iCellOther);
205 }
206 }
207 }
208 }
209 else
210 {
211 for (int iPart = 0; iPart < this->NLocalParts(); iPart++)
212 for (index iCell = this->LocalPartStart(iPart); iCell < this->LocalPartEnd(iPart); iCell++)
213 {
214 std::vector<index> cell2cellRow;
215 auto eCell = this->GetCellElement(iCell);
216 std::vector<index> c2ni(cell2node[iCell].begin(), cell2node[iCell].begin() + eCell.GetNumVertices());
217 std::sort(c2ni.begin(), c2ni.end());
219 {
220 if (iCellOther >= this->NumCell())
221 continue;
222 if (onLocalPartition)
224 continue;
226 std::vector<index> c2nj(cell2node[iCellOther].begin(), cell2node[iCellOther].begin() + eCellOther.GetNumVertices());
227 std::sort(c2nj.begin(), c2nj.end());
228 std::vector<index> intersect;
229 intersect.reserve(9);
230 std::set_intersection(c2ni.begin(), c2ni.end(), c2nj.begin(), c2nj.end(), std::back_inserter(intersect));
231 if (intersect.size() >= this->dim) // for 2d, exactly 2; for 3d, 3 or 4
232 cell2cellRow.push_back(iCellOther);
233 }
234 cell2cellFaceV[iCell] = std::move(cell2cellRow);
235 }
236 }
237 return cell2cellFaceV;
238 }
239
240 static std::vector<index> put_perm_back_to_local_parts(const std::vector<index> &new2old, const std::vector<index> &localPartStarts)
241 {
242 auto fGetIPart = [&](index iCell) -> index
243 {
244 return std::lower_bound(localPartStarts.begin(), localPartStarts.end(), iCell, std::less_equal<index>()) -
245 localPartStarts.begin() - 1;
246 };
247 index nParts = localPartStarts.size() - 1;
248 index N = new2old.size();
249 std::vector<std::vector<index>> outB(nParts);
250 for (index iPart = 0; iPart < nParts; iPart++)
251 outB[iPart].reserve(localPartStarts[iPart + 1] - localPartStarts[iPart]);
252 for (index v : new2old)
253 {
254 index iPart = fGetIPart(v);
255 DNDS_assert_info(iPart >= 0 && iPart < nParts, fmt::format("iPart [{}], v [{}], N [{}]", iPart, v, N));
256 outB[iPart].push_back(v);
257 }
258 std::vector<index> out;
259 out.reserve(new2old.size());
260 for (const auto &vec : outB)
261 {
262 out.insert(out.end(), vec.begin(), vec.end());
263 }
264 DNDS_assert(out.size() == new2old.size());
265 return out;
266 }
267
268 static void check_permutations(const std::vector<index> &new2old, const std::vector<index> &old2new, const std::vector<index> &localPartStarts)
269 {
270 index N = new2old.size();
271 DNDS_assert(N == old2new.size());
272 if (N == 0) // special: natural order
273 return;
274 std::unordered_set<index> counted;
275 counted.reserve(N);
276 for (auto v : new2old)
277 {
278 DNDS_assert(v >= 0 && v < N);
279 DNDS_assert(counted.count(v) == 0);
280 counted.insert(v);
281 }
282 counted.clear();
283 for (auto v : old2new)
284 {
285 DNDS_assert(v >= 0 && v < N);
286 DNDS_assert(counted.count(v) == 0);
287 counted.insert(v);
288 }
289
290 for (index i = 0; i < N; i++)
291 {
292 DNDS_assert(new2old[old2new[i]] == i);
293 DNDS_assert(old2new[new2old[i]] == i);
294 }
295
296 if (localPartStarts.size() > 2)
297 {
298 int nParts = localPartStarts.size() - 1;
299 for (int iPart = 0; iPart < nParts; iPart++)
300 {
301 index start = localPartStarts[iPart];
302 index end = localPartStarts[iPart + 1];
303 // std::cout << start << ", " << end << ", " << N << std::endl;
304 DNDS_assert(start <= end);
305 DNDS_assert(start >= 0);
306 DNDS_assert(end <= N);
307 for (index iCell = localPartStarts[iPart]; iCell < localPartStarts[iPart + 1]; iCell++)
308 {
309 index n2o = new2old[iCell];
310 index o2n = old2new[iCell];
311 DNDS_assert(start <= n2o && n2o < end);
312 DNDS_assert(start <= o2n && o2n < end);
313 }
314 }
315 }
316 }
317
319 {
320 if (!control.useDirectPrec)
321 return;
323 auto &localFillOrderingNew2Old = symLU.localFillOrderingNew2Old;
324 auto &localFillOrderingOld2New = symLU.localFillOrderingOld2New;
325 if (!this->NumCell())
326 return;
327 if (control.getOrderingCode() == -1)
328 {
329 localFillOrderingNew2Old.reserve(this->NumCell());
330 for (index i = 0; i < this->NumCell(); i++)
331 if (i % 2 == 0)
332 localFillOrderingNew2Old.push_back(i);
333 for (index i = 0; i < this->NumCell(); i++)
334 if (i % 2 != 0)
335 localFillOrderingNew2Old.push_back(i);
336 localFillOrderingOld2New.resize(this->NumCell());
337 for (index i = 0; i < this->NumCell(); i++)
338 localFillOrderingOld2New.at(localFillOrderingNew2Old.at(i)) = i;
339 }
340 else if (control.getOrderingCode() == 0)
341 {
342 // do nothing, natural order
343 }
344 else if (control.getOrderingCode() == 1) // Metis
345 {
346
347 if (mpi.rank == mRank)
348 log() << "UnstructuredMesh::ObtainLocalFactFillOrdering(): start calling metis" << std::endl;
349 {
351 localFillOrderingNew2Old = std::move(New2Old);
352 localFillOrderingOld2New = std::move(Old2New);
353 }
354 if (mpi.rank == mRank)
355 log() << "UnstructuredMesh::ObtainLocalFactFillOrdering(): metis done" << std::endl;
356 }
357 else if (control.getOrderingCode() == 2) // MMD
358 {
359 if (mpi.rank == mRank)
360 log() << "UnstructuredMesh::ObtainLocalFactFillOrdering(): start calling boost::minimum_degree_ordering" << std::endl;
361 {
363 localFillOrderingNew2Old = std::move(New2Old);
364 localFillOrderingOld2New = std::move(Old2New);
365 }
366 if (mpi.rank == mRank)
367 log() << "UnstructuredMesh::ObtainLocalFactFillOrdering(): boost done" << std::endl;
368 }
369 else if (control.getOrderingCode() == 3) // RCM
370 {
372 if (mpi.rank == mRank)
373 log() << "UnstructuredMesh::ObtainLocalFactFillOrdering(): start calling boost::cuthill_mckee_ordering" << std::endl;
374 {
376 localFillOrderingNew2Old = std::move(New2Old);
377 localFillOrderingOld2New = std::move(Old2New);
378 }
381 if (mpi.rank == mRank)
382 log() << fmt::format("UnstructuredMesh::ObtainLocalFactFillOrdering(): boost done, old BW [{}] new BW [{}] ", bandWidthOld, bandWidthNew) << std::endl;
383 // for (auto v : localFillOrderingOld2New)
384 // std::cout << v << ", ";
385 // std::cout << std::endl;
386 }
387 else if (control.getOrderingCode() == 4) // CorrectRCM
388 {
390 if (mpi.rank == mRank)
391 log() << "UnstructuredMesh::ObtainLocalFactFillOrdering(): start calling CorrectRCM::CuthillMcKeeOrdering" << std::endl;
392 {
394 this->cell2cellFaceVLocalParts.begin(),
395 this->cell2cellFaceVLocalParts.end(), bandWidthOld, bandWidthNew);
396 localFillOrderingNew2Old = std::move(New2Old);
397 localFillOrderingOld2New = std::move(Old2New);
398 }
401 if (mpi.rank == mRank)
402 log() << fmt::format("UnstructuredMesh::ObtainLocalFactFillOrdering(): CorrectRCM done, old BW [{}] new BW [{}] ", bandWidthOld, bandWidthNew) << std::endl;
403 // for (auto v : localFillOrderingOld2New)
404 // std::cout << v << ", ";
405 // std::cout << std::endl;
406 }
407 else
408 {
409 DNDS_assert_info(false, "No such ordering code");
410 }
411 if (this->NLocalParts() > 1 && control.getOrderingCode() != 0)
412 {
413 localFillOrderingNew2Old = put_perm_back_to_local_parts(localFillOrderingNew2Old, this->localPartitionStarts);
414 for (index i = 0; i < localFillOrderingNew2Old.size(); i++)
415 localFillOrderingOld2New[localFillOrderingNew2Old[i]] = i;
416 }
417 check_permutations(localFillOrderingNew2Old, localFillOrderingOld2New, this->localPartitionStarts);
418 }
419}
#define DNDS_assert_info(expr, info)
Debug-only assertion with an extra std::string info message.
Definition Errors.hpp:117
#define DNDS_assert(expr)
Debug-only assertion (compiled out when DNDS_NDEBUG is defined). Prints the expression + file/line + ...
Definition Errors.hpp:112
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)
Eigen::Matrix< real, 3, Eigen::Dynamic > tSmallCoords
Definition Geometric.hpp:50
std::vector< std::vector< index > > tLocalMatStruct
Definition Geometric.hpp:66
void AllreduceOneIndex(index &v, MPI_Op op, const MPIInfo &mpi)
Single-scalar Allreduce helper for indices (in-place, count = 1).
Definition MPI.hpp:727
DNDS_CONSTANT const index UnInitIndex
Sentinel "not initialised" index value (= INT64_MIN).
Definition Defines.hpp:181
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Definition Defines.hpp:112
double real
Canonical floating-point scalar used throughout DNDSR (double precision).
Definition Defines.hpp:110
std::ostream & log()
Return the current DNDSR log stream (either std::cout or the installed file).
Definition Defines.cpp:50
int MPI_int
MPI counterpart type for MPI_int (= C int). Used for counts and ranks in MPI calls.
Definition MPI.hpp:54
std::vector< index > localFillOrderingNew2Old
Definition Direct.hpp:58
std::vector< index > localFillOrderingOld2New
Definition Direct.hpp:57
void MeshPartitionCell2Cell(const PartitionOptions &options)
void GetCoordsOnCellSerial(index iCell, tSmallCoords &cs, tCoord &coo)
analog of mesh's method
Definition Mesh.hpp:1211
DNDS::ssp< UnstructuredMesh > mesh
Definition Mesh.hpp:1117
std::vector< DNDS::MPI_int > cellPartition
Definition Mesh.hpp:1175
UnstructuredMeshDeviceView< B > t_deviceView
Definition Mesh.hpp:1036
Elem::Element GetCellElement(index iC)
Definition Mesh.hpp:689
AdjPairTracked< tAdj2Pair > face2cell
Definition Mesh.hpp:99
index LocalPartStart(int iPart) const
Definition Mesh.hpp:598
tLocalMatStruct cell2cellFaceVLocalParts
for cell local factorization
Definition Mesh.hpp:172
tLocalMatStruct GetCell2CellFaceVLocal(bool onLocalPartition=false)
AdjPairTracked< tAdjPair > cell2face
interpolated
Definition Mesh.hpp:97
AdjPairTracked< tAdjPair > cell2cell
Definition Mesh.hpp:61
MeshAdjState adjPrimaryState
Definition Mesh.hpp:44
index CellFaceOther(index iCell, index iFace) const
Definition Mesh.hpp:845
std::vector< index > localPartitionStarts
Definition Mesh.hpp:174
MeshAdjState adjFacialState
Definition Mesh.hpp:46
AdjPairTracked< tAdjPair > cell2node
Definition Mesh.hpp:58
void ObtainLocalFactFillOrdering(Direct::SerialSymLUStructure &symLU, Direct::DirectPrecControl control)
AdjPairTracked< tAdjPair > bnd2node
Definition Mesh.hpp:59
index LocalPartEnd(int iPart) const
Definition Mesh.hpp:599
int rank
This rank's 0-based index within comm (-1 until initialised).
Definition MPI.hpp:235
Eigen::Matrix< real, 5, 1 > v
constexpr DNDS::index N
tVec r(NCells)
tVec x(NCells)
const DNDS::index nCell
const tPoint const tPoint const tPoint & p