MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
cartesiangridtree.h
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#ifndef GRIDTREE_H_
8#define GRIDTREE_H_
9
10#include <algorithm>
11#include <bitset>
12#include <type_traits>
13#include <vector>
14#include "INCLUDE/maiamacro.h"
15#include "INCLUDE/maiatypes.h"
16#include "IO/parallelio.h"
17#include "MEMORY/container.h"
18#include "UTIL/functions.h"
20#include "compiler_config.h"
21#include "config.h"
22
23// The following macro enables the "Structure-of-Arrays" memory layout for multi-dimensional node
24// variables. This might be beneficial for GPU computations. Default is "Array-of-Structures".
25// Examples (for nodes nN with four children cM each)
26// Array-of-Structures (AOS): n0c0, n0c1, n0c2, n0c3, n1c0, n1c1, n1c2, n1c3, n2c0, n2c1, ...
27// Structure-of-Arrays (SOA): n0c0, n1c0, n2c0, n3c0, ..., n0c1, n1c1, n2c1, n3c1, ..., n0c2, ...
28// #define GRIDTREE_SOA_MEMORY_LAYOUT
29
30// The macro 'GRIDTREE_SANITY_CHECKS' enables (potentially expensive) sanity checks for many grid
31// operations (but not the accessors). It is enabled for build type "debug"
32
33// The macro 'GRIDTREE_SANITY_CHECKS_ACCESSORS' enables (potentially very expensive) sanity checks
34// for all accessors. It is enabled for build type "extra_debug".
35#ifdef MAIA_EXTRA_DEBUG
36#define GRIDTREE_SANITY_CHECKS_ACCESSORS
37#endif
38
39// Sanity-checking macros for accessors
40#ifdef GRIDTREE_SANITY_CHECKS_ACCESSORS
41#define ENSURE_VALID_ID_ACCESSOR(id) \
42 do { \
43 MAIA_CONTAINER_ENSURE_VALID_ID(id); \
44 } while(false)
45#define ENSURE_VALID_CHILD_POSITION_ACCESSOR(pos) \
46 do { \
47 MAIA_CONTAINER_ENSURE(pos >= 0 && pos < noChildrenPerNode(), \
48 "child position = " + std::to_string(pos) + " out-of-bounds [0, " \
49 + std::to_string(noChildrenPerNode()) + ")", \
50 AT_); \
51 } while(false)
52#define ENSURE_VALID_NEIGHBOR_DIR_ACCESSOR(dir) \
53 do { \
54 MAIA_CONTAINER_ENSURE(dir >= 0 && dir < noNeighborsPerNode(), \
55 "neighbor direction = " + std::to_string(dir) + " out-of-bounds [0, " \
56 + std::to_string(noNeighborsPerNode()) + ")", \
57 AT_); \
58 } while(false)
59#define ENSURE_VALID_COORDINATE_DIR_ACCESSOR(dir) \
60 do { \
61 MAIA_CONTAINER_ENSURE( \
62 dir >= 0 && dir < nDim, \
63 "coordinate direction " + std::to_string(dir) + " out-of-bounds [0, " + std::to_string(nDim) + ")", AT_); \
64 } while(false)
65#define ENSURE_VALID_PROPERTY_ACCESSOR(p) \
66 do { \
67 MAIA_CONTAINER_ENSURE(p != Cell::NumProperties, "Invalid property", AT_); \
68 } while(false)
69#define ENSURE_VALID_SOLVER_ID_ACCESSOR(id) \
70 do { \
71 MAIA_CONTAINER_ENSURE(id >= 0 && id < noSolvers(), "Invalid solver id", AT_); \
72 } while(false)
73#else
74#define ENSURE_VALID_ID_ACCESSOR(id) \
75 do { \
76 } while(false)
77#define ENSURE_VALID_CHILD_POSITION_ACCESSOR(pos) \
78 do { \
79 } while(false)
80#define ENSURE_VALID_NEIGHBOR_DIR_ACCESSOR(dir) \
81 do { \
82 } while(false)
83#define ENSURE_VALID_COORDINATE_DIR_ACCESSOR(dir) \
84 do { \
85 } while(false)
86#define ENSURE_VALID_PROPERTY_ACCESSOR(dir) \
87 do { \
88 } while(false)
89#define ENSURE_VALID_SOLVER_ID_ACCESSOR(id) \
90 do { \
91 } while(false)
92#endif
93
94
96namespace maia {
97namespace grid {
98namespace tree {
99
102
105
108static constexpr MInt MAIA_MULTISOLVER_MAX_NO_SOLVERS = 8;
109
111using SolverBitsetType = std::bitset<MAIA_MULTISOLVER_MAX_NO_SOLVERS>;
112
113// Type traits for invalid values. These values are used to initialize/erase nodes
114template <class T>
115struct Invalid {};
116
117// Invalid value for ids is 'INT_MIN'
118template <>
119struct Invalid<MInt> {
120 static constexpr MInt value() { return std::numeric_limits<MInt>::min(); }
121};
122
123template <>
124struct Invalid<MLong> {
125 static constexpr MLong value() { return std::numeric_limits<MLong>::min(); }
126};
127
128// Invalid value for chars is 'INT_MIN'
129template <>
130struct Invalid<MChar> {
131 static constexpr MInt value() { return std::numeric_limits<MChar>::min(); }
132};
133
134// Invalid value for chars is 'INT_MIN'
135template <>
137 static constexpr MInt value() { return std::numeric_limits<MUchar>::min(); }
138};
139
140// Invalid value for floats is 'NaN'
141template <>
143 static constexpr MFloat value() {
144#ifdef MAIA_PGI_COMPILER
145 return std::numeric_limits<MFloat>::quiet_NaN();
146#else
147 return std::numeric_limits<MFloat>::signaling_NaN();
148#endif
149 }
150};
151
152// Invalid value for bitsets is '0'
153template <>
155 static constexpr PropertyBitsetType value() { return {0}; }
156};
157template <>
159 static constexpr SolverBitsetType value() { return {0}; }
160};
161
162
164// Concept
166//
167// - Only high-level API is exposed to users (i.e., is public)
168// - High-level API calls preserve tree consistency
169// - Bounds and sanity checking in each high-level API call
170// - Low-level API performs only memory operations (i.e., is auxiliary to the high-level calls)
171// - Low-level API and does usually not perform bounds checking
172//
174
175
177template <MInt nDim>
178class Tree : public maia::container::Container<Tree<nDim>, maia::grid::tree::Invalid> {
179 // Necessary for CRTP
181
182 // Make base class functions known to use without this pointer
183 using Base = maia::container::Container<Tree<nDim>, maia::grid::tree::Invalid>;
184 using Base::resetStorage;
185 template <class T>
186 using Storage = typename Base::template Storage<T>;
187
188
189 public:
190 // Types
191 template <class T>
196
197 // Constructors
199 constexpr Tree() = default;
200
201 // Ensure that base class method is found when called from outside
202 using Base::copyData;
203 using Base::fill_invalid;
204 using Base::reset;
205
206 // Parent-child relationship
207 MLong& parent(const MInt id);
208 MLong parent(const MInt id) const;
209 MBool hasParent(const MInt id) const;
210 MLong& child(const MInt id, const MInt pos);
211 MLong child(const MInt id, const MInt pos) const;
212 MBool hasChild(const MInt id, const MInt pos) const;
213 MBool hasChildren(const MInt id) const;
214 MBool hasChildren(const MInt id, const MInt solverId) const;
215 MInt noChildren(const MInt id) const;
216
217 // Neighbors
218 MLong& neighbor(const MInt id, const MInt dir);
219 MLong neighbor(const MInt id, const MInt dir) const;
220 MBool hasNeighbor(const MInt id, const MInt dir) const;
221 MBool hasAnyNeighbor(const MInt id, const MInt dir) const;
222
223 // Other data fields
224 MLong& globalId(const MInt id);
225 MLong globalId(const MInt id) const;
226 MInt& level(const MInt id);
227 MInt level(const MInt id) const;
228 MFloat& coordinate(const MInt id, const MInt dim);
229 MFloat coordinate(const MInt id, const MInt dim) const;
230 const MFloat* coordinate(const MInt id) const;
231 MFloat& weight(const MInt id);
232 MFloat weight(const MInt id) const;
233
234 SolverBitsetType::reference solver(const MInt id, const MInt solverId);
235 MBool solver(const MInt id, const MInt solverId) const;
236 void resetSolver(const MInt id);
237 MUlong solverToBits(const MInt id) const;
238 void solverFromBits(const MInt id, const MUlong bits);
239 MBool cellHasSolver(const MInt cellId, const MInt solverId);
240 SolverBitsetType& solverBits(const MInt id);
241
242 MBool isLeafCell(const MInt id) const;
243 SolverBitsetType::reference isLeafCell(const MInt id, const MInt solverId);
244 MBool isLeafCell(const MInt id, const MInt solverId) const;
245 void resetIsLeafCell(const MInt id);
246 SolverBitsetType& leafCellBits(const MInt id);
247
248 PropertyBitsetType::reference hasProperty(const MInt id, const Cell p);
249 MBool hasProperty(const MInt id, const Cell p) const;
250 void resetProperties(const MInt id);
251 MUlong propertiesToBits(const MInt id) const;
252 void propertiesFromBits(const MInt id, const MUlong bits);
253 MString propertiesToString(const MInt id) const;
254 PropertyBitsetType& properties(const MInt id);
255
256 // Other data fields (subject to change)
257 MInt& noOffsprings(const MInt id);
258 MInt noOffsprings(const MInt id) const;
259 MFloat& workload(const MInt id);
260 MFloat workload(const MInt id) const;
261
262 // Entries per tree node
264 static constexpr MInt noChildrenPerNode() { return 4 * nDim - 4; }
266 static constexpr MInt noNeighborsPerNode() { return 2 * nDim; }
267
269 static constexpr MInt oppositeNeighborDir(const MInt dir) { return dir + 1 - 2 * (dir % 2); }
270
272 static constexpr MInt noProperties() { return maia::grid::cell::p(Cell::NumProperties); }
273
275 static constexpr MInt maxNoSolvers() { return SolverBitsetType().size(); }
276
277 // Methods related to multi-solver features
279 constexpr MInt noSolvers() const { return m_noSolvers; }
280
281 // Set number of solvers
282 void setNoSolvers(const MInt count);
283
284 MInt noNodesBySolver(const MInt solverId) const;
285 MInt nodesBySolver(const MInt solverId, MInt* const ids) const;
286
287 MInt capacity() { return m_parentIds.capacity(); }
288
289 private:
290 // Methods required by base class for CRTP
291 void reset();
292 void invalidate(const MInt begin, const MInt end);
293 template <class Functor, class T>
294 void rawCopyGeneric(Functor&& c, const T& source, const MInt begin, const MInt end, const MInt destination);
295 void deleteConnectivity(const MInt begin, const MInt end);
296 void moveConnectivity(const MInt begin, const MInt end, const MInt to);
297
298 // Data containers
311
314};
315
316
318template <MInt nDim>
320 resetStorage(1, m_parentIds);
321 resetStorage(noChildrenPerNode(), m_childIds);
322 resetStorage(noNeighborsPerNode(), m_neighborIds);
323 resetStorage(1, m_levels);
324 resetStorage(1, m_globalIds);
325 resetStorage(nDim, m_coordinates);
326 resetStorage(1, m_weight);
327 resetStorage(1, m_solver);
328 resetStorage(1, m_isLeafCell);
329 resetStorage(1, m_properties);
330 resetStorage(1, m_noOffsprings);
331 resetStorage(1, m_workload);
332}
333
334
336template <MInt nDim>
338 ENSURE_VALID_ID_ACCESSOR(id);
339 return m_parentIds[id];
340}
342template <MInt nDim>
344 ENSURE_VALID_ID_ACCESSOR(id);
345 return m_parentIds[id];
346}
347
348
350template <MInt nDim>
352 ENSURE_VALID_ID_ACCESSOR(id);
353 return m_parentIds[id] > -1;
354}
355
356
358template <MInt nDim>
359MLong& Tree<nDim>::child(const MInt id, const MInt pos) {
360// Prevent accidental compilation without support for SoA layout
361#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
362#error Missing implementation for structure-of-arrays memory layout.
363#endif
364 ENSURE_VALID_ID_ACCESSOR(id);
365 ENSURE_VALID_CHILD_POSITION_ACCESSOR(pos);
366 return m_childIds[id * noChildrenPerNode() + pos];
367}
369template <MInt nDim>
370MLong Tree<nDim>::child(const MInt id, const MInt pos) const {
371// Prevent accidental compilation without support for SoA layout
372#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
373#error Missing implementation for structure-of-arrays memory layout.
374#endif
375 ENSURE_VALID_ID_ACCESSOR(id);
376 ENSURE_VALID_CHILD_POSITION_ACCESSOR(pos);
377 return m_childIds[id * noChildrenPerNode() + pos];
378}
379
380
382template <MInt nDim>
383MBool Tree<nDim>::hasChild(const MInt id, const MInt pos) const {
384// Prevent accidental compilation without support for SoA layout
385#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
386#error Missing implementation for structure-of-arrays memory layout.
387#endif
388 ENSURE_VALID_ID_ACCESSOR(id);
389 ENSURE_VALID_CHILD_POSITION_ACCESSOR(pos);
390 return m_childIds[id * noChildrenPerNode() + pos] > -1;
391}
392
393
395template <MInt nDim>
397 ENSURE_VALID_ID_ACCESSOR(id);
398 return noChildren(id) > 0;
399}
400
402template <MInt nDim>
403MBool Tree<nDim>::hasChildren(const MInt id, const MInt solverId) const {
404 ENSURE_VALID_ID_ACCESSOR(id);
405 return std::any_of(&m_childIds[id * noChildrenPerNode()], &m_childIds[id * noChildrenPerNode() + noChildrenPerNode()],
406 [&](MLong c) { return c > -1 && solver(c, solverId); });
407}
408
410template <MInt nDim>
412// Prevent accidental compilation without support for SoA layout
413#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
414#error Missing implementation for structure-of-arrays memory layout.
415#endif
416 ENSURE_VALID_ID_ACCESSOR(id);
417 return std::count_if(&m_childIds[id * noChildrenPerNode() + 0],
418 &m_childIds[id * noChildrenPerNode() + noChildrenPerNode()],
419 [](const ParallelIo::size_type childId) { return childId > -1; });
420}
421
422
424template <MInt nDim>
425MLong& Tree<nDim>::neighbor(const MInt id, const MInt dir) {
426// Prevent accidental compilation without support for SoA layout
427#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
428#error Missing implementation for structure-of-arrays memory layout.
429#endif
430 ENSURE_VALID_ID_ACCESSOR(id);
431 ENSURE_VALID_NEIGHBOR_DIR_ACCESSOR(dir);
432 return m_neighborIds[id * noNeighborsPerNode() + dir];
433}
435template <MInt nDim>
436MLong Tree<nDim>::neighbor(const MInt id, const MInt dir) const {
437// Prevent accidental compilation without support for SoA layout
438#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
439#error Missing implementation for structure-of-arrays memory layout.
440#endif
441 ENSURE_VALID_ID_ACCESSOR(id);
442 ENSURE_VALID_NEIGHBOR_DIR_ACCESSOR(dir);
443 return m_neighborIds[id * noNeighborsPerNode() + dir];
444}
445
446
448template <MInt nDim>
449MBool Tree<nDim>::hasNeighbor(const MInt id, const MInt dir) const {
450// Prevent accidental compilation without support for SoA layout
451#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
452#error Missing implementation for structure-of-arrays memory layout.
453#endif
454 ENSURE_VALID_ID_ACCESSOR(id);
455 ENSURE_VALID_NEIGHBOR_DIR_ACCESSOR(dir);
456 return m_neighborIds[id * noNeighborsPerNode() + dir] > -1;
457}
459template <MInt nDim>
460MBool Tree<nDim>::hasAnyNeighbor(const MInt id, const MInt dir) const {
461 ENSURE_VALID_ID_ACCESSOR(id);
462 ENSURE_VALID_NEIGHBOR_DIR_ACCESSOR(dir);
463 return hasNeighbor(id, dir) || (hasParent(id) && hasNeighbor(parent(id), dir));
464}
465
466
468template <MInt nDim>
470 ENSURE_VALID_ID_ACCESSOR(id);
471 return m_globalIds[id];
472}
474template <MInt nDim>
476 ENSURE_VALID_ID_ACCESSOR(id);
477 return m_globalIds[id];
478}
479
480
482template <MInt nDim>
484 ENSURE_VALID_ID_ACCESSOR(id);
485 return m_levels[id];
486}
488template <MInt nDim>
489MInt Tree<nDim>::level(const MInt id) const {
490 ENSURE_VALID_ID_ACCESSOR(id);
491 return m_levels[id];
492}
493
494
496template <MInt nDim>
497MFloat& Tree<nDim>::coordinate(const MInt id, const MInt dir) {
498// Prevent accidental compilation without support for SoA layout
499#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
500#error Missing implementation for structure-of-arrays memory layout.
501#endif
502 ENSURE_VALID_ID_ACCESSOR(id);
503 ENSURE_VALID_COORDINATE_DIR_ACCESSOR(dir);
504 return m_coordinates[id * nDim + dir];
505}
507template <MInt nDim>
508MFloat Tree<nDim>::coordinate(const MInt id, const MInt dir) const {
509// Prevent accidental compilation without support for SoA layout
510#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
511#error Missing implementation for structure-of-arrays memory layout.
512#endif
513 ENSURE_VALID_ID_ACCESSOR(id);
514 ENSURE_VALID_COORDINATE_DIR_ACCESSOR(dir);
515 return m_coordinates[id * nDim + dir];
516}
517
518template <MInt nDim>
519const MFloat* Tree<nDim>::coordinate(const MInt id) const {
520// Prevent accidental compilation without support for SoA layout
521#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
522#error Missing implementation for structure-of-arrays memory layout.
523#endif
524 ENSURE_VALID_ID_ACCESSOR(id);
525 return &m_coordinates[id * nDim];
526}
527
528
530template <MInt nDim>
532 ENSURE_VALID_ID_ACCESSOR(id);
533 return m_weight[id];
534}
536template <MInt nDim>
538 ENSURE_VALID_ID_ACCESSOR(id);
539 return m_weight[id];
540}
541
542
544template <MInt nDim>
546 ENSURE_VALID_ID_ACCESSOR(id);
547 return m_noOffsprings[id];
548}
550template <MInt nDim>
552 ENSURE_VALID_ID_ACCESSOR(id);
553 return m_noOffsprings[id];
554}
555
556
558template <MInt nDim>
560 ENSURE_VALID_ID_ACCESSOR(id);
561 return m_workload[id];
562}
564template <MInt nDim>
566 ENSURE_VALID_ID_ACCESSOR(id);
567 return m_workload[id];
568}
569
570
572template <MInt nDim>
574 ENSURE_VALID_ID_ACCESSOR(id);
575 ENSURE_VALID_SOLVER_ID_ACCESSOR(solverId);
576 return m_solver[id][solverId];
577}
579template <MInt nDim>
580MBool Tree<nDim>::solver(const MInt id, const MInt solverId) const {
581 ENSURE_VALID_ID_ACCESSOR(id);
582 ENSURE_VALID_SOLVER_ID_ACCESSOR(solverId);
583 return m_solver[id][solverId];
584}
586template <MInt nDim>
588 ENSURE_VALID_ID_ACCESSOR(id);
589 m_solver[id].reset();
590}
592template <MInt nDim>
594 ENSURE_VALID_ID_ACCESSOR(id);
595 return m_solver[id].to_ulong();
596}
598template <MInt nDim>
599void Tree<nDim>::solverFromBits(const MInt id, const MUlong bits) {
600 ENSURE_VALID_ID_ACCESSOR(id);
601 m_solver[id] = SolverBitsetType(bits);
602}
604template <MInt nDim>
605MBool Tree<nDim>::cellHasSolver(const MInt cellId, const MInt solverId) {
606 return m_solver[cellId][solverId];
607}
609template <MInt nDim>
611 ENSURE_VALID_ID_ACCESSOR(id);
612 return m_solver[id];
613}
614
615
617template <MInt nDim>
619 ENSURE_VALID_ID_ACCESSOR(id);
620 return (m_isLeafCell[id].any() && m_isLeafCell[id] == m_solver[id]);
621}
623template <MInt nDim>
625 ENSURE_VALID_ID_ACCESSOR(id);
626 ENSURE_VALID_SOLVER_ID_ACCESSOR(solverId);
627 // ASSERT( m_solver[id][solverId], "Invalid cell accessed, not belonging to solver!" );
628 return m_isLeafCell[id][solverId];
629}
631template <MInt nDim>
632MBool Tree<nDim>::isLeafCell(const MInt id, const MInt solverId) const {
633 ENSURE_VALID_ID_ACCESSOR(id);
634 ENSURE_VALID_SOLVER_ID_ACCESSOR(solverId);
635 // ASSERT( m_solver[id][solverId], "Invalid cell accessed, not belonging to solver!" );
636 return m_isLeafCell[id][solverId];
637}
639template <MInt nDim>
641 ENSURE_VALID_ID_ACCESSOR(id);
642 m_isLeafCell[id].reset();
643}
645template <MInt nDim>
647 ENSURE_VALID_ID_ACCESSOR(id);
648 return m_isLeafCell[id];
649}
650
652template <MInt nDim>
654 ENSURE_VALID_ID_ACCESSOR(id);
655 ENSURE_VALID_PROPERTY_ACCESSOR(p);
656 return m_properties[id][maia::grid::cell::p(p)];
657}
659template <MInt nDim>
660MBool Tree<nDim>::hasProperty(const MInt id, const Cell p) const {
661 ENSURE_VALID_ID_ACCESSOR(id);
662 ENSURE_VALID_PROPERTY_ACCESSOR(p);
663 return m_properties[id][maia::grid::cell::p(p)];
664}
666template <MInt nDim>
668 ENSURE_VALID_ID_ACCESSOR(id);
669 m_properties[id].reset();
670}
672template <MInt nDim>
674 ENSURE_VALID_ID_ACCESSOR(id);
675 return m_properties[id].to_ulong();
676}
678template <MInt nDim>
679void Tree<nDim>::propertiesFromBits(const MInt id, const MUlong bits) {
680 ENSURE_VALID_ID_ACCESSOR(id);
681 m_properties[id] = PropertyBitsetType(bits);
682}
684template <MInt nDim>
686 ENSURE_VALID_ID_ACCESSOR(id);
687 return m_properties[id].to_string();
688}
690template <MInt nDim>
692 ENSURE_VALID_ID_ACCESSOR(id);
693 return m_properties[id];
694}
695
696
698template <MInt nDim>
700 MAIA_CONTAINER_ENSURE(count > 0, "Number of solvers must be greater than zero.", AT_);
701 MAIA_CONTAINER_ENSURE(count <= maxNoSolvers(),
702 "Number of solvers out-of-bounds [0, " + std::to_string(maxNoSolvers()) + "].", AT_);
703 m_noSolvers = count;
704}
705
706
708template <MInt nDim>
709MInt Tree<nDim>::noNodesBySolver(const MInt solverId) const {
710 MAIA_CONTAINER_ENSURE(solverId >= 0 && solverId < noSolvers(),
711 "solver id = " + std::to_string(solverId) + " out-of-bounds [0, " + std::to_string(noSolvers())
712 + ")",
713 AT_);
714
715 // Count nodes with solver bit set
716 MInt noNodes = 0;
717 for(MInt id = 0; id < this->size(); id++) {
718 noNodes += solver(id, solverId);
719 }
720
721 return noNodes;
722}
723
724
726template <MInt nDim>
727MInt Tree<nDim>::nodesBySolver(const MInt solverId, MInt* const ids) const {
728 MAIA_CONTAINER_ENSURE(solverId >= 0 && solverId < noSolvers(),
729 "solver id = " + std::to_string(solverId) + " out-of-bounds [0, " + std::to_string(noSolvers())
730 + ")",
731 AT_);
732 MAIA_CONTAINER_ENSURE(ids != nullptr, "Data pointer must not be null", AT_);
733
734 // Loop over all nodes and store ids with solver bit set
735 MInt count = 0;
736 for(MInt id = 0; id < this->size(); id++) {
737 // Skip node if solver bit not set
738 if(!solver(id, solverId)) {
739 continue;
740 }
741
742 // Add id to list and increase count
743 ids[count] = id;
744 count++;
745 }
746
747 return count;
748}
749
750
752template <MInt nDim>
753void Tree<nDim>::invalidate(const MInt begin, const MInt end) {
754// Prevent accidental compilation without support for SoA layout
755#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
756#error Missing implementation for structure-of-arrays memory layout.
757#endif
758
759 // Parent
760 fill_invalid(m_parentIds, begin, end);
761
762 // Children
763 fill_invalid(m_childIds, begin, end, noChildrenPerNode());
764
765 // Neighbors
766 fill_invalid(m_neighborIds, begin, end, noNeighborsPerNode());
767
768 // Global id
769 fill_invalid(m_globalIds, begin, end);
770
771 // Level
772 fill_invalid(m_levels, begin, end);
773
774 // Coordinates
775 fill_invalid(m_coordinates, begin, end, nDim);
776
777 // Solver usage
778 fill_invalid(m_solver, begin, end);
779
780 // Solver usage
781 fill_invalid(m_isLeafCell, begin, end);
782
783 // Weight
784 fill_invalid(m_weight, begin, end);
785
786 // Properties
787 fill_invalid(m_properties, begin, end);
788
789 // No offsprings
790 fill_invalid(m_noOffsprings, begin, end);
791
792 // Workload
793 fill_invalid(m_workload, begin, end);
794}
795
796
798template <MInt nDim>
799template <class Functor, class T>
800void Tree<nDim>::rawCopyGeneric(Functor&& c, const T& source, const MInt begin, const MInt end,
801 const MInt destination) {
802// Prevent accidental compilation without support for SoA layout
803#ifdef GRIDTREE_SOA_MEMORY_LAYOUT
804#error Missing implementation for structure-of-arrays memory layout.
805#endif
806 // Parent
807 copyData(source.m_parentIds, m_parentIds, c, begin, end, destination);
808
809 // Children
810 copyData(source.m_childIds, m_childIds, c, begin, end, destination, noChildrenPerNode());
811
812 // Neighbors
813 copyData(source.m_neighborIds, m_neighborIds, c, begin, end, destination, noNeighborsPerNode());
814
815 // Global id
816 copyData(source.m_globalIds, m_globalIds, c, begin, end, destination);
817
818 // Level
819 copyData(source.m_levels, m_levels, c, begin, end, destination);
820
821 // Coordinates
822 copyData(source.m_coordinates, m_coordinates, c, begin, end, destination, nDim);
823
824 // Solver usage
825 copyData(source.m_solver, m_solver, c, begin, end, destination);
826
827 // Leaf cell flags
828 copyData(source.m_isLeafCell, m_isLeafCell, c, begin, end, destination);
829
830 // Weight
831 copyData(source.m_weight, m_weight, c, begin, end, destination);
832
833 // Properties
834 copyData(source.m_properties, m_properties, c, begin, end, destination);
835
836 // No offsprings
837 copyData(source.m_noOffsprings, m_noOffsprings, c, begin, end, destination);
838
839 // Workload
840 copyData(source.m_workload, m_workload, c, begin, end, destination);
841}
842
843
845template <MInt nDim>
846void Tree<nDim>::deleteConnectivity(const MInt begin, const MInt end) {
847 for(MInt i = begin; i < end; i++) {
848 // Parent
849 if(hasParent(i)) {
850 const MInt p = parent(i);
851 for(MInt j = 0; j < noChildrenPerNode(); j++) {
852 if(child(p, j) == i) {
853 child(p, j) = -1;
854 }
855 }
856 }
857
858 // Children
859 for(MInt j = 0; j < noChildrenPerNode(); j++) {
860 if(hasChild(i, j)) {
861 parent(child(i, j)) = -1;
862 }
863 }
864
865 // Neighbors
866 for(MInt j = 0; j < noNeighborsPerNode(); j++) {
867 if(hasNeighbor(i, j)) {
868 neighbor(neighbor(i, j), oppositeNeighborDir(j)) = -1;
869 }
870 }
871 }
872}
873
874
876template <MInt nDim>
877void Tree<nDim>::moveConnectivity(const MInt begin, const MInt end, const MInt to) {
878 // Auxiliary method for checking if a given id is within the original range that was moved
879 auto inMovedRange = [begin, end](const MInt id) { return (id >= begin && id < end); };
880
881 // General strategy:
882 // 1) Loop over moved nodes and check all tree connections (parents/children/neighbors)
883 // 2) If a given connection is to a node that was moved: apply offset to current node
884 // 3) If a given connection is to a node that was not moved: change connectivity in other node
885 for(MInt from = begin; from < end; from++) {
886 const MInt distance = to - begin;
887 const MInt destination = from + distance;
888
889 // Parent
890 if(hasParent(destination)) {
891 const MInt p = parent(destination);
892 if(inMovedRange(p)) {
893 parent(destination) += distance;
894 } else {
895 for(MInt j = 0; j < noChildrenPerNode(); j++) {
896 if(child(p, j) == from) {
897 child(p, j) = destination;
898 }
899 }
900 }
901 }
902
903 // Children
904 for(MInt j = 0; j < noChildrenPerNode(); j++) {
905 if(hasChild(destination, j)) {
906 const MInt c = child(destination, j);
907 if(inMovedRange(c)) {
908 child(destination, j) += distance;
909 } else {
910 parent(c) = destination;
911 }
912 }
913 }
914
915 // Neighbors
916 for(MInt j = 0; j < noNeighborsPerNode(); j++) {
917 if(hasNeighbor(destination, j)) {
918 const MInt n = neighbor(destination, j);
919 if(inMovedRange(n)) {
920 neighbor(destination, j) += distance;
921 } else {
922 neighbor(n, oppositeNeighborDir(j)) = destination;
923 }
924 }
925 }
926 }
927}
928
929} // namespace tree
930} // namespace grid
931} // namespace maia
932
933
934// Undefine macros that should not be used outside this file
935#undef GRIDTREE_SANITY_CHECKS_ACCESSORS
936#undef ENSURE_VALID_ID_ACCESSOR
937#undef ENSURE_VALID_CHILD_POSITION_ACCESSOR
938#undef ENSURE_VALID_NEIGHBOR_DIR_ACCESSOR
939#undef ENSURE_VALID_COORDINATE_DIR_ACCESSOR
940#undef ENSURE_VALID_PROPERTY_ACCESSOR
941
942#endif // ifndef GRIDTREE_H_
GridCell
Grid cell Property Labels.
void copyData(const Container_ &source, Container_ &target, Functor &&f, const MInt begin, const MInt end, const MInt dest, const MInt solverSize=1)
Copy [begin, end) range with given solver size from source to dest position of target.
Definition: container.h:138
void fill_invalid(Container_ &c, const MInt begin, const MInt end, const MInt solverSize=1, const T value=maia::grid::tree::Invalid< T >::value())
Definition: container.h:131
void resetStorage(const MInt n, Storage< T > &c)
Create new container with given size and replace original one.
Definition: container.h:420
void reset(const MInt capacity)
Reset tree, re-create data structures with given capacity, and set size to zero.
Definition: container.h:187
Class that represents grid tree and contains all relevant per-node data.
MBool hasChild(const MInt id, const MInt pos) const
Return whether node has child at given position.
MInt noChildren(const MInt id) const
Return number of children of given node.
static constexpr MInt maxNoSolvers()
Return maximum number of supported solvers.
void moveConnectivity(const MInt begin, const MInt end, const MInt to)
Update parent/children/neighbors after nodes have moved.
SolverBitsetType::reference solver(const MInt id, const MInt solverId)
Accessor for solver usage.
MFloat & weight(const MInt id)
Accessor for weight.
void propertiesFromBits(const MInt id, const MUlong bits)
Convert properties from bits.
MUlong propertiesToBits(const MInt id) const
Convert properties to bits.
maia::grid::tree::PropertyBitsetType PropertyBitsetType
MBool hasAnyNeighbor(const MInt id, const MInt dir) const
Return whether node or its parent has neighbor in given direction.
static constexpr MInt oppositeNeighborDir(const MInt dir)
Return opposite direction for given neighbor direction.
MString propertiesToString(const MInt id) const
Convert properties to string.
MBool hasParent(const MInt id) const
Return whether node has parent.
MInt & noOffsprings(const MInt id)
Accessor for noOffsprings.
void rawCopyGeneric(Functor &&c, const T &source, const MInt begin, const MInt end, const MInt destination)
Helper function for rawCopy(). Destination may refer to beginning or end of target range.
MLong & globalId(const MInt id)
Accessor for global id.
MLong & neighbor(const MInt id, const MInt dir)
Accessor for neighbor node.
PropertyBitsetType & properties(const MInt id)
Accessor for properties.
static constexpr MInt noChildrenPerNode()
Return maximum number of children per node.
maia::grid::tree::SolverBitsetType SolverBitsetType
typename Base::template Storage< T > Storage
MInt nodesBySolver(const MInt solverId, MInt *const ids) const
Generate list of node ids that are used by a given solver and return number of used nodes.
MInt noNodesBySolver(const MInt solverId) const
Return number of nodes for a given solver.
void invalidate(const MInt begin, const MInt end)
Erase range of nodes such that they contain no sensible values anymore.
MLong & parent(const MInt id)
Accessor for parent node.
MInt m_noSolvers
Number of solvers that are actively using this tree.
void resetSolver(const MInt id)
Reset all solver use.
MBool hasNeighbor(const MInt id, const MInt dir) const
Return whether node has same-level neighbor in given direction.
Storage< MFloat > m_coordinates
MFloat & workload(const MInt id)
Accessor for workload.
Storage< MLong > m_childIds
typename maia::grid::tree::Invalid< T > Invalid
MUlong solverToBits(const MInt id) const
Convert solver usage to bits.
void deleteConnectivity(const MInt begin, const MInt end)
Update parent/children/neighbors before nodes are erased.
Storage< MFloat > m_weight
Storage< SolverBitsetType > m_isLeafCell
MInt & level(const MInt id)
Accessor for level.
constexpr MInt noSolvers() const
Return currently set number of solvers.
MBool isLeafCell(const MInt id) const
Accessor for isLeafCell usage (const version).
SolverBitsetType & leafCellBits(const MInt id)
Accessor for properties.
SolverBitsetType & solverBits(const MInt id)
Accessor for properties.
Storage< MLong > m_globalIds
PropertyBitsetType::reference hasProperty(const MInt id, const Cell p)
Accessor for properties.
MLong & child(const MInt id, const MInt pos)
Accessor for child node.
void setNoSolvers(const MInt count)
Set number of solvers.
Storage< MInt > m_noOffsprings
void solverFromBits(const MInt id, const MUlong bits)
Convert solver usage from bits.
Storage< MLong > m_neighborIds
void resetIsLeafCell(const MInt id)
Reset all isLeafCell.
static constexpr MInt noNeighborsPerNode()
Return maximum number of same-level neighbors per node.
void reset()
Reset tree, re-create data structures with given capacity, and set size to zero.
MBool cellHasSolver(const MInt cellId, const MInt solverId)
Check if solver is contained for cell.
void resetProperties(const MInt id)
Reset all properties.
static constexpr MInt noProperties()
Return number of properties defined for each node.
Storage< MFloat > m_workload
MFloat & coordinate(const MInt id, const MInt dim)
Accessor for coordinates.
Storage< PropertyBitsetType > m_properties
MBool hasChildren(const MInt id) const
Return whether node has any children.
Storage< MLong > m_parentIds
Storage< SolverBitsetType > m_solver
int32_t MInt
Definition: maiatypes.h:62
unsigned char MUchar
Definition: maiatypes.h:57
std::basic_string< char > MString
Definition: maiatypes.h:55
MInt noSolvers
Definition: maiatypes.h:73
double MFloat
Definition: maiatypes.h:52
int64_t MLong
Definition: maiatypes.h:64
bool MBool
Definition: maiatypes.h:58
char MChar
Definition: maiatypes.h:56
MInt id
Definition: maiatypes.h:71
uint64_t MUlong
Definition: maiatypes.h:65
constexpr std::underlying_type< GridCell >::type p(const GridCell property)
Converts property name to underlying integer value.
std::bitset< p(GridCell::NumProperties)> BitsetType
maia::grid::cell::BitsetType PropertyBitsetType
Underlying bitset type for property storage.
std::bitset< MAIA_MULTISOLVER_MAX_NO_SOLVERS > SolverBitsetType
Underlying bitset type for solver use storage (Note: If there are more solvers, change size here)
Namespace for auxiliary functions/classes.
static constexpr PropertyBitsetType value()