26namespace shamrock::sfc {
28 template<
class morton_t>
30 static constexpr morton_t err_code;
35 static constexpr u32 err_code = 4294967295U;
40 static constexpr u64 err_code = 18446744073709551615UL;
43 template<
class Umorton, u32 dim>
49 using int_vec_repr_base =
u16;
50 using int_vec_repr = u16_3;
51 static constexpr int_vec_repr_base dimension = 3;
52 static constexpr int_vec_repr_base max_val = 1024 - 1;
53 static constexpr int_vec_repr_base val_count = 1024;
54 static constexpr int_vec_repr_base significant_bits_p_coord = 10;
55 static constexpr int_vec_repr_base significant_bits = dimension * significant_bits_p_coord;
57 static constexpr u32 err_code = 4294967295U;
59 inline static u32 icoord_to_morton(
u32 x,
u32 y,
u32 z) {
60 u32 xx = bmi::expand_bits<u32, 2>((
u32) x);
61 u32 yy = bmi::expand_bits<u32, 2>((
u32) y);
62 u32 zz = bmi::expand_bits<u32, 2>((
u32) z);
63 return xx * 4 + yy * 2 + zz;
66 inline static bool is_morton_bounding_box(int_vec_repr min, int_vec_repr max)
noexcept {
67 return min.x() == 0 && min.y() == 0 && min.z() == 0 && max.x() == max_val
68 && max.y() == max_val && max.z() == max_val;
72 inline static u32 coord_to_morton(flt x, flt y, flt z) {
74 constexpr bool ok_type = std::is_same<flt, f32>::value || std::is_same<flt, f64>::value;
75 static_assert(ok_type,
"unknown input type");
77 if constexpr (std::is_same<flt, f32>::value) {
79 x = sycl::fmin(sycl::fmax(x * 1024.F, 0.F), 1024.F - 1.F);
80 y = sycl::fmin(sycl::fmax(y * 1024.F, 0.F), 1024.F - 1.F);
81 z = sycl::fmin(sycl::fmax(z * 1024.F, 0.F), 1024.F - 1.F);
83 return icoord_to_morton(x, y, z);
85 }
else if constexpr (std::is_same<flt, f64>::value) {
87 x = sycl::fmin(sycl::fmax(x * 1024., 0.), 1024. - 1.);
88 y = sycl::fmin(sycl::fmax(y * 1024., 0.), 1024. - 1.);
89 z = sycl::fmin(sycl::fmax(z * 1024., 0.), 1024. - 1.);
91 return icoord_to_morton(x, y, z);
95 inline static u16_3 morton_to_icoord(
u32 morton) {
98 pos.s0() = (
u16) bmi::contract_bits<u32, 2>((morton & 0x24924924U) >> 2U);
99 pos.s1() = (
u16) bmi::contract_bits<u32, 2>((morton & 0x12492492U) >> 1U);
100 pos.s2() = (
u16) bmi::contract_bits<u32, 2>((morton & 0x09249249U) >> 0U);
105 inline static u16_3 get_offset(
u32 clz_) {
107 mx.s0() = 1024U >> ((clz_ - 0) / 3);
108 mx.s1() = 1024U >> ((clz_ - 1) / 3);
109 mx.s2() = 1024U >> ((clz_ - 2) / 3);
117 using int_vec_repr_base =
u32;
118 using int_vec_repr = u32_3;
119 static constexpr int_vec_repr_base dimension = 3;
120 static constexpr int_vec_repr_base max_val = 2097152 - 1;
121 static constexpr int_vec_repr_base val_count = 2097152;
122 static constexpr int_vec_repr_base significant_bits_p_coord = 21;
123 static constexpr int_vec_repr_base significant_bits = dimension * significant_bits_p_coord;
125 static constexpr u64 err_code = 18446744073709551615UL;
127 inline static u64 icoord_to_morton(
u64 x,
u64 y,
u64 z) {
128 u64 xx = bmi::expand_bits<u64, 2>((
u64) x);
129 u64 yy = bmi::expand_bits<u64, 2>((
u64) y);
130 u64 zz = bmi::expand_bits<u64, 2>((
u64) z);
131 return xx * 4 + yy * 2 + zz;
134 inline static bool is_morton_bounding_box(int_vec_repr min, int_vec_repr max)
noexcept {
135 return min.x() == 0 && min.y() == 0 && min.z() == 0 && max.x() == max_val
136 && max.y() == max_val && max.z() == max_val;
140 inline static u64 coord_to_morton(flt x, flt y, flt z) {
142 constexpr bool ok_type = std::is_same<flt, f32>::value || std::is_same<flt, f64>::value;
143 static_assert(ok_type,
"unknown input type");
145 if constexpr (std::is_same<flt, f32>::value) {
147 x = sycl::fmin(sycl::fmax(x * 2097152.F, 0.F), 2097152.F - 1.F);
148 y = sycl::fmin(sycl::fmax(y * 2097152.F, 0.F), 2097152.F - 1.F);
149 z = sycl::fmin(sycl::fmax(z * 2097152.F, 0.F), 2097152.F - 1.F);
151 return icoord_to_morton(x, y, z);
153 }
else if constexpr (std::is_same<flt, f64>::value) {
155 x = sycl::fmin(sycl::fmax(x * 2097152., 0.), 2097152. - 1.);
156 y = sycl::fmin(sycl::fmax(y * 2097152., 0.), 2097152. - 1.);
157 z = sycl::fmin(sycl::fmax(z * 2097152., 0.), 2097152. - 1.);
159 return icoord_to_morton(x, y, z);
163 inline static int_vec_repr morton_to_icoord(
u64 morton) {
166 pos.x() = bmi::contract_bits<u64, 2>((morton & 0x4924924924924924U) >> 2U);
167 pos.y() = bmi::contract_bits<u64, 2>((morton & 0x2492492492492492U) >> 1U);
168 pos.z() = bmi::contract_bits<u64, 2>((morton & 0x1249249249249249U) >> 0U);
173 inline static int_vec_repr get_offset(
u32 clz_) {
175 mx.s0() = 2097152U >> ((clz_ + 1) / 3);
176 mx.s1() = 2097152U >> ((clz_ - 0) / 3);
177 mx.s2() = 2097152U >> ((clz_ - 1) / 3);
182 template<
class morton_t,
class _pos_t, u32 dim>
188 using pos_t = _pos_t;
189 using coord_t =
typename shambase::VectorProperties<pos_t>::component_type;
190 using ipos_t =
typename Morton::int_vec_repr;
191 using int_t =
typename Morton::int_vec_repr_base;
196 static constexpr bool implemented_int = std::is_same<pos_t, u32_3>::value
197 || std::is_same<pos_t, u64_3>::value
198 || std::is_same<pos_t, i64_3>::value;
200 static constexpr bool implemented_float
201 = std::is_same<pos_t, f32_3>::value || std::is_same<pos_t, f64_3>::value;
203 static_assert(implemented_int || implemented_float,
"not implemented");
206 static CoordTransform get_transform(pos_t bounding_box_min, pos_t bounding_box_max) {
209 {0, 0, 0}, {Morton::val_count, Morton::val_count, Morton::val_count}},
213 inline static ipos_t to_morton_grid(pos_t pos,
CoordTransform transform) {
215 ipos_t unit_coord = transform.reverse_transform(pos);
217 constexpr int_t zero = 0;
219 unit_coord.x() = sycl::min(sycl::max(unit_coord.x(), zero), Morton::max_val);
220 unit_coord.y() = sycl::min(sycl::max(unit_coord.y(), zero), Morton::max_val);
221 unit_coord.z() = sycl::min(sycl::max(unit_coord.z(), zero), Morton::max_val);
226 inline static pos_t to_real_space(ipos_t pos,
CoordTransform transform) {
228 return transform.transform(pos);
242 template<
class morton_repr>
244 using int_vec_repr_base = std::void_t<>;
245 using int_vec_repr = std::void_t<>;
250 using int_vec_repr_base =
u16;
251 using int_vec_repr = u16_3;
252 static constexpr int_vec_repr_base max_val = 1024 - 1;
260 using int_vec_repr_base =
u32;
261 using int_vec_repr = u32_3;
262 static constexpr int_vec_repr_base max_val = 2097152 - 1;
268 template<
class morton_prec,
class fp_prec>
269 [[deprecated]] morton_prec coord_to_morton(fp_prec x, fp_prec y, fp_prec z);
271 template<
class morton_prec>
272 [[deprecated]]
typename morton_types<morton_prec>::int_vec_repr morton_to_ipos(
275 template<
class morton_prec>
276 [[deprecated]]
typename morton_types<morton_prec>::int_vec_repr get_offset(
u32 clz_);
279 inline u64 coord_to_morton<u64, f64>(
f64 x,
f64 y,
f64 z) {
280 x = sycl::fmin(sycl::fmax(x * 2097152., 0.), 2097152. - 1.);
281 y = sycl::fmin(sycl::fmax(y * 2097152., 0.), 2097152. - 1.);
282 z = sycl::fmin(sycl::fmax(z * 2097152., 0.), 2097152. - 1.);
284 u64 xx = shamrock::sfc::bmi::expand_bits<u64, 2>((
u64) x);
285 u64 yy = shamrock::sfc::bmi::expand_bits<u64, 2>((
u64) y);
286 u64 zz = shamrock::sfc::bmi::expand_bits<u64, 2>((
u64) z);
287 return xx * 4 + yy * 2 + zz;
291 inline u64 coord_to_morton<u64, f32>(
f32 x,
f32 y,
f32 z) {
292 x = sycl::fmin(sycl::fmax(x * 2097152.F, 0.F), 2097152.F - 1.F);
293 y = sycl::fmin(sycl::fmax(y * 2097152.F, 0.F), 2097152.F - 1.F);
294 z = sycl::fmin(sycl::fmax(z * 2097152.F, 0.F), 2097152.F - 1.F);
296 u64 xx = shamrock::sfc::bmi::expand_bits<u64, 2>((
u64) x);
297 u64 yy = shamrock::sfc::bmi::expand_bits<u64, 2>((
u64) y);
298 u64 zz = shamrock::sfc::bmi::expand_bits<u64, 2>((
u64) z);
299 return xx * 4 + yy * 2 + zz;
303 inline u32 coord_to_morton<u32, f64>(
f64 x,
f64 y,
f64 z) {
304 x = sycl::fmin(sycl::fmax(x * 1024., 0.), 1024. - 1.);
305 y = sycl::fmin(sycl::fmax(y * 1024., 0.), 1024. - 1.);
306 z = sycl::fmin(sycl::fmax(z * 1024., 0.), 1024. - 1.);
308 u32 xx = shamrock::sfc::bmi::expand_bits<u32, 2>((
u32) x);
309 u32 yy = shamrock::sfc::bmi::expand_bits<u32, 2>((
u32) y);
310 u32 zz = shamrock::sfc::bmi::expand_bits<u32, 2>((
u32) z);
311 return xx * 4 + yy * 2 + zz;
315 inline u32 coord_to_morton<u32, f32>(
f32 x,
f32 y,
f32 z) {
316 x = sycl::fmin(sycl::fmax(x * 1024.F, 0.F), 1024.F - 1.F);
317 y = sycl::fmin(sycl::fmax(y * 1024.F, 0.F), 1024.F - 1.F);
318 z = sycl::fmin(sycl::fmax(z * 1024.F, 0.F), 1024.F - 1.F);
320 u32 xx = shamrock::sfc::bmi::expand_bits<u32, 2>((
u32) x);
321 u32 yy = shamrock::sfc::bmi::expand_bits<u32, 2>((
u32) y);
322 u32 zz = shamrock::sfc::bmi::expand_bits<u32, 2>((
u32) z);
323 return xx * 4 + yy * 2 + zz;
327 inline u32_3 morton_to_ipos<u64>(
u64 morton) {
330 pos.x() = shamrock::sfc::bmi::contract_bits<u64, 2>((morton & 0x4924924924924924U) >> 2U);
331 pos.y() = shamrock::sfc::bmi::contract_bits<u64, 2>((morton & 0x2492492492492492U) >> 1U);
332 pos.z() = shamrock::sfc::bmi::contract_bits<u64, 2>((morton & 0x1249249249249249U) >> 0U);
338 inline u16_3 morton_to_ipos<u32>(
u32 morton) {
341 pos.s0() = (
u16) shamrock::sfc::bmi::contract_bits<u32, 2>((morton & 0x24924924U) >> 2U);
342 pos.s1() = (
u16) shamrock::sfc::bmi::contract_bits<u32, 2>((morton & 0x12492492U) >> 1U);
343 pos.s2() = (
u16) shamrock::sfc::bmi::contract_bits<u32, 2>((morton & 0x09249249U) >> 0U);
349 inline u32_3 get_offset<u64>(uint clz_) {
351 mx.s0() = 2097152U >> ((clz_ + 1) / 3);
352 mx.s1() = 2097152U >> ((clz_ - 0) / 3);
353 mx.s2() = 2097152U >> ((clz_ - 1) / 3);
358 inline u16_3 get_offset<u32>(uint clz_) {
360 mx.s0() = 1024U >> ((clz_ - 0) / 3);
361 mx.s1() = 1024U >> ((clz_ - 1) / 3);
362 mx.s2() = 1024U >> ((clz_ - 2) / 3);
double f64
Alias for double.
float f32
Alias for float.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
std::uint16_t u16
16 bit unsigned integer
Bit manipulation instruction implementation for SYCL.
Helper struct to get types corresponding to a morton code representation.