Peano
Loading...
Searching...
No Matches
SFC.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
3"""!
4
5Peano space-filling curve as Peano's spacetree traversal runs through it
6
7The routines replicate the traversal order of peano4::grid::Spacetree, i.e.
8they do not implement an arbitrary Peano curve but exactly the one that
9Peano's C++ core uses. The offline load balancing hence plans along the same
10order in which Peano later hands out cells throughout a split.
11
12The order is defined recursively. The root cell starts with all even flags
13unset. A cell runs through its @f$ 3^d @f$ children in a serpentine
14(boustrophedon) order: axis 0 is the fastest axis, axis d-1 the slowest one.
15Along each axis, the cell runs in positive direction if the number of even
16flags set for the other axes is even (peano4::grid::PeanoCurve::isTraversePositiveAlongAxis()),
17and the serpentine then alternates the direction of all faster axes
18(peano4::utils::zfor3). A child inherits the even flags of its parent, but
19the middle child along an axis inverts the flag of this axis
20(peano4::grid::Spacetree::refineState()).
21
22Peano inverts the whole traversal in every other mesh sweep. The routines
23here describe the non-inverted traversal. The inverted one runs through the
24same curve backwards. The offline load balancing ignores this inversion and
25always plans along the non-inverted curve: A split which Peano carries out in
26an inverted sweep picks its cells from the other end of the curve, but it
27still hands over the requested number of cells.
28
29@image html PeanoSFC.png
30
31"""
32import functools
33
34
35def _is_traversal_positive_along_axis(even_flags: tuple, axis: int) -> bool:
36 """!
37 Python counterpart of peano4::grid::PeanoCurve::isTraversePositiveAlongAxis() for a non-inverted traversal
38 """
39 number_of_other_even_flags = sum(
40 1 for other_axis, flag in enumerate(even_flags) if flag and other_axis != axis
41 )
42 return number_of_other_even_flags % 2 == 0
43
44
45@functools.lru_cache(maxsize=None)
46def _children_in_traversal_order(directions: tuple) -> tuple:
47 """!
48
49 The 3^d children of a cell in the order of peano4::utils::zfor3
50
51 @param directions: tuple of bool
52 One flag per axis: True means that the traversal runs in positive
53 direction along this axis.
54
55 """
56 if len(directions) == 1:
57 return tuple((i,) for i in ([0, 1, 2] if directions[0] else [2, 1, 0]))
58
59 faster_axes = _children_in_traversal_order(directions[:-1])
60 result = []
61 for step, i in enumerate([0, 1, 2] if directions[-1] else [2, 1, 0]):
62 sweep = faster_axes if step % 2 == 0 else tuple(reversed(faster_axes))
63 result += [child + (i,) for child in sweep]
64 return tuple(result)
65
66
67def _child_even_flags(even_flags: tuple, child: tuple) -> tuple:
68 """! Even flags of a child: the middle child along an axis inverts this axis' flag"""
69 return tuple(flag ^ (position == 1) for flag, position in zip(even_flags, child))
70
71
72def _cartesian_to_peano(coordinates: tuple, size: int) -> int:
73 dimensions = len(coordinates)
74 even_flags = (False,) * dimensions
75 result = 0
76 coordinates = tuple(coordinates)
77 while size > 1:
78 sub_size = size // 3
79 child = tuple(coordinate // sub_size for coordinate in coordinates)
80 directions = tuple(
81 _is_traversal_positive_along_axis(even_flags, axis)
82 for axis in range(dimensions)
83 )
84 result = result * 3**dimensions + _children_in_traversal_order(
85 directions
86 ).index(child)
87 even_flags = _child_even_flags(even_flags, child)
88 coordinates = tuple(coordinate % sub_size for coordinate in coordinates)
89 size = sub_size
90 return result
91
92
93def _peano_to_cartesian(peano_index: int, size: int, dimensions: int) -> tuple:
94 digits = []
95 remaining_size = size
96 while remaining_size > 1:
97 digits.append(peano_index % 3**dimensions)
98 peano_index //= 3**dimensions
99 remaining_size //= 3
100 digits.reverse()
101
102 even_flags = (False,) * dimensions
103 coordinates = [0] * dimensions
104 sub_size = size
105 for digit in digits:
106 sub_size //= 3
107 directions = tuple(
108 _is_traversal_positive_along_axis(even_flags, axis)
109 for axis in range(dimensions)
110 )
111 child = _children_in_traversal_order(directions)[digit]
112 coordinates = [
113 coordinate + position * sub_size
114 for coordinate, position in zip(coordinates, child)
115 ]
116 even_flags = _child_even_flags(even_flags, child)
117 return tuple(coordinates)
118
119
120def Cartesian_to_Peano_2d(coordinates: tuple[int, int], size: int) -> int:
121 """!
122
123 Map Cartesian index to Peano SFC index.
124
125 This operation accepts a Cartesian index and returns the position of
126 this cell along Peano's traversal (see the file documentation). In the
127 example below
128
129 @image html PeanoSFC.png
130
131 we can hand in (4,2) and get a 10 back.
132
133 Args:
134 coordinates: (x, y) index with entries in [0, size-1]
135 size: Side length of the square grid; must be a power of 3.
136
137 Returns:
138 Integer Peano SFC index in [0, size*size - 1].
139 """
140 return _cartesian_to_peano(coordinates, size)
141
142
143def Cartesian_to_Peano_3d(coordinates: tuple[int, int, int], size: int) -> int:
144 """!
145
146 Map 3-D Cartesian index to Peano SFC index.
147
148 Three-dimensional counterpart of `Cartesian_to_Peano_2d`.
149
150 Args:
151 coordinates: (x, y, z) index with entries in [0, size-1]
152 size: Side length of the cubic grid; must be a power of 3.
153
154 Returns:
155 Integer Peano SFC index in [0, size**3 - 1].
156 """
157 return _cartesian_to_peano(coordinates, size)
158
159
160def Peano_to_Cartesian_2d(peano_index: int, size: int) -> tuple[int, int]:
161 """!
162
163 Inverse of `Cartesian_to_Peano_2d`.
164
165 Args:
166 peano_index: SFC index in [0, size*size - 1].
167 size: Side length of the square grid; must be a power of 3.
168
169 Returns:
170 (x, y) Cartesian coordinates.
171
172 """
173 return _peano_to_cartesian(peano_index, size, 2)
174
175
176def Peano_to_Cartesian_3d(peano_index: int, size: int) -> tuple[int, int, int]:
177 """!
178
179 Inverse of `Cartesian_to_Peano_3d`.
180
181 Args:
182 peano_index: SFC index in [0, size**3 - 1].
183 size: Side length of the cubic grid; must be a power of 3.
184
185 Returns:
186 (x, y, z) Cartesian coordinates.
187
188 """
189 return _peano_to_cartesian(peano_index, size, 3)
tuple _peano_to_cartesian(int peano_index, int size, int dimensions)
Definition SFC.py:93
int _cartesian_to_peano(tuple coordinates, int size)
Definition SFC.py:72
bool _is_traversal_positive_along_axis(tuple even_flags, int axis)
Python counterpart of peano4::grid::PeanoCurve::isTraversePositiveAlongAxis() for a non-inverted trav...
Definition SFC.py:35
tuple _child_even_flags(tuple even_flags, tuple child)
Even flags of a child: the middle child along an axis inverts this axis' flag.
Definition SFC.py:67