Program Listing for File hilbert.h

Return to documentation for file (include/hilbert.h)

#ifndef hilbert_h
#define hilbert_h
#include <cstdlib>
#include <stdint.h>
#include "exafmm_t.h"
#define EXAFMM_HILBERT 0

namespace exafmm_t {
  inline uint64_t levelOffset(int level) {
    return (((uint64_t)1 << 3 * level) - 1) / 7;
  }

  int getLevel(uint64_t i) {
    int level = -1;
    uint64_t offset = 0;
    while (i >= offset) {
      level++;
      offset += (uint64_t)1 << 3 * level;
    }
    return level;
  }

  uint64_t getParent(uint64_t i) {
    int level = getLevel(i);
    return (i - levelOffset(level)) / 8 + levelOffset(level-1);
  }

  uint64_t getChild(uint64_t i) {
    int level = getLevel(i);
    return (i - levelOffset(level)) * 8 + levelOffset(level+1);
  }

  int getOctant(uint64_t key, bool offset=true) {
    int level = getLevel(key);
    if (offset) key -= levelOffset(level);
    return key & 7;
  }

  uint64_t getKey(ivec3 iX, int level, bool offset=true) {
#if EXAFMM_HILBERT
    int M = 1 << (level - 1);
    for (int Q=M; Q>1; Q>>=1) {
      int R = Q - 1;
      for (int d=0; d<3; d++) {
        if (iX[d] & Q) iX[0] ^= R;
        else {
          int t = (iX[0] ^ iX[d]) & R;
          iX[0] ^= t;
          iX[d] ^= t;
        }
      }
    }
    for (int d=1; d<3; d++) iX[d] ^= iX[d-1];
    int t = 0;
    for (int Q=M; Q>1; Q>>=1)
      if (iX[2] & Q) t ^= Q - 1;
    for (int d=0; d<3; d++) iX[d] ^= t;
#endif
    uint64_t i = 0;
    for (int l=0; l<level; l++) {
      i |= (iX[2] & (uint64_t)1 << l) << 2*l;
      i |= (iX[1] & (uint64_t)1 << l) << (2*l + 1);
      i |= (iX[0] & (uint64_t)1 << l) << (2*l + 2);
    }
    if (offset) i += levelOffset(level);
    return i;
  }

  ivec3 get3DIndex(uint64_t i) {
    int level = getLevel(i);
    i -= levelOffset(level);
    ivec3 iX = 0;
    for (int l=0; l<level; l++) {
      iX[2] |= (i & (uint64_t)1 << 3*l) >> 2*l;
      iX[1] |= (i & (uint64_t)1 << (3*l + 1)) >> (2*l + 1);
      iX[0] |= (i & (uint64_t)1 << (3*l + 2)) >> (2*l + 2);
    }
#if EXAFMM_HILBERT
    int N = 2 << (level - 1);
    int t = iX[2] >> 1;
    for (int d=2; d>0; d--) iX[d] ^= iX[d-1];
    iX[0] ^= t;
    for (int Q=2; Q!=N; Q<<=1) {
      int R = Q - 1;
      for (int d=2; d>=0; d--) {
        if (iX[d] & Q) iX[0] ^= R;
        else {
          t = (iX[0] ^ iX[d]) & R;
          iX[0] ^= t;
          iX[d] ^= t;
        }
      }
    }
#endif
    return iX;
  }

  ivec3 get3DIndex(uint64_t i, int level) {
    ivec3 iX = 0;
    for (int l=0; l<level; l++) {
      iX[2] |= (i & (uint64_t)1 << 3*l) >> 2*l;
      iX[1] |= (i & (uint64_t)1 << (3*l + 1)) >> (2*l + 1);
      iX[0] |= (i & (uint64_t)1 << (3*l + 2)) >> (2*l + 2);
    }
#if EXAFMM_HILBERT
    int N = 2 << (level - 1);
    int t = iX[2] >> 1;
    for (int d=2; d>0; d--) iX[d] ^= iX[d-1];
    iX[0] ^= t;
    for (int Q=2; Q!=N; Q<<=1) {
      int R = Q - 1;
      for (int d=2; d>=0; d--) {
        if (iX[d] & Q) iX[0] ^= R;
        else {
          t = (iX[0] ^ iX[d]) & R;
          iX[0] ^= t;
          iX[d] ^= t;
        }
      }
    }
#endif
    return iX;
  }

  ivec3 get3DIndex(vec3 X, int level, vec3 x0, real_t r0) {
    vec3 Xmin = x0 - r0;
    real_t dx = 2 * r0 / (1 << level);
    ivec3 iX;
    for (int d=0; d<3; d++) {
      iX[d] = floor((X[d] - Xmin[d]) / dx);
    }
    return iX;
  }

  vec3 getCoordinates(ivec3 iX, int level, vec3 x0, real_t r0) {
    vec3 Xmin = x0 - r0;
    real_t dx = 2 * r0 / (1 << level);
    vec3 X;
    for (int d=0; d<3; d++) {
      X[d] = (iX[d] + 0.5) * dx + Xmin[d];
    }
    return X;
  }
}
#endif