interac_list.txx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /**
  2. * \file interac_list.txx
  3. * \author Dhairya Malhotra, dhairya.malhotra@gmail.com
  4. * \date 6-11-2012
  5. * \brief This file contains the implementation of the InteracList class.
  6. * Handles the logic for different interaction lists, and determines the
  7. * symmetry class for each interaction.
  8. */
  9. #include <math.h>
  10. #include <algorithm>
  11. #include <tree_node.hpp>
  12. #include <precomp_mat.hpp>
  13. #include <ompUtils.h>
  14. namespace pvfmm{
  15. /**
  16. * \brief Initialize.
  17. */
  18. template <class Node_t>
  19. void InteracList<Node_t>::Initialize(unsigned int dim_, PrecompMat<Real_t>* mat_){
  20. #ifdef PVFMM_NO_SYMMETRIES
  21. use_symmetries=false;
  22. #else
  23. use_symmetries=true;
  24. #endif
  25. dim=dim_;
  26. assert(dim==3); //Only supporting 3D for now.
  27. mat=mat_;
  28. interac_class.resize(Type_Count);
  29. perm_list.resize(Type_Count);
  30. rel_coord.resize(Type_Count);
  31. hash_lut.resize(Type_Count);
  32. InitList(0,0,1,UC2UE_Type);
  33. InitList(0,0,1,DC2DE_Type);
  34. InitList(0,0,1,S2U_Type);
  35. InitList(1,1,2,U2U_Type);
  36. InitList(1,1,2,D2D_Type);
  37. InitList(0,0,1,D2T_Type);
  38. InitList(3,3,2,U0_Type);
  39. InitList(1,0,1,U1_Type);
  40. InitList(3,3,2,U2_Type);
  41. InitList(3,2,1,V_Type);
  42. InitList(1,1,1,V1_Type);
  43. InitList(5,5,2,W_Type);
  44. InitList(5,5,2,X_Type);
  45. InitList(0,0,1,BC_Type);
  46. }
  47. /**
  48. * \brief Number of possible interactions in each list.
  49. */
  50. template <class Node_t>
  51. size_t InteracList<Node_t>::ListCount(Mat_Type t){
  52. return rel_coord[t].Dim(0);
  53. }
  54. /**
  55. * \brief Returns the relative octant coordinates for an interaction i of
  56. * type t.
  57. */
  58. template <class Node_t>
  59. int* InteracList<Node_t>::RelativeCoord(Mat_Type t, size_t i){
  60. return rel_coord[t][i];
  61. }
  62. /**
  63. * \brief For an interaction of type t and index i, returns the symmetry
  64. * class for the same.
  65. */
  66. template <class Node_t>
  67. size_t InteracList<Node_t>::InteracClass(Mat_Type t, size_t i){
  68. return interac_class[t][i];
  69. }
  70. /**
  71. * \brief Returns the list of permutations to be applied to the matrix to
  72. * convert it to its interac_class.
  73. */
  74. template <class Node_t>
  75. std::vector<Perm_Type>& InteracList<Node_t>::PermutList(Mat_Type t, size_t i){
  76. return perm_list[t][i];
  77. }
  78. /**
  79. * \brief Build interaction list for this node.
  80. */
  81. template <class Node_t>
  82. std::vector<Node_t*> InteracList<Node_t>::BuildList(Node_t* n, Mat_Type t){
  83. std::vector<Node_t*> interac_list(ListCount(t),NULL);
  84. int n_collg=(int)pow(3,dim);
  85. int n_child=(int)pow(2,dim);
  86. int rel_coord[3];
  87. switch (t){
  88. case S2U_Type:
  89. {
  90. if(!n->IsGhost() && n->IsLeaf()) interac_list[0]=n;
  91. break;
  92. }
  93. case U2U_Type:
  94. {
  95. if(n->IsGhost() || n->IsLeaf()) return interac_list;
  96. for(int j=0;j<n_child;j++){
  97. rel_coord[0]=-1+(j & 1?2:0);
  98. rel_coord[1]=-1+(j & 2?2:0);
  99. rel_coord[2]=-1+(j & 4?2:0);
  100. int c_hash = coord_hash(rel_coord);
  101. int idx=hash_lut[t][c_hash];
  102. Node_t* chld=(Node_t*)n->Child(j);
  103. if(idx>=0 && !chld->IsGhost()) interac_list[idx]=chld;
  104. }
  105. break;
  106. }
  107. case D2D_Type:
  108. {
  109. if(n->IsGhost() || n->Parent()==NULL) return interac_list;
  110. Node_t* p=(Node_t*)n->Parent();
  111. int p2n=n->Path2Node();
  112. {
  113. rel_coord[0]=-1+(p2n & 1?2:0);
  114. rel_coord[1]=-1+(p2n & 2?2:0);
  115. rel_coord[2]=-1+(p2n & 4?2:0);
  116. int c_hash = coord_hash(rel_coord);
  117. int idx=hash_lut[t][c_hash];
  118. if(idx>=0) interac_list[idx]=p;
  119. }
  120. break;
  121. }
  122. case D2T_Type:
  123. {
  124. if(!n->IsGhost() && n->IsLeaf()) interac_list[0]=n;
  125. break;
  126. }
  127. case U0_Type:
  128. {
  129. if(n->IsGhost() || n->Parent()==NULL || !n->IsLeaf()) return interac_list;
  130. Node_t* p=(Node_t*)n->Parent();
  131. int p2n=n->Path2Node();
  132. for(int i=0;i<n_collg;i++){
  133. Node_t* pc=(Node_t*)p->Colleague(i);
  134. if(pc!=NULL && pc->IsLeaf()){
  135. rel_coord[0]=( i %3)*4-4-(p2n & 1?2:0)+1;
  136. rel_coord[1]=((i/3)%3)*4-4-(p2n & 2?2:0)+1;
  137. rel_coord[2]=((i/9)%3)*4-4-(p2n & 4?2:0)+1;
  138. int c_hash = coord_hash(rel_coord);
  139. int idx=hash_lut[t][c_hash];
  140. if(idx>=0) interac_list[idx]=pc;
  141. }
  142. }
  143. break;
  144. }
  145. case U1_Type:
  146. {
  147. if(n->IsGhost() || !n->IsLeaf()) return interac_list;
  148. for(int i=0;i<n_collg;i++){
  149. Node_t* col=(Node_t*)n->Colleague(i);
  150. if(col!=NULL && col->IsLeaf()){
  151. rel_coord[0]=( i %3)-1;
  152. rel_coord[1]=((i/3)%3)-1;
  153. rel_coord[2]=((i/9)%3)-1;
  154. int c_hash = coord_hash(rel_coord);
  155. int idx=hash_lut[t][c_hash];
  156. if(idx>=0) interac_list[idx]=col;
  157. }
  158. }
  159. break;
  160. }
  161. case U2_Type:
  162. {
  163. if(n->IsGhost() || !n->IsLeaf()) return interac_list;
  164. for(int i=0;i<n_collg;i++){
  165. Node_t* col=(Node_t*)n->Colleague(i);
  166. if(col!=NULL && !col->IsLeaf()){
  167. for(int j=0;j<n_child;j++){
  168. rel_coord[0]=( i %3)*4-4+(j & 1?2:0)-1;
  169. rel_coord[1]=((i/3)%3)*4-4+(j & 2?2:0)-1;
  170. rel_coord[2]=((i/9)%3)*4-4+(j & 4?2:0)-1;
  171. int c_hash = coord_hash(rel_coord);
  172. int idx=hash_lut[t][c_hash];
  173. if(idx>=0){
  174. assert(col->Child(j)->IsLeaf()); //2:1 balanced
  175. interac_list[idx]=(Node_t*)col->Child(j);
  176. }
  177. }
  178. }
  179. }
  180. break;
  181. }
  182. case V_Type:
  183. {
  184. if(n->IsGhost() || n->Parent()==NULL) return interac_list;
  185. Node_t* p=(Node_t*)n->Parent();
  186. int p2n=n->Path2Node();
  187. for(int i=0;i<n_collg;i++){
  188. Node_t* pc=(Node_t*)p->Colleague(i);
  189. if(pc!=NULL?!pc->IsLeaf():0){
  190. for(int j=0;j<n_child;j++){
  191. rel_coord[0]=( i %3)*2-2+(j & 1?1:0)-(p2n & 1?1:0);
  192. rel_coord[1]=((i/3)%3)*2-2+(j & 2?1:0)-(p2n & 2?1:0);
  193. rel_coord[2]=((i/9)%3)*2-2+(j & 4?1:0)-(p2n & 4?1:0);
  194. int c_hash = coord_hash(rel_coord);
  195. int idx=hash_lut[t][c_hash];
  196. if(idx>=0) interac_list[idx]=(Node_t*)pc->Child(j);
  197. }
  198. }
  199. }
  200. break;
  201. }
  202. case V1_Type:
  203. {
  204. if(n->IsGhost() || n->IsLeaf()) return interac_list;
  205. for(int i=0;i<n_collg;i++){
  206. Node_t* col=(Node_t*)n->Colleague(i);
  207. if(col!=NULL && !col->IsLeaf()){
  208. rel_coord[0]=( i %3)-1;
  209. rel_coord[1]=((i/3)%3)-1;
  210. rel_coord[2]=((i/9)%3)-1;
  211. int c_hash = coord_hash(rel_coord);
  212. int idx=hash_lut[t][c_hash];
  213. if(idx>=0) interac_list[idx]=col;
  214. }
  215. }
  216. break;
  217. }
  218. case W_Type:
  219. {
  220. if(n->IsGhost() || !n->IsLeaf()) return interac_list;
  221. for(int i=0;i<n_collg;i++){
  222. Node_t* col=(Node_t*)n->Colleague(i);
  223. if(col!=NULL && !col->IsLeaf()){
  224. for(int j=0;j<n_child;j++){
  225. rel_coord[0]=( i %3)*4-4+(j & 1?2:0)-1;
  226. rel_coord[1]=((i/3)%3)*4-4+(j & 2?2:0)-1;
  227. rel_coord[2]=((i/9)%3)*4-4+(j & 4?2:0)-1;
  228. int c_hash = coord_hash(rel_coord);
  229. int idx=hash_lut[t][c_hash];
  230. if(idx>=0) interac_list[idx]=(Node_t*)col->Child(j);
  231. }
  232. }
  233. }
  234. break;
  235. }
  236. case X_Type:
  237. {
  238. if(n->IsGhost() || n->Parent()==NULL) return interac_list;
  239. Node_t* p=(Node_t*)n->Parent();
  240. int p2n=n->Path2Node();
  241. for(int i=0;i<n_collg;i++){
  242. Node_t* pc=(Node_t*)p->Colleague(i);
  243. if(pc!=NULL && pc->IsLeaf()){
  244. rel_coord[0]=( i %3)*4-4-(p2n & 1?2:0)+1;
  245. rel_coord[1]=((i/3)%3)*4-4-(p2n & 2?2:0)+1;
  246. rel_coord[2]=((i/9)%3)*4-4-(p2n & 4?2:0)+1;
  247. int c_hash = coord_hash(rel_coord);
  248. int idx=hash_lut[t][c_hash];
  249. if(idx>=0) interac_list[idx]=pc;
  250. }
  251. }
  252. break;
  253. }
  254. default:
  255. std::vector<Node_t*> empty_list;
  256. return empty_list;
  257. break;
  258. }
  259. return interac_list;
  260. }
  261. template <class Node_t>
  262. Matrix<typename Node_t::Real_t>& InteracList<Node_t>::ClassMat(int l, Mat_Type type, size_t indx){
  263. size_t indx0=InteracClass(type, indx);
  264. return mat->Mat(l, type, indx0);
  265. }
  266. template <class Node_t>
  267. Permutation<typename Node_t::Real_t>& InteracList<Node_t>::Perm_R(int l, Mat_Type type, size_t indx){
  268. size_t indx0=InteracClass(type, indx);
  269. Matrix<Real_t>& M0=mat->Mat(l, type, indx0);
  270. Permutation<Real_t>& row_perm=mat->Perm_R(type, indx);
  271. if(M0.Dim(0)==0 || M0.Dim(1)==0) return row_perm;
  272. //Get the necessary permutations.
  273. if(row_perm.Dim()==0){
  274. std::vector<Perm_Type>& p_list=PermutList(type, indx);
  275. row_perm=Permutation<Real_t>(M0.Dim(0));
  276. for(int i=p_list.size()-1; i>=0; i--){
  277. Permutation<Real_t>& pr=mat->Perm(type, R_Perm + p_list[i]);
  278. if(pr.Dim()!=M0.Dim(0)){
  279. row_perm=Permutation<Real_t>();
  280. break;
  281. }
  282. row_perm=pr.Transpose()*row_perm;
  283. }
  284. }
  285. return row_perm;
  286. }
  287. template <class Node_t>
  288. Permutation<typename Node_t::Real_t>& InteracList<Node_t>::Perm_C(int l, Mat_Type type, size_t indx){
  289. size_t indx0=InteracClass(type, indx);
  290. Matrix<Real_t>& M0=mat->Mat(l, type, indx0);
  291. Permutation<Real_t>& col_perm=mat->Perm_C(type, indx);
  292. if(M0.Dim(0)==0 || M0.Dim(1)==0) return col_perm;
  293. //Get the necessary permutations.
  294. if(col_perm.Dim()==0){
  295. std::vector<Perm_Type>& p_list=PermutList(type, indx);
  296. col_perm=Permutation<Real_t>(M0.Dim(1));
  297. for(int i=p_list.size()-1; i>=0; i--){
  298. Permutation<Real_t>& pc=mat->Perm(type, C_Perm + p_list[i]);
  299. if(pc.Dim()!=M0.Dim(1)){
  300. col_perm=Permutation<Real_t>();
  301. break;
  302. }
  303. col_perm=col_perm*pc;
  304. }
  305. }
  306. return col_perm;
  307. }
  308. /**
  309. * \brief A hash function defined on the relative coordinates of octants.
  310. */
  311. #define PVFMM_MAX_COORD_HASH 2000
  312. template <class Node_t>
  313. int InteracList<Node_t>::coord_hash(int* c){
  314. const int n=5;
  315. return ( (c[2]+n) * (2*n) + (c[1]+n) ) *(2*n) + (c[0]+n);
  316. }
  317. template <class Node_t>
  318. int InteracList<Node_t>::class_hash(int* c_){
  319. if(!use_symmetries) return coord_hash(c_);
  320. int c[3]={abs(c_[0]), abs(c_[1]), abs(c_[2])};
  321. if(c[1]>c[0] && c[1]>c[2])
  322. {int tmp=c[0]; c[0]=c[1]; c[1]=tmp;}
  323. if(c[0]>c[2])
  324. {int tmp=c[0]; c[0]=c[2]; c[2]=tmp;}
  325. if(c[0]>c[1])
  326. {int tmp=c[0]; c[0]=c[1]; c[1]=tmp;}
  327. assert(c[0]<=c[1] && c[1]<=c[2]);
  328. return coord_hash(&c[0]);
  329. }
  330. /**
  331. * \brief Set relative coordinates of the interacting node in
  332. * rel_coord[Type][idx][1:3].
  333. */
  334. template <class Node_t>
  335. void InteracList<Node_t>::InitList(int max_r, int min_r, int step, Mat_Type t){
  336. size_t count=(size_t)(pow((max_r*2)/step+1,dim)-(min_r>0?pow((min_r*2)/step-1,dim):0));
  337. Matrix<int>& M=rel_coord[t];
  338. M.Resize(count,dim);
  339. hash_lut[t].assign(PVFMM_MAX_COORD_HASH, -1);
  340. std::vector<int> class_size_hash(PVFMM_MAX_COORD_HASH, 0);
  341. std::vector<int> class_disp_hash(PVFMM_MAX_COORD_HASH, 0);
  342. for(int k=-max_r;k<=max_r;k+=step)
  343. for(int j=-max_r;j<=max_r;j+=step)
  344. for(int i=-max_r;i<=max_r;i+=step)
  345. if(abs(i)>=min_r || abs(j)>=min_r || abs(k) >= min_r){
  346. int c[3]={i,j,k};
  347. class_size_hash[class_hash(c)]++;
  348. }
  349. omp_par::scan(&class_size_hash[0], &class_disp_hash[0], PVFMM_MAX_COORD_HASH);
  350. size_t count_=0;
  351. for(int k=-max_r;k<=max_r;k+=step)
  352. for(int j=-max_r;j<=max_r;j+=step)
  353. for(int i=-max_r;i<=max_r;i+=step)
  354. if(abs(i)>=min_r || abs(j)>=min_r || abs(k) >= min_r){
  355. int c[3]={i,j,k};
  356. int& idx=class_disp_hash[class_hash(c)];
  357. for(size_t l=0;l<dim;l++) M[idx][l]=c[l];
  358. hash_lut[t][coord_hash(c)]=idx;
  359. count_++;
  360. idx++;
  361. }
  362. assert(count_==count);
  363. interac_class[t].resize(count);
  364. perm_list[t].resize(count);
  365. if(!use_symmetries){ // Set interac_class=self
  366. for(size_t j=0;j<count;j++){
  367. int c_hash = coord_hash(&M[j][0]);
  368. interac_class[t][j]=hash_lut[t][c_hash];
  369. }
  370. }
  371. else for(size_t j=0;j<count;j++){
  372. if(M[j][0]<0) perm_list[t][j].push_back(ReflecX);
  373. if(M[j][1]<0) perm_list[t][j].push_back(ReflecY);
  374. if(M[j][2]<0) perm_list[t][j].push_back(ReflecZ);
  375. int coord[3];
  376. coord[0]=abs(M[j][0]);
  377. coord[1]=abs(M[j][1]);
  378. coord[2]=abs(M[j][2]);
  379. if(coord[1]>coord[0] && coord[1]>coord[2]){
  380. perm_list[t][j].push_back(SwapXY);
  381. int tmp=coord[0]; coord[0]=coord[1]; coord[1]=tmp;
  382. }
  383. if(coord[0]>coord[2]){
  384. perm_list[t][j].push_back(SwapXZ);
  385. int tmp=coord[0]; coord[0]=coord[2]; coord[2]=tmp;
  386. }
  387. if(coord[0]>coord[1]){
  388. perm_list[t][j].push_back(SwapXY);
  389. int tmp=coord[0]; coord[0]=coord[1]; coord[1]=tmp;
  390. }
  391. assert(coord[0]<=coord[1] && coord[1]<=coord[2]);
  392. int c_hash = coord_hash(&coord[0]);
  393. interac_class[t][j]=hash_lut[t][c_hash];
  394. }
  395. }
  396. #undef PVFMM_MAX_COORD_HASH
  397. }//end namespace