/** * \file interac_list.txx * \author Dhairya Malhotra, dhairya.malhotra@gmail.com * \date 6-11-2012 * \brief This file contains the implementation of the InteracList class. * Handles the logic for different interaction lists, and determines the * symmetry class for each interaction. */ #include #include #include #include namespace pvfmm{ /** * \brief Initialize. */ template void InteracList::Initialize(unsigned int dim_, PrecompMat* mat_){ #ifdef PVFMM_NO_SYMMETRIES use_symmetries=false; #else use_symmetries=true; #endif dim=dim_; assert(dim==3); //Only supporting 3D for now. mat=mat_; interac_class.resize(Type_Count); perm_list.resize(Type_Count); rel_coord.resize(Type_Count); hash_lut.resize(Type_Count); InitList(0,0,1,UC2UE_Type); InitList(0,0,1,DC2DE_Type); InitList(0,0,1,S2U_Type); InitList(1,1,2,U2U_Type); InitList(1,1,2,D2D_Type); InitList(0,0,1,D2T_Type); InitList(3,3,2,U0_Type); InitList(1,0,1,U1_Type); InitList(3,3,2,U2_Type); InitList(3,2,1,V_Type); InitList(1,1,1,V1_Type); InitList(5,5,2,W_Type); InitList(5,5,2,X_Type); InitList(0,0,1,BC_Type); } /** * \brief Number of possible interactions in each list. */ template size_t InteracList::ListCount(Mat_Type t){ return rel_coord[t].Dim(0); } /** * \brief Returns the relative octant coordinates for an interaction i of * type t. */ template int* InteracList::RelativeCoord(Mat_Type t, size_t i){ return rel_coord[t][i]; } /** * \brief For an interaction of type t and index i, returns the symmetry * class for the same. */ template size_t InteracList::InteracClass(Mat_Type t, size_t i){ return interac_class[t][i]; } /** * \brief Returns the list of permutations to be applied to the matrix to * convert it to its interac_class. */ template std::vector& InteracList::PermutList(Mat_Type t, size_t i){ return perm_list[t][i]; } /** * \brief Build interaction list for this node. */ template std::vector InteracList::BuildList(Node_t* n, Mat_Type t){ std::vector interac_list(ListCount(t),NULL); static const int n_collg=(int)pow(3.0,(int)dim); static const int n_child=(int)pow(2.0,(int)dim); int rel_coord[3]; switch (t){ case S2U_Type: { if(!n->IsGhost() && n->IsLeaf()) interac_list[0]=n; break; } case U2U_Type: { if(n->IsGhost() || n->IsLeaf()) return interac_list; for(int j=0;jChild(j); if(idx>=0 && !chld->IsGhost()) interac_list[idx]=chld; } break; } case D2D_Type: { if(n->IsGhost() || n->Parent()==NULL) return interac_list; Node_t* p=(Node_t*)n->Parent(); int p2n=n->Path2Node(); { rel_coord[0]=-1+(p2n & 1?2:0); rel_coord[1]=-1+(p2n & 2?2:0); rel_coord[2]=-1+(p2n & 4?2:0); int c_hash = coord_hash(rel_coord); int idx=hash_lut[t][c_hash]; if(idx>=0) interac_list[idx]=p; } break; } case D2T_Type: { if(!n->IsGhost() && n->IsLeaf()) interac_list[0]=n; break; } case U0_Type: { if(n->IsGhost() || n->Parent()==NULL || !n->IsLeaf()) return interac_list; Node_t* p=(Node_t*)n->Parent(); int p2n=n->Path2Node(); for(int i=0;iColleague(i); if(pc!=NULL && pc->IsLeaf()){ rel_coord[0]=( i %3)*4-4-(p2n & 1?2:0)+1; rel_coord[1]=((i/3)%3)*4-4-(p2n & 2?2:0)+1; rel_coord[2]=((i/9)%3)*4-4-(p2n & 4?2:0)+1; int c_hash = coord_hash(rel_coord); int idx=hash_lut[t][c_hash]; if(idx>=0) interac_list[idx]=pc; } } break; } case U1_Type: { if(n->IsGhost() || !n->IsLeaf()) return interac_list; for(int i=0;iColleague(i); if(col!=NULL && col->IsLeaf()){ rel_coord[0]=( i %3)-1; rel_coord[1]=((i/3)%3)-1; rel_coord[2]=((i/9)%3)-1; int c_hash = coord_hash(rel_coord); int idx=hash_lut[t][c_hash]; if(idx>=0) interac_list[idx]=col; } } break; } case U2_Type: { if(n->IsGhost() || !n->IsLeaf()) return interac_list; for(int i=0;iColleague(i); if(col!=NULL && !col->IsLeaf()){ for(int j=0;j=0){ assert(col->Child(j)->IsLeaf()); //2:1 balanced interac_list[idx]=(Node_t*)col->Child(j); } } } } break; } case V_Type: { if(n->IsGhost() || n->Parent()==NULL) return interac_list; Node_t* p=(Node_t*)n->Parent(); int p2n=n->Path2Node(); for(int i=0;iColleague(i); if(pc!=NULL?!pc->IsLeaf():0){ for(int j=0;j=0) interac_list[idx]=(Node_t*)pc->Child(j); } } } break; } case V1_Type: { if(n->IsGhost() || n->IsLeaf()) return interac_list; for(int i=0;iColleague(i); if(col!=NULL && !col->IsLeaf()){ rel_coord[0]=( i %3)-1; rel_coord[1]=((i/3)%3)-1; rel_coord[2]=((i/9)%3)-1; int c_hash = coord_hash(rel_coord); int idx=hash_lut[t][c_hash]; if(idx>=0) interac_list[idx]=col; } } break; } case W_Type: { if(n->IsGhost() || !n->IsLeaf()) return interac_list; for(int i=0;iColleague(i); if(col!=NULL && !col->IsLeaf()){ for(int j=0;j=0) interac_list[idx]=(Node_t*)col->Child(j); } } } break; } case X_Type: { if(n->IsGhost() || n->Parent()==NULL) return interac_list; Node_t* p=(Node_t*)n->Parent(); int p2n=n->Path2Node(); for(int i=0;iColleague(i); if(pc!=NULL && pc->IsLeaf()){ rel_coord[0]=( i %3)*4-4-(p2n & 1?2:0)+1; rel_coord[1]=((i/3)%3)*4-4-(p2n & 2?2:0)+1; rel_coord[2]=((i/9)%3)*4-4-(p2n & 4?2:0)+1; int c_hash = coord_hash(rel_coord); int idx=hash_lut[t][c_hash]; if(idx>=0) interac_list[idx]=pc; } } break; } default: std::vector empty_list; return empty_list; break; } return interac_list; } template Matrix& InteracList::ClassMat(int l, Mat_Type type, size_t indx){ size_t indx0=InteracClass(type, indx); return mat->Mat(l, type, indx0); } template Permutation& InteracList::Perm_R(int l, Mat_Type type, size_t indx){ size_t indx0=InteracClass(type, indx); Matrix & M0 =mat->Mat (l, type, indx0); Permutation& row_perm=mat->Perm_R(l, type, indx ); if(M0.Dim(0)==0 || M0.Dim(1)==0) return row_perm; //Get the necessary permutations. if(row_perm.Dim()==0){ std::vector p_list=PermutList(type, indx); for(int i=0;i row_perm_=Permutation(M0.Dim(0)); for(int i=0;i& pr=mat->Perm(type, R_Perm + i); if(!pr.Dim()) row_perm_=Permutation(0); } if(row_perm_.Dim()>0) for(int i=p_list.size()-1; i>=0; i--){ assert(type!=V_Type); Permutation& pr=mat->Perm(type, R_Perm + p_list[i]); row_perm_=pr.Transpose()*row_perm_; } row_perm=row_perm_; } return row_perm; } template Permutation& InteracList::Perm_C(int l, Mat_Type type, size_t indx){ size_t indx0=InteracClass(type, indx); Matrix & M0 =mat->Mat (l, type, indx0); Permutation& col_perm=mat->Perm_C(l, type, indx ); if(M0.Dim(0)==0 || M0.Dim(1)==0) return col_perm; //Get the necessary permutations. if(col_perm.Dim()==0){ std::vector p_list=PermutList(type, indx); for(int i=0;i col_perm_=Permutation(M0.Dim(1)); for(int i=0;i& pc=mat->Perm(type, C_Perm + i); if(!pc.Dim()) col_perm_=Permutation(0); } if(col_perm_.Dim()>0) for(int i=p_list.size()-1; i>=0; i--){ assert(type!=V_Type); Permutation& pc=mat->Perm(type, C_Perm + p_list[i]); col_perm_=col_perm_*pc; } col_perm=col_perm_; } return col_perm; } /** * \brief A hash function defined on the relative coordinates of octants. */ #define PVFMM_MAX_COORD_HASH 2000 template int InteracList::coord_hash(int* c){ const int n=5; return ( (c[2]+n) * (2*n) + (c[1]+n) ) *(2*n) + (c[0]+n); } template int InteracList::class_hash(int* c_){ if(!use_symmetries) return coord_hash(c_); int c[3]={abs(c_[0]), abs(c_[1]), abs(c_[2])}; if(c[1]>c[0] && c[1]>c[2]) {int tmp=c[0]; c[0]=c[1]; c[1]=tmp;} if(c[0]>c[2]) {int tmp=c[0]; c[0]=c[2]; c[2]=tmp;} if(c[0]>c[1]) {int tmp=c[0]; c[0]=c[1]; c[1]=tmp;} assert(c[0]<=c[1] && c[1]<=c[2]); return coord_hash(&c[0]); } /** * \brief Set relative coordinates of the interacting node in * rel_coord[Type][idx][1:3]. */ template void InteracList::InitList(int max_r, int min_r, int step, Mat_Type t){ size_t count=(size_t)(pow((max_r*2)/step+1.0,(int)dim)-(min_r>0?pow((min_r*2)/step-1.0,(int)dim):0)); Matrix& M=rel_coord[t]; M.Resize(count,dim); hash_lut[t].assign(PVFMM_MAX_COORD_HASH, -1); std::vector class_size_hash(PVFMM_MAX_COORD_HASH, 0); std::vector class_disp_hash(PVFMM_MAX_COORD_HASH, 0); for(int k=-max_r;k<=max_r;k+=step) for(int j=-max_r;j<=max_r;j+=step) for(int i=-max_r;i<=max_r;i+=step) if(abs(i)>=min_r || abs(j)>=min_r || abs(k) >= min_r){ int c[3]={i,j,k}; class_size_hash[class_hash(c)]++; } omp_par::scan(&class_size_hash[0], &class_disp_hash[0], PVFMM_MAX_COORD_HASH); size_t count_=0; for(int k=-max_r;k<=max_r;k+=step) for(int j=-max_r;j<=max_r;j+=step) for(int i=-max_r;i<=max_r;i+=step) if(abs(i)>=min_r || abs(j)>=min_r || abs(k) >= min_r){ int c[3]={i,j,k}; int& idx=class_disp_hash[class_hash(c)]; for(size_t l=0;lcoord[0] && coord[1]>coord[2]){ perm_list[t][j].push_back(SwapXY); int tmp=coord[0]; coord[0]=coord[1]; coord[1]=tmp; } if(coord[0]>coord[2]){ perm_list[t][j].push_back(SwapXZ); int tmp=coord[0]; coord[0]=coord[2]; coord[2]=tmp; } if(coord[0]>coord[1]){ perm_list[t][j].push_back(SwapXY); int tmp=coord[0]; coord[0]=coord[1]; coord[1]=tmp; } assert(coord[0]<=coord[1] && coord[1]<=coord[2]); int c_hash = coord_hash(&coord[0]); interac_class[t][j]=hash_lut[t][c_hash]; } } #undef PVFMM_MAX_COORD_HASH }//end namespace