Program Listing for File build_list.h¶
↰ Return to documentation for file (include/build_list.h
)
#ifndef build_list_h
#define build_list_h
#include "exafmm_t.h"
#include "geometry.h"
#include "fmm_base.h"
namespace exafmm_t {
template <typename T>
void build_list_parent_level(Node<T>* n, const FmmBase<T>& fmm) {
if (!n->parent) return;
ivec3 rel_coord;
int octant = n->octant;
bool isleaf = n->is_leaf;
for (int i=0; i<27; i++) {
Node<T> * pc = n->parent->colleagues[i];
if (pc && pc->is_leaf) {
rel_coord[0] = ( i %3)*4-4-(octant & 1?2:0)+1;
rel_coord[1] = ((i/3)%3)*4-4-(octant & 2?2:0)+1;
rel_coord[2] = ((i/9)%3)*4-4-(octant & 4?2:0)+1;
int c_hash = hash(rel_coord);
if (isleaf) {
int idx1 = HASH_LUT[P2P0_Type][c_hash];
if (idx1>=0)
n->P2P_list.push_back(pc);
}
int idx2 = HASH_LUT[P2L_Type][c_hash];
if (idx2>=0) {
if (isleaf && n->ntrgs<=fmm.nsurf)
n->P2P_list.push_back(pc);
else
n->P2L_list.push_back(pc);
}
}
}
}
template <typename T>
void build_list_current_level(Node<T>* n) {
ivec3 rel_coord;
bool isleaf = n->is_leaf;
for (int i=0; i<27; i++) {
Node<T> * col = n->colleagues[i];
if(col) {
rel_coord[0] = ( i %3)-1;
rel_coord[1] = ((i/3)%3)-1;
rel_coord[2] = ((i/9)%3)-1;
int c_hash = hash(rel_coord);
if (col->is_leaf && isleaf) {
int idx1 = HASH_LUT[P2P1_Type][c_hash];
if (idx1>=0)
n->P2P_list.push_back(col);
} else if (!col->is_leaf && !isleaf) {
int idx2 = HASH_LUT[M2L_Type][c_hash];
if (idx2>=0)
n->M2L_list[idx2] = col;
}
}
}
}
template <typename T>
void build_list_child_level(Node<T>* n, const FmmBase<T>& fmm) {
if (!n->is_leaf) return;
ivec3 rel_coord;
for(int i=0; i<27; i++) {
Node<T>* col = n->colleagues[i];
if(col && !col->is_leaf) {
for(int j=0; j<NCHILD; j++) {
Node<T>* cc = col->children[j];
rel_coord[0] = ( i %3)*4-4+(j & 1?2:0)-1;
rel_coord[1] = ((i/3)%3)*4-4+(j & 2?2:0)-1;
rel_coord[2] = ((i/9)%3)*4-4+(j & 4?2:0)-1;
int c_hash = hash(rel_coord);
int idx1 = HASH_LUT[P2P2_Type][c_hash];
int idx2 = HASH_LUT[M2P_Type][c_hash];
if (idx1>=0) {
assert(col->children[j]->is_leaf); //2:1 balanced
n->P2P_list.push_back(cc);
}
// since we currently don't save bodies' information in nonleaf nodes
// M2P can only be switched to P2P when source is leaf
if (idx2>=0) {
if (cc->is_leaf && cc->nsrcs<=fmm.nsurf)
n->P2P_list.push_back(cc);
else
n->M2P_list.push_back(cc);
}
}
}
}
}
template <typename T>
void build_list(Nodes<T>& nodes, const FmmBase<T>& fmm) {
#pragma omp parallel for
for(size_t i=0; i<nodes.size(); i++) {
Node<T>* node = &nodes[i];
node->M2L_list.resize(REL_COORD[M2L_Type].size(), nullptr);
build_list_parent_level(node, fmm); // P2P0 & P2L
build_list_current_level(node); // P2P1 & M2L
#if NON_ADAPTIVE
if (node->ntrgs)
build_list_child_level(node, fmm); // P2P2 & M2P
#else
build_list_child_level(node, fmm); // P2P2 & M2P
#endif
}
}
template <typename T>
void set_colleagues(Node<T>* node) {
Node<T> *parent, *colleague, *child;
node->colleagues.resize(27, nullptr);
if (node->level==0) { // root node
node->colleagues[13] = node;
} else { // non-root node
parent = node->parent;
int l = node->octant;
for (int i=0; i<27; ++i) { // loop over parent's colleagues
colleague = parent->colleagues[i];
if (colleague && !colleague->is_leaf) {
for (int j=0; j<8; ++j) { // loop over parent's colleages child
child = colleague->children[j];
if (child) {
bool flag = true;
int a = 1;
int b = 1;
int new_idx = 0;
for (int k=0; k<3; ++k) {
int idx_diff = (((i/b)%3)-1)*2 + ((j/a)%2) - ((l/a)%2);
if (-1>idx_diff || idx_diff>1) flag=false;
new_idx += (idx_diff+1)*b;
a *= 2;
b *= 3;
}
if (flag)
node->colleagues[new_idx] = child;
}
}
}
}
}
if (!node->is_leaf) {
for (int c=0; c<8; ++c) {
if (node->children[c]) {
set_colleagues(node->children[c]);
}
}
}
}
template <typename T>
void set_colleagues(Nodes<T>& nodes) {
set_colleagues(&nodes[0]);
}
}
#endif