interac_list.txx 13 KB

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