Loading...
Searching...
No Matches
morton.hpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6 *
7 * -------------------------------------------------------------------------
8 * License
9 * This file is part of bitpit.
10 *
11 * bitpit is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License v3 (LGPL)
13 * as published by the Free Software Foundation.
14 *
15 * bitpit is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 * License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with bitpit. If not, see <http://www.gnu.org/licenses/>.
22 *
23\*---------------------------------------------------------------------------*/
24
25#ifndef __BITPIT_PABLO_MORTON_HPP__
26#define __BITPIT_PABLO_MORTON_HPP__
27
28#include <algorithm>
29#include <cstdint>
30#include <limits>
31#include <stdexcept>
32
33namespace bitpit {
34
35namespace PABLO {
36
37const uint64_t INVALID_MORTON = std::numeric_limits<uint64_t>::max();
38
61inline int8_t computeMaximumLevel(uint8_t dimension)
62{
63 if (dimension == 0) {
64 return 0;
65 }
66
67 // Evaluate the maximum level of the tree based on the available bits for storing the Morton
68 int8_t level = (8 * sizeof(uint64_t)) / dimension;
69
70 // Limit required for storing the length of the domain
71 level = std::min(static_cast<int8_t>((8 * sizeof(uint32_t)) - 1), level);
72
73 // Limit required for generating the XYZ key of all the vertices
74 level = std::min(static_cast<int8_t>((8 * sizeof(uint64_t)) / dimension - 1), level);
75
76 return level;
77}
78
87inline uint64_t splitBy3(uint32_t a)
88{
89 uint64_t x = a & 0x1fffff; // we only look at the first 21 bits
90 x = (x | x << 32) & 0x001F00000000FFFF; // shift left 32 bits, OR with self, and 0000000000011111000000000000000000000000000000001111111111111111
91 x = (x | x << 16) & 0x001F0000FF0000FF; // shift left 16 bits, OR with self, and 0000000000011111000000000000000011111111000000000000000011111111
92 x = (x | x << 8) & 0x100F00F00F00F00F; // shift left 8 bits, OR with self, and 0001000000001111000000001111000000001111000000001111000000000000
93 x = (x | x << 4) & 0x10C30C30C30C30C3; // shift left 4 bits, OR with self, and 0001000011000011000011000011000011000011000011000011000100000000
94 x = (x | x << 2) & 0x1249249249249249; // shift left 2 bits, OR with self, and 0001001001001001001001001001001001001001001001001001001001001001
95
96 return x;
97}
98
107inline uint64_t splitBy2(uint32_t a)
108{
109 uint64_t x = a;
110 x = (x | x << 32) & 0x00000000FFFFFFFF; // shift left 32 bits, OR with self, and 0000000000000000000000000000000011111111111111111111111111111111
111 x = (x | x << 16) & 0x0000FFFF0000FFFF; // shift left 16 bits, OR with self, and 0000000000000000111111111111111100000000000000001111111111111111
112 x = (x | x << 8) & 0x00FF00FF00FF00FF; // shift left 8 bits, OR with self, and 0000000011111111000000001111111100000000111111110000000011111111
113 x = (x | x << 4) & 0x0F0F0F0F0F0F0F0F; // shift left 4 bits, OR with self, and 0000111100001111000011110000111100001111000011110000111100001111
114 x = (x | x << 2) & 0x3333333333333333; // shift left 2 bits, OR with self, and 0011001100110011001100110011001100110011001100110011001100110011
115 x = (x | x << 1) & 0x5555555555555555; // shift left 1 bits, OR with self, and 0101010101010101010101010101010101010101010101010101010101010101
116
117 return x;
118}
119
128inline uint32_t getThirdBits(uint64_t morton)
129{
130 uint64_t x = morton & 0x1249249249249249;
131 x = (x ^ (x >> 2)) & 0x10C30C30C30C30C3;
132 x = (x ^ (x >> 4)) & 0x100F00F00F00F00F;
133 x = (x ^ (x >> 8)) & 0x001F0000FF0000FF;
134 x = (x ^ (x >> 16)) & 0x001F00000000FFFF;
135 x = (x ^ (x >> 32)) & 0x00000000001FFFFF;
136
137 return static_cast<uint32_t>(x);
138}
139
148inline uint32_t getSecondBits(uint64_t morton)
149{
150 uint64_t x = morton & 0x5555555555555555;
151 x = (x ^ (x >> 1)) & 0x3333333333333333;
152 x = (x ^ (x >> 2)) & 0x0F0F0F0F0F0F0F0F;
153 x = (x ^ (x >> 4)) & 0x00FF00FF00FF00FF;
154 x = (x ^ (x >> 8)) & 0x0000FFFF0000FFFF;
155 x = (x ^ (x >> 16)) & 0x00000000FFFFFFFF;
156
157 return static_cast<uint32_t>(x);
158}
159
171inline uint64_t computeMorton3D(uint32_t x, uint32_t y, uint32_t z)
172{
173 uint64_t morton = splitBy3(x) | (splitBy3(y) << 1) | (splitBy3(z) << 2);
174
175 return morton;
176}
177
188inline uint64_t computeMorton2D(uint32_t x, uint32_t y)
189{
190 uint64_t morton = splitBy2(x) | (splitBy2(y) << 1);
191
192 return morton;
193}
194
207inline uint64_t computeMorton(uint8_t dimension, uint32_t x, uint32_t y, uint32_t z)
208{
209 if (dimension == 3) {
210 return computeMorton3D(x, y, z);
211 } else if (dimension == 2) {
212 return computeMorton2D(x, y);
213 } else {
214 throw std::runtime_error("Requested dimension is not supported");
215 }
216}
217
228inline uint32_t computeCoordinate3D(uint64_t morton, int coord)
229{
230 return getThirdBits(morton >> coord);
231}
232
243inline uint32_t computeCoordinate2D(uint64_t morton, int coord)
244{
245 if (coord < 2) {
246 return getSecondBits(morton >> coord);
247 } else {
248 return 0;
249 }
250}
251
263inline uint32_t computeCoordinate(uint8_t dimension, uint64_t morton, int coord)
264{
265 if (dimension == 3) {
266 return computeCoordinate3D(morton, coord);
267 } else if (dimension == 2) {
268 return computeCoordinate2D(morton, coord);
269 } else {
270 throw std::runtime_error("Requested dimension is not supported");
271 }
272}
273
286inline uint64_t computeXYZKey3D(uint32_t x, uint32_t y, uint32_t z)
287{
288 static const int SHIFT = (8 * sizeof(uint64_t)) / 3;
289
290 uint64_t key = x | (static_cast<uint_fast64_t>(y) << SHIFT) | (static_cast<uint_fast64_t>(z) << (2 * SHIFT));
291
292 return key;
293}
294
306inline uint64_t computeXYZKey2D(uint32_t x, uint32_t y)
307{
308 static const int SHIFT = (8 * sizeof(uint64_t)) / 2;
309
310 uint64_t key = x | (static_cast<uint_fast64_t>(y) << SHIFT);
311
312 return key;
313}
314
328inline uint64_t computeXYZKey(uint8_t dimension, uint32_t x, uint32_t y, uint32_t z)
329{
330 if (dimension == 3) {
331 return computeXYZKey3D(x, y, z);
332 } else if (dimension == 2) {
333 return computeXYZKey2D(x, y);
334 } else {
335 throw std::runtime_error("Requested dimension is not supported");
336 }
337}
338
339}
340
341}
342
343#endif
--- layout: doxygen_footer ---