cheb_utils.txx 30 KB

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