Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
hilbert.hpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
10#pragma once
11
24#include "bmi.hpp"
25#include "shambackends/sycl.hpp"
27
28// modified from :
29// Programming the Hilbert curve
30// killing J., 2004, AIPC, 707, 381. doi:10.1063/1.1751381
31
32namespace shamrock::sfc {
33
34 namespace details {
35
36 template<int bits>
37 inline u64 compute_hilbert_index_3d(u64 x, u64 y, u64 z) {
38
39 const int n = 3;
40 u64 X[3] = {x, y, z};
41
42 u64 M = 1 << (bits - 1), P, Q, t;
43 int i;
44 // Inverse undo
45 for (Q = M; Q > 1; Q >>= 1) {
46 P = Q - 1;
47 for (i = 0; i < n; i++)
48 if (X[i] & Q)
49 X[0] ^= P; // invert
50 else {
51 t = (X[0] ^ X[i]) & P;
52 X[0] ^= t;
53 X[i] ^= t;
54 }
55 } // exchange
56
57 // Gray encode
58 for (i = 1; i < n; i++)
59 X[i] ^= X[i - 1];
60 t = 0;
61 for (Q = M; Q > 1; Q >>= 1)
62 if (X[n - 1] & Q)
63 t ^= Q - 1;
64 for (i = 0; i < n; i++)
65 X[i] ^= t;
66
67 X[0] = shamrock::sfc::bmi::expand_bits<u64, 2>(X[0]) << 2;
68 X[1] = shamrock::sfc::bmi::expand_bits<u64, 2>(X[1]) << 1;
69 X[2] = shamrock::sfc::bmi::expand_bits<u64, 2>(X[2]);
70
71 return X[0] + X[1] + X[2];
72 }
73 } // namespace details
74
75 template<class hilbert_repr, u32 dim>
76 class HilbertCurve {};
77
78 template<>
79 class HilbertCurve<u64, 3> {
80 public:
81 using int_vec_repr_base = u32;
82 using int_vec_repr = u32_3;
83 static constexpr int_vec_repr_base max_val = 2097152 - 1;
84
85 inline static u64 icoord_to_hilbert(u64 x, u64 y, u64 z) {
86 return details::compute_hilbert_index_3d<21>(x, y, z);
87 }
88
89 template<class flt>
90 inline static u64 coord_to_hilbert(flt x, flt y, flt z) {
91
92 constexpr bool ok_type = std::is_same<flt, f32>::value || std::is_same<flt, f64>::value;
93 static_assert(ok_type, "unknown input type");
94
95 if constexpr (std::is_same<flt, f32>::value) {
96
97 x = sycl::fmin(sycl::fmax(x * 2097152.F, 0.F), 2097152.F - 1.F);
98 y = sycl::fmin(sycl::fmax(y * 2097152.F, 0.F), 2097152.F - 1.F);
99 z = sycl::fmin(sycl::fmax(z * 2097152.F, 0.F), 2097152.F - 1.F);
100
101 return icoord_to_hilbert(x, y, z);
102
103 } else if constexpr (std::is_same<flt, f64>::value) {
104
105 x = sycl::fmin(sycl::fmax(x * 2097152., 0.), 2097152. - 1.);
106 y = sycl::fmin(sycl::fmax(y * 2097152., 0.), 2097152. - 1.);
107 z = sycl::fmin(sycl::fmax(z * 2097152., 0.), 2097152. - 1.);
108
109 return icoord_to_hilbert(x, y, z);
110 }
111 }
112 };
113
114 using quad_hilbert_num = std::pair<u64, u64>;
115
116 template<>
117 class HilbertCurve<quad_hilbert_num, 3> {
118
119 static constexpr u64 divisor = HilbertCurve<u64, 3>::max_val + 1;
120
121 public:
122 using int_vec_repr_base = u64;
123 using int_vec_repr = u64_3;
124 static constexpr int_vec_repr_base max_val = divisor * divisor - 1;
125
126 inline static quad_hilbert_num icoord_to_hilbert(u64 x, u64 y, u64 z) {
127
128 u64 upper_val_x = x / divisor;
129 u64 upper_val_y = y / divisor;
130 u64 upper_val_z = z / divisor;
131
132 u64 lower_val_x = x % divisor;
133 u64 lower_val_y = y % divisor;
134 u64 lower_val_z = z % divisor;
135
136 return {
137 details::compute_hilbert_index_3d<21>(upper_val_x, upper_val_y, upper_val_z),
138 details::compute_hilbert_index_3d<21>(lower_val_x, lower_val_y, lower_val_z),
139 };
140 }
141 };
142
143} // namespace shamrock::sfc
144
145[[deprecated]]
146constexpr u64 hilbert_box21_sz = 2097152 - 1;
147
148template<int bits>
149[[deprecated]]
150inline u64 compute_hilbert_index_3d(u64 x, u64 y, u64 z) {
151
152 const int n = 3;
153 u64 X[3] = {x, y, z};
154
155 u64 M = 1 << (bits - 1), P, Q, t;
156 int i;
157 // Inverse undo
158 for (Q = M; Q > 1; Q >>= 1) {
159 P = Q - 1;
160 for (i = 0; i < n; i++)
161 if (X[i] & Q)
162 X[0] ^= P; // invert
163 else {
164 t = (X[0] ^ X[i]) & P;
165 X[0] ^= t;
166 X[i] ^= t;
167 }
168 } // exchange
169
170 // Gray encode
171 for (i = 1; i < n; i++)
172 X[i] ^= X[i - 1];
173 t = 0;
174 for (Q = M; Q > 1; Q >>= 1)
175 if (X[n - 1] & Q)
176 t ^= Q - 1;
177 for (i = 0; i < n; i++)
178 X[i] ^= t;
179
180 X[0] = shamrock::sfc::bmi::expand_bits<u64, 2>(X[0]) << 2;
181 X[1] = shamrock::sfc::bmi::expand_bits<u64, 2>(X[1]) << 1;
182 X[2] = shamrock::sfc::bmi::expand_bits<u64, 2>(X[2]);
183
184 return X[0] + X[1] + X[2];
185}
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
Bit manipulation instruction implementation for SYCL.
Namespace for internal details of the logs module.