cheb_utils.txx 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393
  1. /**
  2. * \file cheb_utils.txx
  3. * \author Dhairya Malhotra, dhairya.malhotra@gmail.com
  4. * \date 2-11-2011
  5. * \brief This file contains chebyshev related functions.
  6. */
  7. #include <omp.h>
  8. #include <cmath>
  9. #include <cassert>
  10. #include <cstdlib>
  11. #include <iostream>
  12. #include <algorithm>
  13. #include <legendre_rule.hpp>
  14. #include <mem_utils.hpp>
  15. #include <mat_utils.hpp>
  16. #include <mem_mgr.hpp>
  17. #include <matrix.hpp>
  18. #include <profile.hpp>
  19. namespace pvfmm{
  20. template <class T>
  21. T machine_eps(){
  22. T eps=1.0;
  23. while(eps+(T)1.0>1.0) eps*=0.5;
  24. return eps;
  25. }
  26. /**
  27. * \brief Returns the values of all chebyshev polynomials up to degree d,
  28. * evaluated at points in the input vector. Output format:
  29. * { T0[in[0]], ..., T0[in[n-1]], T1[in[0]], ..., T(d-1)[in[n-1]] }
  30. */
  31. template <class T>
  32. inline void cheb_poly(int d, const T* in, int n, T* out){
  33. if(d==0){
  34. for(int i=0;i<n;i++)
  35. out[i]=(fabs(in[i])<=1?1.0:0);
  36. }else if(d==1){
  37. for(int i=0;i<n;i++){
  38. out[i]=(fabs(in[i])<=1?1.0:0);
  39. out[i+n]=(fabs(in[i])<=1?in[i]:0);
  40. }
  41. }else{
  42. for(int j=0;j<n;j++){
  43. T x=(fabs(in[j])<=1?in[j]:0);
  44. T y0=(fabs(in[j])<=1?1.0:0);
  45. out[j]=y0;
  46. out[j+n]=x;
  47. T y1=x;
  48. T* y2=&out[2*n+j];
  49. for(int i=2;i<=d;i++){
  50. *y2=2*x*y1-y0;
  51. y0=y1;
  52. y1=*y2;
  53. y2=&y2[n];
  54. }
  55. }
  56. }
  57. }
  58. /**
  59. * \brief Returns the sum of the absolute value of coeffecients of the highest
  60. * order polynomial as an estimate of error.
  61. */
  62. template <class T>
  63. T cheb_err(T* cheb_coeff, int deg, int dof){
  64. T err=0;
  65. int indx=0;
  66. for(int l=0;l<dof;l++)
  67. for(int i=0;i<=deg;i++)
  68. for(int j=0;i+j<=deg;j++)
  69. for(int k=0;i+j+k<=deg;k++){
  70. if(i+j+k==deg) err+=fabs(cheb_coeff[indx]);
  71. indx++;
  72. }
  73. return err;
  74. }
  75. template<typename U1, typename U2>
  76. struct SameType{
  77. bool operator()(){return false;}
  78. };
  79. template<typename U>
  80. struct SameType<U, U>{
  81. bool operator()(){return true;}
  82. };
  83. /**
  84. * \brief Computes Chebyshev approximation from function values at cheb node points.
  85. */
  86. template <class T, class Y>
  87. T cheb_approx(T* fn_v, int cheb_deg, int dof, T* out, mem::MemoryManager* mem_mgr){
  88. int d=cheb_deg+1;
  89. // Precompute
  90. Matrix<Y>* Mp=NULL;
  91. static std::vector<Matrix<Y> > precomp;
  92. #pragma omp critical (CHEB_APPROX)
  93. {
  94. if(precomp.size()<=(size_t)d){
  95. precomp .resize(d+1);
  96. }
  97. if(precomp [d].Dim(0)==0 && precomp [d].Dim(1)==0){
  98. std::vector<Y> x(d);
  99. for(int i=0;i<d;i++)
  100. x[i]=-cos((i+(T)0.5)*const_pi<T>()/d);
  101. std::vector<Y> p(d*d);
  102. cheb_poly(cheb_deg,&x[0],d,&p[0]);
  103. for(int i=d;i<d*d;i++)
  104. p[i]=p[i]*2.0;
  105. for(int i=0;i<d*d;i++)
  106. p[i]=p[i]/d;
  107. Matrix<Y> Mp1(d,d,&p[0],false);
  108. Matrix<Y> Mp1_=Mp1.Transpose();
  109. precomp[d]=Mp1_;
  110. }
  111. Mp=&precomp[d];
  112. }
  113. // Create work buffers
  114. size_t buff_size=dof*d*d*d;
  115. Y* buff=(Y*)(mem_mgr?mem_mgr->malloc(2*buff_size*sizeof(Y)):
  116. malloc(2*buff_size*sizeof(Y)));
  117. Y* buff1=buff+buff_size*0;
  118. Y* buff2=buff+buff_size*1;
  119. Vector<Y> fn_v_in;
  120. if(SameType<T,Y>()()){ // Initialize fn_v_in
  121. fn_v_in.ReInit(d*d*d*dof,fn_v,false);
  122. }else{
  123. fn_v_in.ReInit(d*d*d*dof,buff1,false);
  124. for(size_t i=0;i<fn_v_in.Dim();i++) fn_v_in[i]=fn_v[i];
  125. }
  126. { // Apply Mp along x-dimension
  127. Matrix<Y> Mi(dof*d*d,d,&fn_v_in[0],false);
  128. Matrix<Y> Mo(dof*d*d,d,buff2,false);
  129. Mo=Mi*(*Mp);
  130. Matrix<Y> Mo_t(d,dof*d*d,buff1,false);
  131. for(size_t i=0;i<Mo.Dim(0);i++)
  132. for(size_t j=0;j<Mo.Dim(1);j++){
  133. Mo_t[j][i]=Mo[i][j];
  134. }
  135. }
  136. { // Apply Mp along y-dimension
  137. Matrix<Y> Mi(d*dof*d,d,buff1,false);
  138. Matrix<Y> Mo(d*dof*d,d,buff2,false);
  139. Mo=Mi*(*Mp);
  140. Matrix<Y> Mo_t(d,d*dof*d,buff1,false);
  141. for(size_t i=0;i<Mo.Dim(0);i++)
  142. for(size_t j=0;j<Mo.Dim(1);j++){
  143. Mo_t[j][i]=Mo[i][j];
  144. }
  145. }
  146. { // Apply Mp along z-dimension
  147. Matrix<Y> Mi(d*d*dof,d,buff1,false);
  148. Matrix<Y> Mo(d*d*dof,d,buff2,false);
  149. Mo=Mi*(*Mp);
  150. Matrix<Y> Mo_t(d,d*d*dof,buff1,false);
  151. for(size_t i=0;i<Mo.Dim(0);i++)
  152. for(size_t j=0;j<Mo.Dim(1);j++){
  153. Mo_t[j][i]=Mo[i][j];
  154. }
  155. }
  156. { // Rearrange and write to out
  157. int indx=0;
  158. for(int l=0;l<dof;l++){
  159. for(int i=0;i<d;i++){
  160. for(int j=0;i+j<d;j++){
  161. Y* buff_ptr=&buff1[(j+i*d)*d*dof+l];
  162. for(int k=0;i+j+k<d;k++){
  163. out[indx]=buff_ptr[k*dof];
  164. indx++;
  165. }
  166. }
  167. }
  168. }
  169. }
  170. // Free memory
  171. if(mem_mgr )mem_mgr->free(buff);
  172. return cheb_err(out,cheb_deg,dof);
  173. }
  174. /**
  175. * \brief Returns the values of all legendre polynomials up to degree d,
  176. * evaluated at points in the input vector. Output format:
  177. * { P0[in[0]], ..., P0[in[n-1]], P1[in[0]], ..., P(d-1)[in[n-1]] }
  178. */
  179. template <class T>
  180. inline void legn_poly(int d, T* in, int n, T* out){
  181. if(d==0){
  182. for(int i=0;i<n;i++)
  183. out[i]=(fabs(in[i])<=1?1.0:0);
  184. }else if(d==1){
  185. for(int i=0;i<n;i++){
  186. out[i]=(fabs(in[i])<=1?1.0:0);
  187. out[i+n]=(fabs(in[i])<=1?in[i]:0);
  188. }
  189. }else{
  190. for(int j=0;j<n;j++){
  191. T x=(fabs(in[j])<=1?in[j]:0);
  192. T y0=(fabs(in[j])<=1?1.0:0);
  193. out[j]=y0;
  194. out[j+n]=x;
  195. T y1=x;
  196. T* y2=&out[2*n+j];
  197. for(int i=2;i<=d;i++){
  198. *y2=( (2*i-1)*x*y1-(i-1)*y0 )/i;
  199. y0=y1;
  200. y1=*y2;
  201. y2=&y2[n];
  202. }
  203. }
  204. }
  205. }
  206. /**
  207. * \brief Computes Legendre-Gauss-Lobatto nodes and weights.
  208. */
  209. template <class T>
  210. void gll_quadrature(int deg, T* x_, T* w){//*
  211. T eps=machine_eps<T>()*64;
  212. int d=deg+1;
  213. assert(d>1);
  214. int N=deg;
  215. Vector<T> x(d,x_,false);
  216. for(int i=0;i<d;i++)
  217. x[i]=-cos((const_pi<T>()*i)/N);
  218. Matrix<T> P(d,d); P.SetZero();
  219. T err=1;
  220. Vector<T> xold(d);
  221. while(err>eps){
  222. xold=x;
  223. for(int i=0;i<d;i++){
  224. P[i][0]=1;
  225. P[i][1]=x[i];
  226. }
  227. for(int k=2;k<=N;k++)
  228. for(int i=0;i<d;i++)
  229. P[i][k]=( (2*k-1)*x[i]*P[i][k-1]-(k-1)*P[i][k-2] )/k;
  230. err=0;
  231. for(int i=0;i<d;i++){
  232. T dx=-( x[i]*P[i][N]-P[i][N-1] )/( d*P[i][N] );
  233. err=(err<fabs(dx)?fabs(dx):err);
  234. x[i]=xold[i]+dx;
  235. }
  236. }
  237. for(int i=0;i<d;i++)
  238. w[i]=2.0/(N*d*P[i][N]*P[i][N]);
  239. }
  240. /**
  241. * \brief Computes Chebyshev approximation from function values at GLL points.
  242. */
  243. template <class T, class Y>
  244. T gll2cheb(T* fn_v, int deg, int dof, T* out){//*
  245. //T eps=machine_eps<T>()*64;
  246. int d=deg+1;
  247. static std::vector<Matrix<Y> > precomp;
  248. static std::vector<Matrix<Y> > precomp_;
  249. Matrix<Y>* Mp ;
  250. Matrix<Y>* Mp_;
  251. #pragma omp critical (GLL_TO_CHEB)
  252. {
  253. if(precomp.size()<=(size_t)d){
  254. precomp .resize(d+1);
  255. precomp_.resize(d+1);
  256. std::vector<Y> x(d); //Cheb nodes.
  257. for(int i=0;i<d;i++)
  258. x[i]=-cos((i+(T)0.5)*const_pi<Y>()/d);
  259. Vector<T> w(d);
  260. Vector<T> x_legn(d); // GLL nodes.
  261. gll_quadrature(deg, &x_legn[0], &w[0]);
  262. Matrix<T> P(d,d); //GLL node 2 GLL coeff.
  263. legn_poly(deg,&x_legn[0],d,&P[0][0]);
  264. for(int i=0;i<d;i++)
  265. for(int j=0;j<d;j++)
  266. P[i][j]*=w[j]*0.5*(i<deg?(2*i+1):(i));
  267. Matrix<T> M_gll2cheb(d,d); //GLL coeff 2 cheb node.
  268. legn_poly(deg,&x[0],d,&M_gll2cheb[0][0]);
  269. Matrix<T> M_g2c; //GLL node to cheb node.
  270. M_g2c=M_gll2cheb.Transpose()*P;
  271. std::vector<Y> p(d*d);
  272. cheb_poly(deg,&x[0],d,&p[0]);
  273. for(int i=0;i<d*d;i++)
  274. p[i]=p[i]*2.0/d;
  275. Matrix<Y> Mp1(d,d,&p[0],false);
  276. Mp1=Mp1*M_g2c;
  277. Matrix<Y> Mp1_=Mp1.Transpose();
  278. precomp [d]=Mp1 ;
  279. precomp_[d]=Mp1_;
  280. }
  281. Mp =&precomp [d];
  282. Mp_=&precomp_[d];
  283. }
  284. std::vector<Y> fn_v0(d*d*d*dof);
  285. std::vector<Y> fn_v1(d*d*d);
  286. std::vector<Y> fn_v2(d*d*d);
  287. std::vector<Y> fn_v3(d*d*d);
  288. for(size_t i=0;i<(size_t)(d*d*d*dof);i++)
  289. fn_v0[i]=fn_v[i];
  290. int indx=0;
  291. for(int l=0;l<dof;l++){
  292. {
  293. Matrix<Y> M0(d*d,d,&fn_v0[d*d*d*l],false);
  294. Matrix<Y> M1(d*d,d,&fn_v1[0],false);
  295. M1=M0*(*Mp_);
  296. }
  297. {
  298. Matrix<Y> M0(d,d*d,&fn_v1[0],false);
  299. Matrix<Y> M1(d,d*d,&fn_v2[0],false);
  300. M1=(*Mp)*M0;
  301. }
  302. for(int i=0;i<d;i++){
  303. Matrix<Y> M0(d,d,&fn_v2[d*d*i],false);
  304. Matrix<Y> M1(d,d,&fn_v3[d*d*i],false);
  305. M1=(*Mp)*M0;
  306. }
  307. for(int i=0;i<d;i++)
  308. for(int j=0;j<d;j++){
  309. fn_v3[i*d+j*d*d]/=2.0;
  310. fn_v3[i+j*d*d]/=2.0;
  311. fn_v3[i+j*d]/=2.0;
  312. }
  313. Y sum=0;
  314. for(int i=0;i<d;i++)
  315. for(int j=0;i+j<d;j++)
  316. for(int k=0;i+j+k<d;k++){
  317. sum+=fabs(fn_v3[k+(j+i*d)*d]);
  318. }
  319. for(int i=0;i<d;i++)
  320. for(int j=0;i+j<d;j++)
  321. for(int k=0;i+j+k<d;k++){
  322. out[indx]=fn_v3[k+(j+i*d)*d];
  323. //if(fabs(out[indx])<eps*sum) out[indx]=0;
  324. indx++;
  325. }
  326. }
  327. return cheb_err(out,deg,dof);
  328. }
  329. /**
  330. * \brief Computes Chebyshev approximation from the input function pointer.
  331. */
  332. template <class T>
  333. T cheb_approx(T (*fn)(T,T,T), int cheb_deg, T* coord, T s, std::vector<T>& out){
  334. int d=cheb_deg+1;
  335. std::vector<T> x(d);
  336. for(int i=0;i<d;i++)
  337. x[i]=cos((i+(T)0.5)*const_pi<T>()/d);
  338. std::vector<T> p;
  339. cheb_poly(cheb_deg,&x[0],d,&p[0]);
  340. std::vector<T> x1(d);
  341. std::vector<T> x2(d);
  342. std::vector<T> x3(d);
  343. for(int i=0;i<d;i++){
  344. x1[i]=(x[i]+1.0)/2.0*s+coord[0];
  345. x2[i]=(x[i]+1.0)/2.0*s+coord[1];
  346. x3[i]=(x[i]+1.0)/2.0*s+coord[2];
  347. }
  348. std::vector<T> fn_v(d*d*d);
  349. T* fn_p=&fn_v[0];
  350. for(int i=0;i<d;i++){
  351. for(int j=0;j<d;j++){
  352. for(int k=0;k<d;k++){
  353. *fn_p=fn(x3[k],x2[j],x1[i]);
  354. fn_p++;
  355. }
  356. }
  357. }
  358. out.resize((d*(d+1)*(d+2))/6);
  359. return cheb_approx(&fn_v[0], cheb_deg, 1, &out[0]);
  360. }
  361. /**
  362. * \brief Evaluates polynomial values from input coefficients at points on
  363. * a regular grid defined by in_x, in_y, in_z the values in the input vector.
  364. */
  365. template <class T>
  366. void cheb_eval(const Vector<T>& coeff_, int cheb_deg, const std::vector<T>& in_x, const std::vector<T>& in_y, const std::vector<T>& in_z, Vector<T>& out, mem::MemoryManager* mem_mgr){
  367. size_t d=(size_t)cheb_deg+1;
  368. size_t n_coeff=(d*(d+1)*(d+2))/6;
  369. size_t dof=coeff_.Dim()/n_coeff;
  370. assert(coeff_.Dim()==dof*n_coeff);
  371. // Resize out
  372. size_t n1=in_x.size();
  373. size_t n2=in_y.size();
  374. size_t n3=in_z.size();
  375. out.Resize(n1*n2*n3*dof);
  376. if(n1==0 || n2==0 || n3==0) return;
  377. // Precomputation
  378. std::vector<T> p1(n1*d);
  379. std::vector<T> p2(n2*d);
  380. std::vector<T> p3(n3*d);
  381. cheb_poly(cheb_deg,&in_x[0],n1,&p1[0]);
  382. cheb_poly(cheb_deg,&in_y[0],n2,&p2[0]);
  383. cheb_poly(cheb_deg,&in_z[0],n3,&p3[0]);
  384. Matrix<T> Mp1(d,n1,&p1[0],false);
  385. Matrix<T> Mp2(d,n2,&p2[0],false);
  386. Matrix<T> Mp3(d,n3,&p3[0],false);
  387. // Create work buffers
  388. size_t buff_size=std::max(d,n1)*std::max(d,n2)*std::max(d,n3)*dof;
  389. T* buff=(T*)(mem_mgr?mem_mgr->malloc(2*buff_size*sizeof(T)):
  390. malloc(2*buff_size*sizeof(T)));
  391. Vector<T> v1(buff_size,buff+buff_size*0,false);
  392. Vector<T> v2(buff_size,buff+buff_size*1,false);
  393. { // Rearrange coefficients into a tensor.
  394. Vector<T> coeff(d*d*d*dof,&v1[0],false);
  395. coeff.SetZero();
  396. size_t indx=0;
  397. for(size_t l=0;l<dof;l++){
  398. for(size_t i=0;i<d;i++){
  399. for(size_t j=0;i+j<d;j++){
  400. T* coeff_ptr=&coeff[(j+(i+l*d)*d)*d];
  401. for(size_t k=0;i+j+k<d;k++){
  402. coeff_ptr[k]=coeff_[indx];
  403. indx++;
  404. }
  405. }
  406. }
  407. }
  408. }
  409. { // Apply Mp1
  410. Matrix<T> Mi ( d* d*dof, d,&v1[0],false);
  411. Matrix<T> Mo ( d* d*dof,n1,&v2[0],false);
  412. Matrix<T>::DGEMM(Mo, Mi, Mp1, 0);
  413. Matrix<T> Mo_t(n1, d* d*dof,&v1[0],false);
  414. for(size_t i=0;i<Mo.Dim(0);i++)
  415. for(size_t j=0;j<Mo.Dim(1);j++){
  416. Mo_t[j][i]=Mo[i][j];
  417. }
  418. }
  419. { // Apply Mp2
  420. Matrix<T> Mi (n1* d*dof, d,&v1[0],false);
  421. Matrix<T> Mo (n1* d*dof,n2,&v2[0],false);
  422. Matrix<T>::DGEMM(Mo, Mi, Mp2, 0);
  423. Matrix<T> Mo_t(n2,n1* d*dof,&v1[0],false);
  424. for(size_t i=0;i<Mo.Dim(0);i++)
  425. for(size_t j=0;j<Mo.Dim(1);j++){
  426. Mo_t[j][i]=Mo[i][j];
  427. }
  428. }
  429. { // Apply Mp3
  430. Matrix<T> Mi (n2*n1*dof, d,&v1[0],false);
  431. Matrix<T> Mo (n2*n1*dof,n3,&v2[0],false);
  432. Matrix<T>::DGEMM(Mo, Mi, Mp3, 0);
  433. Matrix<T> Mo_t(n3,n2*n1*dof,&v1[0],false);
  434. for(size_t i=0;i<Mo.Dim(0);i++)
  435. for(size_t j=0;j<Mo.Dim(1);j++){
  436. Mo_t[j][i]=Mo[i][j];
  437. }
  438. }
  439. { // Copy to out
  440. Matrix<T> Mo ( n3*n2*n1,dof,&v1[0],false);
  441. Matrix<T> Mo_t(dof,n3*n2*n1,&out[0],false);
  442. for(size_t i=0;i<Mo.Dim(0);i++)
  443. for(size_t j=0;j<Mo.Dim(1);j++){
  444. Mo_t[j][i]=Mo[i][j];
  445. }
  446. }
  447. // Free memory
  448. if(mem_mgr )mem_mgr->free(buff);
  449. else free(buff);
  450. }
  451. /**
  452. * \brief Evaluates polynomial values from input coefficients at points
  453. * in the coord vector.
  454. */
  455. template <class T>
  456. inline void cheb_eval(Vector<T>& coeff_, int cheb_deg, std::vector<T>& coord, Vector<T>& out){
  457. int dim=3;
  458. int d=cheb_deg+1;
  459. int n=coord.size()/dim;
  460. int dof=coeff_.Dim()/((d*(d+1)*(d+2))/6);
  461. assert(coeff_.Dim()==(size_t)(d*(d+1)*(d+2)*dof)/6);
  462. std::vector<T> coeff(d*d*d*dof);
  463. {// Rearrange data
  464. int indx=0;
  465. for(int l=0;l<dof;l++)
  466. for(int i=0;i<d;i++)
  467. for(int j=0;i+j<d;j++)
  468. for(int k=0;i+j+k<d;k++){
  469. coeff[(k+(j+(i+l*d)*d)*d)]=coeff_[indx];
  470. indx++;
  471. }
  472. }
  473. Matrix<T> coord_(n,dim,&coord[0]);
  474. coord_=coord_.Transpose();
  475. Matrix<T> px(d,n);
  476. Matrix<T> py(d,n);
  477. Matrix<T> pz(d,n);
  478. cheb_poly(cheb_deg,&(coord_[0][0]),n,&(px[0][0]));
  479. cheb_poly(cheb_deg,&(coord_[1][0]),n,&(py[0][0]));
  480. cheb_poly(cheb_deg,&(coord_[2][0]),n,&(pz[0][0]));
  481. Matrix<T> M_coeff0(d*d*dof, d, &coeff[0], false);
  482. Matrix<T> M0 = (M_coeff0 * px).Transpose(); // {n, dof*d*d}
  483. py = py.Transpose();
  484. pz = pz.Transpose();
  485. out.Resize(n*dof);
  486. for(int i=0; i<n; i++)
  487. for(int j=0; j<dof; j++){
  488. Matrix<T> M0_ (d, d, &(M0[i][ j*d*d]), false);
  489. Matrix<T> py_ (d, 1, &(py[i][ 0]), false);
  490. Matrix<T> pz_ (1, d, &(pz[i][ 0]), false);
  491. Matrix<T> M_out(1, 1, &( out[i*dof+j]), false);
  492. M_out += pz_ * M0_ * py_;
  493. }
  494. }
  495. /**
  496. * \brief Returns the values of all Chebyshev basis functions of degree up to d
  497. * evaluated at the point coord.
  498. */
  499. template <class T>
  500. inline void cheb_eval(int cheb_deg, T* coord, T* coeff0,T* buff){
  501. int d=cheb_deg+1;
  502. std::vector<T> coeff(d*d*d);
  503. T* p=&buff[0];
  504. T* p_=&buff[3*d];
  505. cheb_poly(cheb_deg,&coord[0],3,&p[0]);
  506. for(int i=0;i<d;i++){
  507. p_[i]=p[i*3];
  508. p_[i+d]=p[i*3+1];
  509. p_[i+2*d]=p[i*3+2];
  510. }
  511. T* coeff_=&buff[2*3*d];
  512. Matrix<T> v_p0 (1, d, & p_[0],false);
  513. Matrix<T> v_p1 (d, 1, & p_[d],false);
  514. Matrix<T> M_coeff_(d, d, &coeff_[0],false);
  515. M_coeff_ = v_p1 * v_p0; // */
  516. //mat::gemm(CblasRowMajor,CblasNoTrans,CblasNoTrans,d,d,1,1.0,&p_[d],1,&p_[0],d,0.0,&coeff_[0],d);
  517. Matrix<T> v_p2 (d, 1, & p_[2*d],false);
  518. Matrix<T> v_coeff_(1, d*d, &coeff_[ 0],false);
  519. Matrix<T> M_coeff (d, d*d, &coeff [ 0],false);
  520. M_coeff = v_p2 * v_coeff_; // */
  521. //mat::gemm(CblasRowMajor,CblasNoTrans,CblasNoTrans,d,d*d,1,1.0,&p_[2*d],1,&coeff_[0],d*d,0.0,&coeff[0],d*d);
  522. {// Rearrange data
  523. int indx=0;
  524. for(int i=0;i<d;i++)
  525. for(int j=0;i+j<d;j++)
  526. for(int k=0;i+j+k<d;k++){
  527. coeff0[indx]=coeff[(k+(j+i*d)*d)];
  528. indx++;
  529. }
  530. }
  531. }
  532. /**
  533. * \brief Computes a least squares solution for Chebyshev approximation over a
  534. * cube from point samples.
  535. * \param[in] deg Maximum degree of the polynomial.
  536. * \param[in] coord Coordinates of points (x,y,z interleaved).
  537. * \param[in] node_coord Coordinates of the octant.
  538. * \param[in] node_size Length of the side of the octant.
  539. * \param[out] cheb_coeff Output coefficients.
  540. */
  541. template <class T>
  542. void points2cheb(int deg, T* coord, T* val, int n, int dim, T* node_coord, T node_size, Vector<T>& cheb_coeff){
  543. if(n==0) return;
  544. int deg_=((int)(pow((T)n*6,1.0/3.0)+0.5))/2;
  545. deg_=(deg_>deg?deg:deg_);
  546. deg_=(deg_>0?deg_:1);
  547. int deg3=((deg_+1)*(deg_+2)*(deg_+3))/6;
  548. cheb_coeff.Resize(dim*((deg+1)*(deg+2)*(deg+3))/6);
  549. cheb_coeff.SetZero();
  550. //Map coordinates to unit cube
  551. std::vector<T> coord_(n*3);
  552. for(int i=0;i<n;i++){
  553. coord_[i*3 ]=(coord[i*3 ]-node_coord[0])*2.0/node_size-1.0;
  554. coord_[i*3+1]=(coord[i*3+1]-node_coord[1])*2.0/node_size-1.0;
  555. coord_[i*3+2]=(coord[i*3+2]-node_coord[2])*2.0/node_size-1.0;
  556. }
  557. //Compute the matrix M
  558. Matrix<T> M(n,deg3);
  559. std::vector<T> buff((deg_+1)*(deg_+1+3*2));
  560. for(int i=0;i<n;i++)
  561. cheb_eval(deg_,&coord_[i*3],&(M[i][0]),&buff[0]);
  562. //Compute the pinv and get the cheb_coeff.
  563. Matrix<T> M_val(n,dim,&val[0]);
  564. T eps=machine_eps<T>()*64;
  565. Matrix<T> cheb_coeff_=(M.pinv(eps)*M_val).Transpose();
  566. //Set the output
  567. int indx=0;
  568. int indx1=0;
  569. for(int l=0;l<dim;l++)
  570. for(int i=0;i <=deg;i++)
  571. for(int j=0;i+j <=deg;j++)
  572. for(int k=0;i+j+k<=deg;k++){
  573. if(i+j+k<=deg_){
  574. cheb_coeff[indx]=cheb_coeff_[0][indx1];
  575. indx1++;
  576. }else{
  577. cheb_coeff[indx]=0;
  578. }
  579. indx++;
  580. }
  581. }
  582. template <class T>
  583. void quad_rule(int n, T* x, T* w){
  584. static std::vector<Vector<T> > x_lst(10000);
  585. static std::vector<Vector<T> > w_lst(10000);
  586. assert(n<10000);
  587. bool done=false;
  588. #pragma omp critical (QUAD_RULE)
  589. if(x_lst[n].Dim()>0){
  590. Vector<T>& x_=x_lst[n];
  591. Vector<T>& w_=w_lst[n];
  592. for(int i=0;i<n;i++){
  593. x[i]=x_[i];
  594. w[i]=w_[i];
  595. }
  596. done=true;
  597. }
  598. if(done) return;
  599. Vector<T> x_(n);
  600. Vector<T> w_(n);
  601. { //Chebyshev quadrature nodes and weights
  602. for(int i=0;i<n;i++){
  603. x_[i]=-cos((T)(2.0*i+1.0)/(2.0*n)*const_pi<T>());
  604. w_[i]=0;//sqrt(1.0-x_[i]*x_[i])*const_pi<T>()/n;
  605. }
  606. Matrix<T> M(n,n);
  607. cheb_poly(n-1, &x_[0], n, &M[0][0]);
  608. for(size_t i=0;i<n;i++) M[0][i]/=2.0;
  609. std::vector<T> w_sample(n,0);
  610. for(size_t i=0;i<n;i+=2) w_sample=-((T)2.0/(n+1)/(n-1));
  611. //if(n>0) w_sample[0]=2.0;
  612. //if(n>1) w_sample[1]=0.0;
  613. //if(n>2) w_sample[2]=-((T)2.0)/3;
  614. //if(n>3) w_sample[3]=0.0;
  615. //if(n>4) w_sample[4]=-((T)2.0)/15;
  616. //if(n>5) w_sample[5]=0.0;
  617. //if(n>6) w_sample[5]=((T)64)/7-((T)96)/5+((T)36)/3-2;
  618. //if(n>7) w_sample[5]=0;
  619. //if(n>8){
  620. // T eps=machine_eps<T>()*64;
  621. // std::vector<T> qx(n-1);
  622. // std::vector<T> qw(n-1);
  623. // quad_rule(n-1, &qx[0], &qw[0]);
  624. // T err=1.0;
  625. // std::vector<T> w_prev;
  626. // for(size_t iter=1;err>eps*iter;iter*=2){
  627. // w_prev=w_sample;
  628. // w_sample.assign(n,0);
  629. // size_t N=(n-1)*iter;
  630. // std::vector<T> x_sample(N,0);
  631. // Matrix<T> M_sample(n,N);
  632. // for(size_t i=0;i<iter;i++){
  633. // for(size_t j=0;j<n-1;j++){
  634. // x_sample[j+i*(n-1)]=(2*i+qx[j]+1)/iter-1;
  635. // }
  636. // }
  637. // cheb_poly(n-1, &x_sample[0], N, &M_sample[0][0]);
  638. // for(size_t i=0;i<n;i++)
  639. // for(size_t j=0;j<iter;j++)
  640. // for(size_t k=0;k<n-1;k++){
  641. // w_sample[i]+=M_sample[i][k+j*(n-1)]*qw[k];
  642. // }
  643. // for(size_t i=0;i<n;i++) w_sample[i]/=iter;
  644. // for(size_t i=1;i<n;i+=2) w_sample[i]=0.0;
  645. // err=0;
  646. // for(size_t i=0;i<n;i++) err+=fabs(w_sample[i]-w_prev[i]);
  647. // }
  648. //}
  649. for(size_t i=0;i<n;i++)
  650. for(size_t j=0;j<n;j++){
  651. M[i][j]*=w_sample[i];
  652. }
  653. for(size_t i=0;i<n;i++)
  654. for(size_t j=0;j<n;j++){
  655. w_[j]+=M[i][j]*2/n;
  656. }
  657. }
  658. { //Trapezoidal quadrature nodes and weights
  659. //for(int i=0;i<n;i++){
  660. // x_[i]=(2.0*i+1.0)/(1.0*n)-1.0;
  661. // w_[i]=2.0/n;
  662. //}
  663. }
  664. #pragma omp critical (QUAD_RULE)
  665. { // Set x_lst, w_lst
  666. x_lst[n]=x_;
  667. w_lst[n]=w_;
  668. }
  669. quad_rule(n, x, w);
  670. }
  671. template <>
  672. void quad_rule<double>(int n, double* x, double* w){
  673. static std::vector<Vector<double> > x_lst(10000);
  674. static std::vector<Vector<double> > w_lst(10000);
  675. assert(n<10000);
  676. bool done=false;
  677. #pragma omp critical (QUAD_RULE)
  678. if(x_lst[n].Dim()>0){
  679. Vector<double>& x_=x_lst[n];
  680. Vector<double>& w_=w_lst[n];
  681. for(int i=0;i<n;i++){
  682. x[i]=x_[i];
  683. w[i]=w_[i];
  684. }
  685. done=true;
  686. }
  687. if(done) return;
  688. Vector<double> x_(n);
  689. Vector<double> w_(n);
  690. { //Gauss-Legendre quadrature nodes and weights
  691. double alpha=0.0;
  692. double beta=0.0;
  693. double a=-1.0;
  694. double b= 1.0;
  695. int kind = 1;
  696. cgqf ( n, kind, (double)alpha, (double)beta, (double)a, (double)b, &x_[0], &w_[0] );
  697. }
  698. #pragma omp critical (QUAD_RULE)
  699. { // Set x_lst, w_lst
  700. x_lst[n]=x_;
  701. w_lst[n]=w_;
  702. }
  703. quad_rule(n, x, w);
  704. }
  705. template <class T>
  706. std::vector<T> integ_pyramid(int m, T* s, T r, int nx, const Kernel<T>& kernel, int* perm){//*
  707. static mem::MemoryManager mem_mgr(16*1024*1024*sizeof(T));
  708. int ny=nx;
  709. int nz=nx;
  710. T eps=machine_eps<T>()*64;
  711. int k_dim=kernel.ker_dim[0]*kernel.ker_dim[1];
  712. std::vector<T> qp_x(nx), qw_x(nx);
  713. std::vector<T> qp_y(ny), qw_y(ny);
  714. std::vector<T> qp_z(nz), qw_z(nz);
  715. std::vector<T> p_x(nx*m);
  716. std::vector<T> p_y(ny*m);
  717. std::vector<T> p_z(nz*m);
  718. std::vector<T> x_;
  719. { // Build stack along X-axis.
  720. x_.push_back(s[0]);
  721. x_.push_back(fabs(1.0-s[0])+s[0]);
  722. x_.push_back(fabs(1.0-s[1])+s[0]);
  723. x_.push_back(fabs(1.0+s[1])+s[0]);
  724. x_.push_back(fabs(1.0-s[2])+s[0]);
  725. x_.push_back(fabs(1.0+s[2])+s[0]);
  726. std::sort(x_.begin(),x_.end());
  727. for(int i=0;i<x_.size();i++){
  728. if(x_[i]<-1.0) x_[i]=-1.0;
  729. if(x_[i]> 1.0) x_[i]= 1.0;
  730. }
  731. std::vector<T> x_new;
  732. T x_jump=fabs(1.0-s[0]);
  733. if(fabs(1.0-s[1])>eps) x_jump=std::min(x_jump,(T)fabs(1.0-s[1]));
  734. if(fabs(1.0+s[1])>eps) x_jump=std::min(x_jump,(T)fabs(1.0+s[1]));
  735. if(fabs(1.0-s[2])>eps) x_jump=std::min(x_jump,(T)fabs(1.0-s[2]));
  736. if(fabs(1.0+s[2])>eps) x_jump=std::min(x_jump,(T)fabs(1.0+s[2]));
  737. for(int k=0; k<x_.size()-1; k++){
  738. T x0=x_[k];
  739. T x1=x_[k+1];
  740. T A0=0;
  741. T A1=0;
  742. { // A0
  743. T y0=s[1]-(x0-s[0]); if(y0<-1.0) y0=-1.0; if(y0> 1.0) y0= 1.0;
  744. T y1=s[1]+(x0-s[0]); if(y1<-1.0) y1=-1.0; if(y1> 1.0) y1= 1.0;
  745. T z0=s[2]-(x0-s[0]); if(z0<-1.0) z0=-1.0; if(z0> 1.0) z0= 1.0;
  746. T z1=s[2]+(x0-s[0]); if(z1<-1.0) z1=-1.0; if(z1> 1.0) z1= 1.0;
  747. A0=(y1-y0)*(z1-z0);
  748. }
  749. { // A1
  750. T y0=s[1]-(x1-s[0]); if(y0<-1.0) y0=-1.0; if(y0> 1.0) y0= 1.0;
  751. T y1=s[1]+(x1-s[0]); if(y1<-1.0) y1=-1.0; if(y1> 1.0) y1= 1.0;
  752. T z0=s[2]-(x1-s[0]); if(z0<-1.0) z0=-1.0; if(z0> 1.0) z0= 1.0;
  753. T z1=s[2]+(x1-s[0]); if(z1<-1.0) z1=-1.0; if(z1> 1.0) z1= 1.0;
  754. A1=(y1-y0)*(z1-z0);
  755. }
  756. T V=0.5*(A0+A1)*(x1-x0);
  757. if(V<eps) continue;
  758. if(!x_new.size()) x_new.push_back(x0);
  759. x_jump=std::max(x_jump,x0-s[0]);
  760. while(s[0]+x_jump*1.5<x1){
  761. x_new.push_back(s[0]+x_jump);
  762. x_jump*=2.0;
  763. }
  764. if(x_new.back()+eps<x1) x_new.push_back(x1);
  765. }
  766. assert(x_new.size()<30);
  767. x_.swap(x_new);
  768. }
  769. Vector<T> k_out( ny*nz*k_dim,(T*)mem_mgr.malloc( ny*nz*k_dim*sizeof(T)),false); //Output of kernel evaluation.
  770. Vector<T> I0 ( ny*m *k_dim,(T*)mem_mgr.malloc( ny*m *k_dim*sizeof(T)),false);
  771. Vector<T> I1 ( m *m *k_dim,(T*)mem_mgr.malloc( m *m *k_dim*sizeof(T)),false);
  772. Vector<T> I2 (m *m *m *k_dim,(T*)mem_mgr.malloc(m *m *m *k_dim*sizeof(T)),false); I2.SetZero();
  773. if(x_.size()>1)
  774. for(int k=0; k<x_.size()-1; k++){
  775. T x0=x_[k];
  776. T x1=x_[k+1];
  777. { // Set qp_x
  778. std::vector<T> qp(nx);
  779. std::vector<T> qw(nx);
  780. quad_rule(nx,&qp[0],&qw[0]);
  781. for(int i=0; i<nx; i++)
  782. qp_x[i]=(x1-x0)*qp[i]/2.0+(x1+x0)/2.0;
  783. qw_x=qw;
  784. }
  785. cheb_poly(m-1,&qp_x[0],nx,&p_x[0]);
  786. for(int i=0; i<nx; i++){
  787. T y0=s[1]-(qp_x[i]-s[0]); if(y0<-1.0) y0=-1.0; if(y0> 1.0) y0= 1.0;
  788. T y1=s[1]+(qp_x[i]-s[0]); if(y1<-1.0) y1=-1.0; if(y1> 1.0) y1= 1.0;
  789. T z0=s[2]-(qp_x[i]-s[0]); if(z0<-1.0) z0=-1.0; if(z0> 1.0) z0= 1.0;
  790. T z1=s[2]+(qp_x[i]-s[0]); if(z1<-1.0) z1=-1.0; if(z1> 1.0) z1= 1.0;
  791. { // Set qp_y
  792. std::vector<T> qp(ny);
  793. std::vector<T> qw(ny);
  794. quad_rule(ny,&qp[0],&qw[0]);
  795. for(int j=0; j<ny; j++)
  796. qp_y[j]=(y1-y0)*qp[j]/2.0+(y1+y0)/2.0;
  797. qw_y=qw;
  798. }
  799. { // Set qp_z
  800. std::vector<T> qp(nz);
  801. std::vector<T> qw(nz);
  802. quad_rule(nz,&qp[0],&qw[0]);
  803. for(int j=0; j<nz; j++)
  804. qp_z[j]=(z1-z0)*qp[j]/2.0+(z1+z0)/2.0;
  805. qw_z=qw;
  806. }
  807. cheb_poly(m-1,&qp_y[0],ny,&p_y[0]);
  808. cheb_poly(m-1,&qp_z[0],nz,&p_z[0]);
  809. { // k_out = kernel x qw
  810. T src[3]={0,0,0};
  811. std::vector<T> trg(ny*nz*3);
  812. for(int i0=0; i0<ny; i0++){
  813. size_t indx0=i0*nz*3;
  814. for(int i1=0; i1<nz; i1++){
  815. size_t indx1=indx0+i1*3;
  816. trg[indx1+perm[0]]=(s[0]-qp_x[i ])*r*0.5*perm[1];
  817. trg[indx1+perm[2]]=(s[1]-qp_y[i0])*r*0.5*perm[3];
  818. trg[indx1+perm[4]]=(s[2]-qp_z[i1])*r*0.5*perm[5];
  819. }
  820. }
  821. {
  822. Matrix<T> k_val(ny*nz*kernel.ker_dim[0],kernel.ker_dim[1]);
  823. kernel.BuildMatrix(&src[0],1,&trg[0],ny*nz,&k_val[0][0]);
  824. Matrix<T> k_val_t(kernel.ker_dim[1],ny*nz*kernel.ker_dim[0],&k_out[0], false);
  825. k_val_t=k_val.Transpose();
  826. }
  827. for(int kk=0; kk<k_dim; kk++){
  828. for(int i0=0; i0<ny; i0++){
  829. size_t indx=(kk*ny+i0)*nz;
  830. for(int i1=0; i1<nz; i1++){
  831. k_out[indx+i1] *= qw_y[i0]*qw_z[i1];
  832. }
  833. }
  834. }
  835. }
  836. I0.SetZero();
  837. for(int kk=0; kk<k_dim; kk++){
  838. for(int i0=0; i0<ny; i0++){
  839. size_t indx0=(kk*ny+i0)*nz;
  840. size_t indx1=(kk*ny+i0)* m;
  841. for(int i2=0; i2<m; i2++){
  842. for(int i1=0; i1<nz; i1++){
  843. I0[indx1+i2] += k_out[indx0+i1]*p_z[i2*nz+i1];
  844. }
  845. }
  846. }
  847. }
  848. I1.SetZero();
  849. for(int kk=0; kk<k_dim; kk++){
  850. for(int i2=0; i2<ny; i2++){
  851. size_t indx0=(kk*ny+i2)*m;
  852. for(int i0=0; i0<m; i0++){
  853. size_t indx1=(kk* m+i0)*m;
  854. T py=p_y[i0*ny+i2];
  855. for(int i1=0; i0+i1<m; i1++){
  856. I1[indx1+i1] += I0[indx0+i1]*py;
  857. }
  858. }
  859. }
  860. }
  861. T v=(x1-x0)*(y1-y0)*(z1-z0);
  862. for(int kk=0; kk<k_dim; kk++){
  863. for(int i0=0; i0<m; i0++){
  864. T px=p_x[i+i0*nx]*qw_x[i]*v;
  865. for(int i1=0; i0+i1<m; i1++){
  866. size_t indx0= (kk*m+i1)*m;
  867. size_t indx1=((kk*m+i0)*m+i1)*m;
  868. for(int i2=0; i0+i1+i2<m; i2++){
  869. I2[indx1+i2] += I1[indx0+i2]*px;
  870. }
  871. }
  872. }
  873. }
  874. }
  875. }
  876. for(int i=0;i<m*m*m*k_dim;i++)
  877. I2[i]=I2[i]*r*r*r/64.0;
  878. if(x_.size()>1)
  879. Profile::Add_FLOP(( 2*ny*nz*m*k_dim
  880. +ny*m*(m+1)*k_dim
  881. +2*m*(m+1)*k_dim
  882. +m*(m+1)*(m+2)/3*k_dim)*nx*(x_.size()-1));
  883. std::vector<T> I2_(&I2[0], &I2[0]+I2.Dim());
  884. mem_mgr.free(&k_out[0]);
  885. mem_mgr.free(&I0 [0]);
  886. mem_mgr.free(&I1 [0]);
  887. mem_mgr.free(&I2 [0]);
  888. return I2_;
  889. }
  890. template <class T>
  891. std::vector<T> integ(int m, T* s, T r, int n, const Kernel<T>& kernel){//*
  892. //Compute integrals over pyramids in all directions.
  893. int k_dim=kernel.ker_dim[0]*kernel.ker_dim[1];
  894. T s_[3];
  895. s_[0]=s[0]*2.0/r-1.0;
  896. s_[1]=s[1]*2.0/r-1.0;
  897. s_[2]=s[2]*2.0/r-1.0;
  898. T s1[3];
  899. int perm[6];
  900. std::vector<T> U_[6];
  901. s1[0]= s_[0];s1[1]=s_[1];s1[2]=s_[2];
  902. perm[0]= 0; perm[2]= 1; perm[4]= 2;
  903. perm[1]= 1; perm[3]= 1; perm[5]= 1;
  904. U_[0]=integ_pyramid<T>(m,s1,r,n,kernel,perm);
  905. s1[0]=-s_[0];s1[1]=s_[1];s1[2]=s_[2];
  906. perm[0]= 0; perm[2]= 1; perm[4]= 2;
  907. perm[1]=-1; perm[3]= 1; perm[5]= 1;
  908. U_[1]=integ_pyramid<T>(m,s1,r,n,kernel,perm);
  909. s1[0]= s_[1];s1[1]=s_[0];s1[2]=s_[2];
  910. perm[0]= 1; perm[2]= 0; perm[4]= 2;
  911. perm[1]= 1; perm[3]= 1; perm[5]= 1;
  912. U_[2]=integ_pyramid<T>(m,s1,r,n,kernel,perm);
  913. s1[0]=-s_[1];s1[1]=s_[0];s1[2]=s_[2];
  914. perm[0]= 1; perm[2]= 0; perm[4]= 2;
  915. perm[1]=-1; perm[3]= 1; perm[5]= 1;
  916. U_[3]=integ_pyramid<T>(m,s1,r,n,kernel,perm);
  917. s1[0]= s_[2];s1[1]=s_[0];s1[2]=s_[1];
  918. perm[0]= 2; perm[2]= 0; perm[4]= 1;
  919. perm[1]= 1; perm[3]= 1; perm[5]= 1;
  920. U_[4]=integ_pyramid<T>(m,s1,r,n,kernel,perm);
  921. s1[0]=-s_[2];s1[1]=s_[0];s1[2]=s_[1];
  922. perm[0]= 2; perm[2]= 0; perm[4]= 1;
  923. perm[1]=-1; perm[3]= 1; perm[5]= 1;
  924. U_[5]=integ_pyramid<T>(m,s1,r,n,kernel,perm);
  925. std::vector<T> U; U.assign(m*m*m*k_dim,0);
  926. for(int kk=0; kk<k_dim; kk++){
  927. for(int i=0;i<m;i++){
  928. for(int j=0;j<m;j++){
  929. for(int k=0;k<m;k++){
  930. U[kk*m*m*m + k*m*m + j*m + i]+=U_[0][kk*m*m*m + i*m*m + j*m + k];
  931. U[kk*m*m*m + k*m*m + j*m + i]+=U_[1][kk*m*m*m + i*m*m + j*m + k]*(i%2?-1.0:1.0);
  932. }
  933. }
  934. }
  935. }
  936. for(int kk=0; kk<k_dim; kk++){
  937. for(int i=0; i<m; i++){
  938. for(int j=0; j<m; j++){
  939. for(int k=0; k<m; k++){
  940. U[kk*m*m*m + k*m*m + i*m + j]+=U_[2][kk*m*m*m + i*m*m + j*m + k];
  941. U[kk*m*m*m + k*m*m + i*m + j]+=U_[3][kk*m*m*m + i*m*m + j*m + k]*(i%2?-1.0:1.0);
  942. }
  943. }
  944. }
  945. }
  946. for(int kk=0; kk<k_dim; kk++){
  947. for(int i=0; i<m; i++){
  948. for(int j=0; j<m; j++){
  949. for(int k=0; k<m; k++){
  950. U[kk*m*m*m + i*m*m + k*m + j]+=U_[4][kk*m*m*m + i*m*m + j*m + k];
  951. U[kk*m*m*m + i*m*m + k*m + j]+=U_[5][kk*m*m*m + i*m*m + j*m + k]*(i%2?-1.0:1.0);
  952. }
  953. }
  954. }
  955. }
  956. return U;
  957. }
  958. /**
  959. * \brief
  960. * \param[in] r Length of the side of cubic region.
  961. */
  962. template <class T>
  963. std::vector<T> cheb_integ(int m, T* s_, T r_, const Kernel<T>& kernel){
  964. T eps=machine_eps<T>();
  965. T r=r_;
  966. T s[3]={s_[0],s_[1],s_[2]};
  967. int n=m+1;
  968. T err=1.0;
  969. int k_dim=kernel.ker_dim[0]*kernel.ker_dim[1];
  970. std::vector<T> U=integ<T>(m+1,s,r,n,kernel);
  971. std::vector<T> U_;
  972. while(err>eps*n*n){
  973. n=(int)round(n*1.3);
  974. if(n>300){
  975. std::cout<<"Cheb_Integ::Failed to converge.[";
  976. std::cout<<((double)err )<<",";
  977. std::cout<<((double)s[0])<<",";
  978. std::cout<<((double)s[1])<<",";
  979. std::cout<<((double)s[2])<<"]\n";
  980. break;
  981. }
  982. U_=integ<T>(m+1,s,r,n,kernel);
  983. err=0;
  984. for(int i=0;i<(m+1)*(m+1)*(m+1)*k_dim;i++)
  985. if(fabs(U[i]-U_[i])>err)
  986. err=fabs(U[i]-U_[i]);
  987. U=U_;
  988. }
  989. std::vector<T> U0(((m+1)*(m+2)*(m+3)*k_dim)/6);
  990. {// Rearrange data
  991. int indx=0;
  992. const int* ker_dim=kernel.ker_dim;
  993. for(int l0=0;l0<ker_dim[0];l0++)
  994. for(int l1=0;l1<ker_dim[1];l1++)
  995. for(int i=0;i<=m;i++)
  996. for(int j=0;i+j<=m;j++)
  997. for(int k=0;i+j+k<=m;k++){
  998. U0[indx]=U[(k+(j+(i+(l0*ker_dim[1]+l1)*(m+1))*(m+1))*(m+1))];
  999. indx++;
  1000. }
  1001. }
  1002. return U0;
  1003. }
  1004. template <class T>
  1005. std::vector<T> cheb_nodes(int deg, int dim){
  1006. int d=deg+1;
  1007. std::vector<T> x(d);
  1008. for(int i=0;i<d;i++)
  1009. x[i]=-cos((i+(T)0.5)*const_pi<T>()/d)*0.5+0.5;
  1010. if(dim==1) return x;
  1011. int n1=(int)(pow((T)d,dim)+0.5);
  1012. std::vector<T> y(n1*dim);
  1013. for(int i=0;i<dim;i++){
  1014. int n2=(int)(pow((T)d,i)+0.5);
  1015. for(int j=0;j<n1;j++){
  1016. y[j*dim+i]=x[(j/n2)%d];
  1017. }
  1018. }
  1019. return y;
  1020. }
  1021. template <class T>
  1022. void cheb_diff(const Vector<T>& A, int deg, int diff_dim, Vector<T>& B, mem::MemoryManager* mem_mgr=NULL){
  1023. size_t d=deg+1;
  1024. // Precompute
  1025. static Matrix<T> M;
  1026. #pragma omp critical (CHEB_DIFF1)
  1027. if(M.Dim(0)!=(size_t)d){
  1028. M.Resize(d,d);
  1029. for(size_t i=0;i<d;i++){
  1030. for(size_t j=0;j<d;j++) M[j][i]=0;
  1031. for(size_t j=1-(i%2);j<i;j=j+2){
  1032. M[j][i]=2*i*2;
  1033. }
  1034. if(i%2==1) M[0][i]-=i*2;
  1035. }
  1036. }
  1037. // Create work buffers
  1038. size_t buff_size=A.Dim();
  1039. T* buff=(T*)(mem_mgr?mem_mgr->malloc(2*buff_size*sizeof(T)):
  1040. malloc(2*buff_size*sizeof(T)));
  1041. T* buff1=buff+buff_size*0;
  1042. T* buff2=buff+buff_size*1;
  1043. size_t n1=(size_t)(pow((T)d,diff_dim)+0.5);
  1044. size_t n2=A.Dim()/(n1*d);
  1045. for(size_t k=0;k<n2;k++){ // Rearrange A to make diff_dim the last array dimension
  1046. Matrix<T> Mi(d, n1, &A[d*n1*k],false);
  1047. Matrix<T> Mo(d,A.Dim()/d,&buff1[ n1*k],false);
  1048. for(size_t i=0;i< d;i++)
  1049. for(size_t j=0;j<n1;j++){
  1050. Mo[i][j]=Mi[i][j];
  1051. }
  1052. }
  1053. { // Apply M
  1054. Matrix<T> Mi(d,A.Dim()/d,&buff1[0],false);
  1055. Matrix<T> Mo(d,A.Dim()/d,&buff2[0],false);
  1056. Matrix<T>::DGEMM(Mo, M, Mi, 0);
  1057. }
  1058. for(size_t k=0;k<n2;k++){ // Rearrange and write output to B
  1059. Matrix<T> Mi(d,A.Dim()/d,&buff2[ n1*k],false);
  1060. Matrix<T> Mo(d, n1, &B[d*n1*k],false);
  1061. for(size_t i=0;i< d;i++)
  1062. for(size_t j=0;j<n1;j++){
  1063. Mo[i][j]=Mi[i][j];
  1064. }
  1065. }
  1066. // Free memory
  1067. if(mem_mgr )mem_mgr->free(buff);
  1068. else free(buff);
  1069. }
  1070. template <class T>
  1071. void cheb_grad(const Vector<T>& A, int deg, Vector<T>& B, mem::MemoryManager* mem_mgr){
  1072. size_t dim=3;
  1073. size_t d=(size_t)deg+1;
  1074. size_t n_coeff =(d*(d+1)*(d+2))/6;
  1075. size_t n_coeff_=(size_t)(pow((T)d,dim)+0.5);
  1076. size_t dof=A.Dim()/n_coeff;
  1077. // Create work buffers
  1078. T* buff=(T*)(mem_mgr?mem_mgr->malloc(2*n_coeff_*dof*sizeof(T)):
  1079. malloc(2*n_coeff_*dof*sizeof(T)));
  1080. Vector<T> A_(n_coeff_*dof,buff+n_coeff_*0); A_.SetZero();
  1081. Vector<T> B_(n_coeff_*dof,buff+n_coeff_*1); B_.SetZero();
  1082. {// Rearrange data
  1083. size_t indx=0;
  1084. for(size_t l=0;l<dof;l++){
  1085. for(size_t i=0;i<d;i++){
  1086. for(size_t j=0;i+j<d;j++){
  1087. T* A_ptr=&A_[(j+(i+l*d)*d)*d];
  1088. for(size_t k=0;i+j+k<d;k++){
  1089. A_ptr[k]=A[indx];
  1090. indx++;
  1091. }
  1092. }
  1093. }
  1094. }
  1095. }
  1096. B.Resize(A.Dim()*dim);
  1097. for(size_t q=0;q<dim;q++){
  1098. // Compute derivative in direction q
  1099. cheb_diff(A_,deg,q,B_);
  1100. for(size_t l=0;l<dof;l++){// Rearrange data
  1101. size_t indx=(q+l*dim)*n_coeff;
  1102. for(size_t i=0;i<d;i++){
  1103. for(size_t j=0;i+j<d;j++){
  1104. T* B_ptr=&B_[(j+(i+l*d)*d)*d];
  1105. for(size_t k=0;i+j+k<d;k++){
  1106. B[indx]=B_ptr[k];
  1107. indx++;
  1108. }
  1109. }
  1110. }
  1111. }
  1112. }
  1113. // Free memory
  1114. if(mem_mgr )mem_mgr->free(buff);
  1115. else free(buff);
  1116. }
  1117. template <class T>
  1118. void cheb_div(T* A_, int deg, T* B_){
  1119. int dim=3;
  1120. int d=deg+1;
  1121. int n1 =(int)(pow((T)d,dim)+0.5);
  1122. Vector<T> A(n1*dim); A.SetZero();
  1123. Vector<T> B(n1 ); B.SetZero();
  1124. {// Rearrange data
  1125. int indx=0;
  1126. for(int l=0;l<dim;l++)
  1127. for(int i=0;i<d;i++)
  1128. for(int j=0;i+j<d;j++)
  1129. for(int k=0;i+j+k<d;k++){
  1130. A[k+(j+(i+l*d)*d)*d]=A_[indx];
  1131. indx++;
  1132. }
  1133. }
  1134. Matrix<T> MB(n1,1,&B[0],false);
  1135. Matrix<T> MC(n1,1);
  1136. for(int i=0;i<3;i++){
  1137. {
  1138. Vector<T> A_vec(n1,&A[n1*i],false);
  1139. Vector<T> B_vec(n1,MC[0],false);
  1140. cheb_diff(A_vec,3,i,B_vec);
  1141. }
  1142. MB+=MC;
  1143. }
  1144. {// Rearrange data
  1145. int indx=0;
  1146. for(int i=0;i<d;i++)
  1147. for(int j=0;i+j<d;j++)
  1148. for(int k=0;i+j+k<d;k++){
  1149. B_[indx]=B[k+(j+i*d)*d];
  1150. indx++;
  1151. }
  1152. }
  1153. }
  1154. template <class T>
  1155. void cheb_curl(T* A_, int deg, T* B_){
  1156. int dim=3;
  1157. int d=deg+1;
  1158. int n1 =(int)(pow((T)d,dim)+0.5);
  1159. Vector<T> A(n1*dim); A.SetZero();
  1160. Vector<T> B(n1*dim); B.SetZero();
  1161. {// Rearrange data
  1162. int indx=0;
  1163. for(int l=0;l<dim;l++)
  1164. for(int i=0;i<d;i++)
  1165. for(int j=0;i+j<d;j++)
  1166. for(int k=0;i+j+k<d;k++){
  1167. A[k+(j+(i+l*d)*d)*d]=A_[indx];
  1168. indx++;
  1169. }
  1170. }
  1171. Matrix<T> MC1(n1,1);
  1172. Matrix<T> MC2(n1,1);
  1173. for(int i=0;i<3;i++){
  1174. Matrix<T> MB(n1,1,&B[n1*i],false);
  1175. int j1=(i+1)%3;
  1176. int j2=(i+2)%3;
  1177. {
  1178. Vector<T> A1(n1,&A[n1*j1],false);
  1179. Vector<T> A2(n1,&A[n1*j2],false);
  1180. Vector<T> B1(n1,MC1[0],false);
  1181. Vector<T> B2(n1,MC2[0],false);
  1182. cheb_diff(A1,deg,j2,B2);
  1183. cheb_diff(A1,deg,j1,B2);
  1184. }
  1185. MB=MC2;
  1186. MB-=MC1;
  1187. }
  1188. {// Rearrange data
  1189. int indx=0;
  1190. for(int l=0;l<dim;l++)
  1191. for(int i=0;i<d;i++)
  1192. for(int j=0;i+j<d;j++)
  1193. for(int k=0;i+j+k<d;k++){
  1194. B_[indx]=B[k+(j+(i+l*d)*d)*d];
  1195. indx++;
  1196. }
  1197. }
  1198. }
  1199. //TODO: Fix number of cheb_coeff to (d+1)*(d+2)*(d+3)/6 for the following functions.
  1200. template <class T>
  1201. void cheb_laplacian(T* A, int deg, T* B){
  1202. int dim=3;
  1203. int d=deg+1;
  1204. int n1=(int)(pow((T)d,dim)+0.5);
  1205. T* C1=new T[n1];
  1206. T* C2=new T[n1];
  1207. Matrix<T> M_(1,n1,C2,false);
  1208. for(int i=0;i<3;i++){
  1209. Matrix<T> M (1,n1,&B[n1*i],false);
  1210. for(int j=0;j<n1;j++) M[0][j]=0;
  1211. for(int j=0;j<3;j++){
  1212. cheb_diff(&A[n1*i],deg,3,j,C1);
  1213. cheb_diff( C1 ,deg,3,j,C2);
  1214. M+=M_;
  1215. }
  1216. }
  1217. delete[] C1;
  1218. delete[] C2;
  1219. }
  1220. /*
  1221. * \brief Computes image of the chebyshev interpolation along the specified axis.
  1222. */
  1223. template <class T>
  1224. void cheb_img(T* A, T* B, int deg, int dir, bool neg_){
  1225. int d=deg+1;
  1226. int n1=(int)(pow((T)d,3-dir)+0.5);
  1227. int n2=(int)(pow((T)d, dir)+0.5);
  1228. int indx;
  1229. T sgn,neg;
  1230. neg=(T)(neg_?-1.0:1.0);
  1231. for(int i=0;i<n1;i++){
  1232. indx=i%d;
  1233. sgn=(T)(indx%2?-neg:neg);
  1234. for(int j=0;j<n2;j++){
  1235. B[i*n2+j]=sgn*A[i*n2+j];
  1236. }
  1237. }
  1238. }
  1239. }//end namespace