cheb_node.txx 12 KB

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