Peano
Loading...
Searching...
No Matches
Tree.py
Go to the documentation of this file.
1# This file is part of the ExaHyPE2 project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3import numpy as np
4
5class Tree(object):
6 """
7 Data structure for adaptive mesh trees in Peano load balancing.
8
9 This class represents adaptive mesh trees as sequences of grid levels,
10 where each level is stored as a 2D or 3D array. The tree structure is
11 designed to support offline decomposition and load balancing analysis.
12
13 ## Tree Structure Overview
14
15 The main content of this class is a series of 2D or 3D arrays with dimension sizes
16 of 3^(level+1), where level ranges from 1 to the maximum depth of the tree. Each entry
17 in the arrays is a tuple of 2 numbers:
18
19 - **Weight**: 1 if the cell exists, 0 if it doesn't (enables representation of adaptive meshes)
20 - **Subtree ID**: Integer indicating which compute resource/subtree owns the cell
21
22 ## Data Representation Examples
23
24 ### 2D Example: Uniform 2-level tree with 4 subtrees
25
26 Level 1 (3x3 array):
27 ```
28 {(1,0), (1,0), (1,1)
29 (1,1), (1,1), (1,3)
30 (1,2), (1,2), (1,3)}
31 ```
32
33 Level 2 (9x9 array):
34 ```
35 {(1,0), (1,0), (1,0), (1,0), (1,0), (1,0), (1,1), (1,1), (1,1),
36 (1,0), (1,0), (1,0), (1,0), (1,0), (1,0), (1,1), (1,1), (1,1),
37 (1,0), (1,0), (1,0), (1,0), (1,0), (1,0), (1,1), (1,1), (1,1),
38 (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,3), (1,3), (1,3),
39 (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,3), (1,3), (1,3),
40 (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,3), (1,3), (1,3),
41 (1,2), (1,2), (1,2), (1,2), (1,2), (1,2), (1,3), (1,3), (1,3),
42 (1,2), (1,2), (1,2), (1,2), (1,2), (1,2), (1,3), (1,3), (1,3),
43 (1,2), (1,2), (1,2), (1,2), (1,2), (1,2), (1,3), (1,3), (1,3)}
44 ```
45
46 ### Adaptive Mesh Representation
47
48 For adaptive meshes where some regions are not refined, entries have weight 0:
49 ```
50 Level 1: {(1,0), (0,0), (1,0) # Middle cell not refined
51 (1,0), (1,0), (1,0)
52 (1,0), (1,0), (1,0)}
53
54 Level 2: Corresponding 9x9 array with zeros in the middle 3x3 block
55 ```
56
57 ## Key Properties
58
59 - **Hierarchical Structure**: Each level refines the previous by factor of 3 in each dimension
60 - **Adaptive Support**: Zero weights represent non-existent cells in adaptive meshes
61 - **Load Balancing Ready**: Subtree IDs enable domain decomposition analysis
62
63 ## Usage in Load Balancing
64
65 This data structure supports various load balancing operations:
66
67 1. **Tree Analysis**: Count leaf nodes, analyze refinement patterns
68 2. **Splitting Strategies**: Redistribute subtree assignments for load balancing
69 3. **Visualization**: Generate spatial representations of tree structure
70 4. **Export**: Create YAML outputs for integration with Peano's hardcoded load balancer
71
72 ## Coordinate System
73
74 - **2D**: Arrays use (a,b) indexing where a,b ∈ [0, 3^(level+1)-1]
75 - **3D**: Arrays use (a,b,c) indexing where a,b,c ∈ [0, 3^(level+1)-1]
76 - **Level Numbering**: Levels start from 0 (coarsest) to max_level-1 (finest)
77 - **Array Sizes**: Level k has size 3^(k+1) in each dimension
78
79 ## Important Notes
80
81 - The lowest level is 1 with size 3x3 (2D) or 3x3x3 (3D)
82 - All arrays are stored as numpy arrays with dtype=object for tuple storage
83 - Tree metadata (leaf count, split patterns) is automatically updated after modifications
84 - Domain offset and size define the physical coordinate mapping
85
86 ## Related Components
87
88 This class works with:
89 - `GridPatchFileReader`: Reads Peano grid files into Tree format
90 - `RegularGridGenerator`: Creates artificial uniform trees for testing
91 - `SplitTrees`: Implements splitting algorithms for load balancing
92 - `TreeVisualizer`: Generates visual representations of tree structures
93
94 ## Example Usage
95
96 ```python
97 # Create a tree from artificial regular grid
98 tree = RegularGridGenerator("test", max_level=3, dimension=2)
99
100 # Apply load balancing splitting
101 split_tree = split_leaves(tree, number_of_splits=3)
102
103 # Generate visualization
104 TreeVisualizer(split_tree, dimension=2, filename="balanced_tree")
105
106 # Export to YAML
107 generate_tree_yaml(split_tree, "output.yaml")
108 ```
109 """
110
111 def __init__(self, name, dimension, domain_offset, domain_size):
112 """
113 Initialize a new Tree object.
114
115 Args:
116 name (str): Descriptive name for the tree (e.g., "RegularGrid" or filename)
117 dimension (int): Spatial dimension (2 for 2D, 3 for 3D)
118 domain_offset (tuple): Physical coordinates of domain origin
119 domain_size (tuple): Physical size of domain in each dimension
120 """
121 self._name = name
122 self._dimension = dimension
123 self._domain_offset = domain_offset
124 self._domain_size = domain_size
125
126 self._tree_arrays = [] # contains the series of arrays
127 self._leaf_count = 0 # not yet calculated
128 self._subtree_count = 0 # not yet calculated
129 self._split_pattern = [] # not yet calculated
130
131 self._max_level = -1
132 self._weighted = False
133
134
135 def __str__(self):
136 result = (
137 """
138Peano Tree Structure From """ + self._name + """
139Domain offset: """
140 + str(self._domain_offset)
141 + """
142Domain size: """
143 + str(self._domain_size)
144 + """
145Dimension: """
146 + str(self._dimension)
147 + """
148Max Level: """
149 + str(self._max_level)
150 + """
151Leaf count: """
152 + str(self._leaf_count)
153 + """
154Subtree count: """
155 + str(self._subtree_count)
156 + """
157Split pattern: """
158 + str(self._split_pattern)
159 + """
160"""
161 )
162
163 return result
164
165
166 def read_in_tree_from_arrays(self, input_tree_arrays, max_level, weighted=False):
167
168 self._subtree_count = len(input_tree_arrays)
169 self._max_level = max_level
170
171 #initialization
172 for level in range(self._max_level):
173 size = 3**(level+1)
174 if self._dimension==2:
175 new_level_array = np.empty((size, size), dtype=object)
176 for a in range(size):
177 for b in range(size):
178 new_level_array[a][b]=(0,0)
179 elif self._dimension==3:
180 new_level_array = np.empty((size, size, size), dtype=object)
181 for a in range(size):
182 for b in range(size):
183 for c in range(size):
184 new_level_array[a][b][c]=(0,0)
185
186 self._tree_arrays.append(new_level_array)
187
188 #actual read in
189 for i in range(self._subtree_count):
190 for level in range(self._max_level):
191 self.read_in_level_array(input_tree_arrays[i][level], i, level)
192
194
195 if self._weighted:
196 self.update_weight()
197
198
199 def read_in_level_array(self, input_level_arrays, subtree_id, level):
200 if self._dimension==2:
201 for a in range(3**(level+1)):
202 for b in range(3**(level+1)):
203 if input_level_arrays[a][b]==1:
204 self._tree_arrays[level][a][b] = (input_level_arrays[a][b], subtree_id)
205 elif self._dimension==3:
206 for a in range(3**(level+1)):
207 for b in range(3**(level+1)):
208 for c in range(3**(level+1)):
209 if input_level_arrays[a][b][c]==1:
210 self._tree_arrays[level][a][b][c] = (input_level_arrays[a][b][c], subtree_id)
211
212
213 def read_in_tree_from_artificial(self, input_artificial_arrays, max_level, weighted=False):
214 self._subtree_count = 1
215 self._max_level = max_level
216
217 self._tree_arrays = input_artificial_arrays
218
220
221 if self._weighted:
222 self.update_weight()
223
224
226 self._leaf_count = 0
227 self._split_pattern = np.zeros(self._subtree_count)
228
229 for level in range(self._max_level):
230 if self._dimension==2:
231 for a in range(3**(level+1)):
232 for b in range(3**(level+1)):
233 if self._tree_arrays[level][a][b][0]==1:
234 if level==self._max_level-1: #the finest level
235 self._leaf_count += 1
236 self._split_pattern[self._tree_arrays[level][a][b][1]] += 1
237 elif self._tree_arrays[level+1][3*a][3*b][0]==0: #no children
238 self._leaf_count += 1
239 self._split_pattern[self._tree_arrays[level][a][b][1]] += 1
240 elif self._dimension==3:
241 for a in range(3**(level+1)):
242 for b in range(3**(level+1)):
243 for c in range(3**(level+1)):
244 if self._tree_arrays[level][a][b][c][0]==1:
245 if level==self._max_level-1: #the finest level
246 self._leaf_count += 1
247 self._split_pattern[self._tree_arrays[level][a][b][c][1]] += 1
248 elif self._tree_arrays[level+1][3*a][3*b][3*c][0]==0: #no children
249 self._leaf_count += 1
250 self._split_pattern[self._tree_arrays[level][a][b][c][1]] += 1
251
252
253 def update_weight(self):
254 #todo
255 return 0
256
Data structure for adaptive mesh trees in Peano load balancing.
Definition Tree.py:5
update_weight(self)
Definition Tree.py:253
read_in_tree_from_artificial(self, input_artificial_arrays, max_level, weighted=False)
Definition Tree.py:213
read_in_level_array(self, input_level_arrays, subtree_id, level)
Definition Tree.py:199
read_in_tree_from_arrays(self, input_tree_arrays, max_level, weighted=False)
Definition Tree.py:166
__init__(self, name, dimension, domain_offset, domain_size)
Initialize a new Tree object.
Definition Tree.py:111
update_split_pattern(self)
Definition Tree.py:225
__str__(self)
Definition Tree.py:135