cheb_node.txx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /**
  2. * \file cheb_node.cpp
  3. * \author Dhairya Malhotra, dhairya.malhotra@gmail.com
  4. * \date 1-22-2010
  5. * \brief This file contains the implementation of the class Cheb_Node.
  6. */
  7. #include <iostream>
  8. #include <matrix.hpp>
  9. #include <omp.h>
  10. #include <cheb_utils.hpp>
  11. namespace pvfmm{
  12. template <class Real_t>
  13. Cheb_Node<Real_t>::~Cheb_Node(){}
  14. template <class Real_t>
  15. void Cheb_Node<Real_t>::Initialize(TreeNode* parent_, int path2node_, TreeNode::NodeData* data_) {
  16. MPI_Node<Real_t>::Initialize(parent_,path2node_,data_);
  17. //Set Cheb_Node specific data.
  18. NodeData* cheb_data=dynamic_cast<NodeData*>(data_);
  19. Cheb_Node<Real_t>* parent=dynamic_cast<Cheb_Node<Real_t>*>(this->Parent());
  20. if(cheb_data!=NULL){
  21. cheb_deg=cheb_data->cheb_deg;
  22. input_fn=cheb_data->input_fn;
  23. data_dof=cheb_data->data_dof;
  24. tol=cheb_data->tol;
  25. }else if(parent!=NULL){
  26. cheb_deg=parent->cheb_deg;
  27. input_fn=parent->input_fn;
  28. data_dof=parent->data_dof;
  29. tol=parent->tol;
  30. }
  31. //Compute Chebyshev approximation.
  32. if(this->IsLeaf() && !this->IsGhost()){
  33. if(input_fn!=NULL && data_dof>0){
  34. Real_t s=pow(0.5,this->Depth());
  35. int n1=(int)(pow((Real_t)(cheb_deg+1),this->Dim())+0.5);
  36. std::vector<Real_t> coord=cheb_nodes<Real_t>(cheb_deg,this->Dim());
  37. for(int i=0;i<n1;i++){
  38. coord[i*3+0]=coord[i*3+0]*s+this->Coord()[0];
  39. coord[i*3+1]=coord[i*3+1]*s+this->Coord()[1];
  40. coord[i*3+2]=coord[i*3+2]*s+this->Coord()[2];
  41. }
  42. std::vector<Real_t> input_val(n1*data_dof);
  43. input_fn(&coord[0],n1,&input_val[0]);
  44. Matrix<Real_t> M_val(n1,data_dof,&input_val[0],false);
  45. M_val=M_val.Transpose();
  46. cheb_coeff.Resize(((cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3))/6*data_dof); cheb_coeff.SetZero();
  47. cheb_approx<Real_t,Real_t>(&input_val[0], cheb_deg, data_dof, &cheb_coeff[0]);
  48. }else if(this->cheb_value.Dim()>0){
  49. size_t n_ptr=this->cheb_coord.Dim()/this->Dim();
  50. assert(n_ptr*data_dof==this->cheb_value.Dim());
  51. points2cheb<Real_t>(cheb_deg,&(this->cheb_coord[0]),&(this->cheb_value[0]),
  52. this->cheb_coord.Dim()/this->Dim(),data_dof,this->Coord(),
  53. 1.0/(1UL<<this->Depth()), cheb_coeff);
  54. }
  55. }
  56. }
  57. template <class Real_t>
  58. void Cheb_Node<Real_t>::ClearData(){
  59. ChebData().Resize(0);
  60. MPI_Node<Real_t>::ClearData();
  61. }
  62. template <class Real_t>
  63. TreeNode* Cheb_Node<Real_t>::NewNode(TreeNode* n_){
  64. Cheb_Node<Real_t>* n=(n_==NULL?new Cheb_Node<Real_t>():static_cast<Cheb_Node<Real_t>*>(n_));
  65. n->cheb_deg=cheb_deg;
  66. n->input_fn=input_fn;
  67. n->data_dof=data_dof;
  68. n->tol=tol;
  69. return MPI_Node<Real_t>::NewNode(n);
  70. }
  71. template <class Real_t>
  72. bool Cheb_Node<Real_t>::SubdivCond(){
  73. // Do not subdivide beyond max_depth
  74. if(this->Depth()>=this->max_depth-1) return false;
  75. if(!this->IsLeaf()){ // If has non-leaf children, then return true.
  76. int n=(1UL<<this->Dim());
  77. for(int i=0;i<n;i++){
  78. Cheb_Node<Real_t>* ch=static_cast<Cheb_Node<Real_t>*>(this->Child(i));
  79. assert(ch!=NULL); //This should never happen
  80. if(!ch->IsLeaf() || ch->IsGhost()) return true;
  81. }
  82. }
  83. else{ // Do not refine ghost leaf nodes.
  84. if(this->IsGhost()) return false;
  85. }
  86. if(MPI_Node<Real_t>::SubdivCond()) return true;
  87. if(!this->IsLeaf()){
  88. std::vector<Real_t> val((cheb_deg+1)*(cheb_deg+1)*(cheb_deg+1)*data_dof);
  89. std::vector<Real_t> x=cheb_nodes<Real_t>(cheb_deg,1);
  90. std::vector<Real_t> y=x;
  91. std::vector<Real_t> z=x;
  92. Real_t s=pow(0.5,this->Depth());
  93. Real_t* coord=this->Coord();
  94. for(size_t i=0;i<x.size();i++){
  95. x[i]=x[i]*s+coord[0];
  96. y[i]=y[i]*s+coord[1];
  97. z[i]=z[i]*s+coord[2];
  98. }
  99. read_val(x,y,z, cheb_deg+1, cheb_deg+1, cheb_deg+1, &val[0]);
  100. std::vector<Real_t> tmp_coeff(data_dof*((cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3))/6);
  101. cheb_approx<Real_t,Real_t>(&val[0],cheb_deg,data_dof,&tmp_coeff[0]);
  102. return (cheb_err(&(tmp_coeff[0]),cheb_deg,data_dof)>tol);
  103. }else{
  104. assert(cheb_coeff.Dim()>0);
  105. Real_t err=cheb_err(&(cheb_coeff[0]),cheb_deg,data_dof);
  106. return (err>tol);
  107. }
  108. }
  109. template <class Real_t>
  110. void Cheb_Node<Real_t>::Subdivide() {
  111. if(!this->IsLeaf()) return;
  112. MPI_Node<Real_t>::Subdivide();
  113. if(cheb_deg<0 || cheb_coeff.Dim()==0 || input_fn!=NULL) return;
  114. std::vector<Real_t> x(cheb_deg+1);
  115. std::vector<Real_t> y(cheb_deg+1);
  116. std::vector<Real_t> z(cheb_deg+1);
  117. Vector<Real_t> cheb_node=cheb_nodes<Real_t>(cheb_deg,1);
  118. Vector<Real_t> val((size_t)pow(cheb_deg+1,this->Dim())*data_dof);
  119. Vector<Real_t> child_cheb_coeff[8];
  120. int n=(1UL<<this->Dim());
  121. for(int i=0;i<n;i++){
  122. Real_t coord[3]={((i )%2?0:-1.0),
  123. ((i/2)%2?0:-1.0),
  124. ((i/4)%2?0:-1.0)};
  125. for(int j=0;j<=cheb_deg;j++){
  126. x[j]=cheb_node[j]+coord[0];
  127. y[j]=cheb_node[j]+coord[1];
  128. z[j]=cheb_node[j]+coord[2];
  129. }
  130. cheb_eval(cheb_coeff, cheb_deg, x, y, z, val);
  131. assert(val.Dim()==pow(cheb_deg+1,this->Dim())*data_dof);
  132. child_cheb_coeff[i].Resize(data_dof*((cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3))/6);
  133. cheb_approx<Real_t,Real_t>(&val[0],cheb_deg,data_dof,&(child_cheb_coeff[i][0]));
  134. Cheb_Node<Real_t>* child=static_cast<Cheb_Node<Real_t>*>(this->Child(i));
  135. child->cheb_coeff=child_cheb_coeff[i];
  136. assert(child->cheb_deg==cheb_deg);
  137. assert(child->input_fn==input_fn);
  138. assert(child->tol==tol);
  139. }
  140. }
  141. template <class Real_t>
  142. void Cheb_Node<Real_t>::Truncate() {
  143. if(cheb_deg<0 || this->IsLeaf())
  144. return MPI_Node<Real_t>::Truncate();
  145. std::vector<Real_t> cheb_node=cheb_nodes<Real_t>(cheb_deg,1);
  146. std::vector<Real_t> x=cheb_node;
  147. std::vector<Real_t> y=cheb_node;
  148. std::vector<Real_t> z=cheb_node;
  149. std::vector<Real_t> val((cheb_deg+1)*(cheb_deg+1)*(cheb_deg+1)*data_dof);
  150. Real_t s=pow(0.5,this->Depth());
  151. Real_t* coord=this->Coord();
  152. for(size_t i=0;i<x.size();i++){
  153. x[i]=x[i]*s+coord[0];
  154. y[i]=y[i]*s+coord[1];
  155. z[i]=z[i]*s+coord[2];
  156. }
  157. read_val(x,y,z, cheb_deg+1, cheb_deg+1, cheb_deg+1, &val[0]);
  158. cheb_coeff.Resize(data_dof*((cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3))/6);
  159. cheb_approx<Real_t,Real_t>(&val[0],cheb_deg,data_dof,&cheb_coeff[0]);
  160. MPI_Node<Real_t>::Truncate();
  161. }
  162. template <class Real_t>
  163. PackedData Cheb_Node<Real_t>::Pack(bool ghost, void* buff_ptr, size_t offset) {
  164. return MPI_Node<Real_t>::Pack(ghost,buff_ptr, offset);
  165. }
  166. template <class Real_t>
  167. void Cheb_Node<Real_t>::Unpack(PackedData p0, bool own_data) {
  168. MPI_Node<Real_t>::Unpack(p0, own_data);
  169. }
  170. template <class Real_t>
  171. void Cheb_Node<Real_t>::VTU_Data(std::vector<Real_t>& coord, std::vector<Real_t>& value, std::vector<int32_t>& connect, std::vector<int32_t>& offset, std::vector<uint8_t>& types, int lod){
  172. //for(size_t i=0;i<this->pt_coord.Dim();i++) coord.push_back(this->pt_coord[i]);
  173. //for(size_t i=0;i<this->pt_value.Dim();i++) value.push_back(this->pt_value[i]);
  174. Real_t* c=this->Coord();
  175. Real_t s=pow(0.5,this->Depth());
  176. size_t point_cnt=coord.size()/COORD_DIM;
  177. int gridpt_cnt;
  178. std::vector<Real_t> grid_pts;
  179. {
  180. int cheb_deg=lod;
  181. std::vector<Real_t> cheb_node_=cheb_nodes<Real_t>(cheb_deg,1);
  182. gridpt_cnt=cheb_node_.size()+2;
  183. grid_pts.resize(gridpt_cnt);
  184. for(size_t i=0;i<cheb_node_.size();i++) grid_pts[i+1]=cheb_node_[i];
  185. grid_pts[0]=0.0; grid_pts[gridpt_cnt-1]=1.0;
  186. }
  187. for(int i0=0;i0<gridpt_cnt;i0++)
  188. for(int i1=0;i1<gridpt_cnt;i1++)
  189. for(int i2=0;i2<gridpt_cnt;i2++){
  190. coord.push_back(c[0]+grid_pts[i2]*s);
  191. coord.push_back(c[1]+grid_pts[i1]*s);
  192. coord.push_back(c[2]+grid_pts[i0]*s);
  193. for(int j=0;j<data_dof;j++) value.push_back(0.0);
  194. }
  195. for(int i0=0;i0<(gridpt_cnt-1);i0++)
  196. for(int i1=0;i1<(gridpt_cnt-1);i1++)
  197. for(int i2=0;i2<(gridpt_cnt-1);i2++){
  198. for(int j0=0;j0<2;j0++)
  199. for(int j1=0;j1<2;j1++)
  200. for(int j2=0;j2<2;j2++)
  201. connect.push_back(point_cnt + ((i0+j0)*gridpt_cnt + (i1+j1))*gridpt_cnt + (i2+j2)*1);
  202. offset.push_back(connect.size());
  203. types.push_back(11);
  204. }
  205. {// Set point values.
  206. Real_t* val_ptr=&value[point_cnt*data_dof];
  207. std::vector<Real_t> x(gridpt_cnt);
  208. std::vector<Real_t> y(gridpt_cnt);
  209. std::vector<Real_t> z(gridpt_cnt);
  210. for(int i=0;i<gridpt_cnt;i++){
  211. x[i]=c[0]+s*grid_pts[i];
  212. y[i]=c[1]+s*grid_pts[i];
  213. z[i]=c[2]+s*grid_pts[i];
  214. }
  215. this->ReadVal(x, y, z, val_ptr);
  216. //Rearrrange data
  217. //(x1,x2,x3,...,y1,y2,...z1,...) => (x1,y1,z1,x2,y2,z2,...)
  218. Matrix<Real_t> M(data_dof,gridpt_cnt*gridpt_cnt*gridpt_cnt,val_ptr,false);
  219. M=M.Transpose();
  220. }
  221. }
  222. template <class Real_t>
  223. void Cheb_Node<Real_t>::Gradient(){
  224. int dim=3;//this->Dim();
  225. if(this->IsLeaf() && ChebData().Dim()>0){
  226. int n3=((cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3))/6;
  227. Vector<Real_t> coeff(ChebData().Dim()*dim);
  228. for(int i=0;i<data_dof;i++)
  229. cheb_grad(&(ChebData()[n3*i]),cheb_deg,&coeff[n3*i*dim]);
  230. ChebData().Swap(coeff);
  231. Real_t scale=pow(2,this->depth);
  232. for(size_t i=0;i<ChebData().Dim();i++)
  233. ChebData()[i]*=scale;
  234. }
  235. data_dof*=3;
  236. }
  237. template <class Real_t>
  238. void Cheb_Node<Real_t>::Divergence(){
  239. int dim=3;//this->Dim();
  240. if(this->IsLeaf() && ChebData().Dim()>0){
  241. assert(data_dof%3==0);
  242. int n3=((cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3))/6;
  243. Vector<Real_t> coeff(ChebData().Dim()/dim);
  244. for(int i=0;i<data_dof;i=i+dim)
  245. cheb_div(&(ChebData()[n3*i]),cheb_deg,&coeff[n3*(i/dim)]);
  246. ChebData().Swap(coeff);
  247. Real_t scale=pow(2,this->depth);
  248. for(size_t i=0;i<ChebData().Dim();i++)
  249. ChebData()[i]*=scale;
  250. }
  251. data_dof/=dim;
  252. }
  253. template <class Real_t>
  254. void Cheb_Node<Real_t>::Curl(){
  255. int dim=3;//this->Dim();
  256. if(this->IsLeaf() && ChebData().Dim()>0){
  257. assert(data_dof%dim==0);
  258. int n3=((cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3))/6;
  259. Vector<Real_t> coeff(ChebData().Dim());
  260. for(int i=0;i<data_dof;i=i+dim)
  261. cheb_curl(&(ChebData()[n3*i]),cheb_deg,&coeff[n3*i]);
  262. ChebData().Swap(coeff);
  263. Real_t scale=pow(2,this->depth);
  264. for(size_t i=0;i<ChebData().Dim();i++)
  265. ChebData()[i]*=scale;
  266. }
  267. }
  268. template <class Real_t>
  269. void Cheb_Node<Real_t>::read_val(std::vector<Real_t> x,std::vector<Real_t> y, std::vector<Real_t> z, int nx, int ny, int nz, Real_t* val, bool show_ghost/*=true*/){
  270. if(cheb_deg<0) return;
  271. Real_t s=0.5*pow(0.5,this->Depth());
  272. Real_t s_inv=1/s;
  273. if(this->IsLeaf()){
  274. if(cheb_coeff.Dim()!=(size_t)((cheb_deg+1)*(cheb_deg+2)*(cheb_deg+3))/6*data_dof
  275. || (this->IsGhost() && !show_ghost)) return; Vector<Real_t> out;
  276. std::vector<Real_t> x_=x;
  277. std::vector<Real_t> y_=y;
  278. std::vector<Real_t> z_=z;
  279. for(size_t i=0;i<x.size();i++)
  280. x_[i]=(x[i]-this->Coord()[0])*s_inv-1.0;
  281. for(size_t i=0;i<y.size();i++)
  282. y_[i]=(y[i]-this->Coord()[1])*s_inv-1.0;
  283. for(size_t i=0;i<z.size();i++)
  284. z_[i]=(z[i]-this->Coord()[2])*s_inv-1.0;
  285. cheb_eval(cheb_coeff, cheb_deg, x_, y_, z_, out);
  286. for(int l=0;l<data_dof;l++)
  287. for(size_t i=0;i<x.size();i++)
  288. for(size_t j=0;j<y.size();j++)
  289. for(size_t k=0;k<z.size();k++){
  290. val[i+(j+(k+l*nz)*ny)*nx]=out[i+(j+(k+l*z.size())*y.size())*x.size()];
  291. }
  292. return;
  293. }
  294. Real_t coord_[3]={this->Coord()[0]+s, this->Coord()[1]+s, this->Coord()[2]+s};
  295. Real_t* indx[3]={&(std::lower_bound(x.begin(),x.end(),coord_[0])[0]),
  296. &(std::lower_bound(y.begin(),y.end(),coord_[1])[0]),
  297. &(std::lower_bound(z.begin(),z.end(),coord_[2])[0])};
  298. std::vector<Real_t> x1[2]={std::vector<Real_t>(&(x.begin()[0]),indx[0]),std::vector<Real_t>(indx[0],&(x.end()[0]))};
  299. std::vector<Real_t> y1[2]={std::vector<Real_t>(&(y.begin()[0]),indx[1]),std::vector<Real_t>(indx[1],&(y.end()[0]))};
  300. std::vector<Real_t> z1[2]={std::vector<Real_t>(&(z.begin()[0]),indx[2]),std::vector<Real_t>(indx[2],&(z.end()[0]))};
  301. for(int i=0;i<8;i++){
  302. std::vector<Real_t>& x1_=x1[i%2];
  303. std::vector<Real_t>& y1_=y1[(i/2)%2];
  304. std::vector<Real_t>& z1_=z1[(i/4)%2];
  305. if(x1_.size()>0 && y1_.size()>0 && z1_.size()>0){
  306. static_cast<Cheb_Node<Real_t>*>(this->Child(i))->read_val(x1_,y1_,z1_,nx,ny,nz,&val[(i%2?indx[0]-&x[0]:0)+((i/2)%2?indx[1]-&y[0]:0)*nx+((i/4)%2?indx[2]-&z[0]:0)*nx*ny],show_ghost);
  307. }
  308. }
  309. }
  310. }//end namespace