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