fmm_cheb.txx 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. /**
  2. * \file fmm_cheb.txx
  3. * \author Dhairya Malhotra, dhairya.malhotra@gmail.com
  4. * \date 3-07-2011
  5. * \brief This file contains the implementation of the FMM_Cheb class.
  6. */
  7. #include <omp.h>
  8. #include <sstream>
  9. #include <iostream>
  10. #include <cstdlib>
  11. #include <cmath>
  12. #ifdef PVFMM_HAVE_SYS_STAT_H
  13. #include <sys/stat.h>
  14. #endif
  15. #include <dtypes.h>
  16. #include <parUtils.h>
  17. #include <cheb_utils.hpp>
  18. #include <mem_mgr.hpp>
  19. #include <profile.hpp>
  20. namespace pvfmm{
  21. template <class FMMNode>
  22. FMM_Cheb<FMMNode>::~FMM_Cheb() {
  23. if(this->mat!=NULL){
  24. int rank;
  25. MPI_Comm_rank(this->comm,&rank);
  26. if(!rank){
  27. FILE* f=fopen(this->mat_fname.c_str(),"r");
  28. if(f==NULL) { //File does not exists.
  29. { // Delete easy to compute matrices.
  30. Mat_Type type=W_Type;
  31. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  32. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  33. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  34. M.Resize(0,0);
  35. }
  36. type=V_Type;
  37. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  38. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  39. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  40. M.Resize(0,0);
  41. }
  42. type=V1_Type;
  43. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  44. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  45. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  46. M.Resize(0,0);
  47. }
  48. type=U2U_Type;
  49. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  50. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  51. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  52. M.Resize(0,0);
  53. }
  54. type=D2D_Type;
  55. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  56. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  57. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  58. M.Resize(0,0);
  59. }
  60. type=D2T_Type;
  61. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  62. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  63. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  64. M.Resize(0,0);
  65. }
  66. }
  67. this->mat->Save2File(this->mat_fname.c_str());
  68. }else fclose(f);
  69. }
  70. }
  71. }
  72. template <class FMMNode>
  73. void FMM_Cheb<FMMNode>::Initialize(int mult_order, int cheb_deg_, const MPI_Comm& comm_, const Kernel<Real_t>* kernel_, const Kernel<Real_t>* aux_kernel_){
  74. Profile::Tic("InitFMM_Cheb",&comm_,true);{
  75. int rank;
  76. MPI_Comm_rank(comm_,&rank);
  77. int dim=3; //Only supporting 3D
  78. cheb_deg=cheb_deg_;
  79. if(this->mat_fname.size()==0){
  80. std::stringstream st;
  81. st<<PVFMM_PRECOMP_DATA_PATH;
  82. if(!st.str().size()){ // look in PVFMM_DIR
  83. char* pvfmm_dir = getenv ("PVFMM_DIR");
  84. if(pvfmm_dir) st<<pvfmm_dir;
  85. }
  86. #ifndef STAT_MACROS_BROKEN
  87. if(st.str().size()){ // check if the path is a directory
  88. struct stat stat_buff;
  89. if(stat(st.str().c_str(), &stat_buff) || !S_ISDIR(stat_buff.st_mode)){
  90. std::cout<<"error: path not found: "<<st.str()<<'\n';
  91. exit(0);
  92. }
  93. }
  94. #endif
  95. if(st.str().size()) st<<'/';
  96. st<<"Precomp_"<<kernel_->ker_name.c_str()<<"_q"<<cheb_deg<<"_m"<<mult_order;
  97. if(sizeof(Real_t)==8) st<<"";
  98. else if(sizeof(Real_t)==4) st<<"_f";
  99. else st<<"_t"<<sizeof(Real_t);
  100. st<<".data";
  101. this->mat_fname=st.str();
  102. }
  103. if(!rank){
  104. FILE* f=fopen(this->mat_fname.c_str(),"r");
  105. if(f==NULL) { //File does not exists.
  106. std::cout<<"Could not find precomputed data file for "<<kernel_->ker_name.c_str()<<" kernel with q="<<cheb_deg<<" and m="<<mult_order<<".\n";
  107. std::cout<<"This data will be computed and stored for future use at:\n"<<this->mat_fname<<'\n';
  108. std::cout<<"This may take a while...\n";
  109. }else fclose(f);
  110. }
  111. //this->mat->LoadFile(this->mat_fname.c_str(), this->comm);
  112. FMM_Pts<FMMNode>::Initialize(mult_order, comm_, kernel_, aux_kernel_);
  113. this->mat->RelativeTrgCoord()=cheb_nodes<Real_t>(ChebDeg(),dim);
  114. Profile::Tic("PrecompD2T",&this->comm,false,4);
  115. this->PrecompAll(D2T_Type);
  116. Profile::Toc();
  117. //Volume solver.
  118. Profile::Tic("PrecompS2M",&this->comm,false,4);
  119. this->PrecompAll(S2U_Type);
  120. Profile::Toc();
  121. Profile::Tic("PrecompX",&this->comm,false,4);
  122. this->PrecompAll(X_Type);
  123. Profile::Toc();
  124. Profile::Tic("PrecompW",&this->comm,false,4);
  125. this->PrecompAll(W_Type);
  126. Profile::Toc();
  127. Profile::Tic("PrecompU0",&this->comm,false,4);
  128. this->PrecompAll(U0_Type);
  129. Profile::Toc();
  130. Profile::Tic("PrecompU1",&this->comm,false,4);
  131. this->PrecompAll(U1_Type);
  132. Profile::Toc();
  133. Profile::Tic("PrecompU2",&this->comm,false,4);
  134. this->PrecompAll(U2_Type);
  135. Profile::Toc();
  136. Profile::Tic("Save2File",&this->comm,false,4);
  137. if(!rank){
  138. FILE* f=fopen(this->mat_fname.c_str(),"r");
  139. if(f==NULL) { //File does not exists.
  140. { // Delete easy to compute matrices.
  141. Mat_Type type=W_Type;
  142. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  143. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  144. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  145. M.Resize(0,0);
  146. }
  147. type=V_Type;
  148. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  149. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  150. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  151. M.Resize(0,0);
  152. }
  153. type=V1_Type;
  154. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  155. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  156. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  157. M.Resize(0,0);
  158. }
  159. type=U2U_Type;
  160. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  161. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  162. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  163. M.Resize(0,0);
  164. }
  165. type=D2D_Type;
  166. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  167. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  168. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  169. M.Resize(0,0);
  170. }
  171. type=D2T_Type;
  172. for(int l=-BC_LEVELS;l<MAX_DEPTH;l++)
  173. for(size_t indx=0;indx<this->interac_list.ListCount(type);indx++){
  174. Matrix<Real_t>& M=this->mat->Mat(l, type, indx);
  175. M.Resize(0,0);
  176. }
  177. }
  178. this->mat->Save2File(this->mat_fname.c_str());
  179. }else fclose(f);
  180. }
  181. Profile::Toc();
  182. Profile::Tic("Recompute",&this->comm,false,4);
  183. { // Recompute matrices.
  184. this->PrecompAll(W_Type);
  185. this->PrecompAll(V_Type);
  186. this->PrecompAll(V1_Type);
  187. this->PrecompAll(U2U_Type);
  188. this->PrecompAll(D2D_Type);
  189. this->PrecompAll(D2T_Type);
  190. }
  191. Profile::Toc();
  192. }Profile::Toc();
  193. }
  194. template <class FMMNode>
  195. Permutation<typename FMMNode::Real_t>& FMM_Cheb<FMMNode>::PrecompPerm(Mat_Type type, Perm_Type perm_indx){
  196. int dim=3; //Only supporting 3D
  197. //Check if the matrix already exists.
  198. Permutation<Real_t>& P_ = FMM_Pts<FMMNode>::PrecompPerm(type, perm_indx);
  199. if(P_.Dim()!=0) return P_;
  200. //Compute the matrix.
  201. Permutation<Real_t> P;
  202. switch (type){
  203. case UC2UE_Type:
  204. {
  205. break;
  206. }
  207. case DC2DE_Type:
  208. {
  209. break;
  210. }
  211. case S2U_Type:
  212. {
  213. if(perm_indx<C_Perm) P=PrecompPerm(U0_Type, perm_indx);
  214. else P=PrecompPerm(D2D_Type, perm_indx);
  215. break;
  216. }
  217. case U2U_Type:
  218. {
  219. break;
  220. }
  221. case D2D_Type:
  222. {
  223. break;
  224. }
  225. case D2T_Type:
  226. {
  227. if(perm_indx>=C_Perm) P=PrecompPerm(U0_Type, perm_indx);
  228. else P=PrecompPerm(D2D_Type, perm_indx);
  229. break;
  230. }
  231. case U0_Type:
  232. {
  233. int coeff_cnt=((cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3))/6;
  234. int n3=(int)pow((Real_t)(cheb_deg+1),dim);
  235. int dof=(perm_indx<C_Perm?this->kernel->ker_dim[0]:this->kernel->ker_dim[1]);
  236. size_t p_indx=perm_indx % C_Perm;
  237. Permutation<Real_t> P0(n3*dof);
  238. Permutation<Real_t>& ker_perm=this->kernel->perm_vec[perm_indx];
  239. assert(dof=ker_perm.Dim());
  240. if(p_indx==Scaling && this->Homogen()){ // Set level-by-level scaling
  241. const Vector<Real_t>& scal_exp=(perm_indx<C_Perm?this->kernel->src_scal:this->kernel->trg_scal);
  242. assert(dof==scal_exp.Dim());
  243. Vector<Real_t> scal(scal_exp.Dim());
  244. for(size_t i=0;i<scal_exp.Dim();i++){
  245. scal[i]=pow(2.0,(perm_indx<C_Perm?-1.0:0.0)*COORD_DIM+scal_exp[i]);
  246. }
  247. for(int j=0;j<dof;j++){
  248. for(int i=0;i<n3;i++){
  249. P0.scal[j*n3+i]*=scal[j];
  250. }
  251. }
  252. }
  253. { // Set P0.scal
  254. for(int j=0;j<dof;j++){
  255. for(int i=0;i<n3;i++){
  256. P0.scal[j*n3+i]*=ker_perm.scal[j];
  257. }
  258. }
  259. }
  260. if(p_indx==ReflecX || p_indx==ReflecY || p_indx==ReflecZ){
  261. for(int j=0;j<dof;j++)
  262. for(int i=0;i<n3;i++){
  263. int x[3]={i%(cheb_deg+1), (i/(cheb_deg+1))%(cheb_deg+1), i/(cheb_deg+1)/(cheb_deg+1)};
  264. P0.scal[i+n3*j]*=(x[p_indx-ReflecX]%2?-1.0:1.0);
  265. }
  266. }
  267. { // Set P0.perm
  268. int indx[3]={0,1,2};
  269. if(p_indx==SwapXY) {indx[0]=1; indx[1]=0; indx[2]=2;}
  270. if(p_indx==SwapXZ) {indx[0]=2; indx[1]=1; indx[2]=0;}
  271. for(int j=0;j<dof;j++)
  272. for(int i=0;i<n3;i++){
  273. int x[3]={i%(cheb_deg+1), (i/(cheb_deg+1))%(cheb_deg+1), i/(cheb_deg+1)/(cheb_deg+1)};
  274. P0.perm[i+n3*j]=x[indx[0]]+(x[indx[1]]+x[indx[2]]*(cheb_deg+1))*(cheb_deg+1)
  275. +n3*ker_perm.perm[j];
  276. }
  277. }
  278. std::vector<size_t> coeff_map(n3*dof,0);
  279. {
  280. int indx=0;
  281. for(int j=0;j<dof;j++)
  282. for(int i=0;i<n3;i++){
  283. int x[3]={i%(cheb_deg+1), (i/(cheb_deg+1))%(cheb_deg+1), i/(cheb_deg+1)/(cheb_deg+1)};
  284. if(x[0]+x[1]+x[2]<=cheb_deg){
  285. coeff_map[i+n3*j]=indx;
  286. indx++;
  287. }
  288. }
  289. }
  290. P=Permutation<Real_t>(coeff_cnt*dof);
  291. {
  292. int indx=0;
  293. for(int j=0;j<dof;j++)
  294. for(int i=0;i<n3;i++){
  295. int x[3]={i%(cheb_deg+1), (i/(cheb_deg+1))%(cheb_deg+1), i/(cheb_deg+1)/(cheb_deg+1)};
  296. if(x[0]+x[1]+x[2]<=cheb_deg){
  297. P.perm[indx]=coeff_map[P0.perm[i+n3*j]];
  298. P.scal[indx]= P0.scal[i+n3*j] ;
  299. indx++;
  300. }
  301. }
  302. }
  303. break;
  304. }
  305. case U1_Type:
  306. {
  307. P=PrecompPerm(U0_Type, perm_indx);
  308. break;
  309. }
  310. case U2_Type:
  311. {
  312. P=PrecompPerm(U0_Type, perm_indx);
  313. break;
  314. }
  315. case V_Type:
  316. {
  317. break;
  318. }
  319. case V1_Type:
  320. {
  321. break;
  322. }
  323. case W_Type:
  324. {
  325. if(perm_indx>=C_Perm) P=PrecompPerm(U0_Type, perm_indx);
  326. else P=PrecompPerm(D2D_Type, perm_indx);
  327. break;
  328. }
  329. case X_Type:
  330. {
  331. if(perm_indx<C_Perm) P=PrecompPerm(U0_Type, perm_indx);
  332. else P=PrecompPerm(D2D_Type, perm_indx);
  333. break;
  334. }
  335. default:
  336. return FMM_Pts<FMMNode>::PrecompPerm(type, perm_indx);
  337. break;
  338. }
  339. //Save the matrix for future use.
  340. #pragma omp critical (PRECOMP_MATRIX_PTS)
  341. if(P_.Dim()==0){ P_=P;}
  342. return P_;
  343. }
  344. template <class FMMNode>
  345. Matrix<typename FMMNode::Real_t>& FMM_Cheb<FMMNode>::Precomp(int level, Mat_Type type, size_t mat_indx){
  346. if(this->Homogen()) level=0;
  347. //Check if the matrix already exists.
  348. //Compute matrix from symmetry class (if possible).
  349. Matrix<Real_t>& M_ = this->mat->Mat(level, type, mat_indx);
  350. if(M_.Dim(0)!=0 && M_.Dim(1)!=0) return M_;
  351. else{ //Compute matrix from symmetry class (if possible).
  352. size_t class_indx = this->interac_list.InteracClass(type, mat_indx);
  353. if(class_indx!=mat_indx){
  354. Matrix<Real_t>& M0 = this->Precomp(level, type, class_indx);
  355. Permutation<Real_t>& Pr = this->interac_list.Perm_R(level, type, mat_indx);
  356. Permutation<Real_t>& Pc = this->interac_list.Perm_C(level, type, mat_indx);
  357. if(Pr.Dim()>0 && Pc.Dim()>0 && M0.Dim(0)>0 && M0.Dim(1)>0) return M_;
  358. }
  359. }
  360. int myrank, np;
  361. MPI_Comm_rank(this->comm, &myrank);
  362. MPI_Comm_size(this->comm,&np);
  363. size_t progress=0, class_count=0;
  364. { // Determine precomputation progress.
  365. size_t mat_cnt=this->interac_list.ListCount((Mat_Type)type);
  366. for(size_t i=0; i<mat_cnt; i++){
  367. size_t indx=this->interac_list.InteracClass((Mat_Type)type,i);
  368. if(indx==i){
  369. class_count++;
  370. if(i<mat_indx) progress++;
  371. }
  372. }
  373. }
  374. //Compute the matrix.
  375. Matrix<Real_t> M;
  376. int n_src=((cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3))/6;
  377. switch (type){
  378. case S2U_Type:
  379. {
  380. if(this->MultipoleOrder()==0) break;
  381. Real_t r=pow(0.5,level);
  382. Real_t c[3]={0,0,0};
  383. // Coord of upward check surface
  384. std::vector<Real_t> uc_coord=u_check_surf(this->MultipoleOrder(),c,level);
  385. size_t n_uc=uc_coord.size()/3;
  386. // Evaluate potential at check surface.
  387. Matrix<Real_t> M_s2c(n_src*this->aux_kernel->ker_dim[0],n_uc*this->aux_kernel->ker_dim[1]); //source 2 check
  388. Matrix<Real_t> M_s2c_local(n_src*this->aux_kernel->ker_dim[0],n_uc*this->aux_kernel->ker_dim[1]);
  389. {
  390. M_s2c.SetZero();
  391. M_s2c_local.SetZero();
  392. size_t cnt_done=0;
  393. #pragma omp parallel for schedule(dynamic)
  394. for(size_t i=myrank;i<n_uc;i+=np){
  395. std::vector<Real_t> M_=cheb_integ(cheb_deg, &uc_coord[i*3], r, *this->aux_kernel);
  396. #ifdef __VERBOSE__
  397. #pragma omp critical
  398. if(!myrank){
  399. cnt_done++;
  400. std::cout<<"\r Progress: "<<(100*progress*n_uc+100*cnt_done*np)/(class_count*n_uc)<<"% "<<std::flush;
  401. }
  402. #endif
  403. for(int k=0; k<this->aux_kernel->ker_dim[1]; k++)
  404. for(size_t j=0; j<(size_t)M_s2c.Dim(0); j++)
  405. M_s2c_local[j][i*this->aux_kernel->ker_dim[1]+k] = M_[j+k*M_s2c.Dim(0)];
  406. }
  407. if(!myrank) std::cout<<"\r \r"<<std::flush;
  408. MPI_Allreduce(M_s2c_local[0], M_s2c[0], M_s2c.Dim(0)*M_s2c.Dim(1), par::Mpi_datatype<Real_t>::value(), par::Mpi_datatype<Real_t>::sum(), this->comm);
  409. }
  410. Matrix<Real_t>& M_c2e = this->Precomp(level, UC2UE_Type, 0);
  411. M=M_s2c*M_c2e;
  412. break;
  413. }
  414. case D2T_Type:
  415. {
  416. if(this->MultipoleOrder()==0) break;
  417. Matrix<Real_t>& M_s2t=FMM_Pts<FMMNode>::Precomp(level, type, mat_indx);
  418. int n_trg=M_s2t.Dim(1)/this->kernel->ker_dim[1];
  419. // Compute Chebyshev approx from target potential.
  420. M.Resize(M_s2t.Dim(0), n_src*this->kernel->ker_dim [1]);
  421. #pragma omp parallel for schedule(dynamic)
  422. for(size_t j=0; j<(size_t)M_s2t.Dim(0); j++){
  423. Matrix<Real_t> M_trg(n_trg,this->kernel->ker_dim[1],M_s2t[j],false);
  424. M_trg=M_trg.Transpose();
  425. cheb_approx<Real_t,Real_t>(M_s2t[j],cheb_deg,this->kernel->ker_dim[1],M[j]);
  426. }
  427. #pragma omp critical (PRECOMP_MATRIX_PTS)
  428. {
  429. M_s2t.Resize(0,0);
  430. }
  431. break;
  432. }
  433. case U0_Type:
  434. {
  435. // Coord of target points
  436. Real_t s=pow(0.5,level);
  437. int* coord=this->interac_list.RelativeCoord(type,mat_indx);
  438. Real_t coord_diff[3]={(coord[0]-1)*s*0.5,(coord[1]-1)*s*0.5,(coord[2]-1)*s*0.5};
  439. std::vector<Real_t>& rel_trg_coord = this->mat->RelativeTrgCoord();
  440. size_t n_trg = rel_trg_coord.size()/3;
  441. std::vector<Real_t> trg_coord(n_trg*3);
  442. for(size_t j=0;j<n_trg;j++){
  443. trg_coord[j*3+0]=rel_trg_coord[j*3+0]*s-coord_diff[0];
  444. trg_coord[j*3+1]=rel_trg_coord[j*3+1]*s-coord_diff[1];
  445. trg_coord[j*3+2]=rel_trg_coord[j*3+2]*s-coord_diff[2];
  446. }
  447. // Evaluate potential at target points.
  448. Matrix<Real_t> M_s2t(n_src*this->kernel->ker_dim [0], n_trg*this->kernel->ker_dim [1]);
  449. Matrix<Real_t> M_s2t_local(n_src*this->kernel->ker_dim [0], n_trg*this->kernel->ker_dim [1]);
  450. {
  451. M_s2t.SetZero();
  452. M_s2t_local.SetZero();
  453. size_t cnt_done=0;
  454. #pragma omp parallel for schedule(dynamic)
  455. for(size_t i=myrank;i<n_trg;i+=np){
  456. std::vector<Real_t> s2t=cheb_integ(cheb_deg, &trg_coord[i*3], (Real_t)(s*2.0), *this->kernel);
  457. #ifdef __VERBOSE__
  458. #pragma omp critical
  459. if(!myrank){
  460. cnt_done++;
  461. std::cout<<"\r Progress: "<<(100*progress*n_trg+100*cnt_done*np)/(class_count*n_trg)<<"% "<<std::flush;
  462. }
  463. #endif
  464. for(int k=0; k<this->kernel->ker_dim[1]; k++)
  465. for(size_t j=0; j<(size_t)M_s2t.Dim(0); j++)
  466. M_s2t_local[j][i*this->kernel->ker_dim[1]+k] = s2t[j+k*M_s2t.Dim(0)];
  467. }
  468. if(!myrank) std::cout<<"\r \r"<<std::flush;
  469. MPI_Allreduce(M_s2t_local[0], M_s2t[0], M_s2t.Dim(0)*M_s2t.Dim(1), par::Mpi_datatype<Real_t>::value(), par::Mpi_datatype<Real_t>::sum(), this->comm);
  470. }
  471. // Compute Chebyshev approx from target potential.
  472. M.Resize(M_s2t.Dim(0), n_src*this->kernel->ker_dim [1]);
  473. #pragma omp parallel for schedule(dynamic)
  474. for(size_t j=0; j<(size_t)M_s2t.Dim(0); j++){
  475. Matrix<Real_t> M_trg(n_trg,this->kernel->ker_dim[1],M_s2t[j],false);
  476. M_trg=M_trg.Transpose();
  477. cheb_approx<Real_t,Real_t>(M_s2t[j],cheb_deg,this->kernel->ker_dim[1],M[j]);
  478. }
  479. break;
  480. }
  481. case U1_Type:
  482. {
  483. // Coord of target points
  484. Real_t s=pow(0.5,level);
  485. int* coord=this->interac_list.RelativeCoord(type,mat_indx);
  486. Real_t coord_diff[3]={coord[0]*s,coord[1]*s,coord[2]*s};
  487. std::vector<Real_t>& rel_trg_coord = this->mat->RelativeTrgCoord();
  488. size_t n_trg = rel_trg_coord.size()/3;
  489. std::vector<Real_t> trg_coord(n_trg*3);
  490. for(size_t j=0;j<n_trg;j++){
  491. trg_coord[j*3+0]=rel_trg_coord[j*3+0]*s-coord_diff[0];
  492. trg_coord[j*3+1]=rel_trg_coord[j*3+1]*s-coord_diff[1];
  493. trg_coord[j*3+2]=rel_trg_coord[j*3+2]*s-coord_diff[2];
  494. }
  495. // Evaluate potential at target points.
  496. Matrix<Real_t> M_s2t(n_src*this->kernel->ker_dim [0], n_trg*this->kernel->ker_dim [1]);
  497. Matrix<Real_t> M_s2t_local(n_src*this->kernel->ker_dim [0], n_trg*this->kernel->ker_dim [1]);
  498. {
  499. M_s2t.SetZero();
  500. M_s2t_local.SetZero();
  501. size_t cnt_done=0;
  502. #pragma omp parallel for schedule(dynamic)
  503. for(size_t i=myrank;i<n_trg;i+=np){
  504. std::vector<Real_t> s2t=cheb_integ(cheb_deg, &trg_coord[i*3], s, *this->kernel);
  505. #ifdef __VERBOSE__
  506. #pragma omp critical
  507. if(!myrank){
  508. cnt_done++;
  509. std::cout<<"\r Progress: "<<(100*progress*n_trg+100*cnt_done*np)/(class_count*n_trg)<<"% "<<std::flush;
  510. }
  511. #endif
  512. for(int k=0; k<this->kernel->ker_dim[1]; k++)
  513. for(size_t j=0; j<(size_t)M_s2t.Dim(0); j++)
  514. M_s2t_local[j][i*this->kernel->ker_dim[1]+k] = s2t[j+k*M_s2t.Dim(0)];
  515. }
  516. if(!myrank) std::cout<<"\r \r"<<std::flush;
  517. MPI_Allreduce(M_s2t_local[0], M_s2t[0], M_s2t.Dim(0)*M_s2t.Dim(1), par::Mpi_datatype<Real_t>::value(), par::Mpi_datatype<Real_t>::sum(), this->comm);
  518. }
  519. // Compute Chebyshev approx from target potential.
  520. M.Resize(M_s2t.Dim(0), n_src*this->kernel->ker_dim [1]);
  521. #pragma omp parallel for schedule(dynamic)
  522. for(size_t j=0; j<(size_t)M_s2t.Dim(0); j++){
  523. Matrix<Real_t> M_trg(n_trg,this->kernel->ker_dim[1],M_s2t[j],false);
  524. M_trg=M_trg.Transpose();
  525. cheb_approx<Real_t,Real_t>(M_s2t[j],cheb_deg,this->kernel->ker_dim[1],M[j]);
  526. }
  527. break;
  528. }
  529. case U2_Type:
  530. {
  531. // Coord of target points
  532. Real_t s=pow(0.5,level);
  533. int* coord=this->interac_list.RelativeCoord(type,mat_indx);
  534. Real_t coord_diff[3]={(coord[0]+1)*s*0.25,(coord[1]+1)*s*0.25,(coord[2]+1)*s*0.25};
  535. std::vector<Real_t>& rel_trg_coord = this->mat->RelativeTrgCoord();
  536. size_t n_trg = rel_trg_coord.size()/3;
  537. std::vector<Real_t> trg_coord(n_trg*3);
  538. for(size_t j=0;j<n_trg;j++){
  539. trg_coord[j*3+0]=rel_trg_coord[j*3+0]*s-coord_diff[0];
  540. trg_coord[j*3+1]=rel_trg_coord[j*3+1]*s-coord_diff[1];
  541. trg_coord[j*3+2]=rel_trg_coord[j*3+2]*s-coord_diff[2];
  542. }
  543. // Evaluate potential at target points.
  544. Matrix<Real_t> M_s2t(n_src*this->kernel->ker_dim [0], n_trg*this->kernel->ker_dim [1]);
  545. Matrix<Real_t> M_s2t_local(n_src*this->kernel->ker_dim [0], n_trg*this->kernel->ker_dim [1]);
  546. {
  547. M_s2t.SetZero();
  548. M_s2t_local.SetZero();
  549. size_t cnt_done=0;
  550. #pragma omp parallel for schedule(dynamic)
  551. for(size_t i=myrank;i<n_trg;i+=np){
  552. std::vector<Real_t> s2t=cheb_integ(cheb_deg, &trg_coord[i*3], (Real_t)(s*0.5), *this->kernel);
  553. #ifdef __VERBOSE__
  554. #pragma omp critical
  555. if(!myrank){
  556. cnt_done++;
  557. std::cout<<"\r Progress: "<<(100*progress*n_trg+100*cnt_done*np)/(class_count*n_trg)<<"% "<<std::flush;
  558. }
  559. #endif
  560. for(int k=0; k<this->kernel->ker_dim[1]; k++)
  561. for(size_t j=0; j<(size_t)M_s2t.Dim(0); j++)
  562. M_s2t_local[j][i*this->kernel->ker_dim[1]+k] = s2t[j+k*M_s2t.Dim(0)];
  563. }
  564. if(!myrank) std::cout<<"\r \r"<<std::flush;
  565. MPI_Allreduce(M_s2t_local[0], M_s2t[0], M_s2t.Dim(0)*M_s2t.Dim(1), par::Mpi_datatype<Real_t>::value(), par::Mpi_datatype<Real_t>::sum(), this->comm);
  566. }
  567. // Compute Chebyshev approx from target potential.
  568. M.Resize(M_s2t.Dim(0), n_src*this->kernel->ker_dim [1]);
  569. #pragma omp parallel for schedule(dynamic)
  570. for(size_t j=0; j<(size_t)M_s2t.Dim(0); j++){
  571. Matrix<Real_t> M_trg(n_trg,this->kernel->ker_dim[1],M_s2t[j],false);
  572. M_trg=M_trg.Transpose();
  573. cheb_approx<Real_t,Real_t>(M_s2t[j],cheb_deg,this->kernel->ker_dim[1],M[j]);
  574. }
  575. break;
  576. }
  577. case W_Type:
  578. {
  579. if(this->MultipoleOrder()==0) break;
  580. Matrix<Real_t>& M_s2t=FMM_Pts<FMMNode>::Precomp(level, type, mat_indx);
  581. int n_trg=M_s2t.Dim(1)/this->kernel->ker_dim[1];
  582. // Compute Chebyshev approx from target potential.
  583. M.Resize(M_s2t.Dim(0), n_src*this->kernel->ker_dim [1]);
  584. #pragma omp parallel for schedule(dynamic)
  585. for(size_t j=0; j<(size_t)M_s2t.Dim(0); j++){
  586. Matrix<Real_t> M_trg(n_trg,this->kernel->ker_dim[1],M_s2t[j],false);
  587. M_trg=M_trg.Transpose();
  588. cheb_approx<Real_t,Real_t>(M_s2t[j],cheb_deg,this->kernel->ker_dim[1],M[j]);
  589. }
  590. #pragma omp critical (PRECOMP_MATRIX_PTS)
  591. {
  592. M_s2t.Resize(0,0);
  593. }
  594. break;
  595. }
  596. case X_Type:
  597. {
  598. if(this->MultipoleOrder()==0) break;
  599. // Coord of target points
  600. Real_t s=pow(0.5,level-1);
  601. int* coord=this->interac_list.RelativeCoord(type,mat_indx);
  602. Real_t c[3]={-(coord[0]-1)*s*0.25,-(coord[1]-1)*s*0.25,-(coord[2]-1)*s*0.25};
  603. std::vector<Real_t> trg_coord=d_check_surf(this->MultipoleOrder(),c,level);
  604. size_t n_trg=trg_coord.size()/3;
  605. // Evaluate potential at target points.
  606. Matrix<Real_t> M_xs2c(n_src*this->aux_kernel->ker_dim[0], n_trg*this->aux_kernel->ker_dim[1]);
  607. Matrix<Real_t> M_xs2c_local(n_src*this->aux_kernel->ker_dim[0], n_trg*this->aux_kernel->ker_dim[1]);
  608. {
  609. M_xs2c.SetZero();
  610. M_xs2c_local.SetZero();
  611. size_t cnt_done=0;
  612. #pragma omp parallel for schedule(dynamic)
  613. for(size_t i=myrank;i<n_trg;i+=np){
  614. std::vector<Real_t> M_=cheb_integ(cheb_deg, &trg_coord[i*3], s, *this->aux_kernel);
  615. #ifdef __VERBOSE__
  616. #pragma omp critical
  617. if(!myrank){
  618. cnt_done++;
  619. std::cout<<"\r Progress: "<<(100*progress*n_trg+100*cnt_done*np)/(class_count*n_trg)<<"% "<<std::flush;
  620. }
  621. #endif
  622. for(int k=0; k<this->aux_kernel->ker_dim[1]; k++)
  623. for(size_t j=0; j<(size_t)M_xs2c.Dim(0); j++)
  624. M_xs2c_local[j][i*this->aux_kernel->ker_dim[1]+k] = M_[j+k*M_xs2c.Dim(0)];
  625. }
  626. if(!myrank) std::cout<<"\r \r"<<std::flush;
  627. MPI_Allreduce(M_xs2c_local[0], M_xs2c[0], M_xs2c.Dim(0)*M_xs2c.Dim(1), par::Mpi_datatype<Real_t>::value(), par::Mpi_datatype<Real_t>::sum(), this->comm);
  628. }
  629. Matrix<Real_t>& M_c2e = this->Precomp(level, DC2DE_Type, 0);
  630. M=M_xs2c*M_c2e;
  631. break;
  632. }
  633. default:
  634. {
  635. return FMM_Pts<FMMNode>::Precomp(level, type, mat_indx);
  636. break;
  637. }
  638. }
  639. //Save the matrix for future use.
  640. #pragma omp critical (PRECOMP_MATRIX_PTS)
  641. if(M_.Dim(0)==0 && M_.Dim(1)==0){ M_=M;}
  642. return M_;
  643. }
  644. template <class FMMNode>
  645. void FMM_Cheb<FMMNode>::CollectNodeData(std::vector<FMMNode*>& node, std::vector<Matrix<Real_t> >& buff, std::vector<Vector<FMMNode_t*> >& n_list, std::vector<size_t> extra_size){
  646. if( buff.size()<6) buff.resize(6);
  647. if( n_list.size()<6) n_list.resize(6);
  648. if(extra_size.size()<6) extra_size.resize(6,0);
  649. size_t n_coeff=(cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3)/6;
  650. if(node.size()==0) return;
  651. {// 4. cheb_in
  652. int indx=4;
  653. int dof=this->kernel->ker_dim[0];
  654. size_t vec_sz=dof*n_coeff;
  655. std::vector< FMMNode* > node_lst;
  656. for(size_t i=0;i<node.size();i++)
  657. if(node[i]->IsLeaf())
  658. node_lst.push_back(node[i]);
  659. n_list[indx]=node_lst;
  660. extra_size[indx]+=node_lst.size()*vec_sz;
  661. #pragma omp parallel for
  662. for(size_t i=0;i<node.size();i++){ // Move data before resizing buff[indx]
  663. Vector<Real_t>& cheb_in =node[i]->ChebData();
  664. Vector<Real_t> new_buff=cheb_in;
  665. cheb_in.Swap(new_buff);
  666. }
  667. }
  668. {// 5. cheb_out
  669. int indx=5;
  670. int dof=this->kernel->ker_dim[1];
  671. size_t vec_sz=dof*n_coeff;
  672. std::vector< FMMNode* > node_lst;
  673. for(size_t i=0;i<node.size();i++)
  674. if(node[i]->IsLeaf() && !node[i]->IsGhost())
  675. node_lst.push_back(node[i]);
  676. n_list[indx]=node_lst;
  677. extra_size[indx]+=node_lst.size()*vec_sz;
  678. #pragma omp parallel for
  679. for(size_t i=0;i<node.size();i++){ // Move data before resizing buff[indx]
  680. Vector<Real_t>& cheb_out=((FMMData*)node[i]->FMMData())->cheb_out;
  681. cheb_out.ReInit(0);
  682. }
  683. }
  684. FMM_Pts<FMMNode>::CollectNodeData(node, buff, n_list, extra_size);
  685. {// 4. cheb_in
  686. int indx=4;
  687. int dof=this->kernel->ker_dim[0];
  688. size_t vec_sz=dof*n_coeff;
  689. Vector< FMMNode* >& node_lst=n_list[indx];
  690. Real_t* buff_ptr=buff[indx][0]+buff[indx].Dim(0)*buff[indx].Dim(1)-extra_size[indx];
  691. #pragma omp parallel for
  692. for(size_t i=0;i<node_lst.Dim();i++){
  693. Vector<Real_t>& cheb_in =node_lst[i]->ChebData();
  694. mem::memcopy(buff_ptr+i*vec_sz, &cheb_in [0], cheb_in .Dim()*sizeof(Real_t));
  695. cheb_in .ReInit(vec_sz, buff_ptr+i*vec_sz, false);
  696. //if(node_lst[i]->IsGhost()) cheb_in .SetZero();
  697. }
  698. buff[indx].AllocDevice(true);
  699. }
  700. {// 5. cheb_out
  701. int indx=5;
  702. int dof=this->kernel->ker_dim[1];
  703. size_t vec_sz=dof*n_coeff;
  704. Vector< FMMNode* >& node_lst=n_list[indx];
  705. Real_t* buff_ptr=buff[indx][0]+buff[indx].Dim(0)*buff[indx].Dim(1)-extra_size[indx];
  706. #pragma omp parallel for
  707. for(size_t i=0;i<node_lst.Dim();i++){
  708. Vector<Real_t>& cheb_out=((FMMData*)node_lst[i]->FMMData())->cheb_out;
  709. cheb_out.ReInit(vec_sz, buff_ptr+i*vec_sz, false);
  710. cheb_out.SetZero();
  711. }
  712. buff[indx].AllocDevice(true);
  713. }
  714. }
  715. template <class FMMNode>
  716. void FMM_Cheb<FMMNode>::Source2UpSetup(SetupData<Real_t>& setup_data, std::vector<Matrix<Real_t> >& buff, std::vector<Vector<FMMNode_t*> >& n_list, int level, bool device){
  717. if(this->MultipoleOrder()==0) return;
  718. FMM_Pts<FMMNode>::Source2UpSetup(setup_data, buff, n_list, level, device);
  719. { // Set setup_data
  720. setup_data.level=level;
  721. setup_data.kernel=this->aux_kernel;
  722. setup_data.interac_type.resize(1);
  723. setup_data.interac_type[0]=S2U_Type;
  724. setup_data. input_data=&buff[4];
  725. setup_data.output_data=&buff[0];
  726. Vector<FMMNode_t*>& nodes_in =n_list[4];
  727. Vector<FMMNode_t*>& nodes_out=n_list[0];
  728. setup_data.nodes_in .clear();
  729. setup_data.nodes_out.clear();
  730. for(size_t i=0;i<nodes_in .Dim();i++) if(nodes_in [i]->Depth()==level || level==-1) setup_data.nodes_in .push_back(nodes_in [i]);
  731. for(size_t i=0;i<nodes_out.Dim();i++) if(nodes_out[i]->Depth()==level || level==-1) setup_data.nodes_out.push_back(nodes_out[i]);
  732. }
  733. std::vector<void*>& nodes_in =setup_data.nodes_in ;
  734. std::vector<void*>& nodes_out=setup_data.nodes_out;
  735. std::vector<Vector<Real_t>*>& input_vector=setup_data. input_vector; input_vector.clear();
  736. std::vector<Vector<Real_t>*>& output_vector=setup_data.output_vector; output_vector.clear();
  737. for(size_t i=0;i<nodes_in .size();i++) input_vector.push_back(&( ((FMMNode*)nodes_in [i]) )->ChebData() );
  738. for(size_t i=0;i<nodes_out.size();i++) output_vector.push_back(&((FMMData*)((FMMNode*)nodes_out[i])->FMMData())->upward_equiv);
  739. this->SetupInterac(setup_data,device);
  740. }
  741. template <class FMMNode>
  742. void FMM_Cheb<FMMNode>::Source2Up (SetupData<Real_t>& setup_data, bool device){
  743. //Add Source2Up contribution.
  744. this->EvalList(setup_data, device);
  745. }
  746. template <class FMMNode>
  747. void FMM_Cheb<FMMNode>::X_ListSetup(SetupData<Real_t>& setup_data, std::vector<Matrix<Real_t> >& buff, std::vector<Vector<FMMNode_t*> >& n_list, int level, bool device){
  748. if(this->MultipoleOrder()==0) return;
  749. FMM_Pts<FMMNode>::X_ListSetup(setup_data, buff, n_list, level, device);
  750. { // Set setup_data
  751. setup_data.level=level;
  752. setup_data.kernel=this->aux_kernel;
  753. setup_data.interac_type.resize(1);
  754. setup_data.interac_type[0]=X_Type;
  755. setup_data. input_data=&buff[4];
  756. setup_data.output_data=&buff[1];
  757. Vector<FMMNode_t*>& nodes_in =n_list[4];
  758. Vector<FMMNode_t*>& nodes_out=n_list[1];
  759. setup_data.nodes_in .clear();
  760. setup_data.nodes_out.clear();
  761. for(size_t i=0;i<nodes_in .Dim();i++) if(nodes_in [i]->Depth()==level-1 || level==-1) setup_data.nodes_in .push_back(nodes_in [i]);
  762. for(size_t i=0;i<nodes_out.Dim();i++) if(nodes_out[i]->Depth()==level || level==-1) setup_data.nodes_out.push_back(nodes_out[i]);
  763. }
  764. std::vector<void*>& nodes_in =setup_data.nodes_in ;
  765. std::vector<void*>& nodes_out=setup_data.nodes_out;
  766. std::vector<Vector<Real_t>*>& input_vector=setup_data. input_vector; input_vector.clear();
  767. std::vector<Vector<Real_t>*>& output_vector=setup_data.output_vector; output_vector.clear();
  768. for(size_t i=0;i<nodes_in .size();i++) input_vector.push_back(&( ((FMMNode*)nodes_in [i]) )->ChebData() );
  769. for(size_t i=0;i<nodes_out.size();i++) output_vector.push_back(&((FMMData*)((FMMNode*)nodes_out[i])->FMMData())->dnward_equiv);
  770. this->SetupInterac(setup_data,device);
  771. { // Resize device buffer
  772. size_t n=setup_data.output_data->Dim(0)*setup_data.output_data->Dim(1)*sizeof(Real_t);
  773. if(this->dev_buffer.Dim()<n) this->dev_buffer.Resize(n);
  774. }
  775. }
  776. template <class FMMNode>
  777. void FMM_Cheb<FMMNode>::X_List (SetupData<Real_t>& setup_data, bool device){
  778. //Add X_List contribution.
  779. FMM_Pts<FMMNode>::X_List(setup_data, device);
  780. this->EvalList(setup_data, device);
  781. }
  782. template <class FMMNode>
  783. void FMM_Cheb<FMMNode>::W_ListSetup(SetupData<Real_t>& setup_data, std::vector<Matrix<Real_t> >& buff, std::vector<Vector<FMMNode_t*> >& n_list, int level, bool device){
  784. if(this->MultipoleOrder()==0) return;
  785. { // Set setup_data
  786. setup_data.level=level;
  787. setup_data.kernel=this->kernel;
  788. setup_data.interac_type.resize(1);
  789. setup_data.interac_type[0]=W_Type;
  790. setup_data. input_data=&buff[0];
  791. setup_data.output_data=&buff[5];
  792. Vector<FMMNode_t*>& nodes_in =n_list[0];
  793. Vector<FMMNode_t*>& nodes_out=n_list[5];
  794. setup_data.nodes_in .clear();
  795. setup_data.nodes_out.clear();
  796. for(size_t i=0;i<nodes_in .Dim();i++) if(nodes_in [i]->Depth()==level+1 || level==-1) setup_data.nodes_in .push_back(nodes_in [i]);
  797. for(size_t i=0;i<nodes_out.Dim();i++) if(nodes_out[i]->Depth()==level || level==-1) setup_data.nodes_out.push_back(nodes_out[i]);
  798. }
  799. std::vector<void*>& nodes_in =setup_data.nodes_in ;
  800. std::vector<void*>& nodes_out=setup_data.nodes_out;
  801. std::vector<Vector<Real_t>*>& input_vector=setup_data. input_vector; input_vector.clear();
  802. std::vector<Vector<Real_t>*>& output_vector=setup_data.output_vector; output_vector.clear();
  803. for(size_t i=0;i<nodes_in .size();i++) input_vector.push_back(&((FMMData*)((FMMNode*)nodes_in [i])->FMMData())->upward_equiv);
  804. for(size_t i=0;i<nodes_out.size();i++) output_vector.push_back(&((FMMData*)((FMMNode*)nodes_out[i])->FMMData())->cheb_out );
  805. this->SetupInterac(setup_data,device);
  806. { // Resize device buffer
  807. size_t n=setup_data.output_data->Dim(0)*setup_data.output_data->Dim(1)*sizeof(Real_t);
  808. if(this->dev_buffer.Dim()<n) this->dev_buffer.Resize(n);
  809. }
  810. }
  811. template <class FMMNode>
  812. void FMM_Cheb<FMMNode>::W_List (SetupData<Real_t>& setup_data, bool device){
  813. //Add W_List contribution.
  814. this->EvalList(setup_data, device);
  815. }
  816. template <class FMMNode>
  817. void FMM_Cheb<FMMNode>::U_ListSetup(SetupData<Real_t>& setup_data, std::vector<Matrix<Real_t> >& buff, std::vector<Vector<FMMNode_t*> >& n_list, int level, bool device){
  818. FMM_Pts<FMMNode>::U_ListSetup(setup_data, buff, n_list, level, device);
  819. { // Set setup_data
  820. setup_data.level=level;
  821. setup_data.kernel=this->kernel;
  822. setup_data.interac_type.resize(3);
  823. setup_data.interac_type[0]=U0_Type;
  824. setup_data.interac_type[1]=U1_Type;
  825. setup_data.interac_type[2]=U2_Type;
  826. setup_data. input_data=&buff[4];
  827. setup_data.output_data=&buff[5];
  828. Vector<FMMNode_t*>& nodes_in =n_list[4];
  829. Vector<FMMNode_t*>& nodes_out=n_list[5];
  830. setup_data.nodes_in .clear();
  831. setup_data.nodes_out.clear();
  832. for(size_t i=0;i<nodes_in .Dim();i++) if((level-1<=nodes_in [i]->Depth() && nodes_in [i]->Depth()<=level+1) || level==-1) setup_data.nodes_in .push_back(nodes_in [i]);
  833. for(size_t i=0;i<nodes_out.Dim();i++) if(( nodes_out[i]->Depth()==level ) || level==-1) setup_data.nodes_out.push_back(nodes_out[i]);
  834. }
  835. std::vector<void*>& nodes_in =setup_data.nodes_in ;
  836. std::vector<void*>& nodes_out=setup_data.nodes_out;
  837. std::vector<Vector<Real_t>*>& input_vector=setup_data. input_vector; input_vector.clear();
  838. std::vector<Vector<Real_t>*>& output_vector=setup_data.output_vector; output_vector.clear();
  839. for(size_t i=0;i<nodes_in .size();i++) input_vector.push_back(&( ((FMMNode*)nodes_in [i]) )->ChebData());
  840. for(size_t i=0;i<nodes_out.size();i++) output_vector.push_back(&((FMMData*)((FMMNode*)nodes_out[i])->FMMData())->cheb_out );
  841. this->SetupInterac(setup_data,device);
  842. { // Resize device buffer
  843. size_t n=setup_data.output_data->Dim(0)*setup_data.output_data->Dim(1)*sizeof(Real_t);
  844. if(this->dev_buffer.Dim()<n) this->dev_buffer.Resize(n);
  845. }
  846. }
  847. template <class FMMNode>
  848. void FMM_Cheb<FMMNode>::U_List (SetupData<Real_t>& setup_data, bool device){
  849. //Add U_List contribution.
  850. FMM_Pts<FMMNode>::U_List(setup_data, device);
  851. this->EvalList(setup_data, device);
  852. }
  853. template <class FMMNode>
  854. void FMM_Cheb<FMMNode>::Down2TargetSetup(SetupData<Real_t>& setup_data, std::vector<Matrix<Real_t> >& buff, std::vector<Vector<FMMNode_t*> >& n_list, int level, bool device){
  855. if(this->MultipoleOrder()==0) return;
  856. { // Set setup_data
  857. setup_data.level=level;
  858. setup_data.kernel=this->kernel;
  859. setup_data.interac_type.resize(1);
  860. setup_data.interac_type[0]=D2T_Type;
  861. setup_data. input_data=&buff[1];
  862. setup_data.output_data=&buff[5];
  863. Vector<FMMNode_t*>& nodes_in =n_list[1];
  864. Vector<FMMNode_t*>& nodes_out=n_list[5];
  865. setup_data.nodes_in .clear();
  866. setup_data.nodes_out.clear();
  867. for(size_t i=0;i<nodes_in .Dim();i++) if(nodes_in [i]->Depth()==level || level==-1) setup_data.nodes_in .push_back(nodes_in [i]);
  868. for(size_t i=0;i<nodes_out.Dim();i++) if(nodes_out[i]->Depth()==level || level==-1) setup_data.nodes_out.push_back(nodes_out[i]);
  869. }
  870. std::vector<void*>& nodes_in =setup_data.nodes_in ;
  871. std::vector<void*>& nodes_out=setup_data.nodes_out;
  872. std::vector<Vector<Real_t>*>& input_vector=setup_data. input_vector; input_vector.clear();
  873. std::vector<Vector<Real_t>*>& output_vector=setup_data.output_vector; output_vector.clear();
  874. for(size_t i=0;i<nodes_in .size();i++) input_vector.push_back(&((FMMData*)((FMMNode*)nodes_in [i])->FMMData())->dnward_equiv);
  875. for(size_t i=0;i<nodes_out.size();i++) output_vector.push_back(&((FMMData*)((FMMNode*)nodes_out[i])->FMMData())->cheb_out );
  876. this->SetupInterac(setup_data,device);
  877. }
  878. template <class FMMNode>
  879. void FMM_Cheb<FMMNode>::Down2Target (SetupData<Real_t>& setup_data, bool device){
  880. //Add Down2Target contribution.
  881. this->EvalList(setup_data, device);
  882. }
  883. template <class FMMNode>
  884. void FMM_Cheb<FMMNode>::PostProcessing(std::vector<FMMNode_t*>& nodes){
  885. size_t n=nodes.size();
  886. #pragma omp parallel
  887. {
  888. int omp_p=omp_get_num_threads();
  889. int pid = omp_get_thread_num();
  890. size_t a=(pid*n)/omp_p;
  891. size_t b=((pid+1)*n)/omp_p;
  892. //For each node, compute interaction from point sources.
  893. for(size_t i=a;i<b;i++){
  894. Vector<Real_t>& trg_coord=nodes[i]->trg_coord;
  895. Vector<Real_t>& trg_value=nodes[i]->trg_value;
  896. Vector<Real_t>& cheb_out =((FMMData*)nodes[i]->FMMData())->cheb_out;
  897. //Initialize target potential.
  898. size_t trg_cnt=trg_coord.Dim()/COORD_DIM;
  899. //trg_value.assign(trg_cnt*dof*this->kernel->ker_dim[1],0);
  900. //Sample local expansion at target points.
  901. if(trg_cnt>0 && cheb_out.Dim()>0){
  902. Real_t* c=nodes[i]->Coord();
  903. Real_t scale=pow(2.0,nodes[i]->Depth()+1);
  904. std::vector<Real_t> rel_coord(COORD_DIM*trg_cnt);
  905. for(size_t j=0;j<trg_cnt;j++) for(int k=0;k<COORD_DIM;k++)
  906. rel_coord[j*COORD_DIM+k]=(trg_coord[j*COORD_DIM+k]-c[k])*scale-1.0;
  907. cheb_eval(cheb_out, cheb_deg, rel_coord, trg_value);
  908. }
  909. }
  910. }
  911. }
  912. }//end namespace