DNDSR 0.2.1
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
Mesh_InterpolateHelpers.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Mesh.hpp"
4
5#include <cstdlib>
6#include <string>
7#include <unordered_map>
8#include <fmt/core.h>
10
11namespace DNDS::Geom
12{
13 // =================================================================
14 // File-local helpers for InterpolateFace
15 // =================================================================
16 namespace
17 {
18 /**
19 * \brief Result of face enumeration from cell connectivity.
20 */
21 struct FaceEnumerationResult
22 {
23 std::vector<std::vector<DNDS::index>> face2nodeV;
24 std::vector<std::vector<NodePeriodicBits>> face2nodePbiV;
25 std::vector<std::pair<DNDS::index, DNDS::index>> face2cellV;
26 std::vector<ElemInfo> faceElemInfoV;
28 };
29
30 /**
31 * \brief Enumerate unique faces from cell-to-node connectivity.
32 *
33 * Iterates over all cells (local + ghost), extracts topological faces,
34 * deduplicates by sorted vertex comparison (with periodic-aware matching
35 * when \p isPeriodic is true), and populates \p cell2face entries.
36 *
37 * \param[in,out] cell2face Cell-to-face pair (rows resized and entries set).
38 * \param[in] cellElemInfo Cell element info (for element type).
39 * \param[in] cell2node Cell-to-node connectivity.
40 * \param[in] cell2nodePbi Cell-to-node periodic bits (used when isPeriodic).
41 * \param[in] cell2cellSize Total number of cells (father + son).
42 * \param[in] coordsSize Total number of nodes (father + son), for node2face sizing.
43 * \param[in] isPeriodic Whether periodic mesh handling is enabled.
44 */
45 [[maybe_unused]] FaceEnumerationResult EnumerateFacesFromCells(
46 tAdjPair &cell2face,
48 const tAdjPair &cell2node,
50 DNDS::index cell2cellSize,
51 DNDS::index coordsSize,
52 bool isPeriodic)
53 {
54 FaceEnumerationResult result;
55 auto &face2nodeV = result.face2nodeV;
56 auto &face2nodePbiV = result.face2nodePbiV;
57 auto &face2cellV = result.face2cellV;
58 auto &faceElemInfoV = result.faceElemInfoV;
59 auto &nFaces = result.nFaces;
60
61 std::vector<std::vector<DNDS::index>> node2face(coordsSize);
62
63 using idx_pbi_pair = std::pair<index, NodePeriodicBits>;
64 auto idx_pbi_pair_less = [](idx_pbi_pair &L, idx_pbi_pair &R)
65 { return L.first == R.first ? uint8_t(L.second) < uint8_t(R.second) : L.first < R.first; };
66 auto idx_pbi_pair_eq = [](idx_pbi_pair &L, idx_pbi_pair &R)
67 { return L.first == R.first && uint8_t(L.second) == uint8_t(R.second); };
68
69 for (DNDS::index iCell = 0; iCell < cell2cellSize; iCell++)
70 {
71 auto eCell = Elem::Element{cellElemInfo[iCell]->getElemType()};
72 cell2face.ResizeRow(iCell, eCell.GetNumFaces());
73 for (int ic2f = 0; ic2f < eCell.GetNumFaces(); ic2f++)
74 {
75 auto eFace = eCell.ObtainFace(ic2f);
76 std::vector<DNDS::index> faceNodes(eFace.GetNumNodes());
77 eCell.ExtractFaceNodes(ic2f, cell2node[iCell], faceNodes);
78 DNDS::index iFound = -1;
79 std::vector<DNDS::index> faceVerts(faceNodes.begin(), faceNodes.begin() + eFace.GetNumVertices());
80 std::sort(faceVerts.begin(), faceVerts.end());
81
82 std::vector<NodePeriodicBits> faceNodePeriodicBits;
83 std::vector<idx_pbi_pair> faceNodeNodePeriodicBits;
84 if (isPeriodic)
85 {
86 faceNodePeriodicBits.resize(eFace.GetNumNodes());
87 faceNodeNodePeriodicBits.resize(eFace.GetNumNodes());
88 eCell.ExtractFaceNodes(ic2f, cell2nodePbi[iCell], faceNodePeriodicBits);
89 for (size_t i = 0; i < faceNodeNodePeriodicBits.size(); i++)
90 faceNodeNodePeriodicBits[i].first = faceNodes[i], faceNodeNodePeriodicBits[i].second = faceNodePeriodicBits[i];
91 std::sort(faceNodeNodePeriodicBits.begin(), faceNodeNodePeriodicBits.end(),
92 idx_pbi_pair_less);
93 for (size_t i = 1; i < faceNodeNodePeriodicBits.size(); i++)
94 {
95 DNDS_assert_info(!idx_pbi_pair_eq(faceNodeNodePeriodicBits[i - 1], faceNodeNodePeriodicBits[i]),
96 "the face has identical (periodic) nodes");
97 }
98 }
99
100 for (auto iV : faceVerts)
101 if (iFound < 0)
102 for (auto iFOther : node2face[iV])
103 {
104 auto eFaceOther = Elem::Element{faceElemInfoV[iFOther].getElemType()};
105 if (eFaceOther.type != eFace.type)
106 continue;
107 std::vector<DNDS::index> faceVertsOther(
108 face2nodeV[iFOther].begin(),
109 face2nodeV[iFOther].begin() + eFace.GetNumVertices());
110 std::sort(faceVertsOther.begin(), faceVertsOther.end());
111 if (std::equal(faceVerts.begin(), faceVerts.end(), faceVertsOther.begin(), faceVertsOther.end()))
112 {
113 if (isPeriodic)
114 {
115 std::vector<std::pair<index, NodePeriodicBits>> faceNodeNodePeriodicBitsOther(eFaceOther.GetNumNodes());
116 for (size_t i = 0; i < faceNodeNodePeriodicBitsOther.size(); i++)
117 faceNodeNodePeriodicBitsOther[i].first = face2nodeV[iFOther][i],
118 faceNodeNodePeriodicBitsOther[i].second = face2nodePbiV[iFOther][i];
119 std::sort(faceNodeNodePeriodicBitsOther.begin(), faceNodeNodePeriodicBitsOther.end(),
120 idx_pbi_pair_less);
121 auto v0 = faceNodeNodePeriodicBits.at(0).second ^ faceNodeNodePeriodicBitsOther.at(0).second;
122 DNDS_assert(faceNodeNodePeriodicBitsOther.size() == faceNodeNodePeriodicBits.size());
123 bool collaborating = true;
124 for (size_t i = 1; i < faceNodeNodePeriodicBitsOther.size(); i++)
125 if ((faceNodeNodePeriodicBits[i].second ^ faceNodeNodePeriodicBitsOther[i].second) != v0)
126 collaborating = false;
127 if (collaborating)
128 iFound = iFOther;
129 }
130 else
131 iFound = iFOther;
132 }
133 }
134 if (iFound < 0)
135 {
136 // * face not existent yet
137 face2nodeV.emplace_back(faceNodes); // note: faceVerts invalid here!
138 if (isPeriodic)
139 face2nodePbiV.emplace_back(faceNodePeriodicBits);
140 face2cellV.emplace_back(iCell, DNDS::UnInitIndex);
141 // important note: f2nPbi node pbi is always same as cell f2c[0]'s corresponding nodes
142 faceElemInfoV.emplace_back(ElemInfo{eFace.type, 0});
143 for (auto iV : faceVerts)
144 node2face[iV].push_back(nFaces);
145 cell2face(iCell, ic2f) = nFaces;
146 nFaces++;
147 }
148 else
149 {
150 DNDS_assert(face2cellV[iFound].second == DNDS::UnInitIndex);
151 face2cellV[iFound].second = iCell;
152 cell2face(iCell, ic2f) = iFound;
153 }
154 }
155 }
156 return result;
157 }
158
159 /**
160 * \brief Result of face collection/filtering pass.
161 */
162 struct FaceCollectionResult
163 {
164 std::vector<index> iFaceAllToCollected; ///< mapping: old face idx -> collected idx (or UnInitIndex/-1)
165 std::vector<std::vector<index>> faceSendLocals; ///< per-rank lists of local face indices to send as ghost
167 };
168
169 /**
170 * \brief Filter faces: discard ghost-only and duplicate cross-rank faces,
171 * assign ownership to the rank with the lower rank ID.
172 *
173 * \param[in] faceElemInfoV Per-face element info (zone for internal/bnd distinction).
174 * \param[in] face2cellV Per-face cell pair (first, second).
175 * \param[in] nFaces Total enumerated faces.
176 * \param[in] nLocalCells Number of local (father) cells.
177 * \param[in] pLGhostMapping Ghost mapping from cell2node.trans (for global index lookup).
178 * \param[in] pLGlobalMapping Global mapping from cell2node.father (for rank search).
179 * \param[in] nMPIRanks Number of MPI ranks.
180 * \param[in] myRank This process's MPI rank.
181 */
182 [[maybe_unused]] FaceCollectionResult CollectFaces(
183 const std::vector<ElemInfo> &faceElemInfoV,
184 const std::vector<std::pair<DNDS::index, DNDS::index>> &face2cellV,
187 const DNDS::OffsetAscendIndexMapping &ghostMapping,
188 const DNDS::GlobalOffsetsMapping &globalMapping,
189 DNDS::MPI_int nMPIRanks,
190 DNDS::MPI_int myRank)
191 {
192 FaceCollectionResult result;
193 result.iFaceAllToCollected.resize(nFaces);
194 result.faceSendLocals.resize(nMPIRanks);
195 result.nFacesNew = 0;
196
197 for (index iFace = 0; iFace < nFaces; iFace++)
198 {
199 if (faceElemInfoV[iFace].zone <= 0) // if internal
200 {
201 // NOLINTNEXTLINE(bugprone-branch-clone): distinct conditions with same outcome
202 if (face2cellV[iFace].second == UnInitIndex && face2cellV[iFace].first >= nLocalCells) // has not other cell with ghost parent
203 result.iFaceAllToCollected[iFace] = UnInitIndex; // * discard
204 // NOLINTNEXTLINE(bugprone-branch-clone): distinct conditions with same outcome
205 else if (face2cellV[iFace].first >= nLocalCells &&
206 face2cellV[iFace].second >= nLocalCells) // both sides ghost
207 result.iFaceAllToCollected[iFace] = UnInitIndex; // * discard
208 else if (face2cellV[iFace].first >= nLocalCells ||
209 face2cellV[iFace].second >= nLocalCells)
210 {
211 DNDS_assert(face2cellV[iFace].second >= nLocalCells); // should only be the internal as first
212 // * check both sided's info //TODO: optimize so that pLGhostMapping returns rank directly ?
213 index cellGlobL = ghostMapping(-1, face2cellV[iFace].first);
214 index cellGlobR = ghostMapping(-1, face2cellV[iFace].second);
215 MPI_int rankL = UnInitMPIInt, rankR = UnInitMPIInt;
216 index valL = UnInitIndex, valR = UnInitIndex;
217 auto retL = globalMapping.search(cellGlobL, rankL, valL);
218 auto retR = globalMapping.search(cellGlobR, rankR, valR);
219 DNDS_assert(retL && retR && (rankL != rankR));
220 if (rankL > rankR)
221 {
222 result.iFaceAllToCollected[iFace] = -1; // * discard but with ghost
223 }
224 else
225 {
226 DNDS_assert(rankL == myRank);
227 result.faceSendLocals[rankR].push_back(result.nFacesNew);
228 result.iFaceAllToCollected[iFace] = result.nFacesNew++; //*use
229 }
230 }
231 else
232 {
233 result.iFaceAllToCollected[iFace] = result.nFacesNew++; //*use
234 }
235 }
236 else // all bnds would be non duplicate
237 {
238 result.iFaceAllToCollected[iFace] = result.nFacesNew++; //*use
239 }
240 }
241 return result;
242 }
243
244 /**
245 * \brief Copy collected (non-discarded) face data from temporary vectors
246 * into the resized face member arrays, then remap cell2face entries.
247 *
248 * \param[in] faceEnum Face enumeration result (temp vectors).
249 * \param[in] faceCollect Face collection result (mapping + nFacesNew).
250 * \param[out] face2cell Face-to-cell pair (father resized and filled).
251 * \param[out] face2node Face-to-node pair (father resized and filled).
252 * \param[out] face2nodePbi Face-to-node periodic bits pair (if periodic).
253 * \param[out] faceElemInfo Face element info pair (father resized and filled).
254 * \param[in,out] cell2face Cell-to-face pair (entries remapped via iFaceAllToCollected).
255 * \param[in] isPeriodic Whether periodic mesh handling is enabled.
256 * \param[in] mpiComm MPI communicator for barrier.
257 */
258 [[maybe_unused]] void CompactFacesAndRemapCell2Face(
259 const FaceEnumerationResult &faceEnum,
260 const FaceCollectionResult &faceCollect,
261 tAdj2Pair &face2cell,
262 tAdjPair &face2node,
263 tPbiPair &face2nodePbi,
264 tElemInfoArrayPair &faceElemInfo,
265 tAdjPair &cell2face,
266 bool isPeriodic,
267 MPI_Comm mpiComm)
268 {
269 const auto &face2nodeV = faceEnum.face2nodeV;
270 const auto &face2nodePbiV = faceEnum.face2nodePbiV;
271 const auto &face2cellV = faceEnum.face2cellV;
272 const auto &faceElemInfoV = faceEnum.faceElemInfoV;
273 const auto &iFaceAllToCollected = faceCollect.iFaceAllToCollected;
274 index nFacesNew = faceCollect.nFacesNew;
275 index nFaces = faceEnum.nFaces;
276
277 face2cell.father->Resize(nFacesNew);
278 face2node.father->Resize(nFacesNew);
279 if (isPeriodic)
280 face2nodePbi.father->Resize(nFacesNew);
281 faceElemInfo.father->Resize(nFacesNew); //! considering globally duplicate faces
282 nFacesNew = 0;
283 for (DNDS::index iFace = 0; iFace < nFaces; iFace++)
284 {
285 if (iFaceAllToCollected[iFace] >= 0) // ! -1 is also ignored!
286 {
287 face2node.ResizeRow(nFacesNew, face2nodeV[iFace].size());
288 for (DNDS::rowsize if2n = 0; if2n < face2node.RowSize(nFacesNew); if2n++)
289 face2node(nFacesNew, if2n) = face2nodeV[iFace][if2n];
290 if (isPeriodic)
291 {
292 DNDS_assert(face2nodeV[iFace].size() == face2nodePbiV[iFace].size());
293 face2nodePbi.ResizeRow(nFacesNew, face2nodePbiV[iFace].size());
294 for (DNDS::rowsize if2n = 0; if2n < face2nodePbi.RowSize(nFacesNew); if2n++)
295 face2nodePbi(nFacesNew, if2n) = face2nodePbiV[iFace][if2n];
296 }
297 face2cell(nFacesNew, 0) = face2cellV[iFace].first;
298 face2cell(nFacesNew, 1) = face2cellV[iFace].second;
299 faceElemInfo(nFacesNew, 0) = faceElemInfoV[iFace];
300 nFacesNew++;
301 }
302 }
303
304 MPI::Barrier(mpiComm);
305#ifdef DNDS_USE_OMP
306# pragma omp parallel for
307#endif
308 for (DNDS::index iCell = 0; iCell < cell2face.Size(); iCell++) // convert face indices pointers
309 {
310 for (rowsize ic2f = 0; ic2f < cell2face.RowSize(iCell); ic2f++)
311 {
312 cell2face(iCell, ic2f) = iFaceAllToCollected[cell2face(iCell, ic2f)]; // Uninit if to discard
313 }
314 }
315 }
316
317 /**
318 * \brief Match boundary elements to faces, populating faceElemInfo zone IDs
319 * and building bnd2face / face2bnd mappings.
320 *
321 * For each boundary, finds the face that shares the same node set via
322 * the parent cell's cell2face connectivity.
323 */
324 void MatchBoundariesToFaces(
325 const tElemInfoArrayPair &bndElemInfo,
326 const tAdj2Pair &bnd2cell,
327 const tAdjPair &bnd2node,
328 const tAdjPair &cell2face,
329 const tAdjPair &face2node,
330 const tAdjPair &cell2node,
331 tElemInfoArrayPair &faceElemInfo,
332 std::vector<index> &bnd2faceV,
333 std::unordered_map<index, index> &face2bndM,
334 tAdj1Pair &face2bnd,
335 tAdj1Pair &bnd2face)
336 {
337 bnd2faceV.resize(bndElemInfo.father->Size(), -1); // this mapping only uses main (father) part
338 face2bndM.reserve(bndElemInfo.father->Size());
339 std::unordered_map<index, index> iFace2iBnd;
340 for (DNDS::index iBnd = 0; iBnd < bndElemInfo.father->Size(); iBnd++)
341 {
342 DNDS::index pCell = bnd2cell(iBnd, 0);
343 std::vector<DNDS::index> b2nRow = bnd2node[iBnd];
344 std::sort(b2nRow.begin(), b2nRow.end());
345 int nFound = 0;
346 auto faceID = bndElemInfo[iBnd]->zone;
347 for (int ic2f = 0; ic2f < cell2face.RowSize(pCell); ic2f++)
348 {
349 auto iFace = cell2face(pCell, ic2f);
350 if (iFace < 0) //==-1, pointing to ghost face
351 continue;
352 std::vector<DNDS::index> f2nRow = face2node[iFace];
353 std::sort(f2nRow.begin(), f2nRow.end());
354 if (std::equal(b2nRow.begin(), b2nRow.end(), f2nRow.begin(), f2nRow.end()))
355 {
356 if (iFace2iBnd.count(iFace))
357 {
358 DNDS_assert(FaceIDIsPeriodic(faceID)); // only periodic gets to be duplicated
359 index iBndOther = iFace2iBnd[iFace];
360 index iCellA = bnd2cell[iBnd][0];
361 index iCellB = bnd2cell[iBndOther][0];
362 DNDS_assert(iCellA < cell2node.father->Size()); // both points to local non-ghost cells
363 DNDS_assert(iCellB < cell2node.father->Size()); // both points to local non-ghost cells
364 // std::cout << iCellA << " vs " << iCellB << std::endl;
365 if (iCellA > iCellB) // make face corresponds with f2c[0]'s bnd if possible
366 continue;
367 }
368 iFace2iBnd[iFace] = iBnd;
369 nFound++; // two things:
370 // if is periodic, then only gets the bnd info of the main cell's bnd;
371 // if is external bc, then must be non-ghost face
372 faceElemInfo(iFace, 0) = bndElemInfo(iBnd, 0);
373 bnd2faceV[iBnd] = iFace;
374 face2bndM[iFace] = iBnd;
376 FaceIDIsPeriodic(faceID),
377 "bnd elem should have a BC id not interior");
378 }
379 }
380 DNDS_assert(nFound > 0 || (FaceIDIsPeriodic(faceID) && nFound == 0)); // periodic could miss the face
381 }
382
383 face2bnd.father->Resize(face2node.father->Size());
384 for (index iFace = 0; iFace < face2bnd.father->Size(); iFace++)
385 face2bnd.father->operator()(iFace) = face2bndM.count(iFace) ? face2bndM[iFace] : UnInitIndex;
386 bnd2face.father->Resize(bnd2node.father->Size());
387 for (index iBnd = 0; iBnd < bnd2node.father->Size(); iBnd++)
388 bnd2face.father->operator()(iBnd) = bnd2faceV.at(iBnd);
389 }
390
391 /**
392 * \brief Match received ghost faces to cells and assign cell2face entries
393 * that were previously marked -1 (pointing to ghost).
394 *
395 * For each ghost face, iterates over both its cells, finds the matching
396 * topological face slot in cell2face, and assigns the ghost face index.
397 */
398 [[maybe_unused]] void AssignGhostFacesToCells(
399 const tAdj2 &face2cellSon,
400 const tAdj &face2nodeSon,
401 const tElemInfoArray &faceElemInfoSon,
402 tAdjPair &cell2face,
403 const tAdjPair &cell2node,
405 DNDS::index nFatherFaces)
406 {
407#ifdef DNDS_USE_OMP
408# pragma omp parallel for
409#endif
410 for (DNDS::index iFace = 0; iFace < face2cellSon->Size(); iFace++) // face2cell points to local now
411 {
412 // before: first points to inner, //!relies on the order of setting face2cell
413 DNDS_assert((*face2cellSon)(iFace, 0) >= cell2node.father->Size());
414 auto eFace = Elem::Element{(*faceElemInfoSon)(iFace, 0).getElemType()};
415 auto faceVerts = std::vector<index>((*face2nodeSon)[iFace].begin(), (*face2nodeSon)[iFace].begin() + eFace.GetNumVertices());
416 std::sort(faceVerts.begin(), faceVerts.end()); //* do not forget to do set operation sort first
417 for (rowsize if2c = 0; if2c < 2; if2c++)
418 {
419 index iCell = (*face2cellSon)(iFace, if2c);
420 auto cell2faceRow = cell2face[iCell];
421 auto cellNodes = cell2node[iCell];
422 auto eCell = Elem::Element{cellElemInfo(iCell, 0).getElemType()};
423 bool found = false;
424 for (rowsize ic2f = 0; ic2f < cell2face.RowSize(iCell); ic2f++)
425 {
426 auto eFace = eCell.ObtainFace(ic2f);
427 std::vector<index> faceNodesC(eFace.GetNumNodes());
428 eCell.ExtractFaceNodes(ic2f, cellNodes, faceNodesC);
429 std::sort(faceNodesC.begin(), faceNodesC.end());
430 if (std::includes(faceNodesC.begin(), faceNodesC.end(), faceVerts.begin(), faceVerts.end()))
431 {
432 DNDS_assert(cell2face(iCell, ic2f) == -1);
433 cell2face(iCell, ic2f) = iFace + nFatherFaces; // remember is ghost
434 found = true;
435 }
436 }
437 DNDS_assert(found);
438 }
439 }
440 }
441 } // anonymous namespace
442}
#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::vector< std::vector< DNDS::index > > face2nodeV
DNDS::index nFaces
std::vector< std::pair< DNDS::index, DNDS::index > > face2cellV
std::vector< index > iFaceAllToCollected
mapping: old face idx -> collected idx (or UnInitIndex/-1)
std::vector< std::vector< index > > faceSendLocals
per-rank lists of local face indices to send as ghost
std::vector< std::vector< NodePeriodicBits > > face2nodePbiV
std::vector< ElemInfo > faceElemInfoV
Table mapping rank-local row indices to the global index space.
bool search(index globalQuery, MPI_int &rank, index &val) const
Convert a global index to (rank, local). Returns false if out of range.
Mapping between a rank's main data and its ghost copies.
ArrayPair< ArrayNodePeriodicBits< DNDS::NonUniformSize > > tPbiPair
decltype(tAdj2Pair::father) tAdj2
decltype(tAdjPair::father) tAdj
DNDS::ArrayAdjacencyPair< 2 > tAdj2Pair
DNDS::ArrayPair< DNDS::ParArray< ElemInfo > > tElemInfoArrayPair
DNDS::ssp< DNDS::ParArray< ElemInfo > > tElemInfoArray
DNDS::ArrayAdjacencyPair< 1 > tAdj1Pair
DNDS_DEVICE_CALLABLE bool FaceIDIsPeriodic(t_index id)
DNDS::ArrayAdjacencyPair< DNDS::NonUniformSize > tAdjPair
DNDS_DEVICE_CALLABLE bool FaceIDIsExternalBC(t_index id)
MPI_int Barrier(MPI_Comm comm)
Wrapper over MPI_Barrier.
Definition MPI.cpp:247
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
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Definition Defines.hpp:112
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
ssp< TArray > father
Owned-side array (must be resized before ghost setup).
void ResizeRow(index i, rowsize rs)
Resize a single row in the combined address space.
if(DEFINED ENV{DNDS_TEST_NP_LIST}) set(DNDS_TEST_NP_LIST "$ENV
if(g_mpi.rank==0) std auto[rhsDensity, rhsEnergy, incL2]
for(int i=0;i< 10;i++) theta(i
auto result
tElemInfoArrayPair cellElemInfo
input explicitMaps push_back(EntityReorderMap{EntityKind::Cell, cellPartition})