5Peano space-filling curve as Peano's spacetree traversal runs through it
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.
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()).
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.
29@image html PeanoSFC.png
37 Python counterpart of peano4::grid::PeanoCurve::isTraversePositiveAlongAxis() for a non-inverted traversal
39 number_of_other_even_flags = sum(
40 1
for other_axis, flag
in enumerate(even_flags)
if flag
and other_axis != axis
42 return number_of_other_even_flags % 2 == 0
45@functools.lru_cache(maxsize=None)
46def _children_in_traversal_order(directions: tuple) -> tuple:
49 The 3^d children of a cell in the order of peano4::utils::zfor3
51 @param directions: tuple of bool
52 One flag per axis: True means that the traversal runs in positive
53 direction along this axis.
56 if len(directions) == 1:
57 return tuple((i,)
for i
in ([0, 1, 2]
if directions[0]
else [2, 1, 0]))
59 faster_axes = _children_in_traversal_order(directions[:-1])
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]
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))
73 dimensions = len(coordinates)
74 even_flags = (
False,) * dimensions
76 coordinates = tuple(coordinates)
79 child = tuple(coordinate // sub_size
for coordinate
in coordinates)
82 for axis
in range(dimensions)
84 result = result * 3**dimensions + _children_in_traversal_order(
88 coordinates = tuple(coordinate % sub_size
for coordinate
in coordinates)
96 while remaining_size > 1:
97 digits.append(peano_index % 3**dimensions)
98 peano_index //= 3**dimensions
102 even_flags = (
False,) * dimensions
103 coordinates = [0] * dimensions
109 for axis
in range(dimensions)
111 child = _children_in_traversal_order(directions)[digit]
113 coordinate + position * sub_size
114 for coordinate, position
in zip(coordinates, child)
117 return tuple(coordinates)
120def Cartesian_to_Peano_2d(coordinates: tuple[int, int], size: int) -> int:
123 Map Cartesian index to Peano SFC index.
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
129 @image html PeanoSFC.png
131 we can hand in (4,2) and get a 10 back.
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.
138 Integer Peano SFC index in [0, size*size - 1].
143def Cartesian_to_Peano_3d(coordinates: tuple[int, int, int], size: int) -> int:
146 Map 3-D Cartesian index to Peano SFC index.
148 Three-dimensional counterpart of `Cartesian_to_Peano_2d`.
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.
155 Integer Peano SFC index in [0, size**3 - 1].
160def Peano_to_Cartesian_2d(peano_index: int, size: int) -> tuple[int, int]:
163 Inverse of `Cartesian_to_Peano_2d`.
166 peano_index: SFC index in [0, size*size - 1].
167 size: Side length of the square grid; must be a power of 3.
170 (x, y) Cartesian coordinates.
176def Peano_to_Cartesian_3d(peano_index: int, size: int) -> tuple[int, int, int]:
179 Inverse of `Cartesian_to_Peano_3d`.
182 peano_index: SFC index in [0, size**3 - 1].
183 size: Side length of the cubic grid; must be a power of 3.
186 (x, y, z) Cartesian coordinates.
tuple _peano_to_cartesian(int peano_index, int size, int dimensions)
int _cartesian_to_peano(tuple coordinates, int size)
bool _is_traversal_positive_along_axis(tuple even_flags, int axis)
Python counterpart of peano4::grid::PeanoCurve::isTraversePositiveAlongAxis() for a non-inverted trav...
tuple _child_even_flags(tuple even_flags, tuple child)
Even flags of a child: the middle child along an axis inverts this axis' flag.