DNDSR 0.2.1
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
Mesh_Legacy.cpp
Go to the documentation of this file.
1/// @file Mesh_Legacy.cpp
2/// @brief Legacy implementations of mesh pipeline methods, preserved for
3/// comparison testing against DSL-based replacements.
4///
5/// Contains:
6/// - GeneralCell2NodeToNode2Cell (static helper)
7/// - RecoverNode2CellAndNode2BndLegacy
8/// - RecoverCell2CellAndBnd2CellLegacy
9///
10/// These methods are functionally identical to the pre-DSL code. The DSL
11/// replacements (RecoverNode2CellAndNode2Bnd, RecoverCell2CellAndBnd2Cell)
12/// use MeshConnectivity::Inverse and ComposeFiltered respectively.
13
14#include "Mesh.hpp"
15
16#include <unordered_map>
17#include <unordered_set>
18#include <set>
19#include <fmt/core.h>
21
22namespace DNDS::Geom
23{
24 using tIndexMapFunc = std::function<index(index)>;
25
26 static void GeneralCell2NodeToNode2Cell(
27 tCoordPair &coords, tAdjPair &cell2node, tAdjPair &node2cell,
28 const tIndexMapFunc &CellIndexLocal2Global_NoSon,
29 const tIndexMapFunc &NodeIndexLocal2Global_NoSon)
30 {
31 const auto &mpi = coords.father->getMPI();
32 std::unordered_set<index> ghostNodesCompactSet;
33 std::vector<index> ghostNodesCompact;
34 std::unordered_map<index, std::unordered_set<index>> node2CellLocalRecord;
35
36 for (index iCell = 0; iCell < cell2node.father->Size(); iCell++)
37 for (auto iNode : cell2node[iCell])
38 {
39 auto [ret, rank, val] = coords.father->pLGlobalMapping->search(iNode);
40 DNDS_assert_info(ret, "search failed");
41 if (rank != mpi.rank)
42 ghostNodesCompact.push_back(iNode), ghostNodesCompactSet.insert(iNode);
43 node2CellLocalRecord[iNode].insert(CellIndexLocal2Global_NoSon(iCell));
44 }
45
46 // MPI_Barrier(mpi.comm);
47 // std::cout << "here2 " << std::endl;
48
49 tAdj node2cellPast; // + node2cell * a triplet to deal with reverse inserting
50 node2cell.InitPair("node2cell", mpi);
51 node2cellPast = make_ssp<tAdj::element_type>(ObjName{"node2cellPast"}, mpi);
52 //* fill into father
53 node2cell.father->Resize(coords.father->Size());
54 for (index iNode = 0; iNode < coords.father->Size(); iNode++)
55 {
56 index iNodeG = NodeIndexLocal2Global_NoSon(iNode);
57 if (node2CellLocalRecord.count(iNodeG))
58 {
59 node2cell.ResizeRow(iNode, node2CellLocalRecord[iNodeG].size());
60 rowsize in2c = 0;
61 for (auto v : node2CellLocalRecord[iNodeG])
62 node2cell(iNode, in2c++) = v;
63 }
64 }
65 node2cell.TransAttach();
66 node2cell.trans.createFatherGlobalMapping();
67 node2cell.trans.createGhostMapping(ghostNodesCompact);
68 //* fill into son
69 node2cell.son->Resize(node2cell.trans.pLGhostMapping->ghostIndex.size());
70 // std::unordered_set<index> touched; // only used for checking
71 for (auto &[k, s] : node2CellLocalRecord)
72 {
73 MPI_int rank{-1};
74 index val{-1};
75 if (!node2cell.trans.pLGhostMapping->search(k, rank, val))
76 DNDS_assert_info(false, "search failed");
77 if (rank >= 0)
78 {
79 node2cell.son->ResizeRow(val, s.size());
80 rowsize in2c = 0;
81 for (auto v : s)
82 node2cell.son->operator()(val, in2c++) = v;
83 // touched.insert(val);
84 }
85 }
86 // DNDS_assert(touched.size() == node2cell.son->Size());
87
88 // node2cell.trans.pLGhostMapping->pushingIndexGlobal; // where to receive in a push
90 node2cellPastTrans.setFatherSon(node2cell.son, node2cellPast);
91 node2cellPastTrans.createFatherGlobalMapping();
92 std::vector<index> pushSonSeries(node2cell.son->Size());
93 for (index i = 0; i < node2cell.son->Size(); i++)
94 pushSonSeries[i] = i;
95 node2cellPastTrans.createGhostMapping(pushSonSeries, node2cell.trans.pLGhostMapping->ghostStart);
96 node2cellPastTrans.createMPITypes();
97
98 node2cellPastTrans.pullOnce();
99 DNDS_assert(DNDS::size_to_index(node2cell.trans.pLGhostMapping->ghostIndex.size()) == node2cell.son->Size());
100 DNDS_assert(DNDS::size_to_index(node2cell.trans.pLGhostMapping->pushingIndexGlobal.size()) == node2cellPast->Size());
101 // * this state of triplet: node2cell.father - node2cell.son - node2cellPast forms a "unique pushing" for the pair node2cell
102 // * should be made into some standard
103 for (index i = 0; i < node2cellPast->Size(); i++)
104 {
105 index iNodeG = node2cell.trans.pLGhostMapping->pushingIndexGlobal[i]; //?should be right
106 for (auto iCell : (*node2cellPast)[i])
107 node2CellLocalRecord[iNodeG].insert(iCell);
108 }
109 // MPISerialDo(
110 // mpi,
111 // [&]()
112 // {
113 // for (auto &[k, s] : node2CellLocalRecord)
114 // {
115 // if (NodeIndexGlobal2Local_NoSon(k) >= 0 && s.size() != 4)
116 // std::cout << k << ", " << s.size() << "; " << std::flush;
117 // }
118 // std::cout << std::endl;
119 // });
120
121 // reset pair
122 node2cell.InitPair("node2cell", mpi);
123 //* fill into father
124 node2cell.father->Resize(coords.father->Size());
125 for (index iNode = 0; iNode < coords.father->Size(); iNode++)
126 {
127 index iNodeG = NodeIndexLocal2Global_NoSon(iNode);
128 if (node2CellLocalRecord.count(iNodeG))
129 {
130 node2cell.ResizeRow(iNode, node2CellLocalRecord[iNodeG].size());
131 rowsize in2c = 0;
132 for (auto v : node2CellLocalRecord[iNodeG])
133 node2cell(iNode, in2c++) = v;
134 }
135 }
136 }
137
140 {
142 DNDS_assert(cell2node.isGlobal() && bnd2node.isGlobal());
144 DNDS_assert(cell2node.father);
145 DNDS_assert(bnd2node.father);
146
147 /*****************************************************/
148 // * first recover node2cell
149
150 if (!coords.father->pLGlobalMapping)
151 coords.father->createGlobalMapping(); // for NodeIndexLocal2Global_NoSon
152 if (!cell2node.father->pLGlobalMapping)
153 cell2node.father->createGlobalMapping(); // for CellIndexLocal2Global_NoSon
154
155 GeneralCell2NodeToNode2Cell(
157 [this](index v)
158 { return this->CellIndexLocal2Global_NoSon(v); },
159 [this](index v)
160 { return this->NodeIndexLocal2Global_NoSon(v); });
161
162 if (!bnd2node.father->pLGlobalMapping)
163 bnd2node.father->createGlobalMapping(); // for BndIndexLocal2Global_NoSon
164 GeneralCell2NodeToNode2Cell(
166 [this](index v)
167 { return this->BndIndexLocal2Global_NoSon(v); },
168 [this](index v)
169 { return this->NodeIndexLocal2Global_NoSon(v); });
170
172 node2cell.idx.markGlobal();
173 node2bnd.idx.markGlobal();
174
175 // if (mpi.rank == 0)
176 // {
177 // for (index i = 0; i < node2cell.father->Size(); i++)
178 // std::cout << node2cell.RowSize(i) - 4 << std::endl;
179 // for (index i = 0; i < node2bnd.father->Size(); i++)
180 // std::cout << node2bnd.RowSize(i) + 10 << std::endl;
181 // }
182
183 // node2cell.TransAttach();
184 // node2cell.trans.createFatherGlobalMapping();
185 // node2cell.trans.createGhostMapping(ghostNodesCompact);
186 // node2cell.trans.createMPITypes();
187 // node2cell.trans.pullOnce();
188
189 // mesh->node2cell.TransAttach();
190 // mesh->node2cell.trans.BorrowGGIndexing(mesh->coords);
191 // mesh->node2cell.trans.createMPITypes();
192 // mesh->node2cell.trans.pullOnce();
193 }
194
196 {
198 DNDS_assert(cell2node.isGlobal() && bnd2node.isGlobal());
200 DNDS_assert(node2cell.isGlobal() && node2bnd.isGlobal());
202 DNDS_assert(cell2node.father);
203 DNDS_assert(bnd2node.father);
204 DNDS_assert(node2cell.father);
205
207 coords.trans.createFatherGlobalMapping(); // for NodeIndexLocal2Global_NoSon
208 cell2node.TransAttach();
209 cell2node.trans.createFatherGlobalMapping(); // for CellIndexLocal2Global_NoSon
210 bnd2node.TransAttach();
211 bnd2node.trans.createFatherGlobalMapping(); // for BndIndexLocal2Global_NoSon
212
213 // std::cout << "RecoverCell2CellAndBnd2Cell here1" << std::endl;
214
215 std::unordered_set<index> ghostNodesCompactSet;
216 for (index i = 0; i < cell2node.father->Size(); i++)
217 for (auto in : cell2node.father->operator[](i))
219 ghostNodesCompactSet.insert(in);
220 for (index i = 0; i < bnd2node.father->Size(); i++)
221 for (auto in : bnd2node.father->operator[](i))
223 ghostNodesCompactSet.insert(in);
224 std::vector<index> ghostNodes;
225 ghostNodes.reserve(ghostNodesCompactSet.size());
226 for (auto v : ghostNodesCompactSet)
227 ghostNodes.push_back(v);
228 // std::cout << "RecoverCell2CellAndBnd2Cell here2" << std::endl;
229 node2cell.son = make_ssp<decltype(node2cell.son)::element_type>(ObjName{"node2cell.son"}, mpi);
230 node2cell.TransAttach();
231 node2cell.trans.createFatherGlobalMapping();
232 node2cell.trans.createGhostMapping(ghostNodes);
233 node2cell.trans.createMPITypes(); //! warning, this is not actual final official trans, just needed temporarily
234 node2cell.trans.pullOnce();
235
236 std::unordered_map<index, index> iNodeGlobal2LocalAppendInNode2Cell;
237
238 for (index i = 0; i < node2cell.Size(); i++)
239 iNodeGlobal2LocalAppendInNode2Cell[node2cell.trans.pLGhostMapping->operator()(-1, i)] = i;
240
241 for (index i = 0; i < cell2node.father->Size(); i++)
242 for (auto in : cell2node.father->operator[](i))
244
245 cell2cell.InitPair("cell2cell", mpi); // actual outputs need empty but constructed son
246 cell2cell.father->Resize(cell2node.father->Size());
247 for (index i = 0; i < cell2node.father->Size(); i++)
248 {
249 std::set<index> cellRec;
250 for (auto in : cell2node.father->operator[](i))
251 {
254 cellRec.insert(ico);
255 }
257 DNDS_assert(ret == 1);
258 cell2cell.father->ResizeRow(i, cellRec.size());
259 rowsize ic2c = 0;
260 for (auto v : cellRec)
261 cell2cell.father->operator()(i, ic2c++) = v;
262 }
263 // std::cout << "RecoverCell2CellAndBnd2Cell here2.5" << std::endl;
264 bnd2cell.InitPair("bnd2cell", mpi); // actual outputs need empty but constructed son
265 bnd2cell.father->Resize(bnd2node.father->Size());
266
267 // For periodic meshes, store per-bnd candidate cell sets from the node
268 // intersection pass, then resolve via pbi check in a second pass after
269 // ghost-pulling cell2node/cell2nodePbi for the candidate cells.
270 std::vector<std::set<index>> bndCellCandidates;
271 if (isPeriodic)
272 bndCellCandidates.resize(bnd2node.father->Size());
273
274 for (index i = 0; i < bnd2node.father->Size(); i++)
275 {
276 std::set<index> cellRecCur;
277 bool initDone{false};
278 // std::cout << "RecoverCell2CellAndBnd2Cell here L1 1" << std::endl;
279 for (auto in : bnd2node.father->operator[](i))
280 {
282 std::set<index> cellRecCurNew;
284 if (!initDone || cellRecCur.count(ico))
285 cellRecCurNew.insert(ico);
286 std::swap(cellRecCur, cellRecCurNew);
287 initDone = true;
288 }
289
290 // Periodic pbi check and bnd2cell assignment are deferred to the
291 // second pass below (after ghost-pulling cell2node/cell2nodePbi for
292 // the candidate cells). Store candidates per bnd for now.
293 if (isPeriodic)
294 bndCellCandidates[i] = std::move(cellRecCur);
295 else
296 {
297 DNDS_assert_info(cellRecCur.size() == 1, fmt::format("cellRecCur.size() is [{}]", cellRecCur.size()));
298 bnd2cell.father->operator()(i, 0) = *cellRecCur.begin();
299 bnd2cell.father->operator()(i, 1) = UnInitIndex;
300 }
301 }
302
303 /************************************************************/
304 // Periodic: ghost-pull cell2node and cell2nodePbi for all candidate
305 // cells, then do the pbi filter and donor/receiver assignment.
306 /************************************************************/
307 if (isPeriodic)
308 {
309 // Collect all unique candidate cells across all periodic bnds
310 std::vector<index> neededCells;
311 for (index i = 0; i < bnd2cell.father->Size(); i++)
312 {
313 if (!Geom::FaceIDIsPeriodic(bndElemInfo.father->operator()(i, 0).zone))
314 continue;
315 for (auto ic : bndCellCandidates[i])
316 neededCells.push_back(ic);
317 }
318
321 cell2nodePbi.trans.createFatherGlobalMapping();
322 cell2nodePbi.trans.createGhostMapping(neededCells); //! warning, this is not actual final official trans, just needed temporarily
323 cell2nodePbi.trans.createMPITypes();
324 cell2nodePbi.trans.pullOnce();
325 cell2node.son = make_ssp<decltype(cell2node.son)::element_type>(ObjName{"cell2node.son"}, mpi);
326 cell2node.BorrowAndPull(cell2nodePbi); //! warning, this is not actual final official trans, just needed temporarily
327
328 // Now do the periodic pbi filter for each bnd
329 for (index i = 0; i < bnd2cell.father->Size(); i++)
330 {
331 if (!Geom::FaceIDIsPeriodic(bndElemInfo.father->operator()(i, 0).zone))
332 continue;
333
334 auto &cellRecCur = bndCellCandidates[i]; // the pre-pbi candidates (from node intersection)
335 std::set<index> cellRecFiltered;
336 for (auto ic : cellRecCur)
337 {
338 auto [ret, rank, icAppend] = cell2nodePbi.trans.pLGhostMapping->search_indexAppend(ic);
339 DNDS_assert_info(ret, fmt::format("periodic bnd {} candidate cell {} not found in ghost mapping", i, ic));
340
341 bool cellContainsBnd = true;
342 for (int ib2n = 0; ib2n < bnd2node.father->operator[](i).size(); ib2n++)
343 {
344 index iNode = bnd2node.father->operator[](i)[ib2n];
345 auto iNodePbi = bnd2nodePbi.father->operator[](i)[ib2n];
347 for (int ic2n = 0; ic2n < cell2node[icAppend].size(); ic2n++)
348 if (iNode == cell2node(icAppend, ic2n))
349 {
353 }
355 if (nIndexPBIMatchNode == 0)
356 cellContainsBnd = false;
357 }
358 if (cellContainsBnd)
359 cellRecFiltered.insert(ic);
360 }
361
362 // Periodic bnd: 2 cells or 1 (self-periodic)
363 DNDS_assert_info(cellRecFiltered.size() == 2 || cellRecFiltered.size() == 1,
364 fmt::format("periodic bnd {} has {} cells after pbi filter", i, cellRecFiltered.size()));
365 auto it = cellRecFiltered.begin();
366 bnd2cell.father->operator()(i, 0) = *it;
367 if (cellRecFiltered.size() == 2)
368 ++it;
369 bnd2cell.father->operator()(i, 1) = *it;
370 }
371
372 // Swap check: ensure bnd2cell(i, 0) is the donor-side cell
373 for (index i = 0; i < bnd2cell.father->Size(); i++)
374 if (bnd2cell(i, 1) != UnInitIndex && bnd2cell(i, 0) != bnd2cell(i, 1) /* no need to check if both sides are same*/)
375 {
376 index ic0 = bnd2cell(i, 0);
377 index ic1 = bnd2cell(i, 1);
378 auto [ret0, rank0, ic0L] = cell2nodePbi.trans.pLGhostMapping->search_indexAppend(ic0);
379 auto [ret1, rank1, ic1L] = cell2nodePbi.trans.pLGhostMapping->search_indexAppend(ic1);
380 // std::cout << fmt::format("ic0L ic1L, {},{}", ic0L, ic1L) << std::endl;
381 DNDS_assert_info(ret0 && ret1, "search failed");
382 std::vector<Geom::NodePeriodicBits> pbi0, pbi1;
383
384 for (auto in : bnd2node[i])
385 {
386 bool found0{false}, found1{false};
387 for (rowsize ic2n = 0; ic2n < cell2node[ic0L].size(); ic2n++)
388 if (cell2node[ic0L][ic2n] == in)
389 found0 = true, pbi0.push_back(cell2nodePbi(ic0L, ic2n));
390 for (rowsize ic2n = 0; ic2n < cell2node[ic1L].size(); ic2n++)
391 if (cell2node[ic1L][ic2n] == in)
392 found1 = true, pbi1.push_back(cell2nodePbi(ic1L, ic2n));
394 }
396 {
398 b = b & nodePB1;
399 else if (Geom::FaceIDIsPeriodic2(bndElemInfo(i, 0).zone))
400 b = b & nodePB2;
401 else if (Geom::FaceIDIsPeriodic3(bndElemInfo(i, 0).zone))
402 b = b & nodePB3;
403 };
404 for (auto &b : pbi0)
406 for (auto &b : pbi1)
408
410 if (bndElemInfo(i, 0).zone == Geom::BC_ID_PERIODIC_1_DONOR)
412 else if (bndElemInfo(i, 0).zone == Geom::BC_ID_PERIODIC_2_DONOR)
413 bndBit.setP2True();
414 else if (bndElemInfo(i, 0).zone == Geom::BC_ID_PERIODIC_3_DONOR)
415 bndBit.setP3True();
416 else if (!Geom::FaceIDIsPeriodic(bndElemInfo(i, 0).zone))
417 DNDS_assert_info(false, "this bnd with both sides has to be periodic");
418
419 bool match0{true}, match1{true};
420 for (auto b : pbi0)
421 if (b ^ bndBit)
422 match0 = false;
423 for (auto b : pbi1)
424 if (b ^ bndBit)
425 match1 = false;
426 if (match0 && !match1)
427 {
428 } // keep current ordering — match0 alone wins
429 else if (match1 && !match0)
430 std::swap(bnd2cell(i, 0), bnd2cell(i, 1));
431 else
432 {
433 if (mpi.rank >= 0)
434 {
435 for (auto b : pbi0)
436 DNDS::log() << b << ", ";
437 DNDS::log() << " ---- ";
438 for (auto b : pbi1)
439 DNDS::log() << b << ", ";
440 DNDS::log() << " ---- " << bndBit;
441 DNDS::log() << std::endl;
442 }
443 DNDS_assert_info(false,
444 match0
445 ? "this periodic bnd matches both sides"
446 : "this periodic bnd matches no sides");
447 }
448 // if (mpi.rank == 0)
449 // {
450 // if (match1 && !match0)
451 // std::cout << "swap " << i << std::endl;
452 // }
453 }
454 }
455 cell2cell.idx.markGlobal();
456 bnd2cell.idx.markGlobal();
457 }
460 {
462 DNDS_assert(cell2node.isGlobal() && bnd2node.isGlobal());
463 DNDS_assert(cell2cell.father && cell2cell.father->Size() == this->NumCell());
464 DNDS_assert(bnd2cell.father && bnd2cell.father->Size() == this->NumBnd());
465 /********************************/
466 // cells
467 {
468 cell2cell.TransAttach();
469 cell2node.TransAttach();
471 if (isPeriodic)
474
475 cell2cell.trans.createFatherGlobalMapping();
476
477 std::vector<DNDS::index> ghostCells;
478 for (DNDS::index iCell = 0; iCell < cell2cell.father->Size(); iCell++)
479 {
480 for (DNDS::rowsize ic2c = 0; ic2c < cell2cell.father->RowSize(iCell); ic2c++)
481 {
482 auto iCellOther = (*cell2cell.father)(iCell, ic2c);
485 if (!cell2cell.trans.pLGlobalMapping->search(iCellOther, rank, val))
486 DNDS_assert_info(false, "search failed");
487 if (rank != mpi.rank)
488 ghostCells.push_back(iCellOther);
489 }
490 }
491 cell2cell.trans.createGhostMapping(ghostCells);
492
493 cell2cell.trans.createMPITypes();
494 cell2cell.trans.pullOnce();
495 cell2node.BorrowAndPull(cell2cell);
497 if (isPeriodic)
500 }
501
502 /********************************/
503 // cells done, go on to nodes
504 {
507
508 coords.trans.createFatherGlobalMapping();
509
510 std::vector<DNDS::index> ghostNodes;
511 for (DNDS::index iCell = 0; iCell < cell2cell.Size(); iCell++) // note doing full (son + father) traverse
512 {
513 for (DNDS::rowsize ic2c = 0; ic2c < cell2node.RowSize(iCell); ic2c++)
514 {
515 auto iNode = cell2node(iCell, ic2c);
518 if (!coords.trans.pLGlobalMapping->search(iNode, rank, val))
519 DNDS_assert_info(false, "search failed");
520 if (rank != mpi.rank)
521 ghostNodes.push_back(iNode);
522 }
523 }
524 coords.trans.createGhostMapping(ghostNodes);
525 coords.trans.createMPITypes();
526 coords.trans.pullOnce();
528 }
529
530 /********************************/
531 // bnds: added via node2bnd's father part
532 {
533 DNDS_assert(node2bnd.father);
535 DNDS_assert(node2bnd.isGlobal());
536 bnd2cell.TransAttach();
537 bnd2node.TransAttach();
538 if (isPeriodic)
542
543 bnd2cell.trans.createFatherGlobalMapping();
544
545 std::vector<DNDS::index> ghostBnds;
546 for (index iNode = 0; iNode < node2bnd.father->Size(); iNode++)
547 for (auto iBnd : node2bnd[iNode])
548 {
549 auto [ret, rank, val] = bnd2cell.trans.pLGlobalMapping->search(iBnd);
550 DNDS_assert_info(ret, "search failed");
551 if (rank != mpi.rank)
552 ghostBnds.push_back(iBnd);
553 }
554 bnd2cell.trans.createGhostMapping(ghostBnds);
555 bnd2cell.trans.createMPITypes();
556 bnd2cell.trans.pullOnce();
557 bnd2node.BorrowAndPull(bnd2cell);
558 if (isPeriodic)
562
563 // Ghost bnds may reference nodes not yet in the coord ghost layer.
564 // Add those nodes so that AdjGlobal2LocalPrimary can convert bnd2node.
565 // This is collective: all ranks must participate even if some have no extras.
566 {
567 std::vector<DNDS::index> extraGhostNodes;
568 for (DNDS::index iBnd = bnd2node.father->Size(); iBnd < bnd2node.Size(); iBnd++)
569 for (DNDS::rowsize j = 0; j < bnd2node.RowSize(iBnd); j++)
570 {
571 auto iNode = bnd2node(iBnd, j);
574 if (!coords.trans.pLGhostMapping->search_indexAppend(iNode, rank, val))
575 extraGhostNodes.push_back(iNode);
576 }
580 if (nExtraGlobal > 0)
581 {
582 // Rebuild coord ghost mapping with the additional nodes
583 auto &existingGhost = coords.trans.pLGhostMapping->ghostIndex;
584 std::vector<DNDS::index> allGhostNodes(existingGhost.begin(), existingGhost.end());
585 allGhostNodes.insert(allGhostNodes.end(), extraGhostNodes.begin(), extraGhostNodes.end());
586 coords.trans.createGhostMapping(allGhostNodes);
587 node2nodeOrig.trans.BorrowGGIndexing(coords.trans);
588 coords.trans.createMPITypes();
589 node2nodeOrig.trans.createMPITypes();
590 coords.trans.pullOnce();
591 node2nodeOrig.trans.pullOnce();
592 }
593 }
594 }
595
596 // Wire per-adjacency target mappings (mirrors BuildGhostPrimary)
597 {
598 auto cellGhostMap = cellElemInfo.trans.pLGhostMapping;
599 auto nodeGhostMap = coords.trans.pLGhostMapping;
600 auto bndGhostMap = bndElemInfo.trans.pLGhostMapping;
601
602 cell2node.idx.wireTargetMapping(nodeGhostMap);
603 bnd2node.idx.wireTargetMapping(nodeGhostMap);
604 cell2cell.idx.wireTargetMapping(cellGhostMap);
605 bnd2cell.idx.wireTargetMapping(cellGhostMap);
606 node2cell.idx.wireTargetMapping(cellGhostMap);
607 node2bnd.idx.wireTargetMapping(bndGhostMap);
608 }
609 }
612 {
613 DNDS_assert(adjPrimaryState == Adj_PointToLocal); // And also should have primary ghost comm
614 DNDS_assert(cell2node.isLocal() && cell2cell.isLocal() && bnd2node.isLocal());
615
616 // Allocate face-related array pairs
617 cell2face.InitPair("cell2face", mpi);
618 face2cell.InitPair("face2cell", mpi);
619 face2node.InitPair("face2node", mpi);
620 if (isPeriodic)
621 face2nodePbi.InitPair("face2nodePbi", mpi);
622 faceElemInfo.InitPair("faceElemInfo", mpi);
623 face2bnd.InitPair("face2bnd", mpi);
624 bnd2face.InitPair("bnd2face", mpi);
625
626 cell2face.father->Resize(cell2cell.father->Size());
627 cell2face.son->Resize(cell2cell.son->Size());
628
629 // Section B: Enumerate unique faces from cell connectivity
633
634 // Section C: Filter faces — discard ghost-only and duplicate cross-rank
636 faceEnum.faceElemInfoV, faceEnum.face2cellV, faceEnum.nFaces,
637 cell2face.father->Size(),
638 *cell2node.trans.pLGhostMapping, *cell2node.father->pLGlobalMapping,
639 mpi.size, mpi.rank);
640
641 // Section D: Compact collected faces into member arrays, remap cell2face
647 // Wire facial target mappings (ghost mappings available from BuildGhostPrimaryLegacy).
648 face2node.idx.wireTargetMapping(coords.trans.pLGhostMapping);
649 face2cell.idx.wireTargetMapping(cellElemInfo.trans.pLGhostMapping);
650 face2bnd.idx.wireTargetMapping(bndElemInfo.trans.pLGhostMapping);
651 // CompactFacesAndRemapCell2Face produced local indices; mark accordingly.
652 face2node.idx.markLocal();
653 face2cell.idx.markLocal();
654 face2bnd.idx.markLocal();
655
656 // Section E: Match boundary elements to faces
660
661 // Section F: Ghost face communication
662 this->AdjLocal2GlobalFacial();
663
664 // Flatten faceSendLocals into CSR format
665 std::vector<index> faceSendLocalsIdx;
666 std::vector<index> faceSendLocalsStarts(mpi.size + 1);
668 for (MPI_int r = 0; r < mpi.size; r++)
669 faceSendLocalsStarts[r + 1] = faceSendLocalsStarts[r] + faceCollect.faceSendLocals[r].size();
671 for (MPI_int r = 0; r < mpi.size; r++)
672 std::copy(faceCollect.faceSendLocals[r].begin(), faceCollect.faceSendLocals[r].end(),
674
675 face2node.father->Compress(); // before comm
676 if (isPeriodic)
677 face2nodePbi.father->Compress();
678 face2cell.TransAttach();
679 face2cell.trans.createFatherGlobalMapping();
680 face2cell.trans.createGhostMapping(faceSendLocalsIdx, faceSendLocalsStarts);
681 face2cell.trans.createMPITypes();
682 face2cell.trans.pullOnce();
683 face2node.BorrowAndPull(face2cell);
684 if (isPeriodic)
687 face2bnd.BorrowAndPull(face2cell);
688
689 // Wire facial target mappings (ghost mappings now available)
690 face2node.idx.wireTargetMapping(coords.trans.pLGhostMapping);
691 face2cell.idx.wireTargetMapping(cellElemInfo.trans.pLGhostMapping);
692 face2bnd.idx.wireTargetMapping(bndElemInfo.trans.pLGhostMapping);
693
694 this->AdjGlobal2LocalFacial();
695
696 // Section G: Assign ghost faces to cell2face entries marked -1
700 face2cell.father->Size());
701
702 cell2face.father->Compress();
703 cell2face.son->Compress();
704 // Wire C2F target mappings (face ghost mapping available from facial pull).
705 {
706 auto faceGhostMap = face2cell.trans.pLGhostMapping;
707 cell2face.idx.wireTargetMapping(faceGhostMap);
708 bnd2face.idx.wireTargetMapping(faceGhostMap);
709 }
710 // CompactFacesAndRemapCell2Face + AssignGhostFacesToCells produced
711 // local face indices in cell2face; bnd2face is empty but tracks state.
713 cell2face.idx.markLocal();
714 bnd2face.idx.markLocal();
715
716 // Section H: Communicate cell2face and bnd2face ghost data
717 this->AdjLocal2GlobalC2F();
718 cell2face.TransAttach();
719 cell2face.trans.BorrowGGIndexing(cell2node.trans);
720 cell2face.trans.createMPITypes();
721 cell2face.trans.pullOnce();
722 bnd2face.TransAttach();
723 bnd2face.trans.BorrowGGIndexing(bnd2node.trans);
724 bnd2face.trans.createMPITypes();
725 bnd2face.trans.pullOnce();
726 this->AdjGlobal2LocalC2F();
727
728 for (DNDS::index iFace = 0; iFace < faceElemInfo.Size(); iFace++)
729 {
731 {
732 // DNDS_assert(false);
733 }
734 }
735 for (DNDS::index iFace = 0; iFace < faceElemInfo.Size(); iFace++)
736 {
738 {
739 // DNDS_assert(false);
740 }
741 }
742
743 auto gSize = face2node.father->globalSize(); //! sync call!!!
744 if (mpi.rank == 0)
745 log() << "UnstructuredMesh === InterpolateFaceLegacy: total faces " << gSize << std::endl;
746 }
747
748} // namespace DNDS::Geom
#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
Ghost-communication engine for a father / son ParArray pair.
void createMPITypes()
Collective: build the MPI derived datatypes (or in-situ buffers) that describe the ghost send/recv la...
void pullOnce()
Convenience: init + start + wait + clear a single pull.
void setFatherSon(const t_pArray &n_father, const t_pArray &n_son)
Attach father and son arrays. First setup step.
void createGhostMapping(TPullSet &&pullingIndexGlobal)
create ghost by pulling data
void createFatherGlobalMapping()
Collective: build the global offsets table on the father array.
std::function< index(index)> tIndexMapFunc
decltype(tAdjPair::father) tAdj
DNDS_DEVICE_CALLABLE bool FaceIDIsPeriodic(t_index id)
DNDS_DEVICE_CALLABLE bool FaceIDIsPeriodicDonor(t_index id)
DNDS_DEVICE_CALLABLE bool FaceIDIsPeriodicMain(t_index id)
DNDS_DEVICE_CALLABLE bool FaceIDIsPeriodic3(t_index id)
DNDS_DEVICE_CALLABLE bool FaceIDIsPeriodic2(t_index id)
DNDS_DEVICE_CALLABLE bool FaceIDIsPeriodic1(t_index id)
MPI_int Allreduce(const void *sendbuf, void *recvbuf, MPI_int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
Wrapper over MPI_Allreduce.
Definition MPI.cpp:202
const MPI_Datatype DNDS_MPI_INDEX
MPI datatype matching index (= MPI_INT64_T).
Definition MPI.hpp:106
DNDS_CONSTANT const index UnInitIndex
Sentinel "not initialised" index value (= INT64_MIN).
Definition Defines.hpp:181
int32_t rowsize
Row-width / per-row element-count type (signed 32-bit).
Definition Defines.hpp:114
constexpr MPI_int UnInitMPIInt
Sentinel "not initialised" MPI_int value (= -1, invalid rank).
Definition MPI.hpp:66
index size_to_index(size_t v)
Range-checked conversion from size_t to DNDS::index.
Definition Defines.hpp:431
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Definition Defines.hpp:112
ssp< T > make_ssp(Args &&...args)
Type-safe replacement for DNDS_MAKE_SSP. Creates ssp<T> with forwarded args.
Definition Defines.hpp:260
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
DNDS_DEVICE_CALLABLE index Size() const
Combined father + son row count.
Definition ArrayPair.hpp:33
void TransAttach()
Bind the transformer to the current father / son pointers.
ssp< TArray > father
Owned-side array (must be resized before ghost setup).
index Size() const
Combined row count (father->Size() + son->Size()).
void InitPair(const std::string &name, Args &&...args)
Allocate both father and son arrays, forwarding all args to TArray constructor.
ssp< TArray > son
Ghost-side array (sized automatically by createMPITypes / BorrowAndPull).
void BorrowAndPull(TPrimaryPair &primary)
Attach, borrow ghost indexing from a primary pair, create MPI types, and pull once.
void ResizeRow(index i, rowsize rs)
Resize a single row in the combined address space.
TTrans trans
Ghost-communication engine bound to father and son.
static MPI_Datatype CommType()
MeshAdjState adjC2FState
Definition Mesh.hpp:48
UnstructuredMeshDeviceView< B > t_deviceView
Definition Mesh.hpp:1036
index NodeIndexGlobal2Local_NoSon(index i)
Definition Mesh.hpp:323
tPbiPair cell2nodePbi
periodic only, after reader
Definition Mesh.hpp:68
std::unordered_map< index, index > face2bndM
Definition Mesh.hpp:105
index CellIndexLocal2Global_NoSon(index i)
Definition Mesh.hpp:330
tPbiPair face2nodePbi
periodic only, after interpolated
Definition Mesh.hpp:107
AdjPairTracked< tAdj1Pair > face2bnd
Definition Mesh.hpp:102
AdjPairTracked< tAdj2Pair > face2cell
Definition Mesh.hpp:99
index NodeIndexLocal2Global_NoSon(index i)
Definition Mesh.hpp:322
index BndIndexLocal2Global_NoSon(index i)
Definition Mesh.hpp:338
tCoordPair coords
reader
Definition Mesh.hpp:57
MeshAdjState adjN2CBState
Definition Mesh.hpp:50
AdjPairTracked< tAdjPair > cell2face
interpolated
Definition Mesh.hpp:97
AdjPairTracked< tAdjPair > cell2cell
Definition Mesh.hpp:61
std::vector< index > bnd2faceV
Definition Mesh.hpp:104
AdjPairTracked< tAdjPair > face2node
Definition Mesh.hpp:98
MeshAdjState adjPrimaryState
Definition Mesh.hpp:44
AdjPairTracked< tAdj1Pair > bnd2face
Definition Mesh.hpp:101
tElemInfoArrayPair faceElemInfo
Definition Mesh.hpp:100
MeshAdjState adjFacialState
Definition Mesh.hpp:46
AdjPairTracked< tAdjPair > cell2node
Definition Mesh.hpp:58
tElemInfoArrayPair cellElemInfo
Definition Mesh.hpp:62
AdjPairTracked< tAdjPair > node2bnd
Definition Mesh.hpp:87
AdjPairTracked< tAdjPair > bnd2node
Definition Mesh.hpp:59
AdjPairTracked< tAdjPair > node2cell
inverse relations
Definition Mesh.hpp:86
tElemInfoArrayPair bndElemInfo
Definition Mesh.hpp:63
AdjPairTracked< tAdj2Pair > bnd2cell
Definition Mesh.hpp:60
int size
Number of ranks in comm (-1 until initialised).
Definition MPI.hpp:237
int rank
This rank's 0-based index within comm (-1 until initialised).
Definition MPI.hpp:235
MPI_Comm comm
The underlying MPI communicator handle.
Definition MPI.hpp:233
Tag type for naming objects created via make_ssp.
Definition Defines.hpp:254
Eigen::Matrix< real, 5, 1 > v
tVec r(NCells)
tVec b(NCells)
std::vector< DNDS::index > ghostNodes(ghostNodeSet.begin(), ghostNodeSet.end())
std::vector< GhostCell > ghostCells