cheb_utils.txx 35 KB

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