mpi_node.txx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /**
  2. * \file mpi_node.txx
  3. * \author Dhairya Malhotra, dhairya.malhotra@gmail.com
  4. * \date 12-11-2010
  5. * \brief This file contains the implementation of the class MPI_Node.
  6. */
  7. #include <cmath>
  8. #include <matrix.hpp>
  9. #include <mem_mgr.hpp>
  10. namespace pvfmm{
  11. template <class T>
  12. MPI_Node<T>::~MPI_Node(){
  13. }
  14. template <class T>
  15. void MPI_Node<T>::Initialize(TreeNode* parent_,int path2node_, TreeNode::NodeData* data_){
  16. TreeNode::Initialize(parent_,path2node_,data_);
  17. //Set node coordinates.
  18. Real_t coord_offset=((Real_t)1.0)/((Real_t)(((uint64_t)1)<<Depth()));
  19. if(!parent_){
  20. for(int j=0;j<dim;j++) coord[j]=0;
  21. }else if(parent_){
  22. int flag=1;
  23. for(int j=0;j<dim;j++){
  24. coord[j]=((MPI_Node<Real_t>*)parent_)->coord[j]+
  25. ((Path2Node() & flag)?coord_offset:0.0f);
  26. flag=flag<<1;
  27. }
  28. }
  29. //Initialize colleagues array.
  30. int n=pvfmm::pow<unsigned int>(3,Dim());
  31. for(int i=0;i<n;i++) colleague[i]=NULL;
  32. //Set MPI_Node specific data.
  33. typename MPI_Node<Real_t>::NodeData* mpi_data=dynamic_cast<typename MPI_Node<Real_t>::NodeData*>(data_);
  34. if(data_){
  35. max_pts =mpi_data->max_pts;
  36. pt_coord=mpi_data->pt_coord;
  37. pt_value=mpi_data->pt_value;
  38. }else if(parent){
  39. max_pts =((MPI_Node<T>*)parent)->max_pts;
  40. SetGhost(((MPI_Node<T>*)parent)->IsGhost());
  41. }
  42. }
  43. template <class T>
  44. void MPI_Node<T>::ClearData(){
  45. pt_coord.ReInit(0);
  46. pt_value.ReInit(0);
  47. }
  48. template <class T>
  49. MortonId MPI_Node<T>::GetMortonId(){
  50. assert(coord);
  51. Real_t s=0.25/(1UL<<MAX_DEPTH);
  52. return MortonId(coord[0]+s,coord[1]+s,coord[2]+s, Depth()); // TODO: Use interger coordinates instead of floating point.
  53. }
  54. template <class T>
  55. void MPI_Node<T>::SetCoord(MortonId& mid){
  56. assert(coord);
  57. mid.GetCoord(coord);
  58. depth=mid.GetDepth();
  59. }
  60. template <class T>
  61. TreeNode* MPI_Node<T>::NewNode(TreeNode* n_){
  62. MPI_Node<Real_t>* n=(n_?static_cast<MPI_Node<Real_t>*>(n_):mem::aligned_new<MPI_Node<Real_t> >());
  63. n->max_pts=max_pts;
  64. return TreeNode::NewNode(n);
  65. }
  66. template <class T>
  67. bool MPI_Node<T>::SubdivCond(){
  68. int n=(1UL<<this->Dim());
  69. // Do not subdivide beyond max_depth
  70. if(this->Depth()>=this->max_depth-1) return false;
  71. if(!this->IsLeaf()){ // If has non-leaf children, then return true.
  72. for(int i=0;i<n;i++){
  73. MPI_Node<Real_t>* ch=static_cast<MPI_Node<Real_t>*>(this->Child(i));
  74. assert(ch); //ch==NULL should never happen
  75. if(!ch->IsLeaf() || ch->IsGhost()) return true;
  76. }
  77. }
  78. else{ // Do not refine ghost leaf nodes.
  79. if(this->IsGhost()) return false;
  80. }
  81. if(!this->IsLeaf()){
  82. size_t pt_vec_size=0;
  83. for(int i=0;i<n;i++){
  84. MPI_Node<Real_t>* ch=static_cast<MPI_Node<Real_t>*>(this->Child(i));
  85. pt_vec_size+=ch->pt_coord.Dim();
  86. }
  87. return pt_vec_size/Dim()>max_pts;
  88. }else{
  89. return pt_coord.Dim()/Dim()>max_pts;
  90. }
  91. }
  92. template <class T>
  93. void MPI_Node<T>::Subdivide(){
  94. if(!this->IsLeaf()) return;
  95. TreeNode::Subdivide();
  96. int nchld=(1UL<<this->Dim());
  97. if(!IsGhost()){ // Partition point coordinates and values.
  98. std::vector<Vector<Real_t>*> pt_coord;
  99. std::vector<Vector<Real_t>*> pt_value;
  100. std::vector<Vector<size_t>*> pt_scatter;
  101. this->NodeDataVec(pt_coord, pt_value, pt_scatter);
  102. std::vector<std::vector<Vector<Real_t>*> > chld_pt_coord(nchld);
  103. std::vector<std::vector<Vector<Real_t>*> > chld_pt_value(nchld);
  104. std::vector<std::vector<Vector<size_t>*> > chld_pt_scatter(nchld);
  105. for(size_t i=0;i<nchld;i++){
  106. static_cast<MPI_Node<Real_t>*>((MPI_Node<T>*)this->Child(i))
  107. ->NodeDataVec(chld_pt_coord[i], chld_pt_value[i], chld_pt_scatter[i]);
  108. }
  109. Real_t* c=this->Coord();
  110. Real_t s=pvfmm::pow<Real_t>(0.5,this->Depth()+1);
  111. for(size_t j=0;j<pt_coord.size();j++){
  112. if(!pt_coord[j] || !pt_coord[j]->Dim()) continue;
  113. Vector<Real_t>& coord=*pt_coord[j];
  114. size_t npts=coord.Dim()/this->dim;
  115. Vector<size_t> cdata(nchld+1);
  116. for(size_t i=0;i<nchld+1;i++){
  117. long long pt1=-1, pt2=npts;
  118. while(pt2-pt1>1){ // binary search
  119. long long pt3=(pt1+pt2)/2;
  120. assert(pt3<npts);
  121. if(pt3<0) pt3=0;
  122. int ch_id=(coord[pt3*3+0]>=c[0]+s)*1+
  123. (coord[pt3*3+1]>=c[1]+s)*2+
  124. (coord[pt3*3+2]>=c[2]+s)*4;
  125. if(ch_id< i) pt1=pt3;
  126. if(ch_id>=i) pt2=pt3;
  127. }
  128. cdata[i]=pt2;
  129. }
  130. if(pt_coord[j]){
  131. Vector<Real_t>& vec=*pt_coord[j];
  132. size_t dof=vec.Dim()/npts;
  133. if(dof>0) for(size_t i=0;i<nchld;i++){
  134. Vector<Real_t>& chld_vec=*chld_pt_coord[i][j];
  135. chld_vec.ReInit((cdata[i+1]-cdata[i])*dof, &vec[0]+cdata[i]*dof);
  136. }
  137. vec.ReInit(0);
  138. }
  139. if(pt_value[j]){
  140. Vector<Real_t>& vec=*pt_value[j];
  141. size_t dof=vec.Dim()/npts;
  142. if(dof>0) for(size_t i=0;i<nchld;i++){
  143. Vector<Real_t>& chld_vec=*chld_pt_value[i][j];
  144. chld_vec.ReInit((cdata[i+1]-cdata[i])*dof, &vec[0]+cdata[i]*dof);
  145. }
  146. vec.ReInit(0);
  147. }
  148. if(pt_scatter[j]){
  149. Vector<size_t>& vec=*pt_scatter[j];
  150. size_t dof=vec.Dim()/npts;
  151. if(dof>0) for(size_t i=0;i<nchld;i++){
  152. Vector<size_t>& chld_vec=*chld_pt_scatter[i][j];
  153. chld_vec.ReInit((cdata[i+1]-cdata[i])*dof, &vec[0]+cdata[i]*dof);
  154. }
  155. vec.ReInit(0);
  156. }
  157. }
  158. }else{
  159. std::vector<Vector<Real_t>*> pt_coord;
  160. std::vector<Vector<Real_t>*> pt_value;
  161. std::vector<Vector<size_t>*> pt_scatter;
  162. this->NodeDataVec(pt_coord, pt_value, pt_scatter);
  163. for(size_t j=0;j<pt_coord.size();j++){
  164. if(pt_coord[j]) pt_coord[j]->ReInit(0);
  165. if(pt_value[j]) pt_value[j]->ReInit(0);
  166. if(pt_scatter[j]) pt_scatter[j]->ReInit(0);
  167. }
  168. }
  169. };
  170. template <class T>
  171. void MPI_Node<T>::Truncate(){
  172. if(!this->IsLeaf()){
  173. int nchld=(1UL<<this->Dim());
  174. for(size_t i=0;i<nchld;i++){
  175. if(!this->Child(i)->IsLeaf()){
  176. this->Child(i)->Truncate();
  177. }
  178. }
  179. std::vector<Vector<Real_t>*> pt_coord;
  180. std::vector<Vector<Real_t>*> pt_value;
  181. std::vector<Vector<size_t>*> pt_scatter;
  182. this->NodeDataVec(pt_coord, pt_value, pt_scatter);
  183. std::vector<std::vector<Vector<Real_t>*> > chld_pt_coord(nchld);
  184. std::vector<std::vector<Vector<Real_t>*> > chld_pt_value(nchld);
  185. std::vector<std::vector<Vector<size_t>*> > chld_pt_scatter(nchld);
  186. for(size_t i=0;i<nchld;i++){
  187. static_cast<MPI_Node<Real_t>*>((MPI_Node<T>*)this->Child(i))
  188. ->NodeDataVec(chld_pt_coord[i], chld_pt_value[i], chld_pt_scatter[i]);
  189. }
  190. for(size_t j=0;j<pt_coord.size();j++){
  191. if(!pt_coord[j]) continue;
  192. if(pt_coord[j]){
  193. size_t vec_size=0;
  194. for(size_t i=0;i<nchld;i++){
  195. Vector<Real_t>& chld_vec=*chld_pt_coord[i][j];
  196. vec_size+=chld_vec.Dim();
  197. }
  198. Vector<Real_t>& vec=*pt_coord[j];
  199. vec.ReInit(vec_size);
  200. vec_size=0;
  201. for(size_t i=0;i<nchld;i++){
  202. Vector<Real_t>& chld_vec=*chld_pt_coord[i][j];
  203. if(chld_vec.Dim()>0){
  204. mem::memcopy(&vec[vec_size],&chld_vec[0],chld_vec.Dim()*sizeof(Real_t));
  205. vec_size+=chld_vec.Dim();
  206. }
  207. }
  208. }
  209. if(pt_value[j]){
  210. size_t vec_size=0;
  211. for(size_t i=0;i<nchld;i++){
  212. Vector<Real_t>& chld_vec=*chld_pt_value[i][j];
  213. vec_size+=chld_vec.Dim();
  214. }
  215. Vector<Real_t>& vec=*pt_value[j];
  216. vec.ReInit(vec_size);
  217. vec_size=0;
  218. for(size_t i=0;i<nchld;i++){
  219. Vector<Real_t>& chld_vec=*chld_pt_value[i][j];
  220. if(chld_vec.Dim()>0){
  221. mem::memcopy(&vec[vec_size],&chld_vec[0],chld_vec.Dim()*sizeof(Real_t));
  222. vec_size+=chld_vec.Dim();
  223. }
  224. }
  225. }
  226. if(pt_scatter[j]){
  227. size_t vec_size=0;
  228. for(size_t i=0;i<nchld;i++){
  229. Vector<size_t>& chld_vec=*chld_pt_scatter[i][j];
  230. vec_size+=chld_vec.Dim();
  231. }
  232. Vector<size_t>& vec=*pt_scatter[j];
  233. vec.ReInit(vec_size);
  234. vec_size=0;
  235. for(size_t i=0;i<nchld;i++){
  236. Vector<size_t>& chld_vec=*chld_pt_scatter[i][j];
  237. if(chld_vec.Dim()>0){
  238. mem::memcopy(&vec[vec_size],&chld_vec[0],chld_vec.Dim()*sizeof(Real_t));
  239. vec_size+=chld_vec.Dim();
  240. }
  241. }
  242. }
  243. }
  244. }
  245. TreeNode::Truncate();
  246. }
  247. template <class T>
  248. PackedData MPI_Node<T>::Pack(bool ghost, void* buff_ptr, size_t offset){
  249. std::vector<Vector<Real_t>*> pt_coord;
  250. std::vector<Vector<Real_t>*> pt_value;
  251. std::vector<Vector<size_t>*> pt_scatter;
  252. this->NodeDataVec(pt_coord, pt_value, pt_scatter);
  253. PackedData p0;
  254. // Determine data length.
  255. p0.length =sizeof(size_t)+sizeof(int)+sizeof(long long)+sizeof(MortonId);
  256. for(size_t j=0;j<pt_coord.size();j++){
  257. p0.length+=3*sizeof(size_t);
  258. if(pt_coord [j]) p0.length+=(pt_coord [j]->Dim())*sizeof(Real_t);
  259. if(pt_value [j]) p0.length+=(pt_value [j]->Dim())*sizeof(Real_t);
  260. if(pt_scatter[j]) p0.length+=(pt_scatter[j]->Dim())*sizeof(size_t);
  261. }
  262. // Allocate memory.
  263. p0.data=(char*)buff_ptr;
  264. if(!p0.data){
  265. this->packed_data.Resize(p0.length+offset);
  266. p0.data=&this->packed_data[0];
  267. }
  268. char* data_ptr=(char*)p0.data;
  269. data_ptr+=offset;
  270. // Header
  271. ((size_t*)data_ptr)[0]=p0.length;
  272. data_ptr+=sizeof(size_t);
  273. ((int*)data_ptr)[0]=this->Depth();
  274. data_ptr+=sizeof(int);
  275. ((long long*)data_ptr)[0]=this->NodeCost();
  276. data_ptr+=sizeof(long long);
  277. ((MortonId*)data_ptr)[0]=this->GetMortonId();
  278. data_ptr+=sizeof(MortonId);
  279. // Copy Vector data.
  280. for(size_t j=0;j<pt_coord.size();j++){
  281. if(pt_coord[j]){
  282. Vector<Real_t>& vec=*pt_coord[j];
  283. ((size_t*)data_ptr)[0]=vec.Dim(); data_ptr+=sizeof(size_t);
  284. if(vec.Dim()>0 && data_ptr!=(char*)&vec[0])
  285. mem::memcopy(data_ptr, &vec[0], sizeof(Real_t)*vec.Dim());
  286. data_ptr+=vec.Dim()*sizeof(Real_t);
  287. }else{
  288. ((size_t*)data_ptr)[0]=0; data_ptr+=sizeof(size_t);
  289. }
  290. if(pt_value[j]){
  291. Vector<Real_t>& vec=*pt_value[j];
  292. ((size_t*)data_ptr)[0]=vec.Dim(); data_ptr+=sizeof(size_t);
  293. if(vec.Dim()>0 && data_ptr!=(char*)&vec[0])
  294. mem::memcopy(data_ptr, &vec[0], sizeof(Real_t)*vec.Dim());
  295. data_ptr+=vec.Dim()*sizeof(Real_t);
  296. }else{
  297. ((size_t*)data_ptr)[0]=0; data_ptr+=sizeof(size_t);
  298. }
  299. if(pt_scatter[j] && !ghost){
  300. Vector<size_t>& vec=*pt_scatter[j];
  301. ((size_t*)data_ptr)[0]=vec.Dim(); data_ptr+=sizeof(size_t);
  302. if(vec.Dim()>0 && data_ptr!=(char*)&vec[0])
  303. mem::memcopy(data_ptr, &vec[0], sizeof(size_t)*vec.Dim());
  304. data_ptr+=vec.Dim()*sizeof(size_t);
  305. }else{
  306. ((size_t*)data_ptr)[0]=0; data_ptr+=sizeof(size_t);
  307. }
  308. }
  309. return p0;
  310. }
  311. template <class T>
  312. void MPI_Node<T>::Unpack(PackedData p0, bool own_data){
  313. std::vector<Vector<Real_t>*> pt_coord;
  314. std::vector<Vector<Real_t>*> pt_value;
  315. std::vector<Vector<size_t>*> pt_scatter;
  316. this->NodeDataVec(pt_coord, pt_value, pt_scatter);
  317. char* data_ptr=(char*)p0.data;
  318. // Check header
  319. assert(((size_t*)data_ptr)[0]==p0.length);
  320. data_ptr+=sizeof(size_t);
  321. this->depth=(((int*)data_ptr)[0]);
  322. data_ptr+=sizeof(int);
  323. this->NodeCost()=(((long long*)data_ptr)[0]);
  324. data_ptr+=sizeof(long long);
  325. this->SetCoord(((MortonId*)data_ptr)[0]);
  326. data_ptr+=sizeof(MortonId);
  327. for(size_t j=0;j<pt_coord.size();j++){
  328. if(pt_coord[j]){
  329. Vector<Real_t>& vec=*pt_coord[j];
  330. size_t vec_sz=(((size_t*)data_ptr)[0]); data_ptr+=sizeof(size_t);
  331. if(own_data){
  332. vec=Vector<Real_t>(vec_sz,(Real_t*)data_ptr,false);
  333. }else{
  334. vec.ReInit(vec_sz,(Real_t*)data_ptr,false);
  335. }
  336. data_ptr+=vec_sz*sizeof(Real_t);
  337. }else{
  338. assert(!((size_t*)data_ptr)[0]);
  339. data_ptr+=sizeof(size_t);
  340. }
  341. if(pt_value[j]){
  342. Vector<Real_t>& vec=*pt_value[j];
  343. size_t vec_sz=(((size_t*)data_ptr)[0]); data_ptr+=sizeof(size_t);
  344. if(own_data){
  345. vec=Vector<Real_t>(vec_sz,(Real_t*)data_ptr,false);
  346. }else{
  347. vec.ReInit(vec_sz,(Real_t*)data_ptr,false);
  348. }
  349. data_ptr+=vec_sz*sizeof(Real_t);
  350. }else{
  351. assert(!((size_t*)data_ptr)[0]);
  352. data_ptr+=sizeof(size_t);
  353. }
  354. if(pt_scatter[j]){
  355. Vector<size_t>& vec=*pt_scatter[j];
  356. size_t vec_sz=(((size_t*)data_ptr)[0]); data_ptr+=sizeof(size_t);
  357. if(own_data){
  358. vec=Vector<size_t>(vec_sz,(size_t*)data_ptr,false);
  359. }else{
  360. vec.ReInit(vec_sz,(size_t*)data_ptr,false);
  361. }
  362. data_ptr+=vec_sz*sizeof(size_t);
  363. }else{
  364. assert(!((size_t*)data_ptr)[0]);
  365. data_ptr+=sizeof(size_t);
  366. }
  367. }
  368. }
  369. template <class T>
  370. void MPI_Node<T>::ReadVal(std::vector<Real_t> x,std::vector<Real_t> y, std::vector<Real_t> z, Real_t* val, bool show_ghost){
  371. if(!pt_coord.Dim()) return;
  372. size_t n_pts=pt_coord.Dim()/dim;
  373. size_t data_dof=pt_value.Dim()/n_pts;
  374. std::vector<Real_t> v(data_dof,0);
  375. for(size_t i=0;i<n_pts;i++)
  376. for(int j=0;j<data_dof;j++)
  377. v[j]+=pt_value[i*data_dof+j];
  378. for(int j=0;j<data_dof;j++)
  379. v[j]=v[j]/n_pts;
  380. for(size_t i=0;i<x.size()*y.size()*z.size()*data_dof;i++){
  381. val[i]=v[i%data_dof];
  382. }
  383. }
  384. template <class VTUData_t>
  385. void AppendVTUData(VTUData_t& vtu_data, VTUData_t& new_data){
  386. typedef typename VTUData_t::VTKReal_t VTKReal_t;
  387. { // Append new_data to vtk_data
  388. std::vector<VTKReal_t>& new_coord=new_data.coord;
  389. std::vector<std::string>& new_name =new_data.name;
  390. std::vector<std::vector<VTKReal_t> >& new_value=new_data.value;
  391. std::vector<int32_t>& new_connect=new_data.connect;
  392. std::vector<int32_t>& new_offset =new_data.offset;
  393. std::vector<uint8_t>& new_types =new_data.types;
  394. std::vector<VTKReal_t>& vtu_coord=vtu_data.coord;
  395. std::vector<std::string>& vtu_name =vtu_data.name;
  396. std::vector<std::vector<VTKReal_t> >& vtu_value=vtu_data.value;
  397. std::vector<int32_t>& vtu_connect=vtu_data.connect;
  398. std::vector<int32_t>& vtu_offset =vtu_data.offset;
  399. std::vector<uint8_t>& vtu_types =vtu_data.types;
  400. size_t old_pts=vtu_coord.size()/COORD_DIM;
  401. size_t new_pts=new_coord.size()/COORD_DIM;
  402. // New points
  403. for(size_t i=0;i<new_coord.size();i++){
  404. vtu_coord.push_back(new_coord[i]);
  405. }
  406. // Resize old DataArrays
  407. for(size_t i=0;i<vtu_value.size();i++){
  408. size_t curr_size=vtu_value[i].size();
  409. size_t new_size=(curr_size*(old_pts+new_pts))/old_pts;
  410. vtu_value[i].resize(new_size,0);
  411. }
  412. // Add new DataArrays
  413. for(size_t i=0;i<new_name.size();i++){
  414. vtu_name.push_back(new_name[i]);
  415. vtu_value.push_back(std::vector<VTKReal_t>());
  416. std::vector<VTKReal_t>& value=vtu_value.back();
  417. if(new_pts) value.resize((new_value[i].size()*old_pts)/new_pts);
  418. for(size_t j=0;j<new_value[i].size();j++){
  419. value.push_back(new_value[i][j]);
  420. }
  421. }
  422. size_t connect_update=old_pts;
  423. size_t offset_update=vtu_connect.size();
  424. for(size_t i=0;i<new_connect.size();i++){
  425. vtu_connect.push_back(connect_update+new_connect[i]);
  426. }
  427. for(size_t i=0;i<new_offset.size();i++){
  428. vtu_offset.push_back(offset_update+new_offset[i]);
  429. }
  430. for(size_t i=0;i<new_types.size();i++){
  431. vtu_types.push_back(new_types[i]);
  432. }
  433. }
  434. }
  435. template <class T>
  436. template <class VTUData_t, class Node_t>
  437. void MPI_Node<T>::VTU_Data(VTUData_t& vtu_data, std::vector<Node_t*>& nodes, int lod){
  438. typedef typename VTUData_t::VTKReal_t VTKReal_t;
  439. VTUData_t new_data;
  440. { // Set new data
  441. new_data.value.resize(1);
  442. new_data.name.push_back("pt_value");
  443. std::vector<VTKReal_t>& coord=new_data.coord;
  444. std::vector<VTKReal_t>& value=new_data.value[0];
  445. std::vector<int32_t>& connect=new_data.connect;
  446. std::vector<int32_t>& offset =new_data.offset;
  447. std::vector<uint8_t>& types =new_data.types;
  448. size_t point_cnt=0;
  449. size_t connect_cnt=0;
  450. for(size_t nid=0;nid<nodes.size();nid++){
  451. Node_t* n=nodes[nid];
  452. if(n->IsGhost() || !n->IsLeaf()) continue;
  453. for(size_t i=0;i<n->pt_coord.Dim();i+=3){
  454. coord.push_back(n->pt_coord[i+0]);
  455. coord.push_back(n->pt_coord[i+1]);
  456. coord.push_back(n->pt_coord[i+2]);
  457. connect_cnt++;
  458. connect.push_back(point_cnt);
  459. offset.push_back(connect_cnt);
  460. types.push_back(1);
  461. point_cnt++;
  462. }
  463. for(size_t i=0;i<n->pt_value.Dim();i++){
  464. value.push_back(n->pt_value[i]);
  465. }
  466. }
  467. size_t value_dof=(value.size()?value.size()/point_cnt:0);
  468. assert(value_dof*point_cnt==value.size());
  469. for(size_t nid=0;nid<nodes.size();nid++){
  470. Node_t* n=nodes[nid];
  471. if(n->IsGhost() || !n->IsLeaf()) continue;
  472. Real_t* c=n->Coord();
  473. Real_t s=pvfmm::pow<Real_t>(0.5,n->Depth());
  474. for(int i=0;i<8;i++){
  475. coord.push_back(c[0]+(i&1?1:0)*s);
  476. coord.push_back(c[1]+(i&2?1:0)*s);
  477. coord.push_back(c[2]+(i&4?1:0)*s);
  478. for(int j=0;j<value_dof;j++) value.push_back(0.0);
  479. connect.push_back(point_cnt+i);
  480. connect_cnt++;
  481. }
  482. offset.push_back(connect_cnt);
  483. types.push_back(11);
  484. point_cnt+=8;
  485. }
  486. }
  487. AppendVTUData(vtu_data, new_data);
  488. }
  489. }//end namespace