Guest User

Untitled

a guest
May 7th, 2013
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 395.74 KB | None | 0 0
  1. #include "octree.h"
  2. #include <xmmintrin.h>
  3. #include "radix.h"
  4. #include <parallel/algorithm>
  5.  
  6.  
  7. typedef float  _v4sf  __attribute__((vector_size(16)));
  8. typedef int    _v4si  __attribute__((vector_size(16)));
  9.  
  10. struct v4sf
  11. {
  12.   _v4sf data;
  13.   v4sf() {}
  14.   v4sf(const _v4sf _data) : data(_data) {}
  15.   operator const _v4sf&() const {return data;}
  16.   operator       _v4sf&()       {return data;}
  17.  
  18. };
  19.  
  20. #ifdef USE_MPI
  21. #include "mpi.h"
  22. #include <omp.h>
  23. #include "MPIComm.h"
  24. template <> MPI_Datatype MPIComm_datatype<float>() {return MPI_FLOAT; }
  25. MPIComm *myComm;
  26.  
  27. static MPI_Datatype MPI_V4SF = 0;
  28.  
  29.   template <>
  30. MPI_Datatype MPIComm_datatype<v4sf>()
  31. {
  32.   if (MPI_V4SF) return MPI_V4SF;
  33.   else {
  34.     int ss = sizeof(v4sf) / sizeof(float);
  35.     assert(0 == sizeof(v4sf) % sizeof(float));
  36.     MPI_Type_contiguous(ss, MPI_FLOAT, &MPI_V4SF);
  37.     MPI_Type_commit(&MPI_V4SF);
  38.     return MPI_V4SF;
  39.   }
  40. }
  41. void MPIComm_free_type()
  42. {
  43.   if (MPI_V4SF) MPI_Type_free(&MPI_V4SF);
  44. }
  45.  
  46.  
  47.  
  48. #endif
  49.  
  50. #if ENABLE_LOG
  51. extern bool ENABLE_RUNTIME_LOG;
  52. extern bool PREPEND_RANK;
  53. #endif
  54.  
  55. //SSE stuff for local tree-walk
  56.  
  57. inline float __abs(const float x)
  58. {
  59.   return __builtin_fabs(x);
  60. };
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67. #ifdef __AVX__
  68. typedef float  _v8sf  __attribute__((vector_size(32)));
  69. typedef int    _v8si  __attribute__((vector_size(32)));
  70. #endif
  71.  
  72. static inline _v4sf __abs(const _v4sf x)
  73. {
  74.   const _v4si mask = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff};
  75.   return __builtin_ia32_andps(x, (_v4sf)mask);
  76. }
  77.  
  78. #ifdef __AVX__
  79. static inline _v8sf __abs8(const _v8sf x)
  80. {
  81.   const _v8si mask = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
  82.     0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff};
  83.   return __builtin_ia32_andps256(x, (_v8sf)mask);
  84. }
  85. #endif
  86.  
  87.  
  88.  
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97. inline int host_float_as_int(float val)
  98. {
  99.   union{float f; int i;} u; //__float_as_int
  100.   u.f           = val;
  101.   return u.i;
  102. }
  103.  
  104. inline float host_int_as_float(int val)
  105. {
  106.   union{int i; float f;} itof; //__int_as_float
  107.   itof.i           = val;
  108.   return itof.f;
  109. }
  110.  
  111.  
  112. inline void _v4sf_transpose(_v4sf &a, _v4sf &b, _v4sf &c, _v4sf &d){
  113.   _v4sf t0 = __builtin_ia32_unpcklps(a, c); // |c1|a1|c0|a0|
  114.   _v4sf t1 = __builtin_ia32_unpckhps(a, c); // |c3|a3|c2|a2|
  115.   _v4sf t2 = __builtin_ia32_unpcklps(b, d); // |d1|b1|d0|b0|
  116.   _v4sf t3 = __builtin_ia32_unpckhps(b, d); // |d3|b3|d2|b2|
  117.  
  118.   a = __builtin_ia32_unpcklps(t0, t2);
  119.   b = __builtin_ia32_unpckhps(t0, t2);
  120.   c = __builtin_ia32_unpcklps(t1, t3);
  121.   d = __builtin_ia32_unpckhps(t1, t3);
  122. }
  123.  
  124. #ifdef __AVX__
  125. static inline _v8sf pack_2xmm(const _v4sf a, const _v4sf b){
  126.   // v8sf p;
  127.   _v8sf p = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f}; // just avoid warning
  128.   p = __builtin_ia32_vinsertf128_ps256(p, a, 0);
  129.   p = __builtin_ia32_vinsertf128_ps256(p, b, 1);
  130.   return p;
  131. }
  132. inline void _v8sf_transpose(_v8sf &a, _v8sf &b, _v8sf &c, _v8sf &d){
  133.   _v8sf t0 = __builtin_ia32_unpcklps256(a, c); // |c1|a1|c0|a0|
  134.   _v8sf t1 = __builtin_ia32_unpckhps256(a, c); // |c3|a3|c2|a2|
  135.   _v8sf t2 = __builtin_ia32_unpcklps256(b, d); // |d1|b1|d0|b0|
  136.   _v8sf t3 = __builtin_ia32_unpckhps256(b, d); // |d3|b3|d2|b2|
  137.  
  138.   a = __builtin_ia32_unpcklps256(t0, t2);
  139.   b = __builtin_ia32_unpckhps256(t0, t2);
  140.   c = __builtin_ia32_unpcklps256(t1, t3);
  141.   d = __builtin_ia32_unpckhps256(t1, t3);
  142. }
  143. #endif
  144.  
  145. inline int split_node_grav_impbh_box4( // takes 4 tree nodes and returns 4-bit integer
  146.     const _v4sf  nodeCOM,
  147.     const _v4sf  boxCenter[4],
  148.     const _v4sf  boxSize  [4])
  149. {
  150.   _v4sf ncx = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0x00);
  151.   _v4sf ncy = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0x55);
  152.   _v4sf ncz = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0xaa);
  153.   _v4sf ncw = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0xff);
  154.   _v4sf size = __abs(ncw);
  155.  
  156.   _v4sf bcx =  (boxCenter[0]);
  157.   _v4sf bcy =  (boxCenter[1]);
  158.   _v4sf bcz =  (boxCenter[2]);
  159.   _v4sf bcw =  (boxCenter[3]);
  160.   _v4sf_transpose(bcx, bcy, bcz, bcw);
  161.  
  162.   _v4sf bsx =  (boxSize[0]);
  163.   _v4sf bsy =  (boxSize[1]);
  164.   _v4sf bsz =  (boxSize[2]);
  165.   _v4sf bsw =  (boxSize[3]);
  166.   _v4sf_transpose(bsx, bsy, bsz, bsw);
  167.  
  168.   _v4sf dx = __abs(bcx - ncx) - bsx;
  169.   _v4sf dy = __abs(bcy - ncy) - bsy;
  170.   _v4sf dz = __abs(bcz - ncz) - bsz;
  171.  
  172.   _v4sf zero = {0.0, 0.0, 0.0, 0.0};
  173.   dx = __builtin_ia32_maxps(dx, zero);
  174.   dy = __builtin_ia32_maxps(dy, zero);
  175.   dz = __builtin_ia32_maxps(dz, zero);
  176.  
  177.   _v4sf ds2 = dx*dx + dy*dy + dz*dz;
  178. #if 0
  179.   const float c = 10e-4f;
  180.   int ret = __builtin_ia32_movmskps(
  181.       __builtin_ia32_orps(
  182.         __builtin_ia32_cmpleps(ds2,  size),
  183.         __builtin_ia32_cmpltps(ds2 - size, (_v4sf){c,c,c,c})
  184.         )
  185.       );
  186. #else
  187.   int ret = __builtin_ia32_movmskps(
  188.       __builtin_ia32_cmpleps(ds2, size));
  189. #endif
  190.   return ret;
  191. }
  192.  
  193. inline _v4sf split_node_grav_impbh_box4a( // takes 4 tree nodes and returns 4-bit integer
  194.     const _v4sf  nodeCOM,
  195.     const _v4sf  boxCenter[4],
  196.     const _v4sf  boxSize  [4])
  197. {
  198.   _v4sf ncx = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0x00);
  199.   _v4sf ncy = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0x55);
  200.   _v4sf ncz = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0xaa);
  201.   _v4sf ncw = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0xff);
  202.   _v4sf size = __abs(ncw);
  203.  
  204.   _v4sf bcx =  (boxCenter[0]);
  205.   _v4sf bcy =  (boxCenter[1]);
  206.   _v4sf bcz =  (boxCenter[2]);
  207.   _v4sf bcw =  (boxCenter[3]);
  208.   _v4sf_transpose(bcx, bcy, bcz, bcw);
  209.  
  210.   _v4sf bsx =  (boxSize[0]);
  211.   _v4sf bsy =  (boxSize[1]);
  212.   _v4sf bsz =  (boxSize[2]);
  213.   _v4sf bsw =  (boxSize[3]);
  214.   _v4sf_transpose(bsx, bsy, bsz, bsw);
  215.  
  216.   _v4sf dx = __abs(bcx - ncx) - bsx;
  217.   _v4sf dy = __abs(bcy - ncy) - bsy;
  218.   _v4sf dz = __abs(bcz - ncz) - bsz;
  219.  
  220.   const _v4sf zero = {0.0f, 0.0f, 0.0f, 0.0f};
  221.   dx = __builtin_ia32_maxps(dx, zero);
  222.   dy = __builtin_ia32_maxps(dy, zero);
  223.   dz = __builtin_ia32_maxps(dz, zero);
  224.  
  225.   const _v4sf ds2 = dx*dx + dy*dy + dz*dz;
  226. #if 0
  227.   const float c = 10e-4f;
  228.   _v4sf ret =
  229.     __builtin_ia32_orps(
  230.         __builtin_ia32_cmpleps(ds2,  size),
  231.         __builtin_ia32_cmpltps(ds2 - size, (_v4sf){c,c,c,c})
  232.         );
  233. #else
  234.   _v4sf ret =
  235.     __builtin_ia32_cmpleps(ds2, size);
  236. #endif
  237. #if 0
  238.   const _v4si mask1 = {1,1,1,1};
  239.   const _v4si mask2 = {2,2,2,2};
  240.   ret = __builtin_ia32_andps(ret, (_v4sf)mask1);
  241.   ret = __builtin_ia32_orps (ret,
  242.       __builtin_ia32_andps(
  243.         __builtin_ia32_cmpleps(bcw, (_v4sf){0.0f,0.0f,0.0f,0.0f}),
  244.         (_v4sf)mask2));
  245. #endif
  246.   return ret;
  247. }
  248.  
  249. #ifdef __AVX__
  250. inline std::pair<v4sf,v4sf> split_node_grav_impbh_box8a( // takes 4 tree nodes and returns 4-bit integer
  251.     const _v4sf  nodeCOM,
  252.     const _v4sf  boxCenter[8],
  253.     const _v4sf  boxSize  [8])
  254. {
  255. #if 0
  256.   _v4sf ncx0 = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0x00);
  257.   _v4sf ncy0 = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0x55);
  258.   _v4sf ncz0 = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0xaa);
  259.   _v4sf ncw0 = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0xff);
  260.   _v4sf size0 = __abs(ncw0);
  261.  
  262.   _v8sf ncx = pack_2xmm(ncx0, ncx0);
  263.   _v8sf ncy = pack_2xmm(ncy0, ncy0);
  264.   _v8sf ncz = pack_2xmm(ncz0, ncz0);
  265.   _v8sf size = pack_2xmm(size0, size0);
  266.  
  267. #else
  268.   _v8sf com = pack_2xmm(nodeCOM, nodeCOM);
  269.   _v8sf ncx = __builtin_ia32_shufps256(com, com, 0x00);
  270.   _v8sf ncy = __builtin_ia32_shufps256(com, com, 0x55);
  271.   _v8sf ncz = __builtin_ia32_shufps256(com, com, 0xaa);
  272.   _v8sf size = __abs8(__builtin_ia32_shufps256(com, com, 0xff));
  273. #endif
  274.  
  275.   _v8sf bcx = pack_2xmm(boxCenter[0], boxCenter[4]);
  276.   _v8sf bcy = pack_2xmm(boxCenter[1], boxCenter[5]);
  277.   _v8sf bcz = pack_2xmm(boxCenter[2], boxCenter[6]);
  278.   _v8sf bcw = pack_2xmm(boxCenter[3], boxCenter[7]);
  279.   _v8sf_transpose(bcx, bcy, bcz, bcw);
  280.  
  281.   _v8sf bsx = pack_2xmm(boxSize[0], boxSize[4]);
  282.   _v8sf bsy = pack_2xmm(boxSize[1], boxSize[5]);
  283.   _v8sf bsz = pack_2xmm(boxSize[2], boxSize[6]);
  284.   _v8sf bsw = pack_2xmm(boxSize[3], boxSize[7]);
  285.   _v8sf_transpose(bsx, bsy, bsz, bsw);
  286.  
  287.   _v8sf dx = __abs8(bcx - ncx) - bsx;
  288.   _v8sf dy = __abs8(bcy - ncy) - bsy;
  289.   _v8sf dz = __abs8(bcz - ncz) - bsz;
  290.  
  291.   const _v8sf zero = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f,0.0f,0.0f,0.0f};
  292.   dx = __builtin_ia32_maxps256(dx, zero);
  293.   dy = __builtin_ia32_maxps256(dy, zero);
  294.   dz = __builtin_ia32_maxps256(dz, zero);
  295.  
  296.   const _v8sf ds2 = dx*dx + dy*dy + dz*dz;
  297. #if 0
  298.   const float c = 10e-4f;
  299.   _v8sf ret =
  300.     __builtin_ia32_orps256(
  301.         __builtin_ia32_cmpps256(ds2,  size, 18),  /* le */
  302.         __builtin_ia32_cmpps256(ds2 - size, (_v8sf){c,c,c,c,c,c,c,c}, 17)  /* lt */
  303.         );
  304. #else
  305.   _v8sf ret =
  306.     __builtin_ia32_cmpps256(ds2, size, 18);
  307. #endif
  308. #if 0
  309.   const _v4si mask1 = {1,1,1,1};
  310.   const _v4si mask2 = {2,2,2,2};
  311.   ret = __builtin_ia32_andps(ret, (_v4sf)mask1);
  312.   ret = __builtin_ia32_orps (ret,
  313.       __builtin_ia32_andps(
  314.         __builtin_ia32_cmpleps(bcw, (_v4sf){0.0f,0.0f,0.0f,0.0f}),
  315.         (_v4sf)mask2));
  316. #endif
  317.   const _v4sf ret1 = __builtin_ia32_vextractf128_ps256(ret, 0);
  318.   const _v4sf ret2 = __builtin_ia32_vextractf128_ps256(ret, 1);
  319.   return std::make_pair(ret1,ret2);
  320. }
  321. #endif
  322.  
  323.  
  324. template<typename T>
  325. struct Swap
  326. {
  327.   private:
  328.     T &t1;
  329.     T &t2;
  330.  
  331.   public:
  332.  
  333.     Swap(T &_t1, T &_t2) : t1(_t1), t2(_t2) {}
  334.     void swap() {t1.swap(t2);}
  335.     const T& first() const { return t1;}
  336.     T& first() { return t1;}
  337.     const T& second() const { return t2;}
  338.     T& second() { return t2;}
  339. };
  340.  
  341.  
  342. void extractGroups(
  343.     std::vector<real4> &groupCentre,
  344.     std::vector<real4> &groupSize,
  345.     const real4 *nodeCentre,
  346.     const real4 *nodeSize,
  347.     const int cellBeg,
  348.     const int cellEnd,
  349.     const int nNodes)
  350. {
  351.   groupCentre.clear();
  352.   groupCentre.reserve(nNodes);
  353.  
  354.   groupSize.clear();
  355.   groupSize.reserve(nNodes);
  356.  
  357.   const int levelCountMax = nNodes;
  358.   std::vector<int> currLevelVec, nextLevelVec;
  359.   currLevelVec.reserve(levelCountMax);
  360.   nextLevelVec.reserve(levelCountMax);
  361.   Swap<std::vector<int> > levelList(currLevelVec, nextLevelVec);
  362.  
  363.   for (int cell = cellBeg; cell < cellEnd; cell++)
  364.     levelList.first().push_back(cell);
  365.  
  366.   int depth = 0;
  367.   while (!levelList.first().empty())
  368.   {
  369.     //LOGF(stderr, " depth= %d \n", depth++);
  370.     const int csize = levelList.first().size();
  371.     for (int i = 0; i < csize; i++)
  372.     {
  373.       const uint   nodeIdx = levelList.first()[i];
  374.       const float4 centre  = nodeCentre[nodeIdx];
  375.       const float4 size    = nodeSize[nodeIdx];
  376.       const float nodeInfo_x = centre.w;
  377.       const uint  nodeInfo_y = host_float_as_int(size.w);
  378.  
  379.       const bool lleaf = nodeInfo_x <= 0.0f;
  380.       if (!lleaf)
  381.       {
  382.         const int lchild  =    nodeInfo_y & 0x0FFFFFFF;            //Index to the first child of the node
  383.         const int lnchild = (((nodeInfo_y & 0xF0000000) >> 28)) ;  //The number of children this node has
  384. #if 1
  385.         if (lnchild == 8)
  386.         {
  387.           float4 centre1 = centre;
  388.           centre1.w = -1;
  389.           groupCentre.push_back(centre1);
  390.           groupSize  .push_back(size);
  391.         }
  392.         else
  393. #endif
  394.           for (int i = lchild; i < lchild + lnchild; i++)
  395.             levelList.second().push_back(i);
  396.       }
  397.       else
  398.       {
  399.         float4 centre1 = centre;
  400.         centre1.w = -1;
  401.         groupCentre.push_back(centre1);
  402.         groupSize  .push_back(size);
  403.       }
  404.     }
  405.  
  406.     levelList.swap();
  407.     levelList.second().clear();
  408.   }
  409. }
  410.  
  411.  
  412. void octree::mpiInit(int argc,char *argv[], int &procId, int &nProcs)
  413. {
  414. #ifdef USE_MPI
  415.   int  namelen;
  416.   char processor_name[MPI_MAX_PROCESSOR_NAME];
  417.  
  418.   int mpiInitialized = 0;
  419.   MPI_Initialized(&mpiInitialized);
  420.  
  421.   if(!mpiInitialized)
  422.   {
  423.     MPI_Init(&argc,&argv);
  424.     int provided;
  425.     //MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  426.     //assert(provided == MPI_THREAD_MULTIPLE);
  427.  
  428.     //      MPI_Init_thread(&argc, &argv, MPI_THREAD_FUNNELED, &provided);
  429.     //      assert(provided == MPI_THREAD_FUNNELED);
  430.   }
  431.  
  432.   MPI_Comm_size(MPI_COMM_WORLD, &nProcs);
  433.   MPI_Comm_rank(MPI_COMM_WORLD, &procId);
  434.  
  435.   myComm = new MPIComm(procId, nProcs);
  436.  
  437.   MPI_Get_processor_name(processor_name,&namelen);
  438. #else
  439.   char processor_name[] = "Default";
  440. #endif
  441.  
  442. #ifdef PRINT_MPI_DEBUG
  443.   LOGF(stderr, "Proc id: %d @ %s , total processes: %d (mpiInit) \n", procId, processor_name, nProcs);
  444. #endif
  445.   fprintf(stderr, "Proc id: %d @ %s , total processes: %d (mpiInit) \n", procId, processor_name, nProcs);
  446.  
  447.   //Allocate memory for the used buffers
  448.   //    domainRLow  = new double4[nProcs];
  449.   //    domainRHigh = new double4[nProcs];
  450.   //
  451.   //    domHistoryLow   = new int4[nProcs];
  452.   //    domHistoryHigh  = new int4[nProcs];
  453.  
  454.   //Fill domainRX with constants so we can check if its initialized before
  455.   //    for(int i=0; i < nProcs; i++)
  456.   //    {
  457.   //      domainRLow[i] = domainRHigh[i] = make_double4(1e10, 1e10, 1e10, 1e10);
  458.   //
  459.   //      domHistoryLow[i] = domHistoryHigh[i] = make_int4(0,0,0,0);
  460.   //    }
  461.  
  462.   currentRLow  = new double4[nProcs];
  463.   currentRHigh = new double4[nProcs];
  464.   //
  465.   //    xlowPrev  = new double4[nProcs];
  466.   //    xhighPrev = new double4[nProcs];
  467.   //
  468.  
  469.   //    globalCoarseGrpCount     = new uint[nProcs];
  470.   //    globalCoarseGrpOffsets   = new uint[nProcs];
  471.  
  472.   //    nSampleAndSizeValues    = new int2[nProcs];
  473.   curSysState             = new sampleRadInfo[nProcs];
  474.  
  475.   globalGrpTreeCount   = new uint[nProcs];
  476.   globalGrpTreeOffsets = new uint[nProcs];
  477. }
  478.  
  479.  
  480.  
  481. //Utility functions
  482. void octree::mpiSync(){
  483. #ifdef USE_MPI
  484.   MPI_Barrier(MPI_COMM_WORLD);
  485. #endif
  486. }
  487.  
  488. int octree::mpiGetRank(){
  489.   return procId;
  490. }
  491.  
  492. int octree::mpiGetNProcs(){
  493.   return nProcs;
  494. }
  495.  
  496. void octree::AllSum(double &value)
  497. {
  498. #ifdef USE_MPI
  499.   double tmp = -1;
  500.   MPI_Allreduce(&value,&tmp,1, MPI_DOUBLE, MPI_SUM,MPI_COMM_WORLD);
  501.   value = tmp;
  502. #endif
  503. }
  504.  
  505. int octree::SumOnRootRank(int &value)
  506. {
  507. #ifdef USE_MPI
  508.   int temp;
  509.   MPI_Reduce(&value,&temp,1, MPI_INT, MPI_SUM,0, MPI_COMM_WORLD);
  510.   return temp;
  511. #else
  512.   return value;
  513. #endif
  514. }
  515. //end utility
  516.  
  517.  
  518.  
  519. //Main functions
  520.  
  521.  
  522. //Functions related to domain decomposition
  523.  
  524.  
  525. typedef struct hashInfo
  526. {
  527.   int     nHashes;      //Number of hashes that will be send by the process
  528.   int     nParticles;   //Number of particles the sending process has in total
  529.   double  execTime;     //The time it took this process to compute gravity in the previous step
  530.   double  execTime2;    //A second timing number. We dont want execTime and execTime2 to fluctuate too much
  531.   //balance on the one with the largest difference.
  532. } hashInfo;
  533.  
  534. int balanceLoad(int *nParticlesOriginal, int *nParticlesNew, float *load,
  535.     int nProcs, int leftIdx, int nTotal, float loadAvg)
  536. {
  537. #ifdef USE_MPI
  538.   //Sum the total load left and right
  539.   int nProcsLeftSide    = nProcs / 2;
  540.   int nProcsRightSide   = nProcs  - nProcsLeftSide;
  541.   int rightIdx          = leftIdx + nProcsLeftSide;
  542.  
  543.   if(nProcs == 1) {
  544.     LOGF(stderr, "Ready by default \n");
  545.     nParticlesNew[leftIdx] = nTotal;
  546.     return 0;
  547.   }
  548.  
  549.   LOGF(stderr, "Start balance: nProcs: %d, leftIdx: %d, rightIdx: %d nProcLeft: %d  nProcRight: %d nTotal: %d avg: %f\n",
  550.       nProcs, leftIdx, rightIdx, nProcsLeftSide,nProcsRightSide, nTotal, loadAvg);
  551.  
  552.   int nPartLeftOriginal = 0, nPartRightOriginal = 0;
  553.   for(int i=leftIdx;  i < rightIdx;                   i++) nPartLeftOriginal  += nParticlesOriginal[i];
  554.   for(int i=rightIdx; i < rightIdx+nProcsRightSide;   i++) nPartRightOriginal += nParticlesOriginal[i];
  555.  
  556.   //Compute the factor to which to increase by using the received timing numbers
  557.   float loadLeft = 0, loadRight = 0;
  558.   for(int i=leftIdx;  i < rightIdx;                 i++) loadLeft  += load[i];
  559.   for(int i=rightIdx; i < rightIdx+nProcsRightSide; i++) loadRight += load[i];
  560.  
  561.  
  562.   float leftTarget  = (loadAvg*nProcsLeftSide)  / (loadLeft);
  563.   float rightTarget = (loadAvg*nProcsRightSide) / (loadRight);
  564.   //Inverse load, for testing LET
  565.   //LET float leftTarget  = 1./((loadAvg*nProcsLeftSide)  / (loadLeft));
  566.   //float rightTarget = 1./((loadAvg*nProcsRightSide) / (loadRight));
  567.  
  568.   int newLeft = 0, newRight = 0;
  569.   //Check which target we are trying to match, namely the one with minimal work
  570.   if(leftTarget < rightTarget)
  571.     //LET  if(leftTarget > rightTarget)
  572.   {
  573.     //Optimize left
  574.     newLeft  = nPartLeftOriginal*leftTarget;
  575.     newRight = nTotal - newLeft;
  576.   }
  577.   else
  578.   {
  579.     //Optimize right
  580.     newRight  = nPartRightOriginal*rightTarget;
  581.     newLeft   = nTotal - newRight;
  582.   }
  583.  
  584.   LOGF(stderr, "newLeft: %d , newRight: %d nTotal: %d , leftTarget: %f rightTarget: %f , loadLeft: %f loadRight: %f \n",
  585.       newLeft, newRight, nTotal, leftTarget, rightTarget, loadLeft, loadRight);
  586.  
  587.   if(nProcs == 2)
  588.   {
  589.     nParticlesNew[leftIdx] = newLeft;
  590.     nParticlesNew[rightIdx] = newRight;
  591.     return 0;
  592.   }
  593.  
  594.   //Recursive the left and right parts
  595.   balanceLoad(nParticlesOriginal, nParticlesNew, load, nProcsLeftSide, leftIdx,  newLeft, loadAvg);
  596.   balanceLoad(nParticlesOriginal, nParticlesNew, load, nProcsRightSide, rightIdx, newRight, loadAvg);
  597.  
  598. #endif
  599.  
  600.   return 0;
  601. }
  602.  
  603. //Uses one communication by storing data in one buffer and communicate required information,
  604. //such as box-sizes and number of sample particles on this process (Note that the number is only
  605. //used by process-0
  606. void octree::sendCurrentRadiusAndSampleInfo(real4 &rmin, real4 &rmax, int nsample, int *nSamples)
  607. {
  608.   sampleRadInfo curProcState;
  609.  
  610.   curProcState.nsample      = nsample;
  611.   curProcState.rmin         = make_double4(rmin.x, rmin.y, rmin.z, rmin.w);
  612.   curProcState.rmax         = make_double4(rmax.x, rmax.y, rmax.z, rmax.w);
  613.  
  614. #ifdef USE_MPI
  615.   //Get the number of sample particles and the domain size information
  616.   MPI_Allgather(&curProcState, sizeof(sampleRadInfo), MPI_BYTE,  curSysState,
  617.       sizeof(sampleRadInfo), MPI_BYTE, MPI_COMM_WORLD);
  618. #else
  619.   curSysState[0] = curProcState;
  620. #endif
  621.  
  622.   rmin.x                 = (real)(currentRLow[0].x = curSysState[0].rmin.x);
  623.   rmin.y                 = (real)(currentRLow[0].y = curSysState[0].rmin.y);
  624.   rmin.z                 = (real)(currentRLow[0].z = curSysState[0].rmin.z);
  625.   currentRLow[0].w = curSysState[0].rmin.w;
  626.  
  627.   rmax.x                 = (real)(currentRHigh[0].x = curSysState[0].rmax.x);
  628.   rmax.y                 = (real)(currentRHigh[0].y = curSysState[0].rmax.y);
  629.   rmax.z                 = (real)(currentRHigh[0].z = curSysState[0].rmax.z);
  630.   currentRHigh[0].w = curSysState[0].rmax.w;
  631.  
  632.   nSamples[0] = curSysState[0].nsample;
  633.  
  634.   for(int i=1; i < nProcs; i++)
  635.   {
  636.     rmin.x = std::min(rmin.x, (real)curSysState[i].rmin.x);
  637.     rmin.y = std::min(rmin.y, (real)curSysState[i].rmin.y);
  638.     rmin.z = std::min(rmin.z, (real)curSysState[i].rmin.z);
  639.  
  640.     rmax.x = std::max(rmax.x, (real)curSysState[i].rmax.x);
  641.     rmax.y = std::max(rmax.y, (real)curSysState[i].rmax.y);
  642.     rmax.z = std::max(rmax.z, (real)curSysState[i].rmax.z);
  643.  
  644.     currentRLow[i].x = curSysState[i].rmin.x;
  645.     currentRLow[i].y = curSysState[i].rmin.y;
  646.     currentRLow[i].z = curSysState[i].rmin.z;
  647.     currentRLow[i].w = curSysState[i].rmin.w;
  648.  
  649.     currentRHigh[i].x = curSysState[i].rmax.x;
  650.     currentRHigh[i].y = curSysState[i].rmax.y;
  651.     currentRHigh[i].z = curSysState[i].rmax.z;
  652.     currentRHigh[i].w = curSysState[i].rmax.w;
  653.  
  654.     nSamples[i] = curSysState[i].nsample;
  655.   }
  656. }
  657.  
  658. void octree::computeSampleRateSFC(float lastExecTime, int &nSamples, int &sampleRate)
  659. {
  660. #ifdef USE_MPI
  661.   double t00 = get_time();
  662.   //Compute the number of particles to sample.
  663.   //Average the previous and current execution time to make everything smoother
  664.   //results in much better load-balance
  665.   static double prevDurStep  = -1;
  666.   static int    prevSampFreq = -1;
  667.   prevDurStep                = (prevDurStep <= 0) ? lastExecTime : prevDurStep;
  668.   double timeLocal           = (lastExecTime + prevDurStep) / 2;
  669.  
  670. #define LOAD_BALANCE 0
  671. #define LOAD_BALANCE_MEMORY 0
  672.  
  673.   double nrate = 0;
  674.   if(LOAD_BALANCE) //Base load balancing on the computation time
  675.   {
  676.     double timeSum   = 0.0;
  677.  
  678.     //Sum the execution times over all processes
  679.     MPI_Allreduce( &timeLocal, &timeSum, 1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
  680.  
  681.     nrate = timeLocal / timeSum;
  682.  
  683.     if(LOAD_BALANCE_MEMORY)       //Don't fluctuate particles too much
  684.     {
  685. #define SAMPLING_LOWER_LIMIT_FACTOR  (1.9)
  686.  
  687.       double nrate2 = (double)localTree.n / (double) nTotalFreq_ull;
  688.       nrate2       /= SAMPLING_LOWER_LIMIT_FACTOR;
  689.  
  690.       if(nrate < nrate2)
  691.       {
  692.         nrate = nrate2;
  693.       }
  694.  
  695.       double nrate2_sum = 0.0;
  696.  
  697.       MPI_Allreduce(&nrate, &nrate2_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
  698.  
  699.       nrate /= nrate2_sum;
  700.     }
  701.   }
  702.   else
  703.   {
  704.     nrate = (double)localTree.n / (double)nTotalFreq_ull; //Equal number of particles
  705.   }
  706.  
  707.   int    nsamp  = (int)(nTotalFreq_ull*0.001f/4) + 1;  //Total number of sample particles, global
  708.   nSamples      = (int)(nsamp*nrate) + 1;
  709.   sampleRate    = localTree.n / nSamples;
  710.  
  711.   if (procId == 0)
  712.   fprintf(stderr, "NSAMP [%d]: sample: %d nrate: %f final sampleRate: %d localTree.n: %d\tprevious: %d timeLocal: %f prevTimeLocal: %f  Took: %lg\n",
  713.       procId, nSamples, nrate, sampleRate, localTree.n, prevSampFreq,
  714.       timeLocal, prevDurStep,get_time()-t00);
  715.   assert(sampleRate > 1);
  716.  
  717.   prevDurStep  = timeLocal;
  718.   prevSampFreq = sampleRate;
  719.  
  720. #endif
  721. }
  722.  
  723. void octree::exchangeSamplesAndUpdateBoundarySFC(uint4 *sampleKeys,    int  nSamples,
  724.     uint4 *globalSamples, int  *nReceiveCnts, int *nReceiveDpls,
  725.     int    totalCount,   uint4 *parallelBoundaries)
  726. {
  727. #ifdef USE_MPI
  728.   //Send actual data
  729.   MPI_Gatherv(&sampleKeys[0],    nSamples*sizeof(uint4), MPI_BYTE,
  730.       &globalSamples[0], nReceiveCnts, nReceiveDpls, MPI_BYTE,
  731.       0, MPI_COMM_WORLD);
  732.  
  733.  
  734.   if(procId == 0)
  735.   {
  736.     //Sort the keys. Use stable_sort (merge sort) since the separate blocks are already
  737.     //sorted. This is faster than std::sort (quicksort)
  738.     //std::sort(allHashes, allHashes+totalNumberOfHashes, cmp_ph_key());
  739.     double t00 = get_time();
  740.  
  741. #if 0 /* jb2404 */
  742.     //std::stable_sort(globalSamples, globalSamples+totalCount, cmp_ph_key());
  743.     __gnu_parallel::stable_sort(globalSamples, globalSamples+totalCount, cmp_ph_key());
  744. #else
  745. #if 0
  746.     {
  747.       const int BITS = 32*2;  /*  32*1 = 32 bit sort, 32*2 = 64 bit sort, 32*3 = 96 bit sort */
  748.       typedef RadixSort<BITS> Radix;
  749.       LOGF(stderr,"Boundary :: using %d-bit RadixSort\n", BITS);
  750.  
  751.       Radix radix(totalCount);
  752. #if 0
  753.       typedef typename Radix::key_t key_t;
  754. #endif
  755.  
  756.       Radix::key_t *keys;
  757.       posix_memalign((void**)&keys, 64, totalCount*sizeof(Radix::key_t));
  758.  
  759. #pragma omp parallel for
  760.       for (int i = 0; i < totalCount; i++)
  761.         keys[i] = Radix::key_t(globalSamples[i]);
  762.  
  763.       radix.sort(keys);
  764.  
  765. #pragma omp parallel for
  766.       for (int i = 0; i < totalCount; i++)
  767.         globalSamples[i] = keys[i].get_uint4();
  768.  
  769.       free(keys);
  770.  
  771.     }
  772. #else
  773.     {
  774.       LOGF(stderr,"Boundary :: using %d-bit RadixSort\n", 64);
  775.       unsigned long long *keys;
  776.       posix_memalign((void**)&keys, 64, totalCount*sizeof(unsigned long long));
  777.      
  778. #pragma omp parallel for
  779.       for (int i = 0; i < totalCount; i++)
  780.       {
  781.         const uint4 key = globalSamples[i];
  782.         keys[i] =
  783.           static_cast<unsigned long long>(key.y) | (static_cast<unsigned long long>(key.x) << 32);
  784.       }
  785.  
  786. #if 0
  787.       RadixSort64 r(totalCount);
  788.       r.sort(keys);
  789. #else
  790.       __gnu_parallel::sort(keys, keys+totalCount);
  791. #endif
  792. #pragma omp parallel for
  793.       for (int i = 0; i < totalCount; i++)
  794.       {
  795.         const unsigned long long key = keys[i];
  796.         globalSamples[i] = (uint4){
  797.           (uint)((key >> 32) & 0x00000000FFFFFFFF),
  798.           (uint)((key      ) & 0x00000000FFFFFFFF),
  799.           0,0};
  800.       }
  801.       free(keys);
  802.     }
  803. #endif
  804.  
  805. #endif
  806.     LOGF(stderr,"Boundary took: %lg  Items: %d\n", get_time()-t00, totalCount);
  807.  
  808.  
  809.     //Split the samples in equal parts to get the boundaries
  810.  
  811.  
  812.     int procIdx   = 1;
  813.  
  814.     globalSamples[totalCount] = make_uint4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
  815.     parallelBoundaries[0]     = make_uint4(0x0, 0x0, 0x0, 0x0);
  816.     //Chop in equal sized parts
  817.     for(int i=1; i < nProcs; i++)
  818.     {
  819.       int idx = (size_t(i)*size_t(totalCount))/size_t(nProcs);
  820.  
  821.       //jb2404
  822.       if(iter == 0){
  823.       if((i%1000) == 0) fprintf(stderr, " Boundary %d taken from : %d \n" ,i, idx);
  824.       if(i >= nProcs-10) fprintf(stderr, " Boundary %d taken from : %d \n" ,i, idx);
  825.       }
  826.  
  827.       parallelBoundaries[procIdx++] = globalSamples[idx];
  828.     }
  829. #if 0
  830.     int perProc = totalCount / nProcs;
  831.     int tempSum   = 0;
  832.     for(int i=0; i < totalCount; i++)
  833.     {
  834.       tempSum += 1;
  835.       if(tempSum >= perProc)
  836.       {
  837.         //LOGF(stderr, "Boundary at: %d\t%d %d %d %d \t %d \n",
  838.         //              i, globalSamples[i+1].x,globalSamples[i+1].y,globalSamples[i+1].z,globalSamples[i+1].w, tempSum);
  839.         tempSum = 0;
  840.         parallelBoundaries[procIdx++] = globalSamples[i+1];
  841.       }
  842.     }//for totalNumberOfHashes
  843. #endif
  844.  
  845.  
  846.     //Force final boundary to be the highest possible key value
  847.     parallelBoundaries[nProcs]  = make_uint4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
  848.  
  849.     delete[] globalSamples;
  850.   }
  851.  
  852.   //Send the boundaries to all processes
  853.   MPI_Bcast(&parallelBoundaries[0], sizeof(uint4)*(nProcs+1), MPI_BYTE, 0, MPI_COMM_WORLD);
  854.  
  855.   if(procId == -1)
  856.   {
  857.     for(int i=0; i < nProcs; i++)
  858.     {
  859.       LOGF(stderr, "Proc: %d Going from: >= %u %u %u  to < %u %u %u \n",i,
  860.           parallelBoundaries[i].x,   parallelBoundaries[i].y,   parallelBoundaries[i].z,
  861.           parallelBoundaries[i+1].x, parallelBoundaries[i+1].y, parallelBoundaries[i+1].z);
  862.     }
  863.   }
  864. #endif
  865. }
  866. //End Domain decomposition based on Sample particle related functions
  867.  
  868. //Domain decomposition based on particle hashes related functions
  869.  
  870.  
  871. //Uses one communication by storing data in one buffer and communicate required information,
  872. //such as box-sizes and number of sample particles on this process. Nsample is set to 0
  873. //since it is not used in this function/hash-method
  874. void octree::sendCurrentRadiusInfo(real4 &rmin, real4 &rmax)
  875. {
  876.   sampleRadInfo curProcState;
  877.  
  878.   int nsample               = 0; //Place holder to just use same datastructure
  879.   curProcState.nsample      = nsample;
  880.   curProcState.rmin         = make_double4(rmin.x, rmin.y, rmin.z, rmin.w);
  881.   curProcState.rmax         = make_double4(rmax.x, rmax.y, rmax.z, rmax.w);
  882.  
  883. #ifdef USE_MPI
  884.   //Get the number of sample particles and the domain size information
  885.   MPI_Allgather(&curProcState, sizeof(sampleRadInfo), MPI_BYTE,  curSysState,
  886.       sizeof(sampleRadInfo), MPI_BYTE, MPI_COMM_WORLD);
  887. #else
  888.   curSysState[0] = curProcState;
  889. #endif
  890.  
  891.   rmin.x                 = (real)(currentRLow[0].x = curSysState[0].rmin.x);
  892.   rmin.y                 = (real)(currentRLow[0].y = curSysState[0].rmin.y);
  893.   rmin.z                 = (real)(currentRLow[0].z = curSysState[0].rmin.z);
  894.   currentRLow[0].w = curSysState[0].rmin.w;
  895.  
  896.   rmax.x                 = (real)(currentRHigh[0].x = curSysState[0].rmax.x);
  897.   rmax.y                 = (real)(currentRHigh[0].y = curSysState[0].rmax.y);
  898.   rmax.z                 = (real)(currentRHigh[0].z = curSysState[0].rmax.z);
  899.   currentRHigh[0].w = curSysState[0].rmax.w;
  900.  
  901.   for(int i=1; i < nProcs; i++)
  902.   {
  903.     rmin.x = std::min(rmin.x, (real)curSysState[i].rmin.x);
  904.     rmin.y = std::min(rmin.y, (real)curSysState[i].rmin.y);
  905.     rmin.z = std::min(rmin.z, (real)curSysState[i].rmin.z);
  906.  
  907.     rmax.x = std::max(rmax.x, (real)curSysState[i].rmax.x);
  908.     rmax.y = std::max(rmax.y, (real)curSysState[i].rmax.y);
  909.     rmax.z = std::max(rmax.z, (real)curSysState[i].rmax.z);
  910.  
  911.     currentRLow[i].x = curSysState[i].rmin.x;
  912.     currentRLow[i].y = curSysState[i].rmin.y;
  913.     currentRLow[i].z = curSysState[i].rmin.z;
  914.     currentRLow[i].w = curSysState[i].rmin.w;
  915.  
  916.     currentRHigh[i].x = curSysState[i].rmax.x;
  917.     currentRHigh[i].y = curSysState[i].rmax.y;
  918.     currentRHigh[i].z = curSysState[i].rmax.z;
  919.     currentRHigh[i].w = curSysState[i].rmax.w;
  920.   }
  921. }
  922.  
  923.  
  924. void octree::gpu_collect_hashes(int nHashes, uint4 *hashes, uint4 *boundaries, float lastExecTime, float lastExecTime2)
  925. {
  926. #ifdef USE_MPI
  927.   double t0 = get_time();
  928.  
  929.   hashInfo hInfo;
  930.   hInfo.nHashes     = nHashes;
  931.   hInfo.nParticles  = this->localTree.n;
  932.   hInfo.execTime    = lastExecTime;
  933.   hInfo.execTime2   = lastExecTime2;
  934.  
  935.   LOGF(stderr, "Exectime: Proc: %d -> %f \n", procId, hInfo.execTime);
  936.  
  937.   int       *nReceiveCnts  = NULL;
  938.   int       *nReceiveDpls  = NULL;
  939.   float     *execTimes     = NULL;
  940.   float     *execTimes2    = NULL;
  941.   hashInfo  *recvHashInfo  = new hashInfo[nProcs];
  942.  
  943.   //First receive the number of hashes
  944.   MPI_Gather(&hInfo, sizeof(hashInfo), MPI_BYTE, recvHashInfo, sizeof(hashInfo), MPI_BYTE, 0, MPI_COMM_WORLD);
  945.  
  946.   int    totalNumberOfHashes = 0;
  947.   float  timeSum, timeSum2   = 0;
  948.   int    nTotal              = 0;
  949.   uint4  *allHashes          = NULL;
  950.  
  951.   //Compute receive offsets (only process 0), total number of particles, total execution time.
  952.   if(procId == 0)
  953.   {
  954.     nReceiveCnts  = new int  [nProcs];
  955.     nReceiveDpls  = new int  [nProcs];
  956.     execTimes     = new float[nProcs];
  957.     execTimes2    = new float[nProcs];
  958.  
  959.     nReceiveCnts[0]      = recvHashInfo[0].nHashes;
  960.     execTimes[0]         = recvHashInfo[0].execTime;
  961.     execTimes2[0]        = recvHashInfo[0].execTime2;
  962.  
  963.     //Receive counts and displacements
  964.     totalNumberOfHashes += nReceiveCnts[0];
  965.     nReceiveCnts[0]      = nReceiveCnts[0]*sizeof(uint4); //Convert to correct data size
  966.     nReceiveDpls[0]      = 0;
  967.     nTotal               = recvHashInfo[0].nParticles;
  968.     timeSum              = recvHashInfo[0].execTime;
  969.     timeSum2             = recvHashInfo[0].execTime2;
  970.  
  971.  
  972.     for(int i=1; i < nProcs; i++)
  973.     {
  974.       nReceiveCnts[i]      = recvHashInfo[i].nHashes;
  975.       execTimes[i]         = recvHashInfo[i].execTime;
  976.       execTimes2[i]        = recvHashInfo[i].execTime2;
  977.  
  978.       totalNumberOfHashes += nReceiveCnts[i];
  979.       nReceiveCnts[i]      = nReceiveCnts[i]*sizeof(uint4);
  980.       nReceiveDpls[i]      = nReceiveDpls[i-1] + nReceiveCnts[i-1];
  981.  
  982.       nTotal   += recvHashInfo[i].nParticles;
  983.       timeSum  += recvHashInfo[i].execTime;
  984.       timeSum2 += recvHashInfo[i].execTime2;
  985.     }
  986.     allHashes                      = new uint4[totalNumberOfHashes+1];
  987.     allHashes[totalNumberOfHashes] = make_uint4(0,0,0,0); //end boundary
  988.  
  989.  
  990.  
  991.     //Loop so we can decide on which number to balance
  992.     float avgLoadTime1 = timeSum  / nProcs;
  993.     float avgLoadTime2 = timeSum2 / nProcs;
  994.  
  995.     float maxTime1Diff = 0, maxTime2Diff = 0;
  996.     for(int i=0; i < nProcs; i++)
  997.     {
  998.       float temp1 = abs((avgLoadTime1/recvHashInfo[i].execTime)-1);
  999.       maxTime1Diff = max(temp1, maxTime1Diff);
  1000.       float temp2 = abs((avgLoadTime2/recvHashInfo[i].execTime2)-1);
  1001.       maxTime2Diff = max(temp2, maxTime2Diff);
  1002.     }
  1003.  
  1004.     if(0){
  1005.       if(maxTime2Diff > maxTime1Diff)
  1006.       {
  1007.         for(int i=0; i < nProcs; i++)
  1008.         {
  1009.           execTimes[i] = execTimes[2];
  1010.         }
  1011.         timeSum = timeSum2;
  1012.       }}
  1013.  
  1014.     LOGF(stderr, "Max diff  Time1: %f\tTime2: %f Proc0: %f \t %f \n",
  1015.         maxTime1Diff, maxTime2Diff, recvHashInfo[0].execTime, recvHashInfo[0].execTime2);
  1016.   } //if procId == 0
  1017.  
  1018.   //Collect hashes on process 0
  1019.   MPI_Gatherv(&hashes[0],    nHashes*sizeof(uint4), MPI_BYTE,
  1020.       &allHashes[0], nReceiveCnts,          nReceiveDpls, MPI_BYTE,
  1021.       0, MPI_COMM_WORLD);
  1022.  
  1023.   //  MPI_Gatherv((procId ? &sampleArray[0] : MPI_IN_PLACE), nsample*sizeof(real4), MPI_BYTE,
  1024.   //              &sampleArray[0], nReceiveCnts, nReceiveDpls, MPI_BYTE,
  1025.   //              0, MPI_COMM_WORLD);
  1026.  
  1027.   if(procId == 0)
  1028.   {
  1029.     delete[] nReceiveCnts;
  1030.     delete[] nReceiveDpls;
  1031.  
  1032.     int       *nPartPerProc  = new int[nProcs];
  1033.  
  1034.     //Sort the keys. Use stable_sort (merge sort) since the seperate blocks are already
  1035.     //sorted. This is faster than std::sort (quicksort)
  1036.     //std::sort(allHashes, allHashes+totalNumberOfHashes, cmp_ph_key());
  1037.     std::stable_sort(allHashes, allHashes+totalNumberOfHashes, cmp_ph_key());
  1038.  
  1039.  
  1040. #define LOAD_BALANCE 0
  1041. #define LOAD_BALANCE_MEMORY 0
  1042.  
  1043. #if LOAD_BALANCE
  1044.     //Load balancing version, based on gravity approximation execution times.
  1045.  
  1046.     LOGF(stderr, "Time sum: %f \n", timeSum);
  1047.  
  1048.     //Normalize, fractions : timeSum / gravTime -> gives a relative time number
  1049.     float normSum = 0;
  1050.     for(int i=0; i < nProcs; i++){
  1051.       // execTimes[i] = timeSum / execTimes[i];
  1052.       // normSum     += execTimes[i];
  1053.       LOGF(stderr, "Exec after norm: %d\t %f \tn: %d \n",i, execTimes[i],recvHashInfo[i].nParticles );
  1054.     }
  1055.     LOGF(stderr, "Normalized sum:%f  \n",normSum);
  1056.  
  1057.  
  1058.     int *npartPerProcOld = new int[nProcs];
  1059.     float *loadPerProc   = new float[nProcs];
  1060.  
  1061.     for(int i=0; i < nProcs; i++)
  1062.     {
  1063.       npartPerProcOld[i] = recvHashInfo[i].nParticles;
  1064.       loadPerProc[i] = recvHashInfo[i].execTime;
  1065.     }
  1066.     float loadAvg = timeSum / nProcs;
  1067.  
  1068.     //Adjust the boundary locations
  1069.     balanceLoad(npartPerProcOld,nPartPerProc, loadPerProc,
  1070.         nProcs,0,nTotal,loadAvg);
  1071.  
  1072.     delete[] npartPerProcOld;
  1073.     delete[] loadPerProc;
  1074.     //End adjusting
  1075.  
  1076.  
  1077.  
  1078.     //Compute the number of particles to be assign per process
  1079.     for(int i=0; i < nProcs; i++){
  1080.       //        nPartPerProc[i] = (execTimes[i] / normSum) * nTotal;
  1081.  
  1082.       //  nPartPerProc[i] = recvHashInfo[i].nParticles*(2*(execTimes[i] / normSum));
  1083.       //fprintf(stderr, "Npart per proc: %d\t %d \n",i, nPartPerProc[i]);
  1084.     }
  1085.  
  1086.     //Average with number of particles of previous step
  1087.     //TODO
  1088.     //float fac = 0.25; //25% old, 75% new
  1089.     float fac = 0.50; //Average
  1090.     for(int i=0; i < nProcs; i++){
  1091.       LOGF(stderr, "Npart per proc: new %d\told %d (avg final: %d)\n",
  1092.           nPartPerProc[i], recvHashInfo[i].nParticles,
  1093.           ((int)((recvHashInfo[i].nParticles*fac) + (nPartPerProc[i] *(1-fac)))));
  1094.       nPartPerProc[i] = (int)((recvHashInfo[i].nParticles*fac) + (nPartPerProc[i] *(1-fac)));
  1095.  
  1096.     }
  1097.  
  1098.  
  1099.     delete[] execTimes;
  1100.     delete[] execTimes2;
  1101.     //Now try to adjust this with respect to memory load-balance
  1102.  
  1103.     bool doPrint          = true;
  1104.     bool doMemLoadBalance = (LOAD_BALANCE_MEMORY) ? true : false;
  1105.     if(doMemLoadBalance)
  1106.     {
  1107.       const int maxTries          = std::max(10,nProcs);
  1108.       const double maxDiff        = 1.9; //Each process has to be within a factor 1.9 of the maximum load
  1109.       const int allowedDifference = 5;
  1110.  
  1111.       for(int tries = maxTries; tries > 0; tries--)
  1112.       {
  1113.         int maxNumber       = 0;
  1114.         int minNumber       = nPartPerProc[0];
  1115.         int countOutsideMin = 0;
  1116.         int sum             = 0;
  1117.  
  1118.         if(doPrint){
  1119.           LOGF(stderr,"Before memory load adjustment: \n");
  1120.           for(int i=0; i < nProcs; i++){
  1121.             LOGF(stderr, "%d \t %d \n", i, nPartPerProc[i]);
  1122.             sum += nPartPerProc[i];
  1123.           }
  1124.           LOGF(stderr, "Sum: %d \n", sum);
  1125.         }
  1126.  
  1127.         //First find the max and min process load and compute the minimum number of
  1128.         //particles a process should have according to the defined balance
  1129.         maxNumber = countOutsideMin = 0;
  1130.  
  1131.         for(int i=0; i < nProcs; i++){
  1132.           maxNumber = std::max(maxNumber, nPartPerProc[i]);
  1133.           minNumber = std::min(minNumber, nPartPerProc[i]);
  1134.         }
  1135.  
  1136.         double requiredNumber = maxNumber / maxDiff;
  1137.  
  1138.         if(doPrint){
  1139.           LOGF(stderr, "Max: %d  Min: %d , maxDiff factor: %f  required: %f \n",
  1140.               maxNumber, minNumber, maxDiff, requiredNumber);
  1141.         }
  1142.  
  1143.         if((abs(minNumber-requiredNumber)) <= allowedDifference)
  1144.         {
  1145.           break; //Difference between required and achieved is within what we allow, accept this
  1146.         }
  1147.  
  1148.         //Count the number of procs below the minNumber and compute number within the limits
  1149.         for(int i=0; i < nProcs; i++) if(requiredNumber > nPartPerProc[i]) countOutsideMin++;
  1150.         int countInsideMin = nProcs - countOutsideMin;
  1151.  
  1152.         if(countOutsideMin == 0)
  1153.           break; //Success, all within the range minimum required...maximum assigned
  1154.  
  1155.         //Compute particles to be added  to the processes outside the range, we take
  1156.         //(0.5*(Particles Required - minLoad)) / (# processes outside the min range) .
  1157.         //To evenly add particles , to prevent large jumps when # outside is small we use
  1158.         //the factor 0.5. For the particles to be removed we do the same but now use
  1159.         //number of processes inside the min range.
  1160.         int addNumberOfParticles = (0.5*(requiredNumber - minNumber)) / countOutsideMin;
  1161.         addNumberOfParticles     = std::max(1, addNumberOfParticles);
  1162.  
  1163.         int removeNumberOfParticles = (0.5*(requiredNumber - minNumber)) / countInsideMin;
  1164.         removeNumberOfParticles     = std::max(1, removeNumberOfParticles);
  1165.  
  1166.         if(doPrint){
  1167.           LOGF(stderr, "#Outside: %d , #Inside: %d Adding total: %f per proc: %d  Removing total: %f per proc: %d \n",
  1168.               countOutsideMin, countInsideMin, requiredNumber-minNumber,
  1169.               addNumberOfParticles, requiredNumber - minNumber, removeNumberOfParticles);
  1170.         }
  1171.  
  1172.         //Finally modify the particle counts :-)
  1173.         for(int i=0; i < nProcs; i++)
  1174.         {
  1175.           if(nPartPerProc[i] < requiredNumber)
  1176.             nPartPerProc[i] += addNumberOfParticles;
  1177.           else if(nPartPerProc[i] > requiredNumber)
  1178.             nPartPerProc[i] -= removeNumberOfParticles;
  1179.         }//end modify
  1180.  
  1181.         if(doPrint){
  1182.           LOGF(stderr,"After memory load adjustment: \n");
  1183.           for(int i=0; i < nProcs; i++) fprintf(stderr, "%d \t %d \n", i, nPartPerProc[i]);
  1184.           LOGF(stderr, "Tries left: %d \n\n\n", tries);
  1185.         }
  1186.       }//for tries
  1187.     } //if doMemLoadBalance
  1188. #else //#if LOAD_BALANCE
  1189.     //Per process, equal number of particles
  1190.     int nPerProc = nTotal / nProcs;
  1191.     for(int i=0; i < nProcs; i++) nPartPerProc[i] = nPerProc;
  1192.     LOGF(stderr, "Number of particles per process: %d \t %d \n", nTotal, nPerProc);
  1193. #endif
  1194.  
  1195.  
  1196.     //All set and done, get the boundaries
  1197.     int tempSum   = 0;
  1198.     int procIdx   = 1;
  1199.     boundaries[0] = make_uint4(0x0, 0x0, 0x0, 0x0);
  1200.     for(int i=0; i < totalNumberOfHashes; i++)
  1201.     {
  1202.       tempSum += allHashes[i].w;
  1203.       if(tempSum >= nPartPerProc[procIdx-1])
  1204.       {
  1205.         LOGF(stderr, "Boundary at: %d\t%d %d %d %d \t %d \n",
  1206.             i, allHashes[i+1].x,allHashes[i+1].y,allHashes[i+1].z,allHashes[i+1].w, tempSum);
  1207.         tempSum = 0;
  1208.         boundaries[procIdx++] = allHashes[i+1];
  1209.       }
  1210.     }//for totalNumberOfHashes
  1211.  
  1212.  
  1213.     //Force final boundary to be the highest possible key value
  1214.     boundaries[nProcs]  = make_uint4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
  1215.  
  1216.     delete[] nPartPerProc;
  1217.     delete[] allHashes;
  1218.   }//if procId == 0
  1219.   delete[] recvHashInfo;
  1220.  
  1221.  
  1222.   //Send the boundaries to all processes
  1223.   MPI_Bcast(boundaries,  sizeof(uint4)*(nProcs+1),MPI_BYTE,0,MPI_COMM_WORLD);
  1224.  
  1225.   if(procId == 0){
  1226.     for(int i=0; i < nProcs; i++)
  1227.     {
  1228.       LOGF(stderr, "Proc: %d Going from: >= %u %u %u  to < %u %u %u \n",i,
  1229.           boundaries[i].x,boundaries[i].y,boundaries[i].z,boundaries[i+1].x,boundaries[i+1].y,boundaries[i+1].z);
  1230.     }
  1231.     LOGF(stderr, "Exchanging and sorting of hashes took: %f \n", get_time()-t0);
  1232.   }
  1233.  
  1234.  
  1235.  
  1236.  
  1237. #endif //if USE_MPI
  1238.   //exit(0);
  1239. }
  1240.  
  1241.  
  1242.   template<class T>
  1243. int octree::MP_exchange_particle_with_overflow_check(int ibox,
  1244.     T *source_buffer,
  1245.     vector<T> &recv_buffer,
  1246.     int firstloc,
  1247.     int nparticles,
  1248.     int isource,
  1249.     int &nsend,
  1250.     unsigned int &recvCount)
  1251. {
  1252. #ifdef USE_MPI
  1253.   MPI_Status status;
  1254.   int local_proc_id = procId;
  1255.   nsend = nparticles;
  1256.  
  1257.   //first send&get the number of particles to send&get
  1258.   unsigned int nreceive;
  1259.  
  1260.   //Send and get the number of particles that are exchanged
  1261.   MPI_Sendrecv(&nsend,1,MPI_INT,ibox,local_proc_id*10,
  1262.       &nreceive,1,MPI_INT,isource,isource*10,MPI_COMM_WORLD,
  1263.       &status);
  1264.  
  1265.   int ss         = sizeof(T);
  1266.   int sendoffset = nparticles-nsend;
  1267.  
  1268.   //Resize the receive buffer
  1269.   if((nreceive + recvCount) > recv_buffer.size())
  1270.   {
  1271.     recv_buffer.resize(nreceive + recvCount);
  1272.   }
  1273.  
  1274.  
  1275.   //Send the actual particles
  1276.   MPI_Sendrecv(&source_buffer[firstloc+sendoffset],ss*nsend,MPI_BYTE,ibox,local_proc_id*10+1,
  1277.       &recv_buffer[recvCount],ss*nreceive,MPI_BYTE,isource,isource*10+1,
  1278.       MPI_COMM_WORLD,&status);
  1279.  
  1280.   recvCount += nreceive;
  1281.  
  1282.   //     int iret = 0;
  1283.   //     int giret;
  1284.   //     MPI_Allreduce(&iret, &giret,1, MPI_INT, MPI_MAX,MPI_COMM_WORLD);
  1285.   //     return giret;
  1286. #endif
  1287.   return 0;
  1288. }
  1289.  
  1290.  
  1291. //Function that uses the GPU to get a set of particles that have to be
  1292. //send to other processes
  1293. void octree::gpuRedistributeParticles_SFC(uint4 *boundaries)
  1294. {
  1295.   //Memory buffers to hold the extracted particle information
  1296.   my_dev::dev_mem<uint>  validList(devContext);
  1297.   my_dev::dev_mem<uint>  compactList(devContext);
  1298.  
  1299.   int memOffset1 = compactList.cmalloc_copy(localTree.generalBuffer1,
  1300.       localTree.n, 0);
  1301.   int memOffset2 = validList.cmalloc_copy(localTree.generalBuffer1,
  1302.       localTree.n, memOffset1);
  1303.  
  1304. //https://github.com/egaburov/fvmhd3d/blob/master/MPI/myMPI.h
  1305.  
  1306.   uint4 lowerBoundary = boundaries[this->procId];
  1307.   uint4 upperBoundary = boundaries[this->procId+1];
  1308.  
  1309.   validList.zeroMem();
  1310.   domainCheckSFC.set_arg<int>(0,     &localTree.n);
  1311.   domainCheckSFC.set_arg<uint4>(1,   &lowerBoundary);
  1312.   domainCheckSFC.set_arg<uint4>(2,   &upperBoundary);
  1313.   domainCheckSFC.set_arg<cl_mem>(3,  localTree.bodies_key.p());
  1314.   domainCheckSFC.set_arg<cl_mem>(4,  validList.p());
  1315.   domainCheckSFC.setWork(localTree.n, 128);
  1316.   domainCheckSFC.execute(execStream->s());
  1317.   execStream->sync();
  1318.  
  1319.   //Create a list of valid and invalid particles
  1320.   this->resetCompact();  //Make sure compact has been reset
  1321.   int validCount;
  1322.   gpuSplit(devContext, validList, compactList, localTree.n, &validCount);
  1323.  
  1324.   LOGF(stderr, "Found %d particles outside my domain, inside: %d \n", validCount, localTree.n-validCount);
  1325.  
  1326.  
  1327.   //Check if the memory size, of the generalBuffer is large enough to store the exported particles
  1328.   //if not allocate more but make sure that the copy of compactList survives
  1329.   int tempSize = localTree.generalBuffer1.get_size() - localTree.n;
  1330.   int needSize = (int)(1.01f*(validCount*(sizeof(bodyStruct)/sizeof(int))));
  1331.  
  1332. #if 0
  1333.   if(tempSize < needSize)
  1334.   {
  1335.     int itemsNeeded = needSize + localTree.n + 4096; //Slightly larger as before for offset space
  1336.  
  1337.     compactList.d2h();  //Copy the compact list to the host we need this list intact
  1338.     int *tempBuf = new int[localTree.n];
  1339.     memcpy(tempBuf, &compactList[0], localTree.n*sizeof(int));
  1340.  
  1341.     //Resize the general buffer
  1342.     localTree.generalBuffer1.cresize(itemsNeeded, false);
  1343.     //Reset memory pointers
  1344.     memOffset1 = compactList.cmalloc_copy(localTree.generalBuffer1,
  1345.         localTree.n, 0);
  1346.  
  1347.     //Restore the compactList
  1348.     memcpy(&compactList[0], tempBuf, localTree.n*sizeof(int));
  1349.     compactList.h2d();
  1350.  
  1351.     delete[] tempBuf;
  1352.   }
  1353.  
  1354.   my_dev::dev_mem<bodyStruct>  bodyBuffer(devContext);
  1355.  
  1356.   memOffset1 = bodyBuffer.cmalloc_copy(localTree.generalBuffer1,
  1357.       validCount, memOffset1);
  1358.  
  1359.  
  1360.   extractOutOfDomainParticlesAdvancedSFC.set_arg<int>(0,    &validCount);
  1361.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(1, compactList.p());
  1362.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(2, localTree.bodies_Ppos.p());
  1363.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(3, localTree.bodies_Pvel.p());
  1364.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(4, localTree.bodies_pos.p());
  1365.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(5, localTree.bodies_vel.p());
  1366.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(6, localTree.bodies_acc0.p());
  1367.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(7, localTree.bodies_acc1.p());
  1368.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(8, localTree.bodies_time.p());
  1369.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(9, localTree.bodies_ids.p());
  1370.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(10, localTree.bodies_key.p());
  1371.   extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(11, bodyBuffer.p());
  1372.   extractOutOfDomainParticlesAdvancedSFC.setWork(validCount, 128);
  1373.   extractOutOfDomainParticlesAdvancedSFC.execute(execStream->s());
  1374.  
  1375.   bodyBuffer.d2h(validCount);
  1376.  
  1377. #else
  1378.  
  1379.   int stepSize          = (tempSize / (sizeof(bodyStruct) / sizeof(int)))-512;
  1380.  
  1381.   bool doInOneGo = true;
  1382.  
  1383.   bodyStruct *extraBodyBuffer = NULL;
  1384.  
  1385.   if(stepSize > needSize)
  1386.   {
  1387.     //We can do it in one go
  1388.     doInOneGo = true;
  1389.   }
  1390.   else
  1391.   {
  1392.     //We need an extra CPU buffer
  1393.     doInOneGo       = false;
  1394.     extraBodyBuffer = new bodyStruct[validCount];
  1395.     assert(extraBodyBuffer != NULL);
  1396.   }
  1397.  
  1398.   my_dev::dev_mem<bodyStruct>  bodyBuffer(devContext);
  1399.  
  1400.   memOffset1 = bodyBuffer.cmalloc_copy(localTree.generalBuffer1,
  1401.       stepSize, memOffset1);
  1402.  
  1403.   int extractOffset = 0;
  1404.   for(unsigned int i=0; i < validCount; i+= stepSize)
  1405.   {
  1406.     int items = min(stepSize, (int)(validCount-i));
  1407.  
  1408.     if(items > 0)
  1409.     {
  1410.       extractOutOfDomainParticlesAdvancedSFC.set_arg<int>(0,    &extractOffset);
  1411.       extractOutOfDomainParticlesAdvancedSFC.set_arg<int>(1,    &items);
  1412.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(2, compactList.p());
  1413.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(3, localTree.bodies_Ppos.p());
  1414.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(4, localTree.bodies_Pvel.p());
  1415.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(5, localTree.bodies_pos.p());
  1416.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(6, localTree.bodies_vel.p());
  1417.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(7, localTree.bodies_acc0.p());
  1418.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(8, localTree.bodies_acc1.p());
  1419.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(9, localTree.bodies_time.p());
  1420.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(10, localTree.bodies_ids.p());
  1421.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(11, localTree.bodies_key.p());
  1422.       extractOutOfDomainParticlesAdvancedSFC.set_arg<cl_mem>(12, bodyBuffer.p());
  1423.       extractOutOfDomainParticlesAdvancedSFC.setWork(items, 128);
  1424.       extractOutOfDomainParticlesAdvancedSFC.execute(execStream->s());
  1425.  
  1426.       bodyBuffer.d2h(items); // validCount);
  1427.       if(!doInOneGo)
  1428.       {
  1429.         //Do the extra memory copy to the CPU buffer
  1430.         memcpy(&extraBodyBuffer[extractOffset], &bodyBuffer[0], sizeof(bodyStruct)*items);
  1431.         extractOffset += items;
  1432.       }
  1433.     }
  1434.   }//end for
  1435.  
  1436.   if(doInOneGo)
  1437.   {
  1438.     extraBodyBuffer = &bodyBuffer[0]; //Assign correct pointer
  1439.   }
  1440.  
  1441. #endif
  1442.  
  1443.  
  1444.   //Now we have to move particles from the back of the array to the invalid spots
  1445.   //this can be done in parallel with exchange operation to hide some time
  1446.  
  1447.   //One integer for counting, true-> initialize to zero so counting starts at 0
  1448.   my_dev::dev_mem<uint>  atomicBuff(devContext);
  1449.   memOffset1 = atomicBuff.cmalloc_copy(localTree.generalBuffer1,1, memOffset1);
  1450.   atomicBuff.zeroMem();
  1451.  
  1452.  
  1453.   //Internal particle movement
  1454.   internalMoveSFC.set_arg<int>(0,     &validCount);
  1455.   internalMoveSFC.set_arg<int>(1,     &localTree.n);
  1456.   internalMoveSFC.set_arg<uint4>(2,   &lowerBoundary);
  1457.   internalMoveSFC.set_arg<uint4>(3,   &upperBoundary);
  1458.   internalMoveSFC.set_arg<cl_mem>(4,  compactList.p());
  1459.   internalMoveSFC.set_arg<cl_mem>(5,  atomicBuff.p());
  1460.   internalMoveSFC.set_arg<cl_mem>(6,  localTree.bodies_Ppos.p());
  1461.   internalMoveSFC.set_arg<cl_mem>(7,  localTree.bodies_Pvel.p());
  1462.   internalMoveSFC.set_arg<cl_mem>(8,  localTree.bodies_pos.p());
  1463.   internalMoveSFC.set_arg<cl_mem>(9,  localTree.bodies_vel.p());
  1464.   internalMoveSFC.set_arg<cl_mem>(10, localTree.bodies_acc0.p());
  1465.   internalMoveSFC.set_arg<cl_mem>(11, localTree.bodies_acc1.p());
  1466.   internalMoveSFC.set_arg<cl_mem>(12, localTree.bodies_time.p());
  1467.   internalMoveSFC.set_arg<cl_mem>(13, localTree.bodies_ids.p());
  1468.   internalMoveSFC.set_arg<cl_mem>(14, localTree.bodies_key.p());
  1469.   internalMoveSFC.setWork(validCount, 128);
  1470.   internalMoveSFC.execute(execStream->s());
  1471.  
  1472.   //this->gpu_exchange_particles_with_overflow_check_SFC(localTree, &bodyBuffer[0], compactList, validCount);
  1473.   this->gpu_exchange_particles_with_overflow_check_SFC(localTree, &extraBodyBuffer[0], compactList, validCount);
  1474.  
  1475.   if(!doInOneGo) delete[] extraBodyBuffer;
  1476.  
  1477. } //End gpuRedistributeParticles
  1478.  
  1479. //Exchange particles with other processes
  1480. int octree::gpu_exchange_particles_with_overflow_check_SFC(tree_structure &tree,
  1481.     bodyStruct *particlesToSend,
  1482.     my_dev::dev_mem<uint> &extractList,
  1483.     int nToSend)
  1484. {
  1485. #ifdef USE_MPI
  1486.  
  1487.   int myid      = procId;
  1488.   int nproc     = nProcs;
  1489.   int iloc      = 0;
  1490.   int nbody     = nToSend;
  1491.  
  1492.  
  1493.   bodyStruct  tmpp;
  1494.  
  1495.   //  int *firstloc   = new int[nProcs+1];
  1496.   //  int *nparticles = new int[nProcs+1];
  1497.   //  int *nreceive   = new int[nProcs];
  1498.   //  int *nsendbytes = new int[nProcs];
  1499.   //  int *nrecvbytes = new int[nProcs];
  1500.   //
  1501.   //  int *nsendDispls = new int [nProcs+1];
  1502.   //  int *nrecvDispls = new int [nProcs+1];
  1503.  
  1504.   int *firstloc    = &exchangePartBuffer[0*nProcs];                //Size nProcs+1
  1505.   int *nparticles  = &exchangePartBuffer[1*(nProcs+1)];            //Size nProcs+1
  1506.   int *nsendDispls = &exchangePartBuffer[2*(nProcs+1)];            //Size nProcs+1
  1507.   int *nrecvDispls = &exchangePartBuffer[3*(nProcs+1)];            //Size nProcs+1
  1508.   int *nreceive    = &exchangePartBuffer[4*(nProcs+1)];            //Size nProcs
  1509.   int *nsendbytes  = &exchangePartBuffer[4*(nProcs+1) + 1*nProcs]; //Size nProcs
  1510.   int *nrecvbytes  = &exchangePartBuffer[4*(nProcs+1) + 2*nProcs]; //Size nProcs
  1511.  
  1512.  
  1513.  
  1514.   memset(nparticles,  0, sizeof(int)*(nProcs+1));
  1515.   memset(nreceive,    0, sizeof(int)*(nProcs));
  1516.   memset(nsendbytes,  0, sizeof(int)*(nProcs));
  1517.   memset(nsendDispls, 0, sizeof(int)*(nProcs));
  1518.  
  1519.   // Loop over particles and determine which particle needs to go where
  1520.   // reorder the bodies in such a way that bodies that have to be send
  1521.   // away are stored after each other in the array
  1522.   double t1 = get_time();
  1523.  
  1524.   //Array reserve some memory before hand , 1%
  1525.   vector<bodyStruct> array2Send;
  1526.   array2Send.reserve((int)(nToSend*1.5));
  1527.  
  1528.  
  1529.  
  1530.   static int firstSort = 1;
  1531. if(firstSort)
  1532. {
  1533.   std::vector<int> offsets(nProcs+1);
  1534.   std::vector<int> items(nProcs+1);
  1535.  
  1536.   int location       = 0;
  1537.   offsets[location]  = 0;
  1538.  
  1539.   for(int i=0; i < nToSend; i++)
  1540.   {
  1541.     uint4 key  = particlesToSend[i].key;
  1542.  
  1543.     bool assigned = false;
  1544.     while(!assigned)
  1545.     {
  1546.       uint4 lowerBoundary = tree.parallelBoundaries[location];
  1547.       uint4 upperBoundary = tree.parallelBoundaries[location+1];
  1548.  
  1549.       int bottom = cmp_uint4(key, lowerBoundary);
  1550.       int top    = cmp_uint4(key, upperBoundary);
  1551.  
  1552.       assert(bottom >= 0);
  1553.  
  1554.       if(top < 0)
  1555.       {
  1556.         //is in box
  1557.         assigned = true;
  1558.       }
  1559.       else
  1560.       {
  1561.         //outside box
  1562.         offsets[++location] = i;
  1563.         assert(location < nProcs);
  1564.       }
  1565.     }//while
  1566.   }//for
  1567.  
  1568.   //Fill remaining processes
  1569.   while(location <= nProcs)
  1570.     offsets[++location] = nToSend;
  1571.  
  1572.   //Fill items
  1573.   for(int ib=0; ib < nProcs; ib++)
  1574.   {
  1575.     items[ib] = offsets[ib+1]-offsets[ib];
  1576.   }
  1577.  
  1578.   assert(items[procId] == 0);
  1579.  
  1580.   for(int ib =0; ib < nProcs; ib++)
  1581.   {
  1582.     nparticles[ib] = items[ib];
  1583.     nsendbytes[ib] = nparticles[ib]*sizeof(bodyStruct);
  1584.     nsendDispls[ib] = offsets[ib]*sizeof(bodyStruct);
  1585.   }
  1586.  
  1587. //  char buff[512];
  1588. //  sprintf(buff, "Proc: ");
  1589. //  for(int i=0; i < nProcs; i++)
  1590. //  {
  1591. //    sprintf(buff, "%s [%d, %d] ", buff, nparticles[i], nsendbytes[i]);
  1592. //  }
  1593. //  LOGF(stderr,"%s \n", buff);
  1594.  
  1595.   array2Send.clear();
  1596.   array2Send.insert(array2Send.end(), particlesToSend, particlesToSend+nToSend);
  1597.  
  1598. #if 1
  1599.   for(int ib=0; ib < nProcs; ib++)
  1600.   {
  1601.     uint4 lowerBoundary = tree.parallelBoundaries[ib];
  1602.     uint4 upperBoundary = tree.parallelBoundaries[ib+1];
  1603.  
  1604.     for(int i= offsets[ib]; i <  offsets[ib+1]; i++)
  1605.     {
  1606.       uint4 key  = particlesToSend[i].key;
  1607.       int bottom = cmp_uint4(key, lowerBoundary);
  1608.       int top    = cmp_uint4(key, upperBoundary);
  1609.  
  1610.       if(bottom >= 0 && top < 0)
  1611.       {
  1612.         //Inside
  1613.       }
  1614.       else
  1615.       {
  1616.         assert(!"Particle not in the box");
  1617.       }
  1618.     }//for i
  1619.   }//for ib
  1620. #endif
  1621.  
  1622.  
  1623.   //LOGF(stderr,  "EXCHANGE reorder iter: %d  took: %lg \tItems: %d Total-n: %d\n",
  1624. if(iter == 0 && procId == 0)
  1625.   fprintf(stderr,  "EXCHANGE reorder iter: %d  took: %lg \tItems: %d Total-n: %d\n",
  1626.       iter, get_time()-t1, nToSend, tree.n);
  1627.  
  1628.  
  1629. firstSort = 0;
  1630. }
  1631. else
  1632.  
  1633.  
  1634.  {
  1635.   //Sort the statistics, causing the processes with which we interact most to be on top
  1636.   std::sort(fullGrpAndLETRequestStatistics, fullGrpAndLETRequestStatistics+nProcs, cmp_uint2_reverse());
  1637.  
  1638.  
  1639.   for(int ib=0;ib<nproc;ib++)
  1640.   {
  1641.     //    int ibox          = (ib+myid)%nproc;
  1642.     int ibox = fullGrpAndLETRequestStatistics[ib].y;
  1643.  
  1644.     firstloc[ibox]    = iloc;      //Index of the first particle send to proc: ibox
  1645.     nsendDispls[ibox] = iloc*sizeof(bodyStruct);
  1646.  
  1647.     for(int i=iloc; i<nbody;i++)
  1648.     {
  1649.       uint4 lowerBoundary = tree.parallelBoundaries[ibox];
  1650.       uint4 upperBoundary = tree.parallelBoundaries[ibox+1];
  1651.  
  1652.       uint4 key  = particlesToSend[i].key;
  1653.       int bottom = cmp_uint4(key, lowerBoundary);
  1654.       int top    = cmp_uint4(key, upperBoundary);
  1655.  
  1656.  
  1657.       if(bottom >= 0 && top < 0)
  1658.       {
  1659.         //Reorder the particle information
  1660.         tmpp                  = particlesToSend[iloc];
  1661.         particlesToSend[iloc] = particlesToSend[i];
  1662.         particlesToSend[i]    = tmpp;
  1663.  
  1664.         //Put the particle in the array of to send particles
  1665.         array2Send.push_back(particlesToSend[iloc]);
  1666.  
  1667.         iloc++;
  1668.       }// end if
  1669.     }//for i=iloc
  1670.     nparticles[ibox] = iloc-firstloc[ibox];//Number of particles that has to be send to proc: ibox
  1671.     nsendbytes[ibox] = nparticles[ibox]*sizeof(bodyStruct);
  1672.   } // for(int ib=0;ib<nproc;ib++)
  1673.  
  1674.  
  1675.   //   printf("Required search time: %lg ,proc: %d found in our own box: %d n: %d  to others: %ld \n",
  1676.   //          get_time()-t1, myid, nparticles[myid], tree.n, array2Send.size());
  1677.   if(iloc < nbody)
  1678.   {
  1679.     LOGF(stderr, "Exchange_particle error: A particle could not be assigned to a box: iloc: %d total: %d \n", iloc,nbody);
  1680.     exit(0);
  1681.   }
  1682.   LOGF(stderr,  "EXCHANGE reorder iter: %d  took: %lg \tItems: %d Total-n: %d\n",
  1683.       iter, get_time()-t1, nToSend, tree.n);
  1684.  
  1685.  }
  1686.   t1 = get_time();
  1687. #if 0
  1688.   MPI_Alltoall(nparticles, 1, MPI_INT, nreceive, 1, MPI_INT, MPI_COMM_WORLD);
  1689.  
  1690.  
  1691.   //Compute how much we will receive and the offsets and displacements
  1692.   nrecvDispls[0]   = 0;
  1693.   nrecvbytes [0]   = nreceive[0]*sizeof(bodyStruct);
  1694.   unsigned int recvCount  = nreceive[0];
  1695.   for(int i=1; i < nProcs; i++)
  1696.   {
  1697.     nrecvbytes [i] = nreceive[i]*sizeof(bodyStruct);
  1698.     nrecvDispls[i] = nrecvDispls[i-1] + nrecvbytes [i-1];
  1699.     recvCount     += nreceive[i];
  1700.   }
  1701.  
  1702.   //  LOGF(stderr,"Going to receive: %d || %d %d : %d %d\n",
  1703.   //      recvCount, nrecvbytes[0], nrecvDispls[0],
  1704.   //      nrecvbytes[1], nrecvDispls[1]);
  1705.   //  LOGF(stderr,"Going to send: %d || %d %d : %d %d\n",
  1706.   //      nToSend, nsendbytes[0], nsendDispls[0],
  1707.   //        nsendbytes[1], nsendDispls[1]);
  1708.  
  1709.   vector<bodyStruct> recv_buffer3(recvCount);
  1710.  
  1711.   MPI_Alltoallv(&array2Send[0],   nsendbytes, nsendDispls, MPI_BYTE,
  1712.       &recv_buffer3[0], nrecvbytes, nrecvDispls, MPI_BYTE,
  1713.       MPI_COMM_WORLD);
  1714.  
  1715.   //  delete[] nsendbytes;
  1716.   //  delete[] nrecvbytes;
  1717.   //  delete[] nreceive;
  1718.   //  delete[] nsendDispls;
  1719.   //  delete[] nrecvDispls;
  1720.  
  1721. #elif 0
  1722.   MPI_Alltoall(nparticles, 1, MPI_INT, nreceive, 1, MPI_INT, MPI_COMM_WORLD);
  1723.   double t92 = get_time();
  1724.   unsigned int recvCount  = nreceive[0];
  1725.   for (int i = 1; i < nproc; i++)
  1726.   {
  1727.     recvCount     += nreceive[i];
  1728.   }
  1729.   vector<bodyStruct> recv_buffer3(recvCount);
  1730.   double t93=get_time();
  1731.  
  1732.   int recvOffset = 0;
  1733.  
  1734.   static MPI_Status stat;
  1735.   for (int dist = 1; dist < nproc; dist++)
  1736.   {
  1737.     const int src = (nproc + myid - dist) % nproc;
  1738.     const int dst = (nproc + myid + dist) % nproc;
  1739.     const int scount = nsendbytes[dst];
  1740.     const int rcount = nreceive[src]*sizeof(bodyStruct);
  1741.     if ((myid/dist) & 1)
  1742.     {
  1743.  
  1744.       if (scount > 0) MPI_Send(&array2Send[nsendDispls[dst]/sizeof(bodyStruct)], scount, MPI_BYTE, dst, 1, MPI_COMM_WORLD);
  1745.       if (rcount > 0) MPI_Recv(&recv_buffer3[recvOffset], rcount, MPI_BYTE   , src, 1, MPI_COMM_WORLD, &stat);
  1746.  
  1747.       recvOffset +=  nreceive[src];
  1748.     }
  1749.     else
  1750.     {
  1751.       if (rcount > 0) MPI_Recv(&recv_buffer3[recvOffset], rcount, MPI_BYTE   , src, 1, MPI_COMM_WORLD, &stat);
  1752.       if (scount > 0) MPI_Send(&array2Send[nsendDispls[dst]/sizeof(bodyStruct)], scount, MPI_BYTE, dst, 1, MPI_COMM_WORLD);
  1753.  
  1754.       recvOffset +=  nreceive[src];
  1755.     }
  1756.   }
  1757.  
  1758.  
  1759.   //  delete[] nsendbytes;
  1760.   //  delete[] nrecvbytes;
  1761.   //  delete[] nreceive;
  1762.   //  delete[] nsendDispls;
  1763.   //  delete[] nrecvDispls;
  1764.   double t94 = get_time();
  1765.  
  1766. #elif 1
  1767.  
  1768.   double t91 = get_time();
  1769.   MPI_Alltoall(nparticles, 1, MPI_INT, nreceive, 1, MPI_INT, MPI_COMM_WORLD);
  1770.  
  1771.  
  1772.  
  1773.   double t92 = get_time();
  1774.   unsigned int recvCount  = nreceive[0];
  1775.  
  1776.   for (int i = 1; i < nproc; i++)
  1777.   {
  1778.     recvCount     += nreceive[i];
  1779.   }
  1780.   vector<bodyStruct> recv_buffer3(recvCount);
  1781.   double t93=get_time();
  1782.  
  1783.   int recvOffset = 0;
  1784.  
  1785. #define NMAXPROC 32768
  1786.   static MPI_Status stat[NMAXPROC];
  1787.   static MPI_Request req[NMAXPROC*2];
  1788.  
  1789.   int nreq = 0;
  1790.   for (int dist = 1; dist < nproc; dist++)
  1791.   {
  1792.     const int src    = (nproc + myid - dist) % nproc;
  1793.     const int dst    = (nproc + myid + dist) % nproc;
  1794.     const int scount = nsendbytes[dst];
  1795.     const int rcount = nreceive[src]*sizeof(bodyStruct);
  1796.  
  1797. #if 1
  1798.     if (scount > 0) MPI_Isend(&array2Send[nsendDispls[dst]/sizeof(bodyStruct)], scount, MPI_BYTE, dst, 1, MPI_COMM_WORLD, &req[nreq++]);
  1799.     if(rcount > 0)
  1800.     {
  1801.       MPI_Irecv(&recv_buffer3[recvOffset], rcount, MPI_BYTE, src, 1, MPI_COMM_WORLD, &req[nreq++]);
  1802.       recvOffset += nreceive[src];
  1803.     }
  1804. #else
  1805.  
  1806.     MPI_Status stat;
  1807.     MPI_Sendrecv(&array2Send[nsendDispls[dst]/sizeof(bodyStruct)],
  1808.               scount, MPI_BYTE, dst, 1,
  1809.             &recv_buffer3[recvOffset], rcount, MPI_BYTE, src, 1, MPI_COMM_WORLD, &stat);
  1810.       recvOffset += nreceive[src];
  1811. #endif 
  1812.   }
  1813.  
  1814.   double t94 = get_time();
  1815.   MPI_Waitall(nreq, req, stat);
  1816.  
  1817.   LOGF(stderr, "EXCHANGE comm iter: %d  a2asize: %lg alloc: %lg data-start: %lg data-wait: %lg \n",
  1818.       iter, t92-t91, t93-t92, t94-t93, get_time() -t94);
  1819.  
  1820. #else
  1821.  
  1822.   //Allocate two times the amount of memory of that which we send
  1823.   vector<bodyStruct> recv_buffer3(nbody*2);
  1824.   unsigned int recvCount = 0;
  1825.  
  1826.   //Exchange the data with the other processors
  1827.   int ibend = -1;
  1828.   int nsend;
  1829.   int isource = 0;
  1830.   for(int ib=nproc-1;ib>0;ib--)
  1831.   {
  1832.     int ibox = (ib+myid)%nproc; //index to send...
  1833.  
  1834.     if (ib == nproc-1)
  1835.     {
  1836.       isource= (myid+1)%nproc;
  1837.     }
  1838.     else
  1839.     {
  1840.       isource = (isource+1)%nproc;
  1841.       if (isource == myid)isource = (isource+1)%nproc;
  1842.     }
  1843.  
  1844.  
  1845.     if(MP_exchange_particle_with_overflow_check<bodyStruct>(ibox, &array2Send[0],
  1846.           recv_buffer3, firstloc[ibox] - nparticles[myid],
  1847.           nparticles[ibox], isource,
  1848.           nsend, recvCount))
  1849.     {
  1850.       ibend = ibox; //Here we get if exchange failed
  1851.       ib = 0;
  1852.     }//end if mp exchang
  1853.   }//end for all boxes
  1854.  
  1855.  
  1856.   if(ibend == -1){
  1857.  
  1858.   }else{
  1859.     //Something went wrong
  1860.     cerr << "ERROR in exchange_particles_with_overflow_check! \n"; exit(0);
  1861.   }
  1862. #endif
  1863.  
  1864.   LOGF(stderr,"Required inter-process communication time: %lg ,proc: %d\n", get_time()-t1, myid);
  1865.  
  1866.   //Compute the new number of particles:
  1867.   int newN = tree.n + recvCount - nToSend;
  1868.  
  1869. #if 1
  1870.   if(iter < 1){ /* jb2404 */
  1871.   fprintf(stderr, "Proc: %d Exchange, received %d \tSend: %d newN: %d\n",
  1872.                 procId, recvCount, nToSend, newN);
  1873.     }
  1874. #endif
  1875.  
  1876.   execStream->sync();   //make certain that the particle movement on the device
  1877.   //is complete before we resize
  1878.  
  1879.   //Allocate 10% extra if we have to allocate, to reduce the total number of
  1880.   //memory allocations
  1881.   int memSize = newN;
  1882.   if(tree.bodies_acc0.get_size() < newN)
  1883.     memSize = newN * MULTI_GPU_MEM_INCREASE;
  1884.  
  1885.   LOGF(stderr,"Going to allocate memory for %d particles \n", newN);
  1886.  
  1887.   //Have to resize the bodies vector to keep the numbering correct
  1888.   //but do not reduce the size since we need to preserve the particles
  1889.   //in the over sized memory
  1890.   tree.bodies_pos. cresize(memSize + 1, false);
  1891.   tree.bodies_acc0.cresize(memSize,     false);
  1892.   tree.bodies_acc1.cresize(memSize,     false);
  1893.   tree.bodies_vel. cresize(memSize,     false);
  1894.   tree.bodies_time.cresize(memSize,     false);
  1895.   tree.bodies_ids. cresize(memSize + 1, false);
  1896.   tree.bodies_Ppos.cresize(memSize + 1, false);
  1897.   tree.bodies_Pvel.cresize(memSize + 1, false);
  1898.   tree.bodies_key. cresize(memSize + 1, false);
  1899.  
  1900.   //This one has to be at least the same size as the number of particles in order to
  1901.   //have enough space to store the other buffers
  1902.   //Can only be resized after we are done since we still have
  1903.   //parts of memory pointing to that buffer (extractList)
  1904.   //Note that we allocate some extra memory to make everything texture/memory aligned
  1905.   tree.generalBuffer1.cresize_nocpy(3*(memSize)*4 + 4096, false);
  1906.  
  1907.  
  1908.   //Now we have to copy the data in batches in case the generalBuffer1 is not large enough
  1909.   //Amount we can store:
  1910.   int spaceInIntSize    = 3*(memSize)*4;
  1911.   int stepSize          = spaceInIntSize / (sizeof(bodyStruct) / sizeof(int));
  1912.  
  1913.   my_dev::dev_mem<bodyStruct>  bodyBuffer(devContext);
  1914.  
  1915.   int memOffset1 = bodyBuffer.cmalloc_copy(localTree.generalBuffer1,
  1916.       stepSize, 0);
  1917.  
  1918. //  fprintf(stderr, "Exchange, received %d \tSend: %d newN: %d\tItems that can be insert in one step: %d\n",
  1919. //      recvCount, nToSend, newN, stepSize);
  1920.   LOGF(stderr, "Exchange, received %d \tSend: %d newN: %d\tItems that can be insert in one step: %d\n",
  1921.       recvCount, nToSend, newN, stepSize);
  1922.  
  1923.   int insertOffset = 0;
  1924.   for(unsigned int i=0; i < recvCount; i+= stepSize)
  1925.   {
  1926.     int items = min(stepSize, (int)(recvCount-i));
  1927.  
  1928.     if(items > 0)
  1929.     {
  1930.       //Copy the data from the MPI receive buffers into the GPU-send buffer
  1931.       memcpy(&bodyBuffer[0], &recv_buffer3[insertOffset], sizeof(bodyStruct)*items);
  1932.  
  1933.       bodyBuffer.h2d(items);
  1934.  
  1935.       //Start the kernel that puts everything in place
  1936.       insertNewParticlesSFC.set_arg<int>(0,    &nToSend);
  1937.       insertNewParticlesSFC.set_arg<int>(1,    &items);
  1938.       insertNewParticlesSFC.set_arg<int>(2,    &tree.n);
  1939.       insertNewParticlesSFC.set_arg<int>(3,    &insertOffset);
  1940.       insertNewParticlesSFC.set_arg<cl_mem>(4, localTree.bodies_Ppos.p());
  1941.       insertNewParticlesSFC.set_arg<cl_mem>(5, localTree.bodies_Pvel.p());
  1942.       insertNewParticlesSFC.set_arg<cl_mem>(6, localTree.bodies_pos.p());
  1943.       insertNewParticlesSFC.set_arg<cl_mem>(7, localTree.bodies_vel.p());
  1944.       insertNewParticlesSFC.set_arg<cl_mem>(8, localTree.bodies_acc0.p());
  1945.       insertNewParticlesSFC.set_arg<cl_mem>(9, localTree.bodies_acc1.p());
  1946.       insertNewParticlesSFC.set_arg<cl_mem>(10, localTree.bodies_time.p());
  1947.       insertNewParticlesSFC.set_arg<cl_mem>(11, localTree.bodies_ids.p());
  1948.       insertNewParticlesSFC.set_arg<cl_mem>(12, localTree.bodies_key.p());
  1949.       insertNewParticlesSFC.set_arg<cl_mem>(13, bodyBuffer.p());
  1950.       insertNewParticlesSFC.setWork(items, 128);
  1951.       insertNewParticlesSFC.execute(execStream->s());
  1952.     }
  1953.  
  1954.     insertOffset += items;
  1955.   }
  1956.  
  1957.   //   printf("Required gpu malloc time step 1: %lg \t Size: %d \tRank: %d \t Size: %d \n",
  1958.   //          get_time()-t1, newN, mpiGetRank(), tree.bodies_Ppos.get_size());
  1959.   //   t1 = get_time();
  1960.   tree.setN(newN);
  1961.  
  1962.   //Resize the arrays of the tree
  1963.   reallocateParticleMemory(tree);
  1964.  
  1965.   //   printf("Required gpu malloc time step 2: %lg \n", get_time()-t1);
  1966.   //   printf("Total GPU interaction time: %lg \n", get_time()-t2);
  1967.  
  1968. #endif
  1969.   int retValue = 0;
  1970.  
  1971.   //  delete[] firstloc;
  1972.   //  delete[] nparticles;
  1973.  
  1974.   return retValue;
  1975. }
  1976.  
  1977.  
  1978.  
  1979. //Functions related to the LET Creation and Exchange
  1980.  
  1981. //Broadcast the group-tree structure (used during the LET creation)
  1982. //First we gather the size, so we can create/allocate memory
  1983. //and then we broad-cast the final structure
  1984. //This basically is a sync-operation and therefore can be quite costly
  1985. //Maybe we want to do this in a separate thread
  1986. /****** EGABUROV ****/
  1987. void octree::sendCurrentInfoGrpTree()
  1988. {
  1989. #ifdef USE_MPI
  1990.  
  1991. #if 1  /* new group code, EGABUROV *****/
  1992.   localTree.boxSizeInfo.waitForCopyEvent();
  1993.   localTree.boxCenterInfo.waitForCopyEvent();
  1994.  
  1995.   std::vector<real4> groupCentre, groupSize;
  1996.   extractGroups(
  1997.       groupCentre, groupSize,
  1998.       &localTree.boxCenterInfo[0],
  1999.       &localTree.boxSizeInfo[0],
  2000.       localTree.level_list[localTree.startLevelMin].x,
  2001.       localTree.level_list[localTree.startLevelMin].y,
  2002.       localTree.n_nodes);
  2003.  
  2004.   groupCentre.insert(groupCentre.end(), groupSize.begin(), groupSize.end());
  2005.  
  2006.   int nGroups = groupCentre.size();
  2007.   LOGF(stderr, "ExtractGroups n: %d [%d]  size= %f %f %f  cnt= %f %f %f \n",
  2008.       nGroups, (int)groupSize.size(),
  2009.       groupSize[0].x, groupSize[0].y, groupSize[0].z,
  2010.       groupCentre[0].x, groupCentre[0].y, groupCentre[0].z);
  2011.  
  2012.  
  2013.   std::vector<int> globalSizeArray(nProcs), displacement(nProcs,0);
  2014.   MPI_Allgather(&nGroups,  sizeof(int), MPI_BYTE,
  2015.       &globalSizeArray[0], sizeof(int), MPI_BYTE, MPI_COMM_WORLD); /* to globalSize Array */
  2016.  
  2017.   int runningOffset = 0;
  2018.   for (int i = 0; i < nProcs; i++)
  2019.   {
  2020.     this->globalGrpTreeCount[i] = globalSizeArray[i];
  2021.     this->globalGrpTreeOffsets[i] = runningOffset;
  2022.     fullGrpAndLETRequest[i] = 0;
  2023.  
  2024.     displacement[i] = runningOffset*sizeof(real4);
  2025.  
  2026.     runningOffset += globalSizeArray[i];
  2027.     globalSizeArray[i] *= sizeof(real4);
  2028.   }
  2029.  
  2030.  
  2031.  
  2032.   if (globalGrpTreeCntSize) delete[] globalGrpTreeCntSize;
  2033.   const int totalNumberOfGroups = runningOffset;  /*check if defined */
  2034.   globalGrpTreeCntSize = new real4[totalNumberOfGroups]; /* totalNumberOfGroups = 2*nGroups_recvd */
  2035.  
  2036.   /* compute displacements for allgatherv */
  2037.   MPI_Allgatherv(
  2038.       &groupCentre[0], sizeof(real4)*nGroups, MPI_BYTE,
  2039.       globalGrpTreeCntSize, &globalSizeArray[0], &displacement[0], MPI_BYTE,
  2040.       MPI_COMM_WORLD);
  2041.  
  2042.  
  2043.  
  2044. #elif 1
  2045.   /*
  2046.      als ontvangst van alltoall positief, sturen we de size van de kleine tree
  2047.      als negatief is het ook de size en geven we aan dat we ook de
  2048.      volledige tree willen (vergelijk baar met een sendReq van 1 in de vorige code)
  2049.  
  2050.      daarna all gather met de psotieve size en offsets om alles te ontvange
  2051.  
  2052.      daarna voor de negatieve doen we de volledige tree, maar daarvoor hebben we size
  2053.      voor nodig. Oke werkt niet
  2054.  
  2055.      gebruikt uint2 voor sendeq
  2056.  
  2057.      uint2.x = size van de top tree. Als positief, dan heben we alleen dit nodig. Als negatief willen we volledige tree
  2058.      uint2.y = size van de volledige tree.
  2059.  
  2060.      na de all2all doen we een all_gatherv, voor de kleine tree die iedereen krijgt
  2061.      daarna isend/irecv zoals in domain exchange voor de volledige tree.
  2062.      Hopelijk is dat sneller dan de huidige methode
  2063.      */
  2064.  
  2065.   if(nProcs > NUMBER_OF_FULL_EXCHANGE)
  2066.   {
  2067.     //Sort the data and take the top NUMBER_OF_FULL_EXCHANGE to be used
  2068.     std::partial_sort(fullGrpAndLETRequestStatistics,
  2069.         fullGrpAndLETRequestStatistics+NUMBER_OF_FULL_EXCHANGE, //Top items
  2070.         fullGrpAndLETRequestStatistics+nProcs,
  2071.         cmp_uint2_reverse());
  2072.  
  2073.     //Set the top NUMBER_OF_FULL_EXCHANGE to be active
  2074.     memset(fullGrpAndLETRequest, 0, sizeof(int)*nProcs);
  2075.     for(int i=0; i < NUMBER_OF_FULL_EXCHANGE; i++)
  2076.     {
  2077.       fullGrpAndLETRequest[fullGrpAndLETRequestStatistics[i].y] = 1;
  2078.     }
  2079.   }
  2080.   else
  2081.   {
  2082.     //Set everything active, except ourself
  2083.     for(int i=0; i < nProcs; i++)
  2084.       fullGrpAndLETRequest[i] = 1;
  2085.     fullGrpAndLETRequest[procId] = 0;
  2086.   }
  2087.  
  2088.  
  2089.   std::vector<int2> sendReq2(nProcs);
  2090.   std::vector<int2> recvReq2(nProcs);
  2091.  
  2092.   //Set the sizes and indicate what we need and don't need
  2093.   //if .x is negative, we need the full tree
  2094.   for(int i=0; i < nProcs; i++)
  2095.   {
  2096.     sendReq2[i].x = grpTree_n_topNodes*2;
  2097.     sendReq2[i].y = grpTree_n_nodes*2;
  2098.     if(fullGrpAndLETRequest[i] == 1) sendReq2[i].x = -1*sendReq2[i].x;
  2099.   }
  2100.   //Do the all2all
  2101.  
  2102.  
  2103.   double t00 = get_time();
  2104.   //gather the requests
  2105.   MPI_Alltoall(&sendReq2[0], 1*sizeof(int2), MPI_BYTE,
  2106.       &recvReq2[0], 1*sizeof(int2), MPI_BYTE,
  2107.       MPI_COMM_WORLD);
  2108.   double t10 = get_time();
  2109.  
  2110.   //Compute offsets, sizes, displacements, etc
  2111.   unsigned int allGatherRecvOffset = 0;
  2112.  
  2113.   unsigned int nWantFullTreeCount = 0;
  2114.   unsigned int nWantFullTreeList[nProcs];
  2115.  
  2116.   int *allGatherRecvSizeBytes = &infoGrpTreeBuffer[0*nProcs];
  2117.   int *allGatherRecvDispBytes = &infoGrpTreeBuffer[1*nProcs];
  2118.  
  2119.   for(int i=0; i < nProcs; i++)
  2120.   {
  2121.     if(recvReq2[i].x < 0)
  2122.     {
  2123.       nWantFullTreeList[nWantFullTreeCount++] = i;
  2124.     }
  2125.  
  2126.     //The size of the all gather is always the same
  2127.     allGatherRecvSizeBytes[i] = abs(recvReq2[i].x)   * sizeof(real4);
  2128.  
  2129.     /* egaburov */
  2130.     if(fullGrpAndLETRequest[i] == 1)
  2131.     {
  2132.       //Fill in the full info for later, eventhough we first receive
  2133.       //the small tree
  2134.       this->globalGrpTreeCount[i]   = recvReq2[i].y;  /* egaburov, this stores , it is used by getLETopt */
  2135.       this->globalGrpTreeOffsets[i] = allGatherRecvOffset;
  2136.  
  2137.       allGatherRecvDispBytes[i]     = allGatherRecvOffset * sizeof(real4);
  2138.       allGatherRecvOffset          += recvReq2[i].y;
  2139.     }
  2140.     /* egaburov */
  2141.     else
  2142.     {
  2143.       //Fill in the small-tree info, which is enough for us
  2144.       this->globalGrpTreeCount[i]   = abs(recvReq2[i].x);
  2145.       this->globalGrpTreeOffsets[i] = allGatherRecvOffset;
  2146.  
  2147.       allGatherRecvDispBytes[i]     = allGatherRecvOffset * sizeof(real4);
  2148.       allGatherRecvOffset          += abs(recvReq2[i].x);
  2149.     }
  2150.   } //for i < nProcs
  2151.  
  2152.  
  2153.   //Allocate memory
  2154.   if(globalGrpTreeCntSize) delete[] globalGrpTreeCntSize;
  2155.   globalGrpTreeCntSize = new real4[allGatherRecvOffset];
  2156.  
  2157.   double t30 = get_time();
  2158.  
  2159.  
  2160.   //Do the all gather
  2161.   MPI_Allgatherv(&localGrpTreeCntSize[0],                     //Begin of array
  2162.       sizeof(real4)*(2*grpTree_n_topNodes),        //Number of top-nodes
  2163.       MPI_BYTE,
  2164.       globalGrpTreeCntSize,                        //Receive buffer
  2165.       allGatherRecvSizeBytes,                      //Array with size per node
  2166.       allGatherRecvDispBytes,                      //Array with offset per node
  2167.       MPI_BYTE, MPI_COMM_WORLD);
  2168.  
  2169.   double t40 = get_time();
  2170.  
  2171.   //Next do the non-blocking send and receives
  2172. #define NMAXPROC 32768
  2173.   static MPI_Status stat[NMAXPROC];
  2174.   static MPI_Request req[NMAXPROC*2];
  2175.  
  2176.   int nreq = 0;
  2177.  
  2178.   //The sends
  2179.   for(int i=0; i < nWantFullTreeCount; i++)
  2180.   {
  2181.     int dst  = nWantFullTreeList[i];
  2182.     int size = sizeof(real4)*2*grpTree_n_nodes; //Times two it is size and center in one
  2183.     //LOGF(stderr, "Sending full to: %d size: %d \n", dst, size);
  2184.     MPI_Isend(&localGrpTreeCntSize[2*grpTree_n_topNodes], size,
  2185.         MPI_BYTE, dst, 42, MPI_COMM_WORLD, &req[nreq++]);
  2186.   }
  2187.  
  2188.   //The receives
  2189.   for(int i=0; i < min(NUMBER_OF_FULL_EXCHANGE, nProcs); i++)
  2190.   {
  2191.     if(fullGrpAndLETRequestStatistics[i].y == procId) continue;
  2192.     int src    = fullGrpAndLETRequestStatistics[i].y;
  2193.     int size   = this->globalGrpTreeCount[src]   * sizeof(real4);
  2194.     int offset = this->globalGrpTreeOffsets[src];
  2195.  
  2196.     //LOGF(stderr, "Receiving full %d from: %d size: %d  Offset: %d\n", i, src, size, offset);
  2197.     MPI_Irecv(&globalGrpTreeCntSize[offset], size, MPI_BYTE,
  2198.         src, 42, MPI_COMM_WORLD, &req[nreq++]);
  2199.   }
  2200.  
  2201.   double t50 = get_time();
  2202.   MPI_Waitall(nreq, req, stat);
  2203.   double t60 = get_time();
  2204.  
  2205.   LOGF(stderr, "Gathering Grp-Tree timings, request: %lg allocs: %lg AllGather: %lg Sends: %lg Wait: %lg Total: %lg NGroups: %d\n",
  2206.       t10-t00, t30-t10, t40-t30, t50-t40, t60-t50, t60-t00, allGatherRecvOffset / 2);
  2207.  
  2208. #elif 1
  2209.  
  2210.   //Per process a request for a full node or only the topnode
  2211.  
  2212.   int *sendReq           = &infoGrpTreeBuffer[0*nProcs];
  2213.   int *recvReq           = &infoGrpTreeBuffer[1*nProcs];
  2214.   int *incomingDataSizes = &infoGrpTreeBuffer[2*nProcs];
  2215.   int *sendDisplacement  = &infoGrpTreeBuffer[3*nProcs];
  2216.   int *sendCount         = &infoGrpTreeBuffer[4*nProcs];
  2217.   int *recvDisplacement  = &infoGrpTreeBuffer[5*nProcs];
  2218.   int *recvSizeBytes     = &infoGrpTreeBuffer[6*nProcs];
  2219.  
  2220.   if(nProcs > NUMBER_OF_FULL_EXCHANGE)
  2221.   {
  2222.     //Sort the data and take the top NUMBER_OF_FULL_EXCHANGE to be used
  2223.     std::partial_sort(fullGrpAndLETRequestStatistics,
  2224.         fullGrpAndLETRequestStatistics+NUMBER_OF_FULL_EXCHANGE, //Top items
  2225.         fullGrpAndLETRequestStatistics+nProcs,
  2226.         cmp_uint2_reverse());
  2227.  
  2228.     //Set the top NUMBER_OF_FULL_EXCHANGE to be active
  2229.     memset(fullGrpAndLETRequest, 0, sizeof(int)*nProcs);
  2230.     for(int i=0; i < NUMBER_OF_FULL_EXCHANGE; i++)
  2231.     {
  2232.       fullGrpAndLETRequest[fullGrpAndLETRequestStatistics[i].y] = 1;
  2233.     }
  2234.   }
  2235.   else
  2236.   {
  2237.     //Set everything active, except ourself
  2238.     for(int i=0; i < nProcs; i++)
  2239.       fullGrpAndLETRequest[i] = 1;
  2240.     fullGrpAndLETRequest[procId] = 0;
  2241.   }
  2242.  
  2243.   memcpy(sendReq, fullGrpAndLETRequest, sizeof(int)*nProcs);
  2244.  
  2245.  
  2246.   double t00 = get_time();
  2247.   //gather the requests
  2248.   MPI_Alltoall(sendReq, 1, MPI_INT, recvReq, 1, MPI_INT, MPI_COMM_WORLD);
  2249.   double t10 = get_time();
  2250.  
  2251.  
  2252.   //Debug print
  2253.   //    char buff[512];
  2254.   //    sprintf(buff, "%d A:\t", procId);
  2255.   //
  2256.   //    {
  2257.   //      for(int i=0; i < nProcs; i++)
  2258.   //      {
  2259.   //        sprintf(buff, "%s%d\t",buff, recvReq[i]);
  2260.   //      }
  2261.   //      LOGF(stderr, "%s\n", buff);
  2262.   //    }
  2263.  
  2264.   //We now know which process requires the full-tree (recvReq[process] == 1)
  2265.   //and which process can get away with only the top-node (recvReq[process] == 0)
  2266.  
  2267.   int outGoingFullRequests = 0;
  2268.   //Set the memory sizes, reuse sendReq, also directly set memory displacements, we need those anyway
  2269.   for(int i=0; i < nProcs; i++)
  2270.   {
  2271.     if(recvReq[i] == 1)
  2272.     {
  2273.       sendReq[i]          = 2*grpTree_n_nodes; //Times two since we send size and center in one array
  2274.       sendDisplacement[i] = 2*sizeof(real4)*grpTree_n_topNodes;  //Jump 2 ahead, first 2 is top-node only
  2275.       outGoingFullRequests++;                 //Count how many full-trees we send. That is how many
  2276.       //direct receives we expect in LET phase
  2277.     }
  2278.     else
  2279.     {
  2280.       if(procId != i)
  2281.       {
  2282.         sendReq[i]          = 2*grpTree_n_topNodes;   //2 times a float4
  2283.         sendDisplacement[i] = 0;
  2284.       }
  2285.       else
  2286.       {
  2287.         //Make sure to not include ourself
  2288.         sendReq[i] = 0; sendDisplacement[i] = 0;
  2289.       }
  2290.     }
  2291.   }
  2292.   //Send the memory sizes
  2293.   MPI_Alltoall(sendReq, 1, MPI_INT, incomingDataSizes, 1, MPI_INT, MPI_COMM_WORLD);
  2294.   double t20 = get_time();
  2295.   //Debug print
  2296.   //    sprintf(buff, "%d B:\t", procId);
  2297.   //    {
  2298.   //      for(int i=0; i < nProcs; i++)
  2299.   //      {
  2300.   //        sprintf(buff, "%s%d\t",buff, incomingDataSizes[i]);
  2301.   //      }
  2302.   //      LOGF(stderr, "%s\n", buff);
  2303.   //    }
  2304.  
  2305.   //Compute memory offsets, for the receive
  2306.   unsigned int recvCount  = incomingDataSizes[0];
  2307.   recvDisplacement[0]     = 0;
  2308.   sendReq[0]              = sendReq[0]*sizeof(real4);
  2309.   recvSizeBytes [0]       = incomingDataSizes[0]*sizeof(real4);
  2310.  
  2311.   this->globalGrpTreeCount[0]   = incomingDataSizes[0];
  2312.   this->globalGrpTreeOffsets[0] = 0;
  2313.  
  2314.   for(int i=1; i < nProcs; i++)
  2315.   {
  2316.     sendReq[i]          = sendReq[i]*sizeof(real4);
  2317.     recvSizeBytes [i]   = incomingDataSizes[i]*sizeof(real4);
  2318.     recvDisplacement[i] = recvDisplacement[i-1] + recvSizeBytes [i-1];
  2319.     recvCount          += incomingDataSizes[i];
  2320.  
  2321.     this->globalGrpTreeCount[i]   = incomingDataSizes[i];
  2322.     this->globalGrpTreeOffsets[i] = this->globalGrpTreeOffsets[i-1] + this->globalGrpTreeCount[i-1];
  2323.   }
  2324.  
  2325.   //Debug print
  2326.   //    sprintf(buff, "%d C:\t", procId);
  2327.   //    {
  2328.   //      for(int i=0; i < nProcs; i++)
  2329.   //      {
  2330.   //        sprintf(buff, "%s[%d,%d]\t",buff, recvSizeBytes[i],recvDisplacement[i]);
  2331.   //      }
  2332.   //      LOGF(stderr, "%s\n", buff);
  2333.   //    }
  2334.  
  2335.   //Allocate memory
  2336.   if(globalGrpTreeCntSize) delete[] globalGrpTreeCntSize;
  2337.   globalGrpTreeCntSize = new real4[recvCount];
  2338.  
  2339.   double t30 = get_time();
  2340.  
  2341.   //Compute how much we will receive and the offsets and displacements
  2342.  
  2343.   assert(0);
  2344. #if 0
  2345.   MPI_Alltoallv(&localGrpTreeCntSize[0], sendReq, sendDisplacement, MPI_BYTE,
  2346.       &globalGrpTreeCntSize[0], recvSizeBytes, recvDisplacement, MPI_BYTE,
  2347.       MPI_COMM_WORLD);
  2348. #else
  2349.   myComm->ugly_all2allv_char((float*)&localGrpTreeCntSize[0], sendReq, (float*)&globalGrpTreeCntSize[0], recvSizeBytes);
  2350. #endif
  2351.   double t40 = get_time();
  2352.  
  2353.   LOGF(stderr, "Gathering Grp-Tree timings, request: %lg size: %lg MemOffset: %lg data: %lg Total: %lg NGroups: %d\n",
  2354.       t10-t00, t20-t10, t30-t20, t40-t30, t40-t00, recvCount);
  2355.  
  2356.   //    exit(0);
  2357. #elif 1
  2358.   //Send the full groups to all processes
  2359.   int *treeGrpCountBytes   = new int[nProcs];
  2360.   int *receiveOffsetsBytes = new int[nProcs];
  2361.  
  2362.   double t0 = get_time();
  2363.   //Send the number of group-tree-nodes that belongs to this process, and gather
  2364.   //that information from the other processors
  2365.   int temp = 2*grpTree_n_nodes; //Times two since we send size and center in one array
  2366.   if(grpTree_n_nodes == 0) temp = 1;
  2367.   MPI_Allgather(&temp,                    sizeof(int),  MPI_BYTE,
  2368.       this->globalGrpTreeCount, sizeof(uint), MPI_BYTE, MPI_COMM_WORLD);
  2369.  
  2370.   double tSize = get_time()-t0;
  2371.  
  2372.  
  2373.   //Compute offsets using prefix sum and total number of groups we will receive
  2374.   this->globalGrpTreeOffsets[0]   = 0;
  2375.   treeGrpCountBytes[0]            = this->globalGrpTreeCount[0]*sizeof(real4);
  2376.   receiveOffsetsBytes[0]          = 0;
  2377.   for(int i=1; i < nProcs; i++)
  2378.   {
  2379.     this->globalGrpTreeOffsets[i]  = this->globalGrpTreeOffsets[i-1] + this->globalGrpTreeCount[i-1];
  2380.  
  2381.     treeGrpCountBytes[i]   = this->globalGrpTreeCount[i]  *sizeof(real4);
  2382.     receiveOffsetsBytes[i] = this->globalGrpTreeOffsets[i]*sizeof(real4);
  2383.  
  2384.     //      LOGF(stderr,"Proc: %d Received on idx: %d\t%d prefix: %d \n", procId, i, globalGrpTreeCount[i], globalGrpTreeOffsets[i]);
  2385.   }
  2386.  
  2387.   int totalNumberOfGroups = this->globalGrpTreeOffsets[nProcs-1]+this->globalGrpTreeCount[nProcs-1];
  2388.  
  2389.   //Allocate memory
  2390.   if(globalGrpTreeCntSize) delete[] globalGrpTreeCntSize;
  2391.   globalGrpTreeCntSize = new real4[totalNumberOfGroups];
  2392.  
  2393.   double t2 = get_time();
  2394.   //Exchange the coarse group boundaries
  2395.   MPI_Allgatherv(&localGrpTreeCntSize[2],  temp*sizeof(real4), MPI_BYTE,
  2396.       globalGrpTreeCntSize, treeGrpCountBytes,
  2397.       receiveOffsetsBytes,  MPI_BYTE, MPI_COMM_WORLD);
  2398.  
  2399.   LOGF(stderr, "Gathering Grp-Tree timings, size: %lg data: %lg Total: %lg NGroups: %d\n",
  2400.       tSize, get_time()-t2, get_time()-t0, totalNumberOfGroups);
  2401.  
  2402.   delete[] treeGrpCountBytes;
  2403.   delete[] receiveOffsetsBytes;
  2404.  
  2405.  
  2406. #else
  2407.   //Send the full groups to all processes
  2408.   int *treeGrpCountBytes   = new int[nProcs];
  2409.   int *receiveOffsetsBytes = new int[nProcs];
  2410.  
  2411.   double t0 = get_time();
  2412.   //Send the number of group-tree-nodes that belongs to this process, and gather
  2413.   //that information from the other processors
  2414.   int temp = 2*grpTree_n_nodes; //Times two since we send size and center in one array
  2415.   if(grpTree_n_nodes == 0) temp = 1;
  2416.   MPI_Allgather(&temp,                    sizeof(int),  MPI_BYTE,
  2417.       this->globalGrpTreeCount, sizeof(uint), MPI_BYTE, MPI_COMM_WORLD);
  2418.  
  2419.   double tSize = get_time()-t0;
  2420.  
  2421.  
  2422.   //Compute offsets using prefix sum and total number of groups we will receive
  2423.   this->globalGrpTreeOffsets[0]   = 0;
  2424.   treeGrpCountBytes[0]            = this->globalGrpTreeCount[0]*sizeof(real4);
  2425.   receiveOffsetsBytes[0]          = 0;
  2426.   for(int i=1; i < nProcs; i++)
  2427.   {
  2428.     this->globalGrpTreeOffsets[i]  = this->globalGrpTreeOffsets[i-1] + this->globalGrpTreeCount[i-1];
  2429.  
  2430.     treeGrpCountBytes[i]   = this->globalGrpTreeCount[i]  *sizeof(real4);
  2431.     receiveOffsetsBytes[i] = this->globalGrpTreeOffsets[i]*sizeof(real4);
  2432.  
  2433.     //      LOGF(stderr,"Proc: %d Received on idx: %d\t%d prefix: %d \n", procId, i, globalGrpTreeCount[i], globalGrpTreeOffsets[i]);
  2434.   }
  2435.  
  2436.   int totalNumberOfGroups = this->globalGrpTreeOffsets[nProcs-1]+this->globalGrpTreeCount[nProcs-1];
  2437.  
  2438.   //Allocate memory
  2439.   if(globalGrpTreeCntSize) delete[] globalGrpTreeCntSize;
  2440.   globalGrpTreeCntSize = new real4[totalNumberOfGroups];
  2441.  
  2442.   double t2 = get_time();
  2443.   //Exchange the coarse group boundaries
  2444.   MPI_Allgatherv(localGrpTreeCntSize,  temp*sizeof(real4), MPI_BYTE,
  2445.       globalGrpTreeCntSize, treeGrpCountBytes,
  2446.       receiveOffsetsBytes,  MPI_BYTE, MPI_COMM_WORLD);
  2447.  
  2448.   LOGF(stderr, "Gathering Grp-Tree timings, size: %lg data: %lg Total: %lg NGroups: %d\n",
  2449.       tSize, get_time()-t2, get_time()-t0, totalNumberOfGroups);
  2450.  
  2451.   delete[] treeGrpCountBytes;
  2452.   delete[] receiveOffsetsBytes;
  2453. #endif
  2454.  
  2455.  
  2456. #else
  2457.   //TODO check if we need something here
  2458.   //  curSysState[0] = curProcState;
  2459. #endif
  2460. }
  2461.  
  2462.  
  2463.  
  2464. //////////////////////////////////////////////////////
  2465. // ***** Local essential tree functions ************//
  2466. //////////////////////////////////////////////////////
  2467.  
  2468. inline int split_node_grav_impbh(
  2469.     const _v4sf nodeCOM1,
  2470.     const _v4sf boxCenter1,
  2471.     const _v4sf boxSize1)
  2472. {
  2473.   const _v4si mask = {0xffffffff, 0xffffffff, 0xffffffff, 0x0};
  2474.   const _v4sf size = __abs(__builtin_ia32_shufps(nodeCOM1, nodeCOM1, 0xFF));
  2475.  
  2476.   //mask to prevent NaN signalling / Overflow ? Required to get good pre-SB performance
  2477.   const _v4sf nodeCOM   = __builtin_ia32_andps(nodeCOM1,   (_v4sf)mask);
  2478.   const _v4sf boxCenter = __builtin_ia32_andps(boxCenter1, (_v4sf)mask);
  2479.   const _v4sf boxSize   = __builtin_ia32_andps(boxSize1,   (_v4sf)mask);
  2480.  
  2481.  
  2482.   const _v4sf dr   = __abs(boxCenter - nodeCOM) - boxSize;
  2483.   const _v4sf ds   = dr + __abs(dr);
  2484.   const _v4sf dsq  = ds*ds;
  2485.   const _v4sf t1   = __builtin_ia32_haddps(dsq, dsq);
  2486.   const _v4sf t2   = __builtin_ia32_haddps(t1, t1);
  2487.   const _v4sf ds2  = __builtin_ia32_shufps(t2, t2, 0x00)*(_v4sf){0.25f, 0.25f, 0.25f, 0.25f};
  2488.  
  2489.  
  2490. #if 1
  2491.   const float c = 10e-4f;
  2492.   const int res = __builtin_ia32_movmskps(
  2493.       __builtin_ia32_orps(
  2494.         __builtin_ia32_cmpleps(ds2,  size),
  2495.         __builtin_ia32_cmpltps(ds2 - size, (_v4sf){c,c,c,c})
  2496.         )
  2497.       );
  2498. #else
  2499.   const int res = __builtin_ia32_movmskps(
  2500.       __builtin_ia32_cmpleps(ds2,  size));
  2501. #endif
  2502.  
  2503.   return res;
  2504. }
  2505.  
  2506.  
  2507. template<typename T, int STRIDE>
  2508. void shuffle2vec(
  2509.     std::vector<T> &data1,
  2510.     std::vector<T> &data2)
  2511. {
  2512.   const int n = data1.size();
  2513.   assert(n%STRIDE == 0);
  2514.   std::vector<int> keys(n/STRIDE);
  2515.   for (int i = 0, idx=0; i < n; i += STRIDE, idx++)
  2516.     keys[idx] = i;
  2517.   std::random_shuffle(keys.begin(), keys.end());
  2518.  
  2519.   std::vector<T> rdata1(n), rdata2(n);
  2520.   for (int i = 0, idx=0; i < n; i += STRIDE, idx++)
  2521.   {
  2522.     const int key = keys[idx];
  2523.     for (int j = 0; j < STRIDE; j++)
  2524.     {
  2525.       rdata1[i+j] = data1[key+j];
  2526.       rdata2[i+j] = data2[key+j];
  2527.     }
  2528.   }
  2529.  
  2530.   data1.swap(rdata1);
  2531.   data2.swap(rdata2);
  2532. }
  2533. template<bool TRANSPOSE>
  2534. inline int split_node_grav_impbh_box4simd1( // takes 4 tree nodes and returns 4-bit integer
  2535.     const _v4sf  ncx,
  2536.     const _v4sf  ncy,
  2537.     const _v4sf  ncz,
  2538.     const _v4sf  size,
  2539.     const _v4sf  boxCenter[4],
  2540.     const _v4sf  boxSize  [4])
  2541. {
  2542.  
  2543.   _v4sf bcx =  (boxCenter[0]);
  2544.   _v4sf bcy =  (boxCenter[1]);
  2545.   _v4sf bcz =  (boxCenter[2]);
  2546.   _v4sf bcw =  (boxCenter[3]);
  2547.  
  2548.   _v4sf bsx =  (boxSize[0]);
  2549.   _v4sf bsy =  (boxSize[1]);
  2550.   _v4sf bsz =  (boxSize[2]);
  2551.   _v4sf bsw =  (boxSize[3]);
  2552.  
  2553.   if (TRANSPOSE)
  2554.   {
  2555.     _v4sf_transpose(bcx, bcy, bcz, bcw);
  2556.     _v4sf_transpose(bsx, bsy, bsz, bsw);
  2557.   }
  2558.  
  2559.   const _v4sf zero = {0.0, 0.0, 0.0, 0.0};
  2560.  
  2561.   _v4sf dx = __abs(bcx - ncx) - bsx;
  2562.   _v4sf dy = __abs(bcy - ncy) - bsy;
  2563.   _v4sf dz = __abs(bcz - ncz) - bsz;
  2564.  
  2565.   dx = __builtin_ia32_maxps(dx, zero);
  2566.   dy = __builtin_ia32_maxps(dy, zero);
  2567.   dz = __builtin_ia32_maxps(dz, zero);
  2568.  
  2569.   const _v4sf ds2 = dx*dx + dy*dy + dz*dz;
  2570. #if 0
  2571.   const float c = 10e-4;
  2572.   const int ret = __builtin_ia32_movmskps(
  2573.       __builtin_ia32_orps(
  2574.         __builtin_ia32_cmpleps(ds2,  size),
  2575.         __builtin_ia32_cmpltps(ds2 - size, (_v4sf){c,c,c,c})
  2576.         )
  2577.       );
  2578. #else
  2579.   const int ret = __builtin_ia32_movmskps(
  2580.       __builtin_ia32_cmpleps(ds2, size));
  2581. #endif
  2582.   return ret;
  2583. }
  2584. int2 getLET1(
  2585.     real4 **LETBuffer_ptr,
  2586.     const real4 *nodeCentre,
  2587.     const real4 *nodeSize,
  2588.     const real4 *multipole,
  2589.     const int cellBeg,
  2590.     const int cellEnd,
  2591.     const real4 *bodies,
  2592.     const int nParticles,
  2593.     const real4 *groupSizeInfo,
  2594.     const real4 *groupCentreInfo,
  2595.     const int nGroups,
  2596.     const int nNodes,
  2597.     unsigned long long &nflops)
  2598. {
  2599.   std::vector<int2> LETBuffer_node;
  2600.   std::vector<int > LETBuffer_ptcl;
  2601.   LETBuffer_node.reserve(nNodes);
  2602.   LETBuffer_ptcl.reserve(nParticles);
  2603.  
  2604.   nflops = 0;
  2605.  
  2606.   int nExportPtcl = 0;
  2607.   int nExportCell = 0;
  2608.   int nExportCellOffset = cellEnd;
  2609.  
  2610.   nExportCell += cellBeg;
  2611.   for (int node = 0; node < cellBeg; node++)
  2612.     LETBuffer_node.push_back((int2){node, host_float_as_int(nodeSize[node].w)});
  2613.  
  2614.  
  2615.   const _v4sf*            bodiesV = (const _v4sf*)bodies;
  2616.   const _v4sf*          nodeSizeV = (const _v4sf*)nodeSize;
  2617.   const _v4sf*        nodeCentreV = (const _v4sf*)nodeCentre;
  2618.   const _v4sf*         multipoleV = (const _v4sf*)multipole;
  2619.   const _v4sf*   groupSizeV = (const _v4sf*)groupSizeInfo;
  2620.   const _v4sf* groupCenterV = (const _v4sf*)groupCentreInfo;
  2621.  
  2622.  
  2623.  
  2624.   const int levelCountMax = nNodes;
  2625.   std::vector<int> currLevelVec, nextLevelVec;
  2626.   currLevelVec.reserve(levelCountMax);
  2627.   nextLevelVec.reserve(levelCountMax);
  2628.   Swap<std::vector<int> > levelList(currLevelVec, nextLevelVec);
  2629.  
  2630.   const int SIMDW  = 4;
  2631.  
  2632.   const int nGroups4 = ((nGroups-1)/SIMDW + 1)*SIMDW;
  2633.   std::vector<v4sf> groupCentreSIMD(nGroups4), groupSizeSIMD(nGroups4);
  2634. #if 1
  2635.   const bool TRANSPOSE_SPLIT = false;
  2636. #else
  2637.   const bool TRANSPOSE_SPLIT = true;
  2638. #endif
  2639.   for (int ib = 0; ib < nGroups4; ib += SIMDW)
  2640.   {
  2641.     _v4sf bcx = groupCenterV[std::min(ib+0,nGroups-1)];
  2642.     _v4sf bcy = groupCenterV[std::min(ib+1,nGroups-1)];
  2643.     _v4sf bcz = groupCenterV[std::min(ib+2,nGroups-1)];
  2644.     _v4sf bcw = groupCenterV[std::min(ib+3,nGroups-1)];
  2645.  
  2646.     _v4sf bsx = groupSizeV[std::min(ib+0,nGroups-1)];
  2647.     _v4sf bsy = groupSizeV[std::min(ib+1,nGroups-1)];
  2648.     _v4sf bsz = groupSizeV[std::min(ib+2,nGroups-1)];
  2649.     _v4sf bsw = groupSizeV[std::min(ib+3,nGroups-1)];
  2650.  
  2651.     if (!TRANSPOSE_SPLIT)
  2652.     {
  2653.       _v4sf_transpose(bcx, bcy, bcz, bcw);
  2654.       _v4sf_transpose(bsx, bsy, bsz, bsw);
  2655.     }
  2656.  
  2657.     groupCentreSIMD[ib+0] = bcx;
  2658.     groupCentreSIMD[ib+1] = bcy;
  2659.     groupCentreSIMD[ib+2] = bcz;
  2660.     groupCentreSIMD[ib+3] = bcw;
  2661.  
  2662.     groupSizeSIMD[ib+0] = bsx;
  2663.     groupSizeSIMD[ib+1] = bsy;
  2664.     groupSizeSIMD[ib+2] = bsz;
  2665.     groupSizeSIMD[ib+3] = bsw;
  2666.   }
  2667.  
  2668.   for (int cell = cellBeg; cell < cellEnd; cell++)
  2669.     levelList.first().push_back(cell);
  2670.  
  2671.   while (!levelList.first().empty())
  2672.   {
  2673.     const int csize = levelList.first().size();
  2674. #if 1
  2675.     if (nGroups > 128)   /* randomizes algo, can give substantial speed-up */
  2676.       shuffle2vec<v4sf,SIMDW>(groupCentreSIMD, groupSizeSIMD);
  2677. #endif
  2678.     for (int i = 0; i < csize; i++)
  2679.     {
  2680.       const uint        nodeIdx  = levelList.first()[i];
  2681.       const float nodeInfo_x = nodeCentre[nodeIdx].w;
  2682.       const uint  nodeInfo_y = host_float_as_int(nodeSize[nodeIdx].w);
  2683.  
  2684.       _v4sf nodeCOM = multipoleV[nodeIdx*3];
  2685.       nodeCOM       = __builtin_ia32_vec_set_v4sf (nodeCOM, nodeInfo_x, 3);
  2686.  
  2687.       int split = false;
  2688.  
  2689.       /**************/
  2690.  
  2691.  
  2692.       const _v4sf vncx = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0x00);
  2693.       const _v4sf vncy = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0x55);
  2694.       const _v4sf vncz = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0xaa);
  2695.       const _v4sf vncw = __builtin_ia32_shufps(nodeCOM, nodeCOM, 0xff);
  2696.       const _v4sf vsize = __abs(vncw);
  2697.  
  2698.       nflops += nGroups*20;  /* effective flops, can be less */
  2699.       for (int ib = 0; ib < nGroups4 && !split; ib += SIMDW)
  2700.         split |= split_node_grav_impbh_box4simd1<TRANSPOSE_SPLIT>(vncx,vncy,vncz,vsize, (_v4sf*)&groupCentreSIMD[ib], (_v4sf*)&groupSizeSIMD[ib]);
  2701.  
  2702.       /**************/
  2703.  
  2704.       real4 size  = nodeSize[nodeIdx];
  2705.       int sizew = 0xFFFFFFFF;
  2706.  
  2707.       if (split)
  2708.       {
  2709.         const bool lleaf = nodeInfo_x <= 0.0f;
  2710.         if (!lleaf)
  2711.         {
  2712.           const int lchild  =    nodeInfo_y & 0x0FFFFFFF;            //Index to the first child of the node
  2713.           const int lnchild = (((nodeInfo_y & 0xF0000000) >> 28)) ;  //The number of children this node has
  2714.           sizew = (nExportCellOffset | (lnchild << LEAFBIT));
  2715.           nExportCellOffset += lnchild;
  2716.           for (int i = lchild; i < lchild + lnchild; i++)
  2717.             levelList.second().push_back(i);
  2718.         }
  2719.         else
  2720.         {
  2721.           const int pfirst =    nodeInfo_y & BODYMASK;
  2722.           const int np     = (((nodeInfo_y & INVBMASK) >> LEAFBIT)+1);
  2723.           sizew = (nExportPtcl | ((np-1) << LEAFBIT));
  2724.           for (int i = pfirst; i < pfirst+np; i++)
  2725.             LETBuffer_ptcl.push_back(i);
  2726.           nExportPtcl += np;
  2727.         }
  2728.       }
  2729.  
  2730.       LETBuffer_node.push_back((int2){nodeIdx, sizew});
  2731.       nExportCell++;
  2732.     }
  2733.  
  2734.     levelList.swap();
  2735.     levelList.second().clear();
  2736.   }
  2737.  
  2738.   assert((int)LETBuffer_ptcl.size() == nExportPtcl);
  2739.   assert((int)LETBuffer_node.size() == nExportCell);
  2740.  
  2741.   /* now copy data into LETBuffer */
  2742.   {
  2743.     //LETBuffer.resize(nExportPtcl + 5*nExportCell);
  2744. #pragma omp critical //Malloc seems to be not so thread safe..
  2745.     *LETBuffer_ptr = (real4*)malloc(sizeof(real4)*(1+ nExportPtcl + 5*nExportCell));
  2746.     real4 *LETBuffer = *LETBuffer_ptr;
  2747.     _v4sf *vLETBuffer      = (_v4sf*)(&LETBuffer[1]);
  2748.     //_v4sf *vLETBuffer      = (_v4sf*)&LETBuffer     [0];
  2749.  
  2750.     int nStoreIdx = nExportPtcl;
  2751.     int multiStoreIdx = nStoreIdx + 2*nExportCell;
  2752.     for (int i = 0; i < nExportPtcl; i++)
  2753.     {
  2754.       const int idx = LETBuffer_ptcl[i];
  2755.       vLETBuffer[i] = bodiesV[idx];
  2756.     }
  2757.     for (int i = 0; i < nExportCell; i++)
  2758.     {
  2759.       const int2 packed_idx = LETBuffer_node[i];
  2760.       const int idx = packed_idx.x;
  2761.       const float sizew = host_int_as_float(packed_idx.y);
  2762.       const _v4sf size = __builtin_ia32_vec_set_v4sf(nodeSizeV[idx], sizew, 3);
  2763.  
  2764.       //       vLETBuffer[nStoreIdx            ] = nodeCentreV[idx];     /* centre */
  2765.       //       vLETBuffer[nStoreIdx+nExportCell] = size;                 /*  size  */
  2766.  
  2767.       vLETBuffer[nStoreIdx+nExportCell] = nodeCentreV[idx];     /* centre */
  2768.       vLETBuffer[nStoreIdx            ] = size;                 /*  size  */
  2769.  
  2770.       vLETBuffer[multiStoreIdx++      ] = multipoleV[3*idx+0];  /* multipole.x */
  2771.       vLETBuffer[multiStoreIdx++      ] = multipoleV[3*idx+1];  /* multipole.x */
  2772.       vLETBuffer[multiStoreIdx++      ] = multipoleV[3*idx+2];  /* multipole.x */
  2773.       nStoreIdx++;
  2774.     }
  2775.   }
  2776.  
  2777.   return (int2){nExportCell, nExportPtcl};
  2778. }
  2779. int2 getLETopt(
  2780.     //std::vector<real4> &LETBuffer,
  2781.     real4 **LETBuffer_ptr,
  2782.     const real4 *nodeCentre,
  2783.     const real4 *nodeSize,
  2784.     const real4 *multipole,
  2785.     const int cellBeg,
  2786.     const int cellEnd,
  2787.     const real4 *bodies,
  2788.     const int nParticles,
  2789.     const real4 *groupSizeInfo,
  2790.     const real4 *groupCentreInfo,
  2791.     const int groupBeg,
  2792.     const int groupEnd,
  2793.     const int nNodes,
  2794.     unsigned long long &nflops)
  2795. {
  2796.   std::vector<int2> LETBuffer_node;
  2797.   std::vector<int > LETBuffer_ptcl;
  2798.   LETBuffer_node.reserve(nNodes);
  2799.   LETBuffer_ptcl.reserve(nParticles);
  2800.  
  2801.   nflops = 0;
  2802.  
  2803.   int nExportCell = 0;
  2804.   int nExportPtcl = 0;
  2805.   int nExportCellOffset = cellEnd;
  2806.  
  2807.   const _v4sf*            bodiesV = (const _v4sf*)bodies;
  2808.   const _v4sf*          nodeSizeV = (const _v4sf*)nodeSize;
  2809.   const _v4sf*        nodeCentreV = (const _v4sf*)nodeCentre;
  2810.   const _v4sf*         multipoleV = (const _v4sf*)multipole;
  2811.   const _v4sf*   grpNodeSizeInfoV = (const _v4sf*)groupSizeInfo;
  2812.   const _v4sf* grpNodeCenterInfoV = (const _v4sf*)groupCentreInfo;
  2813.  
  2814.   const int levelCountMax = nNodes;
  2815.   std::vector<uint4> currLevelVec, nextLevelVec;
  2816.   currLevelVec.reserve(levelCountMax);
  2817.   nextLevelVec.reserve(levelCountMax);
  2818.   Swap<std::vector<uint4> > levelList(currLevelVec, nextLevelVec);
  2819.  
  2820.   std::vector<int> currGroupLevelVec, nextGroupLevelVec;
  2821.   currGroupLevelVec.reserve(levelCountMax);
  2822.   nextGroupLevelVec.reserve(levelCountMax);
  2823.   Swap<std::vector<int> > levelGroups(currGroupLevelVec, nextGroupLevelVec);
  2824.  
  2825.   nExportCell += cellBeg;
  2826.   for (int node = 0; node < cellBeg; node++)
  2827.     LETBuffer_node.push_back((int2){node, host_float_as_int(nodeSize[node].w)});
  2828.  
  2829.  
  2830. #if 0 /* AVX */
  2831. #ifndef __AVX__
  2832. #error "AVX is not defined"
  2833. #endif
  2834.   const int SIMDW  = 8;
  2835.   std::vector< std::pair<v4sf,v4sf> > groupSplitFlag;
  2836. #define AVXIMBH
  2837. #else
  2838.   const int SIMDW  = 4;
  2839.   std::vector<v4sf> groupSplitFlag;
  2840. #define SSEIMBH
  2841. #endif
  2842.   groupSplitFlag.reserve(levelCountMax);
  2843.  
  2844.   /* copy group info into current level buffer */
  2845.   for (int group = groupBeg; group < groupEnd; group++)
  2846.     levelGroups.first().push_back(group);
  2847.  
  2848.   for (int cell = cellBeg; cell < cellEnd; cell++)
  2849.     levelList.first().push_back((uint4){cell, 0, (int)levelGroups.first().size(),0});
  2850.  
  2851.   while (!levelList.first().empty())
  2852.   {
  2853.     const int csize = levelList.first().size();
  2854.     for (int i = 0; i < csize; i++)
  2855.     {
  2856.       const uint4       nodePacked = levelList.first()[i];
  2857.  
  2858.       const uint  nodeIdx  = nodePacked.x;
  2859.       const float nodeInfo_x = nodeCentre[nodeIdx].w;
  2860.       const uint  nodeInfo_y = host_float_as_int(nodeSize[nodeIdx].w);
  2861.  
  2862.       const _v4sf nodeCOM  = __builtin_ia32_vec_set_v4sf(multipoleV[nodeIdx*3], nodeInfo_x, 3);
  2863.       const bool lleaf = nodeInfo_x <= 0.0f;
  2864.  
  2865.       const int groupBeg = nodePacked.y;
  2866.       const int groupEnd = nodePacked.z;
  2867.       nflops += 20*((groupEnd - groupBeg-1)/SIMDW+1)*SIMDW;
  2868.  
  2869.       groupSplitFlag.clear();
  2870.       for (int ib = groupBeg; ib < groupEnd; ib += SIMDW)
  2871.       {
  2872.         _v4sf centre[SIMDW], size[SIMDW];
  2873.         for (int laneIdx = 0; laneIdx < SIMDW; laneIdx++)
  2874.         {
  2875.           const int group = levelGroups.first()[std::min(ib+laneIdx, groupEnd-1)];
  2876.           centre[laneIdx] = grpNodeCenterInfoV[group];
  2877.           size  [laneIdx] =   grpNodeSizeInfoV[group];
  2878.         }
  2879. #ifdef AVXIMBH
  2880.         groupSplitFlag.push_back(split_node_grav_impbh_box8a(nodeCOM, centre, size));
  2881. #else
  2882.         groupSplitFlag.push_back(split_node_grav_impbh_box4a(nodeCOM, centre, size));
  2883. #endif
  2884.       }
  2885.  
  2886.       const int groupNextBeg = levelGroups.second().size();
  2887.       int split = false;
  2888.       for (int idx = groupBeg; idx < groupEnd; idx++)
  2889.       {
  2890.         const bool gsplit = ((uint*)&groupSplitFlag[0])[idx - groupBeg];
  2891.         if (gsplit)
  2892.         {
  2893.           split = true;
  2894.           const int group = levelGroups.first()[idx];
  2895.           if (!lleaf)
  2896.           {
  2897.             const bool gleaf = groupCentreInfo[group].w <= 0.0f;
  2898.             if (!gleaf)
  2899.             {
  2900.               const int childinfoGrp  = ((uint4*)groupSizeInfo)[group].w;
  2901.               const int gchild  =   childinfoGrp & 0x0FFFFFFF;
  2902.               const int gnchild = ((childinfoGrp & 0xF0000000) >> 28) ;
  2903.               for (int i = gchild; i <= gchild+gnchild; i++)
  2904.                 levelGroups.second().push_back(i);
  2905.             }
  2906.             else
  2907.               levelGroups.second().push_back(group);
  2908.           }
  2909.           else
  2910.             break;
  2911.         }
  2912.       }
  2913.  
  2914.       real4 size  = nodeSize[nodeIdx];
  2915.       int sizew = 0xFFFFFFFF;
  2916.  
  2917.       if (split)
  2918.       {
  2919.         if (!lleaf)
  2920.         {
  2921.           const int lchild  =    nodeInfo_y & 0x0FFFFFFF;            //Index to the first child of the node
  2922.           const int lnchild = (((nodeInfo_y & 0xF0000000) >> 28)) ;  //The number of children this node has
  2923.           sizew = (nExportCellOffset | (lnchild << LEAFBIT));
  2924.           nExportCellOffset += lnchild;
  2925.           for (int i = lchild; i < lchild + lnchild; i++)
  2926.             levelList.second().push_back((uint4){i,groupNextBeg,(int)levelGroups.second().size()});
  2927.         }
  2928.         else
  2929.         {
  2930.           const int pfirst =    nodeInfo_y & BODYMASK;
  2931.           const int np     = (((nodeInfo_y & INVBMASK) >> LEAFBIT)+1);
  2932.           sizew = (nExportPtcl | ((np-1) << LEAFBIT));
  2933.           for (int i = pfirst; i < pfirst+np; i++)
  2934.             LETBuffer_ptcl.push_back(i);
  2935.           nExportPtcl += np;
  2936.         }
  2937.       }
  2938.  
  2939.       LETBuffer_node.push_back((int2){nodeIdx, sizew});
  2940.       nExportCell++;
  2941.  
  2942.     }
  2943.     levelList.swap();
  2944.     levelList.second().clear();
  2945.  
  2946.     levelGroups.swap();
  2947.     levelGroups.second().clear();
  2948.   }
  2949.  
  2950.   assert((int)LETBuffer_ptcl.size() == nExportPtcl);
  2951.   assert((int)LETBuffer_node.size() == nExportCell);
  2952.  
  2953.   /* now copy data into LETBuffer */
  2954.   {
  2955.     //LETBuffer.resize(nExportPtcl + 5*nExportCell);
  2956. #pragma omp critical //Malloc seems to be not so thread safe..
  2957.     *LETBuffer_ptr = (real4*)malloc(sizeof(real4)*(1+ nExportPtcl + 5*nExportCell));
  2958.     real4 *LETBuffer = *LETBuffer_ptr;
  2959.     _v4sf *vLETBuffer      = (_v4sf*)(&LETBuffer[1]);
  2960.     //_v4sf *vLETBuffer      = (_v4sf*)&LETBuffer     [0];
  2961.  
  2962.     int nStoreIdx = nExportPtcl;
  2963.     int multiStoreIdx = nStoreIdx + 2*nExportCell;
  2964.     for (int i = 0; i < nExportPtcl; i++)
  2965.     {
  2966.       const int idx = LETBuffer_ptcl[i];
  2967.       vLETBuffer[i] = bodiesV[idx];
  2968.     }
  2969.     for (int i = 0; i < nExportCell; i++)
  2970.     {
  2971.       const int2 packed_idx = LETBuffer_node[i];
  2972.       const int idx = packed_idx.x;
  2973.       const float sizew = host_int_as_float(packed_idx.y);
  2974.       const _v4sf size = __builtin_ia32_vec_set_v4sf(nodeSizeV[idx], sizew, 3);
  2975.  
  2976.       //       vLETBuffer[nStoreIdx            ] = nodeCentreV[idx];     /* centre */
  2977.       //       vLETBuffer[nStoreIdx+nExportCell] = size;                 /*  size  */
  2978.  
  2979.       vLETBuffer[nStoreIdx+nExportCell] = nodeCentreV[idx];     /* centre */
  2980.       vLETBuffer[nStoreIdx            ] = size;                 /*  size  */
  2981.  
  2982.       vLETBuffer[multiStoreIdx++      ] = multipoleV[3*idx+0];  /* multipole.x */
  2983.       vLETBuffer[multiStoreIdx++      ] = multipoleV[3*idx+1];  /* multipole.x */
  2984.       vLETBuffer[multiStoreIdx++      ] = multipoleV[3*idx+2];  /* multipole.x */
  2985.       nStoreIdx++;
  2986.     }
  2987.   }
  2988.  
  2989.   return (int2){nExportCell, nExportPtcl};
  2990. }
  2991.  
  2992.  
  2993.  
  2994. //Compute PH key, same function as on device
  2995. static uint4 host_get_key(int4 crd)
  2996. {
  2997.   const int bits = 30;  //20 to make it same number as morton order
  2998.   int i,xi, yi, zi;
  2999.   int mask;
  3000.   int key;
  3001.  
  3002.   //0= 000, 1=001, 2=011, 3=010, 4=110, 5=111, 6=101, 7=100
  3003.   //000=0=0, 001=1=1, 011=3=2, 010=2=3, 110=6=4, 111=7=5, 101=5=6, 100=4=7
  3004.   const int C[8] = {0, 1, 7, 6, 3, 2, 4, 5};
  3005.  
  3006.   int temp;
  3007.  
  3008.   mask = 1 << (bits - 1);
  3009.   key  = 0;
  3010.  
  3011.   uint4 key_new;
  3012.  
  3013.   for(i = 0; i < bits; i++, mask >>= 1)
  3014.   {
  3015.     xi = (crd.x & mask) ? 1 : 0;
  3016.     yi = (crd.y & mask) ? 1 : 0;
  3017.     zi = (crd.z & mask) ? 1 : 0;
  3018.  
  3019.     int index = (xi << 2) + (yi << 1) + zi;
  3020.  
  3021.     if(index == 0)
  3022.     {
  3023.       temp = crd.z; crd.z = crd.y; crd.y = temp;
  3024.     }
  3025.     else  if(index == 1 || index == 5)
  3026.     {
  3027.       temp = crd.x; crd.x = crd.y; crd.y = temp;
  3028.     }
  3029.     else  if(index == 4 || index == 6)
  3030.     {
  3031.       crd.x = (crd.x) ^ (-1);
  3032.       crd.z = (crd.z) ^ (-1);
  3033.     }
  3034.     else  if(index == 7 || index == 3)
  3035.     {
  3036.       temp = (crd.x) ^ (-1);
  3037.       crd.x = (crd.y) ^ (-1);
  3038.       crd.y = temp;
  3039.     }
  3040.     else
  3041.     {
  3042.       temp = (crd.z) ^ (-1);
  3043.       crd.z = (crd.y) ^ (-1);
  3044.       crd.y = temp;
  3045.     }
  3046.  
  3047.     key = (key << 3) + C[index];
  3048.  
  3049.     if(i == 19)
  3050.     {
  3051.       key_new.y = key;
  3052.       key = 0;
  3053.     }
  3054.     if(i == 9)
  3055.     {
  3056.       key_new.x = key;
  3057.       key = 0;
  3058.     }
  3059.   } //end for
  3060.  
  3061.   key_new.z = key;
  3062.  
  3063.   return key_new;
  3064. }
  3065.  
  3066. typedef struct letObject
  3067. {
  3068.   real4       *buffer;
  3069.   int          size;
  3070.   int          destination;
  3071. #ifdef USE_MPI
  3072.   MPI_Request  req;
  3073. #endif
  3074. } letObject;
  3075.  
  3076.  
  3077.  
  3078. int octree::recursiveTopLevelCheck(uint4 checkNode, real4* treeBoxSizes, real4* treeBoxCenters, real4* treeBoxMoments,
  3079.     real4* grpCenter, real4* grpSize, int &DistanceCheck, int &DistanceCheckPP, int maxLevel)
  3080. {
  3081.   int nodeID = checkNode.x;
  3082.   int grpID  = checkNode.y;
  3083.   int endGrp = checkNode.z;
  3084.  
  3085.   real4 nodeCOM  = treeBoxMoments[nodeID*3];
  3086.   real4 nodeSize = treeBoxSizes  [nodeID];
  3087.   real4 nodeCntr = treeBoxCenters[nodeID];
  3088.  
  3089.   //     LOGF(stderr,"Checking node: %d grpID: %d endGrp: %d depth: %d \n",nodeID, grpID, endGrp, maxLevel);
  3090.  
  3091.   int res = maxLevel;
  3092.  
  3093.   nodeCOM.w = nodeCntr.w;
  3094.   for(int grp=grpID; grp < endGrp; grp++)
  3095.   {
  3096.     real4 grpcntr = grpCenter[grp];
  3097.     real4 grpsize = grpSize[grp];
  3098.  
  3099.     bool split = false;
  3100.     {
  3101.       //         DistanceCheck++;
  3102.       //         DistanceCheckPP++;
  3103.       //Compute the distance between the group and the cell
  3104.       float3 dr = make_float3(fabs((float)grpcntr.x - nodeCOM.x) - (float)grpsize.x,
  3105.           fabs((float)grpcntr.y - nodeCOM.y) - (float)grpsize.y,
  3106.           fabs((float)grpcntr.z - nodeCOM.z) - (float)grpsize.z);
  3107.  
  3108.       dr.x += fabs(dr.x); dr.x *= 0.5f;
  3109.       dr.y += fabs(dr.y); dr.y *= 0.5f;
  3110.       dr.z += fabs(dr.z); dr.z *= 0.5f;
  3111.  
  3112.       //Distance squared, no need to do sqrt since opening criteria has been squared
  3113.       float ds2    = dr.x*dr.x + dr.y*dr.y + dr.z*dr.z;
  3114.  
  3115.       if (ds2     <= fabs(nodeCOM.w))           split = true;
  3116.       if (fabs(ds2 - fabs(nodeCOM.w)) < 10e-04) split = true; //Limited precision can result in round of errors. Use this as extra safe guard
  3117.  
  3118.       //         LOGF(stderr,"Node: %d grp: %d  split: %d || %f %f\n", nodeID, grp, split, ds2, nodeCOM.w);
  3119.     }
  3120.     //       LOGF(stderr,"Node: %d grp: %d  split: %d Leaf: %d \t %d %f \n",nodeID, grp, split, nodeCntr.w <= 0,(host_float_as_int(nodeSize.w) == 0xFFFFFFFF), nodeCntr.w);
  3121.  
  3122.     if(split)
  3123.     {
  3124.       if(host_float_as_int(nodeSize.w) == 0xFFFFFFFF)
  3125.       {
  3126.         //We want to split, but then we go to deep. So we need a full tree-walk
  3127.         return -1;
  3128.       }
  3129.  
  3130.       int child, nchild;
  3131.       int childinfo = host_float_as_int(nodeSize.w);
  3132.       bool leaf = nodeCntr.w <= 0;
  3133.  
  3134.       if(!leaf)
  3135.       {
  3136.         //Node
  3137.         child    =    childinfo & 0x0FFFFFFF;           //Index to the first child of the node
  3138.         nchild   = (((childinfo & 0xF0000000) >> 28)) ; //The number of children this node has
  3139.  
  3140.         //Process node children
  3141.         for(int y=child; y < child+nchild; y++)
  3142.         {
  3143.           //Go one level deeper into the tree
  3144.           //uint4 nextCheck = make_uint4(y, grp, endGrp, 0);
  3145.           uint4 nextCheck = make_uint4(y, grpID, endGrp, 0);
  3146.           int res2 = recursiveTopLevelCheck(nextCheck, treeBoxSizes, treeBoxCenters, treeBoxMoments,
  3147.               grpCenter, grpSize, DistanceCheck, DistanceCheckPP, maxLevel+1);
  3148.           if(res2 < 0) return -1;
  3149.  
  3150.           res = max(res,res2); //Return max level reached
  3151.         }
  3152.       }//!leaf
  3153.       else
  3154.       {
  3155.         //It is a leaf, no need to check any other groups
  3156.         return res;
  3157.       }
  3158.       //No need to check further groups since this one already succeeded
  3159.       grp = endGrp;
  3160.     }//Split
  3161.   }
  3162.   return res;
  3163. }
  3164.  
  3165. int octree::recursiveBasedTopLEvelsCheckStart(tree_structure &tree,
  3166.     real4 *treeBuffer,
  3167.     real4 *grpCenter,
  3168.     real4 *grpSize,
  3169.     int startGrp,
  3170.     int endGrp,
  3171.     int &DistanceCheck)
  3172. {
  3173.   //Tree info
  3174.   const int nParticles = host_float_as_int(treeBuffer[0].x);
  3175.   const int nNodes     = host_float_as_int(treeBuffer[0].y);
  3176.  
  3177.   //  LOGF(stderr,"Working with %d and %d || %d %d\n", nParticles, nNodes, 1+nParticles+nNodes,nTopLevelTrees );
  3178.  
  3179.   real4* treeBoxSizes   = &treeBuffer[1+nParticles];
  3180.   real4* treeBoxCenters = &treeBuffer[1+nParticles+nNodes];
  3181.   real4* treeBoxMoments = &treeBuffer[1+nParticles+2*nNodes];
  3182.  
  3183.   const int nodeID = 0;
  3184.   uint4 checkNode = make_uint4(nodeID, startGrp, endGrp, 0);
  3185.  
  3186.   int DistanceCheckPP = 0;
  3187.   int maxLevel = recursiveTopLevelCheck(checkNode, treeBoxSizes, treeBoxCenters, treeBoxMoments,
  3188.       grpCenter, grpSize, DistanceCheck, DistanceCheckPP, 0);
  3189.  
  3190.  
  3191.   //  LOGF(stderr, "Finally Max level found: %d Process : %d \n", maxLevel, ibox)
  3192.   return maxLevel;
  3193. }
  3194.  
  3195.  
  3196.  
  3197. void octree::essential_tree_exchangeV2(tree_structure &tree,
  3198.     tree_structure &remote,
  3199.     nInfoStruct *nodeInfo,
  3200.     vector<real4> &topLevelTrees,
  3201.     vector<uint2> &topLevelTreesSizeOffset,
  3202.     int     nTopLevelTrees)
  3203. {
  3204. #ifdef USE_MPI
  3205.   double t0         = get_time();
  3206.  
  3207.   bool mergeOwntree = false;              //Default do not include our own tree-structure, thats mainly used for testing
  3208.   int level_start   = tree.startLevelMin; //Depth of where to start the tree-walk
  3209.   int procTrees     = 0;                  //Number of trees that we've received and processed
  3210.  
  3211.   real4  *bodies              = &tree.bodies_Ppos[0];
  3212.   real4  *velocities          = &tree.bodies_Pvel[0];
  3213.   real4  *multipole           = &tree.multipole[0];
  3214.   real4  *nodeSizeInfo        = &tree.boxSizeInfo[0];
  3215.   real4  *nodeCenterInfo      = &tree.boxCenterInfo[0];
  3216.  
  3217.   real4 **treeBuffers;
  3218.  
  3219.   //creates a new array of pointers to int objects, with space for the local tree
  3220.   treeBuffers  = new real4*[mpiGetNProcs()];
  3221.   int *treeBuffersSource = new int[nProcs];
  3222.  
  3223.   real4 *recvAllToAllBuffer = NULL;
  3224.   real4 *recvAllGatherVBuffer = NULL;
  3225.  
  3226.  
  3227.   //Timers for the LET Exchange
  3228.   static double totalLETExTime    = 0;
  3229.   thisPartLETExTime               = 0;
  3230.   double tStart                   = get_time();
  3231.  
  3232.  
  3233.   int topNodeOnTheFlyCount = 0;
  3234.  
  3235.   this->fullGrpAndLETRequestStatistics[procId] = make_uint2(0, procId); //Reset our box
  3236.  
  3237.   uint2 node_begend;
  3238.   node_begend.x   = tree.level_list[level_start].x;
  3239.   node_begend.y   = tree.level_list[level_start].y;
  3240.  
  3241.   int resultOfQuickCheck[nProcs];
  3242.  
  3243.   int quickCheckSendSizes [nProcs];
  3244.   int quickCheckSendOffset[nProcs];
  3245.  
  3246.   int quickCheckRecvSizes [nProcs];
  3247.   int quickCheckRecvOffset[nProcs];
  3248.  
  3249.  
  3250.   int nCompletedQuickCheck = 0;
  3251.  
  3252.   resultOfQuickCheck[procId]    = 99; //Mark ourself
  3253.   quickCheckSendSizes[procId]   =  0;
  3254.   quickCheckSendOffset[procId]  =  0;
  3255.  
  3256.   int nQuickCheckSends          = 0;
  3257.  
  3258.  
  3259.   omp_set_num_threads(16);
  3260.  
  3261.   letObject *computedLETs = new letObject[nProcs-1];
  3262.  
  3263.   int omp_ticket      = 0;
  3264.   int nComputedLETs   = 0;
  3265.   int nReceived       = 0;
  3266.   int nSendOut        = 0;
  3267.  
  3268.  
  3269.   //Use multiple OpenMP threads in parallel to build and exchange LETs
  3270. #pragma omp parallel
  3271.   {
  3272.     int tid      = omp_get_thread_num();
  3273.     int nthreads = omp_get_num_threads();
  3274.  
  3275.     if(tid != 1) //Thread 0, does LET creation and GPU control, Thread == 1 does MPI communication, all others do LET creation
  3276.     {
  3277.       nInfoStruct  *nodeInfo_private;
  3278.       uint2        *curLevelStack;
  3279.       uint2        *nextLevelStack;
  3280.  
  3281.  
  3282.  
  3283. #pragma omp critical
  3284.       {
  3285.         nodeInfo_private = new nInfoStruct[localTree.n_nodes];
  3286.  
  3287.         //Disabled wit the new getLETopt function
  3288.         //const int LETCreateStackSize = 2*512*1024; //TODO make this dynamic in some sense
  3289.         //  curLevelStack    = new uint2[LETCreateStackSize];
  3290.         //  nextLevelStack   = new uint2[LETCreateStackSize];
  3291.       }
  3292.       //Each thread requires it's own copy since we modify some values during checking
  3293.       memcpy(&nodeInfo_private[0], &nodeInfo[0], sizeof(nInfoStruct)*localTree.n_nodes);
  3294.  
  3295.  
  3296.       int DistanceCheck = 0;
  3297.       double tGrpTest = get_time();
  3298.  
  3299.       while(true) //Continue until everything is computed
  3300.       {
  3301.         int currentTicket = 0;
  3302.  
  3303. #pragma omp critical
  3304.         currentTicket = omp_ticket++; //Get a unique ticket to determine which process to build the LET for
  3305.  
  3306.         if(currentTicket == (nProcs-1)) //Skip ourself
  3307.         {
  3308.           // LOGF(stderr,"Quick test was done, thread: %d checks: %d Since start: %lg\n", tid, DistanceCheck, get_time()-tGrpTest);
  3309.  
  3310.           /*    char buff[5120];
  3311.                 sprintf(buff, "GrpTesting tookB: %lg Checks: %d Res: ", get_time()-tGrpTest, DistanceCheck);
  3312.                 for(int i=0; i < nProcs; i++)
  3313.                 {
  3314.                 sprintf(buff, "%s%d\t",buff, resultOfQuickCheck[i]);
  3315.                 }
  3316.                 LOGF(stderr, "%s\n", buff);
  3317.                 */
  3318.           continue;
  3319.         }
  3320.  
  3321.         if(currentTicket >= (2*(nProcs) -1)) //Break out if everything is processed
  3322.           break;
  3323.  
  3324.         bool doQuickLETCheck = (currentTicket < (nProcs - 1));
  3325.         int ib               = (nProcs-1)-(currentTicket%nProcs);
  3326.         int ibox             = (ib+procId)%nProcs; //index to send...
  3327.  
  3328.         //Above could be replaced by a priority list, based on previous
  3329.         //loops (eg nearest neighbours first)
  3330.  
  3331.         double t1 = get_time();
  3332.  
  3333.         int doFullGrp = fullGrpAndLETRequest[ibox];
  3334.  
  3335.         //Group info for this process
  3336.         int idx          =   globalGrpTreeOffsets[ibox];
  3337.         real4 *grpCenter =  &globalGrpTreeCntSize[idx];
  3338.         idx             += this->globalGrpTreeCount[ibox] / 2; //Divide by two to get halfway
  3339.         real4 *grpSize   =  &globalGrpTreeCntSize[idx];
  3340.  
  3341.         //Retrieve required for the tree-walk from the top node
  3342.         union{int i; float f;} itof; //float as int
  3343.  
  3344.         itof.f       = grpCenter[0].x;
  3345.         int startGrp = itof.i;
  3346.         itof.f       = grpCenter[0].y;
  3347.         int endGrp   = itof.i;
  3348.  
  3349.         if(!doFullGrp)
  3350.         {
  3351.           //This is a topNode only
  3352.           startGrp = 0;
  3353.           endGrp   = this->globalGrpTreeCount[ibox] / 2;
  3354.         }
  3355.  
  3356.  
  3357.         if(doQuickLETCheck)
  3358.         {
  3359.  
  3360.           //Use this to 'disable' the Quick LET checks, with this disabled all
  3361.           //communication will be done as point to point
  3362.           //#define DO_NOT_DO_QUICK_LET_CHECK
  3363.  
  3364. #ifdef DO_NOT_DO_QUICK_LET_CHECK
  3365.  
  3366.           resultOfQuickCheck[ibox]   = -1;
  3367.           quickCheckSendSizes[ibox]  = 0;
  3368.           quickCheckSendOffset[ibox] = 0;
  3369. #pragma omp critical
  3370.           nCompletedQuickCheck++;
  3371.           continue;
  3372. #else
  3373.  
  3374.  
  3375.           if(doFullGrp)
  3376.           {
  3377.             //can skip this one beforehand, otherwise we would not have received the full-grp info
  3378.             resultOfQuickCheck[ibox]   = -1;
  3379.             quickCheckSendSizes[ibox]  = 0;
  3380.             quickCheckSendOffset[ibox] = 0;
  3381.           }
  3382.           else
  3383.           {
  3384.             //Determine if we do the quick-check, or the full check
  3385.             int maxLevel = recursiveBasedTopLEvelsCheckStart(tree,
  3386.                 &topLevelTrees[topLevelTreesSizeOffset[nTopLevelTrees].y],
  3387.                 grpCenter, grpSize, startGrp, endGrp, DistanceCheck);
  3388.             resultOfQuickCheck[ibox] = maxLevel;
  3389.  
  3390.             //#define MAXLEVELSIZE_ALLGATHER 2048
  3391.             #define MAXLEVELSIZE_ALLGATHER -1
  3392.             #if 0
  3393.             if(maxLevel >= 0)
  3394.             {
  3395.               if((topLevelTreesSizeOffset[maxLevel].x * sizeof(real4)) > MAXLEVELSIZE_ALLGATHER)
  3396.               {
  3397.                 LOGF(stderr, "NOT using : %d  %d \t size: %d \n", ibox, maxLevel, topLevelTreesSizeOffset[maxLevel].x * sizeof(real4));
  3398.                 resultOfQuickCheck[ibox] = -1;
  3399.                 maxLevel = -1;
  3400.               }
  3401.             }
  3402.             #endif
  3403.  
  3404.             if(maxLevel >= 0)
  3405.             {
  3406.               quickCheckSendSizes[ibox]  = topLevelTreesSizeOffset[maxLevel].x; //Size
  3407.               quickCheckSendOffset[ibox] = topLevelTreesSizeOffset[maxLevel].y; //Offset
  3408. #pragma omp critical
  3409.               nQuickCheckSends++;
  3410.  
  3411.               //Store the statistics
  3412.               this->fullGrpAndLETRequestStatistics[ibox] = make_uint2(maxLevel, ibox);
  3413.             }
  3414.             else
  3415.             {
  3416.               quickCheckSendSizes[ibox]   = 0;
  3417.               quickCheckSendOffset[ibox]  = 0;
  3418.             }
  3419.  
  3420.             //Also set the size and offset for the alltoall call. It will be two calls
  3421.             //first with integer size -> alltoall
  3422.             //second with integer size and offsets and displacements -> alltoallV
  3423.           }
  3424.  
  3425. #pragma omp critical
  3426.           nCompletedQuickCheck++;
  3427.  
  3428.           continue;
  3429. #endif
  3430.         }
  3431.         //Only continue if 'nCompletedQuickCheck' is done, otherwise some thread might still be
  3432.         //executing the quick check!
  3433.         while(1)
  3434.         {
  3435.           if(nCompletedQuickCheck == nProcs-1)
  3436.             break;
  3437.           usleep(10);
  3438.         }
  3439.  
  3440.         //If we arrive here, we did the quick tests, so now go checking if we need to do the full test
  3441.         if(resultOfQuickCheck[ibox] >= 0)
  3442.         {
  3443.           //We can skip this process, its been taken care of during the quick check
  3444.           continue;
  3445.         }
  3446.  
  3447.  
  3448.         int countNodes = 0, countParticles = 0;
  3449. #if 0
  3450.         double tz = get_time();
  3451.         if(tree.n > 0)
  3452.         {
  3453.           tree_walking_tree_stack_versionC13(
  3454.               &localTree.multipole[0], &nodeInfo_private[0], //Local Tree
  3455.               grpSize, grpCenter, //remote Tree
  3456.               node_begend.x, node_begend.y, startGrp, endGrp-1,
  3457.               countNodes, countParticles,
  3458.               curLevelStack, nextLevelStack);
  3459.         }
  3460.         double tCount = get_time()-tz;
  3461.  
  3462.         //Record the number of particles required
  3463.         //this->fullGrpAndLETRequestStatistics[ibox] = make_uint2(countParticles, ibox);
  3464.  
  3465.         //Test, use particles and node stats, but let particles count more heavy
  3466.         this->fullGrpAndLETRequestStatistics[ibox] = make_uint2(countParticles*10 + countNodes, ibox);
  3467.  
  3468.         //Buffer that will contain all the data:
  3469.         //|real4| 2*particleCount*real4| nodes*real4 | nodes*real4 | nodes*3*real4 |
  3470.         //1 + 1*particleCount + nodeCount + nodeCount + 3*nodeCount
  3471.  
  3472.         //Increase the number of particles and the number of nodes by the texture-offset
  3473.         //such that these are correctly aligned in memory
  3474.         //countParticles += getTextureAllignmentOffset(countParticles, sizeof(real4));
  3475.         //countNodes     += getTextureAllignmentOffset(countNodes    , sizeof(real4));
  3476.  
  3477.         //0-1 )                               Info about #particles, #nodes, start and end of tree-walk
  3478.         //1- Npart)                           The particle positions
  3479.         //1+1*Npart-Nnode )                   The nodeSizeData
  3480.         //1+1*Npart+Nnode   - Npart+2*Nnode ) The nodeCenterData
  3481.         //1+1*Npart+2*Nnode - Npart+5*Nnode ) The multipole data, is 3x number of nodes (mono and quadrupole data)
  3482.         int bufferSize = 1 + 1*countParticles + 5*countNodes;
  3483.  
  3484.  
  3485.         //We could try to reuse an existing buffer. TODO
  3486.  
  3487.         real4 *LETDataBuffer;
  3488. #pragma omp critical //Malloc seems to be not so thread safe..
  3489.         LETDataBuffer = (real4*)malloc(sizeof(real4)*bufferSize);
  3490.  
  3491.         double ty = get_time();
  3492.         stackFill(&LETDataBuffer[1],
  3493.             &localTree.boxCenterInfo[0],  &localTree.boxSizeInfo[0], &localTree.bodies_Ppos[0],
  3494.             &localTree.multipole[0],        nodeInfo_private, countParticles, countNodes,
  3495.             node_begend.x, node_begend.y, (uint*)curLevelStack, (uint*)nextLevelStack);
  3496.  
  3497.         if (ENABLE_RUNTIME_LOG)
  3498.         {
  3499.           fprintf(stderr,"Proc: %d LET count&fill [%d,%d]: Dest: %d Count: %lg Fill; %lg, Total : %lg (#P: %d \t#N: %d) \tsince start: %lg \n",
  3500.               procId, procId, tid, ibox, doFullGrp, tCount, get_time() - ty, get_time()-t1, countParticles, countNodes, get_time()-t0);
  3501.         }
  3502.  
  3503. #else
  3504.         double tz = get_time();
  3505.         real4 *LETDataBuffer;
  3506.         unsigned long long int nflops = 0;
  3507.  
  3508. #if 0
  3509.         if (ENABLE_RUNTIME_LOG)
  3510.           fprintf(stderr,"Proc: %d starting getLetOp  Dest: %d \n", procId, ibox);
  3511.         int2  nExport = getLETopt(
  3512.             &LETDataBuffer,
  3513.             &nodeCenterInfo[0],
  3514.             &nodeSizeInfo[0],
  3515.             &multipole[0],
  3516.             node_begend.x,
  3517.             node_begend.y,
  3518.             &bodies[0],
  3519.             tree.n,
  3520.             grpSize,
  3521.             grpCenter,
  3522.             startGrp,
  3523.             endGrp,
  3524.             tree.n_nodes, nflops);
  3525. #else
  3526.         if (ENABLE_RUNTIME_LOG)
  3527.           fprintf(stderr,"Proc: %d starting getLet1  Dest: %d \n", procId, ibox);
  3528.         assert(startGrp == 0);
  3529.         int2  nExport = getLET1(
  3530.             &LETDataBuffer,
  3531.             &nodeCenterInfo[0],
  3532.             &nodeSizeInfo[0],
  3533.             &multipole[0],
  3534.             node_begend.x,
  3535.             node_begend.y,
  3536.             &bodies[0],
  3537.             tree.n,
  3538.             grpSize,
  3539.             grpCenter,
  3540.             endGrp,
  3541.             tree.n_nodes, nflops);
  3542. #endif
  3543.  
  3544.         countParticles  = nExport.y;
  3545.         countNodes      = nExport.x;
  3546.         int bufferSize  = 1 + 1*countParticles + 5*countNodes;
  3547.         //Test, use particles and node stats, but let particles count more heavy
  3548.         this->fullGrpAndLETRequestStatistics[ibox] = make_uint2(countParticles*10 + countNodes, ibox);
  3549.         if (ENABLE_RUNTIME_LOG)
  3550.         {
  3551.           fprintf(stderr,"Proc: %d LET getLetOp count&fill [%d,%d]: Full: %d Dest: %d Total : %lg (#P: %d \t#N: %d) nNodes= %d  nGroups= %d \tsince start: %lg \n", procId, procId, tid, doFullGrp, ibox, get_time()-tz,countParticles, countNodes,
  3552.              tree.n_nodes, endGrp, get_time()-t0);
  3553.         }
  3554.  
  3555.  
  3556. #endif
  3557.  
  3558.         //Set the tree properties, before we exchange the data
  3559.         LETDataBuffer[0].x = host_int_as_float(countParticles);    //Number of particles in the LET
  3560.         LETDataBuffer[0].y = host_int_as_float(countNodes);        //Number of nodes     in the LET
  3561.         LETDataBuffer[0].z = host_int_as_float(node_begend.x);     //First node on the level that indicates the start of the tree walk
  3562.         LETDataBuffer[0].w = host_int_as_float(node_begend.y);     //last node on the level that indicates the start of the tree walk
  3563.  
  3564.         //In a critical section to prevent multiple threads writing to the same location
  3565. #pragma omp critical
  3566.         {
  3567.           computedLETs[nComputedLETs].buffer      = LETDataBuffer;
  3568.           computedLETs[nComputedLETs].destination = ibox;
  3569.           computedLETs[nComputedLETs].size        = sizeof(real4)*bufferSize;
  3570.           nComputedLETs++;
  3571.         }
  3572.  
  3573.  
  3574.         if(tid == 0)
  3575.         {
  3576.           //This determines if we interrupt the computation by starting a gravity kernel on the GPU
  3577.           if(gravStream->isFinished())
  3578.           {
  3579.             LOGF(stderr,"GRAVFINISHED %d recvTree: %d  Time: %lg Since start: %lg\n",
  3580.                 procId, nReceived, get_time()-t1, get_time()-t0);
  3581.  
  3582.             //Only start if there actually is new data
  3583.             if((nReceived - procTrees) > 0)
  3584.             {
  3585.               int recvTree      = 0;
  3586.               int topNodeCount  = 0;
  3587.               int oriTopCount   = 0;
  3588. #pragma omp critical(updateReceivedProcessed)
  3589.               {
  3590.                 recvTree             = nReceived;
  3591.                 topNodeCount         = topNodeOnTheFlyCount;
  3592.                 oriTopCount          = topNodeOnTheFlyCount;
  3593.                 topNodeOnTheFlyCount = 0;
  3594.               }
  3595.  
  3596.               double t000 = get_time();
  3597.               mergeAndLaunchLETStructures(tree, remote, treeBuffers, treeBuffersSource,
  3598.                   topNodeCount, recvTree, mergeOwntree, procTrees, tStart);
  3599.               LOGF(stderr, "Merging and launching iter: %d took: %lg \n", iter, get_time()-t000);
  3600.  
  3601.  
  3602.               //Correct the topNodeOnTheFlyCounter
  3603. #pragma omp critical(updateReceivedProcessed)
  3604.               {
  3605.                 //Compute how many are left, and add these back to the globalCounter
  3606.                 int nTopNodesLeft     = oriTopCount-topNodeCount;
  3607.                 topNodeOnTheFlyCount += nTopNodesLeft;
  3608.               }
  3609.  
  3610.               totalLETExTime += thisPartLETExTime;
  3611.             }// (nReceived - procTrees) > 0)
  3612.           }// isFinished
  3613.         }//tid == 0
  3614.  
  3615.       }//end while
  3616.  
  3617.       //All data that has to be send out is computed
  3618.       if(tid == 0)
  3619.       {
  3620.         //Thread 0 starts the GPU work so it stays alive until that is complete
  3621.         while(procTrees != nProcs-1) //Exit when everything is processed
  3622.         {
  3623.           bool startGrav = false;
  3624.           if(nReceived == nProcs-1) //Indicates that we have received all there is to receive
  3625.           {
  3626.             startGrav = true;
  3627.           }
  3628.  
  3629.           //This determines if we interrupt the computation/waiting by starting a gravity kernel on the GPU
  3630.           //Since the GPU is being idle
  3631.           if(gravStream->isFinished())
  3632.           {
  3633.             //Only start if there actually is new data
  3634.             if((nReceived - procTrees) > 0) startGrav = true;
  3635.           }
  3636.  
  3637.           if(startGrav)
  3638.           {
  3639.             int recvTree      = 0;
  3640.             int topNodeCount  = 0;
  3641.             int oriTopCount   = 0;
  3642. #pragma omp critical(updateReceivedProcessed)
  3643.             {
  3644.               recvTree             = nReceived;
  3645.               topNodeCount         = topNodeOnTheFlyCount;
  3646.               oriTopCount          = topNodeOnTheFlyCount;
  3647.               topNodeOnTheFlyCount = 0;
  3648.             }
  3649.  
  3650.             double t000 = get_time();
  3651.             mergeAndLaunchLETStructures(tree, remote, treeBuffers, treeBuffersSource,
  3652.                 topNodeCount,recvTree, mergeOwntree, procTrees, tStart);
  3653.             LOGF(stderr, "Merging and launching iter: %d took: %lg \n", iter, get_time()-t000);
  3654.  
  3655.             //Correct the topNodeOnTheFlyCounter
  3656. #pragma omp critical(updateReceivedProcessed)
  3657.             {
  3658.               //Compute how many are left, and add these back to the globalCounter
  3659.               int nTopNodesLeft     = oriTopCount-topNodeCount;
  3660.               topNodeOnTheFlyCount += nTopNodesLeft;
  3661.             }
  3662.  
  3663.             totalLETExTime += thisPartLETExTime;
  3664.           }
  3665.           else
  3666.           {
  3667.             usleep(10);
  3668.           }//if startGrav
  3669.         }//while 1
  3670.       }//if tid==0
  3671.  
  3672.  
  3673.       //delete[] curLevelStack;
  3674.       //delete[] nextLevelStack;
  3675.       delete[] nodeInfo_private;
  3676.     }
  3677.     else if(tid == 1)
  3678.     {
  3679.  
  3680.       //All to all part
  3681.  
  3682. #ifndef DO_NOT_DO_QUICK_LET_CHECK
  3683.       while(1)
  3684.       {
  3685.         if(nCompletedQuickCheck == nProcs-1)
  3686.           break;
  3687.         usleep(10);
  3688.       }
  3689.  
  3690.       //Send the sizes
  3691.  
  3692. #if MAXLEVELSIZE_ALLGATHER > 0
  3693.     //Combined all_gatherv and alltoall
  3694.     //First determine the maximum level
  3695.  
  3696.     int allGatherLevel = 0;
  3697.     for(int level=0; level < nTopLevelTrees; level++)
  3698.     {
  3699.       if((topLevelTreesSizeOffset[level].x * sizeof(real4)) > MAXLEVELSIZE_ALLGATHER)
  3700.         break;
  3701.       allGatherLevel++;
  3702.     }
  3703.  
  3704.     int allGatherLevelSize   = topLevelTreesSizeOffset[allGatherLevel].x*sizeof(real4);
  3705.     int allGatherLevelOffset = topLevelTreesSizeOffset[allGatherLevel].y*sizeof(real4);
  3706.  
  3707.     //Build up the data we are going to send/receive
  3708.     //To each process we send a copy of the tree at level 'allGatherLevel'
  3709.     //using all_gatherv
  3710.     //We indicate if that is sufficient, if not we indicate if we do an alltoallv send
  3711.     //or an getLET send.
  3712.  
  3713.     std::vector<int4> summaryOfDataToSend(nProcs);
  3714.     std::vector<int4> summaryOfDataToReceive(nProcs);
  3715.  
  3716.    // std::vector<int4> all2allVSizes  (nProcs);
  3717.    // std::vector<int4> all2allVOffsets(nProcs);
  3718.  
  3719.     resultOfQuickCheck[procId]    = -1; //Mark ourself
  3720.     quickCheckSendSizes[procId]   =  0;
  3721.     quickCheckSendOffset[procId]  =  0;
  3722.  
  3723.     for(int proc = 0; proc < nProcs; proc++)
  3724.     {
  3725.       if(resultOfQuickCheck[proc] >= 0 && resultOfQuickCheck[proc] <= allGatherLevel)
  3726.       {//Send using allGather
  3727.         summaryOfDataToSend[proc].x = 1; //It needs the top level
  3728.         summaryOfDataToSend[proc].y = allGatherLevelSize; //Size of the top level
  3729.         summaryOfDataToSend[proc].z = 0; //Not used
  3730.  
  3731.         //Set quickCheckSize to zero since it will not do an all2all
  3732.         quickCheckSendSizes[proc]   =  0;
  3733.         quickCheckSendOffset[proc]  =  0;
  3734.       }
  3735.       else if(resultOfQuickCheck[proc] >= 0)
  3736.       {//Send using alltoall
  3737.         summaryOfDataToSend[proc].x = 2; //It needs the top level
  3738.         summaryOfDataToSend[proc].y = allGatherLevelSize; //Size of the top level
  3739.         summaryOfDataToSend[proc].z = sizeof(real4)*topLevelTreesSizeOffset[resultOfQuickCheck[proc]].x; //alltoall size
  3740.        
  3741.          
  3742.         quickCheckSendSizes[proc]   =  sizeof(real4)*topLevelTreesSizeOffset[resultOfQuickCheck[proc]].x;
  3743.         quickCheckSendOffset[proc]  =  sizeof(real4)*topLevelTreesSizeOffset[resultOfQuickCheck[proc]].y;        
  3744.       }
  3745.       else
  3746.       { //Send with getLET
  3747.         summaryOfDataToSend[proc].x = 3; //It needs the top level
  3748.         summaryOfDataToSend[proc].y = allGatherLevelSize; //Size of the top level
  3749.        
  3750.         quickCheckSendSizes[proc]   =  0;
  3751.         quickCheckSendOffset[proc]  =  0;        
  3752.       }
  3753.     }//for each process
  3754.  
  3755.     LOGF(stderr, "Going to do the all to all size communication! Iter: %d Since begin: %lg \n", iter, get_time()-tStart);
  3756.     double t100 = get_time();
  3757.     MPI_Alltoall(
  3758.                   &summaryOfDataToSend[0],    sizeof(int4), MPI_BYTE,
  3759.                   &summaryOfDataToReceive[0], sizeof(int4), MPI_BYTE,
  3760.                   MPI_COMM_WORLD);
  3761.  
  3762.     LOGF(stderr, "Completed_alltoall size comm! Iter: %d Took: %lg ( %lg )\n", iter, get_time()-t100, get_time()-t0);
  3763.  
  3764.     //Count the number of incomming data items
  3765.     //First the allgather, size and offsets
  3766.     int allGatherOffset = 0;
  3767.     int allToAllOffset  = 0;
  3768.     std::vector<int> allGatherSizes(nProcs);  //Sizes to receive
  3769.     std::vector<int> allGatherOffsets(nProcs); //offsets
  3770.     std::vector<int> allGatherUses   (nProcs);  //Indicate if we use this (1) or not (-1)
  3771.  
  3772.     //We could reduce memory use by putting the non-used data in a seperate buffer, for now just
  3773.     //put it in a lineair array
  3774.     for(int proc = 0; proc < nProcs; proc++)
  3775.     {
  3776.       allGatherSizes[proc]   = summaryOfDataToReceive[proc].y;
  3777.       allGatherOffsets[proc] = allGatherOffset;
  3778.       allGatherOffset       += summaryOfDataToReceive[proc].y;
  3779.  
  3780.       if(summaryOfDataToReceive[proc].x == 1)
  3781.         allGatherUses[proc] = 1;
  3782.       else
  3783.         allGatherUses[proc] = -1;
  3784.        
  3785.       //Sum the alltoall size to be able to alloc
  3786.       if(summaryOfDataToReceive[proc].x == 2)
  3787.         allToAllOffset += summaryOfDataToReceive[proc].z;
  3788.     }
  3789.  
  3790.     recvAllGatherVBuffer =  new real4[allGatherOffset / sizeof(real4)];
  3791.     recvAllToAllBuffer   =  new real4[allToAllOffset  / sizeof(real4)];
  3792.    
  3793.     double tGatherStart = get_time();
  3794.  
  3795.     MPI_Allgatherv(&(topLevelTrees[allGatherLevelOffset / sizeof(real4)]),    //Begin of array
  3796.                    allGatherLevelSize,                      //Number of top-nodes
  3797.                    MPI_BYTE,
  3798.                    recvAllGatherVBuffer,               //Receive buffer
  3799.                    &allGatherSizes[0],      //Array with size per node
  3800.                    &allGatherOffsets[0],    //Array with offset per node
  3801.                    MPI_BYTE, MPI_COMM_WORLD);
  3802.  
  3803.     double tGatherEnd = get_time();
  3804.    
  3805.     LOGF(stderr, "All_GatherV took: %lg ( %lg ) Size: %lg  \n",
  3806.                   tGatherEnd-tGatherStart, get_time()-t0, (allGatherOffset  / sizeof(real4)*sizeof(real4))/(double)(1024*1024));
  3807.    
  3808.       for(int i=0; i < nProcs; i++)
  3809.       {
  3810.         int offset   = allGatherOffsets[i] / sizeof(real4);
  3811.         int p        = host_float_as_int(recvAllGatherVBuffer[offset].x);
  3812.         int n        = host_float_as_int(recvAllGatherVBuffer[offset].y);
  3813.         int topStart = host_float_as_int(recvAllGatherVBuffer[offset].z);
  3814.         int topEnd   = host_float_as_int(recvAllGatherVBuffer[offset].w);
  3815.  
  3816.         LOGF(stderr, "I received from %d  the following [%d %d \t | %d  %d \n",
  3817.             i, p, n, topStart, topEnd);
  3818.       }
  3819.  
  3820.       #pragma omp critical(updateReceivedProcessed)
  3821.       {
  3822.         //This is in a critical section since topNodeOnTheFlyCount is reset
  3823.         //by the GPU worker thread (thread == 0)
  3824.           int offset = 0;
  3825.         for(int i=0;  i < nProcs; i++)
  3826.         {
  3827.           if(allGatherUses[i] > 0)
  3828.           {
  3829.             int offset             = allGatherOffsets[i] / sizeof(real4);
  3830.             treeBuffers[nReceived] = &recvAllGatherVBuffer[offset];
  3831.  
  3832.             //Increase the top-node count
  3833.             int p        = host_float_as_int(treeBuffers[nReceived][0].x);
  3834.             int n        = host_float_as_int(treeBuffers[nReceived][0].y);
  3835.             int topStart = host_float_as_int(treeBuffers[nReceived][0].z);
  3836.             int topEnd   = host_float_as_int(treeBuffers[nReceived][0].w);
  3837.  
  3838. //          LOGF(stderr, "Received from: %d  start: %d end: %d P: %d N: %d\n",
  3839.  //                       i, topStart, topEnd, p, n);
  3840.  
  3841.             topNodeOnTheFlyCount        += (topEnd-topStart);
  3842.             treeBuffersSource[nReceived] = 1; //1 indicate quick check source
  3843.             nReceived++;
  3844.           }
  3845.         }
  3846.       LOGF(stderr, "Received trees using quickcheck-agv: %d top-nodes: %d \n", nReceived, topNodeOnTheFlyCount);
  3847.     }
  3848.  
  3849.     //Receive data using alltoall
  3850.     allToAllOffset  = 0;
  3851.     std::vector<int> allToAllRecvSizes  (nProcs);  //Sizes to receive
  3852.     std::vector<int> allToAllRecvOffsets(nProcs);  //offsets
  3853.     std::vector<int> allToAllUses   (nProcs);  //Indicate if we use this (1) or not (-1)    
  3854.     for(int proc = 0; proc < nProcs; proc++)
  3855.     {
  3856.       if(summaryOfDataToReceive[proc].x == 2)
  3857.       {
  3858.         allGatherUses[proc] = 1;
  3859.         allToAllRecvSizes[proc]    = summaryOfDataToReceive[proc].z;
  3860.         allToAllRecvOffsets[proc]  = allToAllOffset;
  3861.         allToAllOffset            += summaryOfDataToReceive[proc].z;
  3862.       }      
  3863.       else
  3864.       {
  3865.         allGatherUses[proc]        = -1;
  3866.         allToAllRecvSizes[proc]    = 0;
  3867.         allToAllRecvOffsets[proc]  = 0;      
  3868.       }
  3869.     }    
  3870.  
  3871.     LOGF(stderr, "Starting 1D alltoall \n");
  3872.     double t110 = get_time();
  3873.     MPI_Alltoallv(&topLevelTrees[0],  
  3874.                   quickCheckSendSizes, quickCheckSendOffset, MPI_BYTE,
  3875.                   &recvAllToAllBuffer[0],
  3876.                   &allToAllRecvSizes[0], &allToAllRecvOffsets[0], MPI_BYTE,
  3877.                   MPI_COMM_WORLD);
  3878.     LOGF(stderr, "[%d] Completed_alltoall 1D data communication! Iter: %d Took: %lg ( %lg )\tSize: %lg MB \n",
  3879.         procId, iter, get_time()-t110,  get_time()-t0, (allToAllOffset  / sizeof(real4)*sizeof(real4))/(double)(1024*1024));    
  3880.    
  3881.     #pragma omp critical(updateReceivedProcessed)
  3882.     {
  3883.       //This is in a critical section since topNodeOnTheFlyCount is reset
  3884.       //by the GPU worker thread (thread == 0)
  3885.       int offset    = 0;
  3886.       int na2acount = 0;
  3887.       int na2atopnode = 0;
  3888.       for(int i=0;  i < nProcs; i++)
  3889.       {
  3890.         if(allGatherUses[i] > 0)
  3891.         {
  3892.           int items              = allToAllRecvSizes[i]  / sizeof(real4);
  3893.           treeBuffers[nReceived] = &recvAllToAllBuffer[offset];
  3894.           offset                += items;
  3895.  
  3896.           //Increase the top-node count
  3897.           int p        = host_float_as_int(treeBuffers[nReceived][0].x);
  3898.           int n        = host_float_as_int(treeBuffers[nReceived][0].y);
  3899.           int topStart = host_float_as_int(treeBuffers[nReceived][0].z);
  3900.           int topEnd   = host_float_as_int(treeBuffers[nReceived][0].w);
  3901.  
  3902.    //       LOGF(stderr, "Received from: %d  start: %d end: %d P: %d N: %d\n",
  3903.    //                     i, topStart, topEnd, p, n);
  3904.                        
  3905.           na2atopnode += (topEnd-topStart);                            
  3906.  
  3907.           topNodeOnTheFlyCount        += (topEnd-topStart);
  3908.           treeBuffersSource[nReceived] = 1; //1 indicate quick check source
  3909.           nReceived++;
  3910.           na2acount++;
  3911.         }
  3912.       }
  3913.       if (ENABLE_RUNTIME_LOG)
  3914.       {
  3915.         fprintf(stderr,"Proc: %d Received trees using quickcheck-a2a: %d top-nodes: %d \n", procId, na2acount, na2atopnode);
  3916.       }
  3917.       }
  3918.  
  3919.  
  3920.       #else
  3921.  
  3922.  
  3923.  
  3924.       LOGF(stderr, "Going to do the alltoall size communication! Iter: %d Since begin: %lg \n", iter, get_time()-tStart);
  3925.       double t100 = get_time();
  3926.       MPI_Alltoall(quickCheckSendSizes, 1, MPI_INT, quickCheckRecvSizes, 1, MPI_INT, MPI_COMM_WORLD);
  3927.       LOGF(stderr, "Completed_alltoall size communication! Iter: %d Took: %lg ( %lg )\n", iter, get_time()-t100, get_time()-t0);
  3928.  
  3929.       //Compute offsets, allocate memory
  3930.       int recvCountItems      = quickCheckRecvSizes[0];
  3931.       quickCheckRecvSizes[0]  = quickCheckRecvSizes[0]*sizeof(real4);
  3932.       quickCheckRecvOffset[0] = 0;
  3933.       for(int i=1; i < nProcs; i++)
  3934.       {
  3935.         recvCountItems         += quickCheckRecvSizes[i];
  3936.         quickCheckRecvSizes[i]  = quickCheckRecvSizes[i]*sizeof(real4);
  3937.         quickCheckRecvOffset[i] = quickCheckRecvSizes[i-1] +  quickCheckRecvOffset[i-1];
  3938.       }
  3939.       //int totalSize = quickCheckRecvOffset[nProcs-1] + quickCheckRecvSizes[nProcs-1];
  3940.       /*          char buff[5120];
  3941.                   sprintf(buff, "AlltoAllSend: ");
  3942.                   for(int i=0; i < nProcs; i++)
  3943.                   {
  3944.                   sprintf(buff, "%s[%d,%d]\t",buff, quickCheckSendSizes[i], quickCheckSendOffset[i]);
  3945.                   }
  3946.                   LOGF(stderr, "%s\n", buff);
  3947.  
  3948.                   sprintf(buff, "AlltoAllRecv: ");
  3949.                   for(int i=0; i < nProcs; i++)
  3950.                   {
  3951.                   sprintf(buff, "%s[%d,%d]\t",buff, quickCheckRecvSizes[i], quickCheckRecvOffset[i]);
  3952.                   }
  3953.                   LOGF(stderr, "%s\n", buff);
  3954.  
  3955.                   int test2 = quickCheckRecvSizes[nProcs-1] + quickCheckRecvOffset[nProcs-1];
  3956.                   LOGF(stderr, "Allocating %ld size: %f MB \n", (recvCountItems*sizeof(real4)),(recvCountItems*sizeof(real4))/((float)(1024*1024)));
  3957.                   LOGF(stderr, "Allocating2 %d |  %d | %d  \n", test2, sizeof(real4), test2 / sizeof(real4));
  3958.                   */
  3959.       //      quickCheckSendOffset , quickCheckSendSizes
  3960.       //
  3961.       double tmem = get_time();
  3962.       recvAllToAllBuffer =  new real4[recvCountItems];
  3963.       LOGF(stderr, "Completed_alltoall mem alloc! Iter: %d Took: %lg \n", iter, get_time()-tmem);
  3964.  
  3965.       //Convert the values to bytes to get correct offsets and sizes
  3966.       for(int i=0; i < nProcs; i++)
  3967.       {
  3968.         quickCheckSendSizes[i]  *= sizeof(real4);
  3969.         quickCheckSendOffset[i] *= sizeof(real4);
  3970.  
  3971.       }
  3972.  
  3973.       double t110 = get_time();
  3974.  
  3975. #if 0
  3976.       LOGF(stderr, "Starting 1D alltoall \n");
  3977.       MPI_Alltoallv(&topLevelTrees[0],       quickCheckSendSizes, quickCheckSendOffset, MPI_BYTE,
  3978.           &recvAllToAllBuffer[0],  quickCheckRecvSizes, quickCheckRecvOffset, MPI_BYTE,
  3979.           MPI_COMM_WORLD);
  3980.       LOGF(stderr, "[%d] Completed_alltoall 1D data communication! Iter: %d Took: %lg ( %lg )\tSize: %ld MB \n",
  3981.           procId, iter, get_time()-t110,  get_time()-t0, (recvCountItems*sizeof(real4))/(1024*1024));
  3982. #else
  3983.       {
  3984.  
  3985.     #if 1  /* use this if data is aligned */
  3986.         typedef v4sf vec4;
  3987.     #else  /* otherwise use this to avoid segfault on the unaligned data */
  3988.         typedef float4 vec4;
  3989.     #endif
  3990.  
  3991.        std::vector<v4sf> topLevel;
  3992.         int nsendtotal = 0;
  3993.         for (int i= 0; i < nProcs; i++)
  3994.         nsendtotal += quickCheckSendSizes[i]/sizeof(v4sf);
  3995.  
  3996.         topLevel.resize(nsendtotal);
  3997.         int cntr = 0;
  3998.         for (int i= 0; i < nProcs; i++)
  3999.         {
  4000.       assert(quickCheckSendSizes[i] % sizeof(vec4) == 0);
  4001.       assert(quickCheckSendOffset[i] % sizeof(vec4) == 0);
  4002.           const int nsend = quickCheckSendSizes [i]/sizeof(v4sf);
  4003.           const int displ = quickCheckSendOffset[i]/sizeof(v4sf);
  4004.           for (int j = 0; j < nsend; j++)
  4005.             topLevel[cntr++] = ((v4sf*)&topLevelTrees[0])[displ + j];
  4006.         }
  4007.  
  4008.         LOGF(stderr, "Starting 2D alltoall copy took: %lg \n", get_time()-t110);
  4009.     mpiSync();
  4010. #if 0
  4011.         myComm->ugly_all2allv_char((float*)&topLevel[0],
  4012.             quickCheckSendSizes,
  4013.             (float*)&recvAllToAllBuffer[0]);
  4014. #else
  4015. double tbla = get_time();
  4016.         std::vector<int> scount_topLevel(nProcs);
  4017.         for (int i= 0; i < nProcs; i++)
  4018.           scount_topLevel[i] = quickCheckSendSizes[i]/sizeof(v4sf);
  4019.         myComm->all2allv_2D(topLevel, &scount_topLevel[0]);
  4020.         for (size_t i = 0; i < topLevel.size(); i++)
  4021.           ((v4sf*)recvAllToAllBuffer)[i] = topLevel[i];
  4022. double tbla2  = get_time();
  4023. LOGF(stderr,"Prep took: %lg  Items: %d \n", tbla2-tbla, topLevel.size());
  4024. #endif
  4025.  
  4026.  
  4027. #if 1
  4028.         int temp[nProcs];
  4029.         int newIdx = 0;
  4030.         for(int x=0; x<myComm->n_proc_i; x++)
  4031.         {
  4032.           for(int y=0; y<myComm->n_proc_j; y++)
  4033.           {
  4034.             //int k        = x*myComm->n_proc_j + y*myComm->n_proc_i;
  4035.             int k = myComm->n_proc_i*y + x;
  4036.             temp[newIdx] = quickCheckRecvSizes[k];
  4037.             //LOGF(stderr, "Recv moving %d -> %d value: %d \n", k, newIdx, temp[newIdx]);
  4038.             newIdx++;
  4039.           }
  4040.         }
  4041.         memcpy(quickCheckRecvSizes, temp, sizeof(int)*nProcs);
  4042. #endif
  4043.       }
  4044.  
  4045.       LOGF(stderr, "[%d] Completed_alltoall 2D data communication! Iter: %d Took: %lg ( %lg )\tSize: %f MB \n",
  4046.           procId, iter, get_time()-t110,  get_time()-t0, (recvCountItems*sizeof(real4))/(double)(1024*1024));
  4047. #endif
  4048.  
  4049.  
  4050. #pragma omp critical(updateReceivedProcessed)
  4051.       {
  4052.         //This is in a critical section since topNodeOnTheFlyCount is reset
  4053.         //by the GPU worker thread (thread == 0)
  4054.     //
  4055. //  char buff[4096];
  4056. //  sprintf(buff, "Proc: %d Recv Ori: ", procId);
  4057.     //
  4058.         int offset = 0;
  4059.         for(int i=0;  i < nProcs; i++)
  4060.         {
  4061.  
  4062.  //   sprintf(buff,"%s [%d, %d ], ", buff,quickCheckRecvSizes[i], quickCheckRecvOffset[i]);
  4063.  
  4064.           int items  = quickCheckRecvSizes[i]  / sizeof(real4);
  4065.           if(items > 0)
  4066.           {
  4067.             //int offset = quickCheckRecvOffset[i] / sizeof(real4);
  4068.  
  4069.             treeBuffers[nReceived] = &recvAllToAllBuffer[offset];
  4070.  
  4071.             offset += items;
  4072.  
  4073.             //Increase the top-node count
  4074.             int topStart = host_float_as_int(treeBuffers[nReceived][0].z);
  4075.             int topEnd   = host_float_as_int(treeBuffers[nReceived][0].w);
  4076.  
  4077.         LOGF(stderr, "Received from: %d  start: %d end: %d  offset: %d  offset old: %d\n",
  4078.                  i, topStart, topEnd, offset, quickCheckRecvOffset[i] / sizeof(real4));
  4079.  
  4080.             topNodeOnTheFlyCount += (topEnd-topStart);
  4081.             treeBuffersSource[nReceived] = 1; //1 indicate quick check source
  4082.             nReceived++;
  4083.           }
  4084.         }
  4085.    //   LOGF(stderr,"%s\n", buff);
  4086.       }
  4087.  
  4088.  
  4089.       LOGF(stderr, "Received trees using quickcheck: %d top-nodes: %d \n", nReceived, topNodeOnTheFlyCount);
  4090.  
  4091. #endif //the alltoall only code
  4092. #endif //#ifndef DO_NOT_DO_QUICK_LET_CHECK
  4093.  
  4094.  
  4095.       while(1)
  4096.       {
  4097.         //Sending part
  4098.         int tempComputed = nComputedLETs;
  4099.  
  4100.         if(tempComputed > nSendOut)
  4101.         {
  4102.           for(int i=nSendOut; i < tempComputed; i++)
  4103.           {
  4104.             //fprintf(stderr,"[%d] Sending out data to: %d \n", procId, computedLETs[i].destination);
  4105.             MPI_Isend(&(computedLETs[i].buffer)[0],computedLETs[i].size,
  4106.                 MPI_BYTE, computedLETs[i].destination, 999,
  4107.                 MPI_COMM_WORLD, &(computedLETs[i].req));
  4108.           }
  4109.           nSendOut = tempComputed;
  4110.         }
  4111.  
  4112.         //Receiving
  4113.         MPI_Status probeStatus;
  4114.         MPI_Status recvStatus;
  4115.         int flag  = 0;
  4116.  
  4117.         do
  4118.         {
  4119.           MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &probeStatus);
  4120.  
  4121.           if(flag)
  4122.           {
  4123.             int count;
  4124.             MPI_Get_count(&probeStatus, MPI_BYTE, &count);
  4125.             //fprintf(stderr,"%d\tThere is a message of size: %d %ld From: %d tag: %d\n",tid, count, count / sizeof(real4), probeStatus.MPI_SOURCE, probeStatus.MPI_TAG);
  4126.  
  4127.             double tY = get_time();
  4128.             real4 *recvDataBuffer = new real4[count / sizeof(real4)];
  4129.             double tZ = get_time();
  4130.             MPI_Recv(&recvDataBuffer[0], count, MPI_BYTE, probeStatus.MPI_SOURCE, probeStatus.MPI_TAG, MPI_COMM_WORLD,&recvStatus);
  4131.  
  4132.             LOGF(stderr, "Receive complete from: %d  || recvTree: %d since start: %lg ( %lg ) alloc: %lg Recv: %lg Size: %d\n",
  4133.                 recvStatus.MPI_SOURCE, 0, get_time()-tStart,get_time()-t0,tZ-tY, get_time()-tZ, count);
  4134.  
  4135.             treeBuffers[nReceived] = recvDataBuffer;
  4136.             treeBuffersSource[nReceived] = 0; //0 indicates point to point source
  4137.  
  4138.             //Increase the top-node count
  4139.             int topStart = host_float_as_int(treeBuffers[nReceived][0].z);
  4140.             int topEnd   = host_float_as_int(treeBuffers[nReceived][0].w);
  4141.  
  4142.  
  4143. #pragma omp critical(updateReceivedProcessed)
  4144.             {
  4145.               //This is in a critical section since topNodeOnTheFlyCount is reset
  4146.               //by the GPU worker thread (thread == 0)
  4147.               topNodeOnTheFlyCount += (topEnd-topStart);
  4148.               nReceived++;
  4149.             }
  4150.  
  4151.             flag = 0;
  4152.           }//if flag
  4153.  
  4154.           //TODO we could at an other probe here to keep, receiving data
  4155.           //untill there is nothing more
  4156.  
  4157.         }while(flag);
  4158.  
  4159.         //Exit if we have send and received all there is
  4160.         if(nReceived == nProcs-1)
  4161.           if((nSendOut+nQuickCheckSends) == nProcs-1)
  4162.             break;
  4163.  
  4164.         //Check if we can clean up some sends in between the receive/send process
  4165.         MPI_Status waitStatus;
  4166.         int testFlag = 0;
  4167.         for(int i=0; i  < nSendOut; i++)
  4168.         {
  4169.           if(computedLETs[i].buffer != NULL) MPI_Test(&(computedLETs[i].req), &testFlag, &waitStatus);
  4170.           if (testFlag)
  4171.           {
  4172.             free(computedLETs[i].buffer);
  4173.             computedLETs[i].buffer = NULL;
  4174.             testFlag               = 0;
  4175.           }
  4176.         }//end for nSendOut
  4177.  
  4178.         //TODO only do this sleep if we did not send/receive something
  4179.  
  4180.         usleep(10);
  4181.  
  4182.       } //while (1) surrounding the thread-id==1 code
  4183.  
  4184.       //Wait till all outgoing sends have completed
  4185.       MPI_Status waitStatus;
  4186.       for(int i=0; i < nSendOut; i++)
  4187.       {
  4188.         if(computedLETs[i].buffer)
  4189.         {
  4190.           MPI_Wait(&(computedLETs[i].req), &waitStatus);
  4191.           free(computedLETs[i].buffer);
  4192.           computedLETs[i].buffer = NULL;
  4193.         }
  4194.       }//for i < nSendOut
  4195.  
  4196.     }//if tid = 1
  4197.   }//end OMP section
  4198.  
  4199. #if 1 //Moved freeing of memory to here for ha-pacs workaround
  4200.   for(int i=0; i < nProcs-1; i++)
  4201.   {
  4202.     if(treeBuffersSource[i] == 0) //Check if its a point to point source
  4203.     {
  4204.       delete[] treeBuffers[i];    //Free the memory of this part of the LET
  4205.       treeBuffers[i] = NULL;
  4206.     }
  4207.   }
  4208. #endif
  4209.  
  4210.   if(recvAllToAllBuffer) delete[] recvAllToAllBuffer;
  4211.   delete[] treeBuffersSource;
  4212.   delete[] computedLETs;
  4213.   delete[] treeBuffers;
  4214.   LOGF(stderr,"LET Creation and Exchanging time [%d] curStep: %g\t   Total: %g  Full-step: %lg  since last start: %lg\n", procId, thisPartLETExTime, totalLETExTime, get_time()-t0, get_time()-tStart);
  4215.  
  4216. #endif
  4217. }//essential tree-exchange
  4218.  
  4219.  
  4220. void octree::mergeAndLaunchLETStructures(
  4221.     tree_structure &tree, tree_structure &remote,
  4222.     real4 **treeBuffers, int *treeBuffersSource,
  4223.     int &topNodeOnTheFlyCount,
  4224.     int &recvTree, bool &mergeOwntree, int &procTrees, double &tStart)
  4225. {
  4226.   //Now we have to merge the separate tree-structures into one big-tree
  4227.  
  4228.   int PROCS  = recvTree-procTrees;
  4229.  
  4230.  
  4231. #if 0 //This is no longer safe now that we use OpenMP and overlapping communication/computation
  4232.   //to use this (only in debug/test case) make sure GPU work is only launched AFTER ALL data
  4233.   //is received
  4234.   if(mergeOwntree)
  4235.   {
  4236.     real4  *bodies              = &tree.bodies_Ppos[0];
  4237.     real4  *velocities          = &tree.bodies_Pvel[0];
  4238.     real4  *multipole           = &tree.multipole[0];
  4239.     real4  *nodeSizeInfo        = &tree.boxSizeInfo[0];
  4240.     real4  *nodeCenterInfo      = &tree.boxCenterInfo[0];
  4241.     int     level_start         = tree.startLevelMin;
  4242.     //Add the processors own tree to the LET tree
  4243.     int particleCount   = tree.n;
  4244.     int nodeCount       = tree.n_nodes;
  4245.  
  4246.     int realParticleCount = tree.n;
  4247.     int realNodeCount     = tree.n_nodes;
  4248.  
  4249.     particleCount += getTextureAllignmentOffset(particleCount, sizeof(real4));
  4250.     nodeCount     += getTextureAllignmentOffset(nodeCount    , sizeof(real4));
  4251.  
  4252.     int bufferSizeLocal = 1 + 1*particleCount + 5*nodeCount;
  4253.  
  4254.     treeBuffers[PROCS]  = new real4[bufferSizeLocal];
  4255.  
  4256.     //Note that we use the real*Counts otherwise we read out of the array boundaries!!
  4257.     int idx = 1;
  4258.     memcpy(&treeBuffers[PROCS][idx], &bodies[0],         sizeof(real4)*realParticleCount);
  4259.     idx += particleCount;
  4260.     //      memcpy(&treeBuffers[PROCS][idx], &velocities[0],     sizeof(real4)*realParticleCount);
  4261.     //      idx += particleCount;
  4262.     memcpy(&treeBuffers[PROCS][idx], &nodeSizeInfo[0],   sizeof(real4)*realNodeCount);
  4263.     idx += nodeCount;
  4264.     memcpy(&treeBuffers[PROCS][idx], &nodeCenterInfo[0], sizeof(real4)*realNodeCount);
  4265.     idx += nodeCount;
  4266.     memcpy(&treeBuffers[PROCS][idx], &multipole[0],      sizeof(real4)*realNodeCount*3);
  4267.  
  4268.     treeBuffers[PROCS][0].x = host_int_as_float(particleCount);
  4269.     treeBuffers[PROCS][0].y = host_int_as_float(nodeCount);
  4270.     treeBuffers[PROCS][0].z = host_int_as_float(tree.level_list[level_start].x);
  4271.     treeBuffers[PROCS][0].w = host_int_as_float(tree.level_list[level_start].y);
  4272.  
  4273.     topNodeOnTheFlyCount += (tree.level_list[level_start].y-tree.level_list[level_start].x);
  4274.  
  4275.     PROCS                   = PROCS + 1; //Signal that we added one more tree-structure
  4276.     mergeOwntree            = false;     //Set it to false in case we do not merge all trees at once, we only include our own once
  4277.   }
  4278. #endif
  4279.  
  4280.   //Arrays to store and compute the offsets
  4281.   int *particleSumOffsets  = new int[mpiGetNProcs()+1];
  4282.   int *nodeSumOffsets      = new int[mpiGetNProcs()+1];
  4283.   int *startNodeSumOffsets = new int[mpiGetNProcs()+1];
  4284.   uint2 *nodesBegEnd       = new uint2[mpiGetNProcs()+1];
  4285.  
  4286.   //Offsets start at 0 and then are increased by the number of nodes of each LET tree
  4287.   particleSumOffsets[0]           = 0;
  4288.   nodeSumOffsets[0]               = 0;
  4289.   startNodeSumOffsets[0]          = 0;
  4290.   nodesBegEnd[mpiGetNProcs()].x   = nodesBegEnd[mpiGetNProcs()].y = 0; //Make valgrind happy
  4291.   int totalTopNodes               = 0;
  4292.  
  4293.   //#define DO_NOT_USE_TOP_TREE //If this is defined there is no tree-build on top of the start nodes
  4294.   vector<real4> topBoxCenters(1*topNodeOnTheFlyCount);
  4295.   vector<real4> topBoxSizes  (1*topNodeOnTheFlyCount);
  4296.   vector<real4> topMultiPoles(3*topNodeOnTheFlyCount);
  4297.   vector<real4> topTempBuffer(3*topNodeOnTheFlyCount);
  4298.   vector<int  > topSourceProc; //Do not assign size since we use 'insert'
  4299.  
  4300.  
  4301.   int nParticlesCounted   = 0;
  4302.   int nNodesCounted       = 0;
  4303.   int nProcsProcessed     = 0;
  4304.   bool continueProcessing = true;
  4305.  
  4306.   //Calculate the offsets
  4307.   for(int i=0; i < PROCS ; i++)
  4308.   {
  4309.     int particles = host_float_as_int(treeBuffers[procTrees+i][0].x);
  4310.     int nodes     = host_float_as_int(treeBuffers[procTrees+i][0].y);
  4311.  
  4312.     nParticlesCounted += particles;
  4313.     nNodesCounted     += nodes;
  4314.  
  4315.     //Check if we go over the limit, if so, we have two options:
  4316.     // - Ignore this last one, if we have processed nodes before (nProcsProcessed > 0)
  4317.     // - Process this one anyway and hope we have enough memory, do this if nProcsProcessed == 0
  4318.     //   otherwise we would make no progress
  4319.  
  4320.     int localLimit   =  tree.n            + 5*tree.n_nodes;
  4321.     int currentCount =  nParticlesCounted + 5*nNodesCounted;
  4322.  
  4323.     if(currentCount > localLimit)
  4324.     {
  4325.       LOGF(stderr, "Processing breaches memory limit. Limits local: %d, current: %d processed: %d \n",
  4326.           localLimit, currentCount, nProcsProcessed);
  4327.  
  4328.       if(nProcsProcessed > 0)
  4329.       {
  4330.         break; //Ignore this process, will be used next loop
  4331.       }
  4332.  
  4333.       //Stop after this process
  4334.       continueProcessing = false;
  4335.     }
  4336.     nProcsProcessed++;
  4337.  
  4338.     //Continue processing this domain
  4339.  
  4340.     nodesBegEnd[i].x = host_float_as_int(treeBuffers[procTrees+i][0].z);
  4341.     nodesBegEnd[i].y = host_float_as_int(treeBuffers[procTrees+i][0].w);
  4342.  
  4343.     particleSumOffsets[i+1]     = particleSumOffsets[i]  + particles;
  4344.     nodeSumOffsets[i+1]         = nodeSumOffsets[i]      + nodes - nodesBegEnd[i].y;    //Without the top-nodes
  4345.     startNodeSumOffsets[i+1]    = startNodeSumOffsets[i] + nodesBegEnd[i].y-nodesBegEnd[i].x;
  4346.  
  4347.     //Copy the properties for the top-nodes
  4348.     int nTop = nodesBegEnd[i].y-nodesBegEnd[i].x;
  4349.     memcpy(&topBoxSizes[totalTopNodes],
  4350.         &treeBuffers[procTrees+i][1+1*particles+nodesBegEnd[i].x],             sizeof(real4)*nTop);
  4351.     memcpy(&topBoxCenters[totalTopNodes],
  4352.         &treeBuffers[procTrees+i][1+1*particles+nodes+nodesBegEnd[i].x],       sizeof(real4)*nTop);
  4353.     memcpy(&topMultiPoles[3*totalTopNodes],
  4354.         &treeBuffers[procTrees+i][1+1*particles+2*nodes+3*nodesBegEnd[i].x], 3*sizeof(real4)*nTop);
  4355.     topSourceProc.insert(topSourceProc.end(), nTop, i ); //Assign source process id
  4356.  
  4357.     totalTopNodes += nodesBegEnd[i].y-nodesBegEnd[i].x;
  4358.  
  4359.     if(continueProcessing == false)
  4360.       break;
  4361.   }
  4362.  
  4363.   //Modify NPROCS, to set it to what we actually processed. Same for the
  4364.   //number of top-nodes, which is later passed back to the calling function
  4365.   //to update the overall number of top-nodes that is left to be processed
  4366.   PROCS                = nProcsProcessed;
  4367.   topNodeOnTheFlyCount = totalTopNodes;
  4368.  
  4369.  
  4370.  
  4371.  
  4372. #ifndef DO_NOT_USE_TOP_TREE
  4373.   uint4 *keys          = new uint4[topNodeOnTheFlyCount];
  4374.   //Compute the keys for the top nodes based on their centers
  4375.   for(int i=0; i < topNodeOnTheFlyCount; i++)
  4376.   {
  4377.     real4 nodeCenter = topBoxCenters[i];
  4378.     int4 crd;
  4379.     crd.x = (int)((nodeCenter.x - tree.corner.x) / tree.corner.w);
  4380.     crd.y = (int)((nodeCenter.y - tree.corner.y) / tree.corner.w);
  4381.     crd.z = (int)((nodeCenter.z - tree.corner.z) / tree.corner.w);
  4382.  
  4383.     keys[i]   = host_get_key(crd);
  4384.     keys[i].w = i;
  4385.   }//for i,
  4386.  
  4387.   //Sort the cells by their keys
  4388.   std::sort(keys, keys+topNodeOnTheFlyCount, cmp_ph_key());
  4389.  
  4390.   int *topSourceTempBuffer = (int*)&topTempBuffer[2*topNodeOnTheFlyCount]; //Allocated after sizes and centers
  4391.  
  4392.   //Shuffle the top-nodes after sorting
  4393.   for(int i=0; i < topNodeOnTheFlyCount; i++)
  4394.   {
  4395.     topTempBuffer[i]                      = topBoxSizes[i];
  4396.     topTempBuffer[i+topNodeOnTheFlyCount] = topBoxCenters[i];
  4397.     topSourceTempBuffer[i]                = topSourceProc[i];
  4398.   }
  4399.   for(int i=0; i < topNodeOnTheFlyCount; i++)
  4400.   {
  4401.     topBoxSizes[i]   = topTempBuffer[                       keys[i].w];
  4402.     topBoxCenters[i] = topTempBuffer[topNodeOnTheFlyCount + keys[i].w];
  4403.     topSourceProc[i] = topSourceTempBuffer[                 keys[i].w];
  4404.   }
  4405.   for(int i=0; i < topNodeOnTheFlyCount; i++)
  4406.   {
  4407.     topTempBuffer[3*i+0]                  = topMultiPoles[3*i+0];
  4408.     topTempBuffer[3*i+1]                  = topMultiPoles[3*i+1];
  4409.     topTempBuffer[3*i+2]                  = topMultiPoles[3*i+2];
  4410.   }
  4411.   for(int i=0; i < topNodeOnTheFlyCount; i++)
  4412.   {
  4413.     topMultiPoles[3*i+0]                  = topTempBuffer[3*keys[i].w+0];
  4414.     topMultiPoles[3*i+1]                  = topTempBuffer[3*keys[i].w+1];
  4415.     topMultiPoles[3*i+2]                  = topTempBuffer[3*keys[i].w+2];
  4416.   }
  4417.  
  4418.   //Build the tree
  4419.   //Assume we do not need more than 4 times number of top nodes.
  4420.   //but use a minimum of 2048 to be save
  4421.   uint2 *nodes    = new uint2[max(4*topNodeOnTheFlyCount, 2048)];
  4422.   uint4 *nodeKeys = new uint4[max(4*topNodeOnTheFlyCount, 2048)];
  4423.  
  4424.   //Build the tree
  4425.   uint node_levels[MAXLEVELS];
  4426.   int topTree_n_levels;
  4427.   int topTree_startNode;
  4428.   int topTree_endNode;
  4429.   int topTree_n_nodes;
  4430.   build_NewTopLevels(topNodeOnTheFlyCount,   &keys[0],          nodes,
  4431.       nodeKeys,        node_levels,       topTree_n_levels,
  4432.       topTree_n_nodes, topTree_startNode, topTree_endNode);
  4433.  
  4434.   LOGF(stderr, "Start %d end: %d Number of Original nodes: %d \n", topTree_startNode, topTree_endNode, topNodeOnTheFlyCount);
  4435.  
  4436.   //Next compute the properties
  4437.   float4  *topTreeCenters    = new float4 [  topTree_n_nodes];
  4438.   float4  *topTreeSizes      = new float4 [  topTree_n_nodes];
  4439.   float4  *topTreeMultipole  = new float4 [3*topTree_n_nodes];
  4440.   double4 *tempMultipoleRes  = new double4[3*topTree_n_nodes];
  4441.  
  4442.   computeProps_TopLevelTree(topTree_n_nodes,
  4443.       topTree_n_levels,
  4444.       node_levels,
  4445.       nodes,
  4446.       topTreeCenters,
  4447.       topTreeSizes,
  4448.       topTreeMultipole,
  4449.       &topBoxCenters[0],
  4450.       &topBoxSizes[0],
  4451.       &topMultiPoles[0],
  4452.       tempMultipoleRes);
  4453.  
  4454.   //Tree properties computed, now do some magic to put everything in one array
  4455.  
  4456. #else
  4457.   int topTree_n_nodes = 0;
  4458. #endif //DO_NOT_USE_TOP_TREE
  4459.  
  4460.   //Modify the offsets of the children to fix the index references to their childs
  4461.   for(int i=0; i < topNodeOnTheFlyCount; i++)
  4462.   {
  4463.     real4 center  = topBoxCenters[i];
  4464.     real4 size    = topBoxSizes  [i];
  4465.     int   srcProc = topSourceProc[i];
  4466.  
  4467.     bool leaf        = center.w <= 0;
  4468.  
  4469.     int childinfo    = host_float_as_int(size.w);
  4470.     int child, nchild;
  4471.  
  4472.     if(childinfo == 0xFFFFFFFF)
  4473.     {
  4474.       //End point, do not modify it should not be split
  4475.       child = childinfo;
  4476.     }
  4477.     else
  4478.     {
  4479.       if(!leaf)
  4480.       {
  4481.         //Node
  4482.         child    =    childinfo & 0x0FFFFFFF;                  //Index to the first child of the node
  4483.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;        //The number of children this node has
  4484.  
  4485.         //Calculate the new start for non-leaf nodes.
  4486.         child = child - nodesBegEnd[srcProc].y + topTree_n_nodes + totalTopNodes + nodeSumOffsets[srcProc];
  4487.         child = child | (nchild << 28);                        //Merging back in one integer
  4488.  
  4489.         if(nchild == 0) child = 0;                             //To prevent incorrect negative values
  4490.       }//if !leaf
  4491.       else
  4492.       { //Leaf
  4493.         child   =   childinfo & BODYMASK;                      //the first body in the leaf
  4494.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  4495.  
  4496.         child   =  child + particleSumOffsets[srcProc];        //Increasing offset
  4497.         child   = child | ((nchild-1) << LEAFBIT);             //Merging back to one integer
  4498.       }//end !leaf
  4499.     }//if endpoint
  4500.  
  4501.     topBoxSizes[i].w =  host_int_as_float(child);      //store the modified offset
  4502.   }//For topNodeOnTheFly
  4503.  
  4504.  
  4505.   //Compute total particles and total nodes, totalNodes is WITHOUT topNodes
  4506.   int totalParticles    = particleSumOffsets[PROCS];
  4507.   int totalNodes        = nodeSumOffsets[PROCS];
  4508.  
  4509.   //To bind parts of the memory to different textures, the memory start address
  4510.   //has to be aligned with XXX bytes, so nodeInformation*sizeof(real4) has to be
  4511.   //increased by an offset, so that the node data starts at a XXX byte boundary
  4512.   //this is already done on the sending process, but since we modify the structure
  4513.   //it has to be done again
  4514.   int nodeTextOffset = getTextureAllignmentOffset(totalNodes+totalTopNodes+topTree_n_nodes, sizeof(real4));
  4515.   int partTextOffset = getTextureAllignmentOffset(totalParticles                          , sizeof(real4));
  4516.  
  4517.   totalParticles    += partTextOffset;
  4518.  
  4519.   //Compute the total size of the buffer
  4520.   int bufferSize     = 1*(totalParticles) + 5*(totalNodes+totalTopNodes+topTree_n_nodes + nodeTextOffset);
  4521.  
  4522.   thisPartLETExTime += get_time() - tStart;
  4523.   //Allocate memory on host and device to store the merged tree-structure
  4524.   if(bufferSize > remote.fullRemoteTree.get_size())
  4525.   {
  4526.     //Can only resize if we are sure the LET is not running
  4527.     if(letRunning)
  4528.     {
  4529.       gravStream->sync(); //Wait till the LET run is finished
  4530.     }
  4531.     remote.fullRemoteTree.cresize_nocpy(bufferSize, false);  //Change the size but ONLY if we need more memory
  4532.   }
  4533.   tStart = get_time();
  4534.  
  4535.   real4 *combinedRemoteTree = &remote.fullRemoteTree[0];
  4536.  
  4537.   //First copy the properties of the top_tree nodes and the original top-nodes
  4538.  
  4539. #ifndef DO_NOT_USE_TOP_TREE
  4540.   //The top-tree node properties
  4541.   //Sizes
  4542.   memcpy(&combinedRemoteTree[1*(totalParticles)],
  4543.       topTreeSizes, sizeof(real4)*topTree_n_nodes);
  4544.   //Centers
  4545.   memcpy(&combinedRemoteTree[1*(totalParticles) + (totalNodes + totalTopNodes + topTree_n_nodes + nodeTextOffset)],
  4546.       topTreeCenters, sizeof(real4)*topTree_n_nodes);
  4547.   //Multipoles
  4548.   memcpy(&combinedRemoteTree[1*(totalParticles) +
  4549.       2*(totalNodes+totalTopNodes+topTree_n_nodes+nodeTextOffset)],
  4550.       topTreeMultipole, sizeof(real4)*topTree_n_nodes*3);
  4551.  
  4552.   //Cleanup
  4553.   delete[] keys;
  4554.   delete[] nodes;
  4555.   delete[] nodeKeys;
  4556.   delete[] topTreeCenters;
  4557.   delete[] topTreeSizes;
  4558.   delete[] topTreeMultipole;
  4559.   delete[] tempMultipoleRes;
  4560. #endif
  4561.  
  4562.   //The top-boxes properties
  4563.   //sizes
  4564.   memcpy(&combinedRemoteTree[1*(totalParticles) + topTree_n_nodes],
  4565.       &topBoxSizes[0], sizeof(real4)*topNodeOnTheFlyCount);
  4566.   //Node center information
  4567.   memcpy(&combinedRemoteTree[1*(totalParticles) + (totalNodes + totalTopNodes + topTree_n_nodes + nodeTextOffset) + topTree_n_nodes],
  4568.       &topBoxCenters[0], sizeof(real4)*topNodeOnTheFlyCount);
  4569.   //Multipole information
  4570.   memcpy(&combinedRemoteTree[1*(totalParticles) +
  4571.       2*(totalNodes+totalTopNodes+topTree_n_nodes+nodeTextOffset)+3*topTree_n_nodes],
  4572.       &topMultiPoles[0], sizeof(real4)*topNodeOnTheFlyCount*3);
  4573.  
  4574.   //Copy all the 'normal' pieces of the different trees at the correct memory offsets
  4575.   for(int i=0; i < PROCS; i++)
  4576.   {
  4577.     //Get the properties of the LET, TODO this should be changed in int_as_float instead of casts
  4578.     int remoteP      = host_float_as_int(treeBuffers[i+procTrees][0].x);    //Number of particles
  4579.     int remoteN      = host_float_as_int(treeBuffers[i+procTrees][0].y);    //Number of nodes
  4580.     int remoteB      = host_float_as_int(treeBuffers[i+procTrees][0].z);    //Begin id of top nodes
  4581.     int remoteE      = host_float_as_int(treeBuffers[i+procTrees][0].w);    //End   id of top nodes
  4582.     int remoteNstart = remoteE-remoteB;
  4583.  
  4584.     //Particles
  4585.     memcpy(&combinedRemoteTree[particleSumOffsets[i]],   &treeBuffers[i+procTrees][1], sizeof(real4)*remoteP);
  4586.  
  4587.     //Non start nodes, nodeSizeInfo
  4588.     memcpy(&combinedRemoteTree[1*(totalParticles) +  totalTopNodes + topTree_n_nodes + nodeSumOffsets[i]],
  4589.         &treeBuffers[i+procTrees][1+1*remoteP+remoteE], //From the last start node onwards
  4590.         sizeof(real4)*(remoteN-remoteE));
  4591.  
  4592.     //Non start nodes, nodeCenterInfo
  4593.     memcpy(&combinedRemoteTree[1*(totalParticles) + totalTopNodes + topTree_n_nodes + nodeSumOffsets[i] +
  4594.         (totalNodes + totalTopNodes + topTree_n_nodes + nodeTextOffset)],
  4595.         &treeBuffers[i+procTrees][1+1*remoteP+remoteE + remoteN], //From the last start node onwards
  4596.         sizeof(real4)*(remoteN-remoteE));
  4597.  
  4598.     //Non start nodes, multipole
  4599.     memcpy(&combinedRemoteTree[1*(totalParticles) +  3*(totalTopNodes+topTree_n_nodes) +
  4600.         3*nodeSumOffsets[i] + 2*(totalNodes+totalTopNodes+topTree_n_nodes+nodeTextOffset)],
  4601.         &treeBuffers[i+procTrees][1+1*remoteP+remoteE*3 + 2*remoteN], //From the last start node onwards
  4602.         sizeof(real4)*(remoteN-remoteE)*3);
  4603.  
  4604.     /*
  4605.        |real4| 1*particleCount*real4| nodes*real4 | nodes*real4 | nodes*3*real4 |
  4606.        1 + 1*particleCount + nodeCount + nodeCount + 3*nodeCount
  4607.  
  4608.        Info about #particles, #nodes, start and end of tree-walk
  4609.        The particle positions
  4610.        The nodeSizeData
  4611.        The nodeCenterData
  4612.        The multipole data, is 3x number of nodes (mono and quadrupole data)
  4613.  
  4614.        Now that the data is copied, modify the offsets of the tree so that everything works
  4615.        with the new correct locations and references. This takes place in two steps:
  4616.        First  the top nodes
  4617.        Second the normal nodes
  4618.        Has to be done in two steps since they are not continuous in memory if NPROCS > 2
  4619.        */
  4620.  
  4621.     //Modify the non-top nodes for this process
  4622.     int modStart =  totalTopNodes + topTree_n_nodes + nodeSumOffsets[i] + 1*(totalParticles);
  4623.     int modEnd   =  modStart      + remoteN-remoteE;
  4624.  
  4625.     for(int j=modStart; j < modEnd; j++)
  4626.     {
  4627.       real4 nodeCenter = combinedRemoteTree[j+totalTopNodes+topTree_n_nodes+totalNodes+nodeTextOffset];
  4628.       real4 nodeSize   = combinedRemoteTree[j];
  4629.       bool leaf        = nodeCenter.w <= 0;
  4630.  
  4631.       int childinfo = host_float_as_int(nodeSize.w);
  4632.       int child, nchild;
  4633.  
  4634.       if(childinfo == 0xFFFFFFFF)
  4635.       { //End point
  4636.         child = childinfo;
  4637.       }
  4638.       else
  4639.       {
  4640.         if(!leaf)
  4641.         {
  4642.           //Node
  4643.           child    =    childinfo & 0x0FFFFFFF;                   //Index to the first child of the node
  4644.           nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  4645.  
  4646.           //Calculate the new start (non-leaf)
  4647.           child = child - nodesBegEnd[i].y + totalTopNodes + topTree_n_nodes + nodeSumOffsets[i];
  4648.  
  4649.           child = child | (nchild << 28); //Combine and store
  4650.  
  4651.           if(nchild == 0) child = 0;                              //To prevent incorrect negative values
  4652.         }else{ //Leaf
  4653.           child   =   childinfo & BODYMASK;                       //the first body in the leaf
  4654.           nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);      //number of bodies in the leaf masked with the flag
  4655.  
  4656.           child = child + particleSumOffsets[i];                 //Modify the particle offsets
  4657.           child = child | ((nchild-1) << LEAFBIT);               //Merging the data back into one integer
  4658.         }//end !leaf
  4659.       }
  4660.       combinedRemoteTree[j].w =  host_int_as_float(child);      //Store the modified value
  4661.     }//for non-top nodes
  4662.  
  4663. #if 0 //Ha-pacs fix
  4664.     if(treeBuffersSource[i+procTrees] == 0) //Check if its a point to point source
  4665.     {
  4666.       delete[] treeBuffers[i+procTrees];    //Free the memory of this part of the LET
  4667.       treeBuffers[i+procTrees] = NULL;
  4668.     }
  4669. #endif
  4670.  
  4671.  
  4672.   } //for PROCS
  4673.  
  4674.   /*
  4675.      The final tree structure looks as follows:
  4676.      particlesT1, particlesT2,...mparticlesTn |,
  4677.      topNodeSizeT1, topNodeSizeT2,..., topNodeSizeT2 | nodeSizeT1, nodeSizeT2, ...nodeSizeT3 |,
  4678.      topNodeCentT1, topNodeCentT2,..., topNodeCentT2 | nodeCentT1, nodeCentT2, ...nodeCentT3 |,
  4679.      topNodeMultT1, topNodeMultT2,..., topNodeMultT2 | nodeMultT1, nodeMultT2, ...nodeMultT3
  4680.  
  4681.      NOTE that the Multi-pole data consists of 3 float4 values per node
  4682.      */
  4683.   //     fprintf(stderr,"Modifying the LET took: %g \n", get_time()-t1);
  4684.  
  4685.   LOGF(stderr,"Number of local bodies: %d number LET bodies: %d number LET nodes: %d top nodes: %d Processed trees: %d (%d) \n",
  4686.       tree.n, totalParticles, totalNodes, totalTopNodes, PROCS, procTrees);
  4687.  
  4688.   //Store the tree properties (number of particles, number of nodes, start and end topnode)
  4689.   remote.remoteTreeStruct.x = totalParticles;
  4690.   remote.remoteTreeStruct.y = totalNodes+totalTopNodes+topTree_n_nodes;
  4691.   remote.remoteTreeStruct.z = nodeTextOffset;
  4692.  
  4693. #ifndef DO_NOT_USE_TOP_TREE
  4694.   //Using this we use our newly build tree as starting point
  4695.   totalTopNodes             = topTree_startNode << 16 | topTree_endNode;
  4696.  
  4697.   //Using this we get back our original start-points and do not use the extra tree.
  4698.   //totalTopNodes             = (topTree_n_nodes << 16) | (topTree_n_nodes+topNodeOnTheFlyCount);
  4699. #else
  4700.   totalTopNodes             = (0 << 16) | (topNodeOnTheFlyCount);  //If its a merged tree we start at 0
  4701. #endif
  4702.  
  4703.   remote.remoteTreeStruct.w = totalTopNodes;
  4704.   topNodeOnTheFlyCount      = 0; //Reset counters
  4705.  
  4706.   delete[] particleSumOffsets;
  4707.   delete[] nodeSumOffsets;
  4708.   delete[] startNodeSumOffsets;
  4709.   delete[] nodesBegEnd;
  4710.  
  4711.  
  4712.  
  4713.   thisPartLETExTime += get_time() - tStart;
  4714.  
  4715.   //procTrees = recvTree;
  4716.   procTrees += PROCS; //Changed since PROCS can be smaller than total number that can be processed
  4717.  
  4718.  
  4719. #if 0
  4720.   if(iter == 20)
  4721.   {
  4722.     char fileName[256];
  4723.     sprintf(fileName, "letParticles-%d.bin", mpiGetRank());
  4724.     ofstream nodeFile;
  4725.     //nodeFile.open(nodeFileName.c_str());
  4726.     nodeFile.open(fileName, ios::out | ios::binary | ios::app);
  4727.     if(nodeFile.is_open())
  4728.     {
  4729.       for(int i=0; i < totalParticles; i++)
  4730.       {
  4731.         nodeFile.write((char*)&combinedRemoteTree[i], sizeof(real4));
  4732.       }
  4733.       nodeFile.close();
  4734.     }
  4735.   }
  4736. #endif
  4737.  
  4738.   //Check if we need to summarize which particles are active,
  4739.   //only done during the last approximate_gravity_let call
  4740.   bool doActivePart = (procTrees == mpiGetNProcs() -1);
  4741.  
  4742.   approximate_gravity_let(this->localTree, this->remoteTree, bufferSize, doActivePart);
  4743. }
  4744.  
  4745.  
  4746. //SSE optimized MAC check
  4747. inline int split_node_grav_impbh_sse(
  4748.     const _v4sf nodeCOM1,
  4749.     const _v4sf boxCenter1,
  4750.     const _v4sf boxSize1)
  4751. {
  4752.   const _v4si mask = {0xffffffff, 0xffffffff, 0xffffffff, 0x0};
  4753.   const _v4sf size = __abs(__builtin_ia32_shufps(nodeCOM1, nodeCOM1, 0xFF));
  4754.  
  4755.   //mask to prevent NaN signalling / Overflow ? Required to get good pre-SB performance
  4756.   const _v4sf nodeCOM   = __builtin_ia32_andps(nodeCOM1,   (_v4sf)mask);
  4757.   const _v4sf boxCenter = __builtin_ia32_andps(boxCenter1, (_v4sf)mask);
  4758.   const _v4sf boxSize   = __builtin_ia32_andps(boxSize1,   (_v4sf)mask);
  4759.  
  4760.  
  4761.   const _v4sf dr   = __abs(boxCenter - nodeCOM) - boxSize;
  4762.   const _v4sf ds   = dr + __abs(dr);
  4763.   const _v4sf dsq  = ds*ds;
  4764.   const _v4sf t1   = __builtin_ia32_haddps(dsq, dsq);
  4765.   const _v4sf t2   = __builtin_ia32_haddps(t1, t1);
  4766.   const _v4sf ds2  = __builtin_ia32_shufps(t2, t2, 0x00)*(_v4sf){0.25f, 0.25f, 0.25f, 0.25f};
  4767.  
  4768.  
  4769.   const float c = 10e-4f;
  4770.   const int res = __builtin_ia32_movmskps(
  4771.       __builtin_ia32_orps(
  4772.         __builtin_ia32_cmpleps(ds2,  size),
  4773.         __builtin_ia32_cmpltps(ds2 - size, (_v4sf){c,c,c,c})
  4774.         )
  4775.       );
  4776.  
  4777.   //return 1;
  4778.   return res;
  4779.  
  4780. }
  4781.  
  4782. //Walk the group tree over the local-data tree.
  4783. //Counts the number of particles and nodes that will be selected
  4784. void octree::tree_walking_tree_stack_versionC13(
  4785.     real4 *multipoleS, nInfoStruct* nodeInfoS, //Local Tree
  4786.     real4* grpNodeSizeInfoS, real4* grpNodeCenterInfoS, //remote Tree
  4787.     int start, int end, int startGrp, int endGrp,
  4788.     int &nAcceptedNodes, int &nParticles,
  4789.     uint2 *curLevel, uint2 *nextLevel)
  4790. {
  4791. #ifdef USE_MPI
  4792.  
  4793.   //nodeInfo.z bit values:
  4794.   //  bit 0 : Node has been visit (1)
  4795.   //  bit 1 : Node is split  (2)
  4796.   //  bit 2 : Node is a leaf which particles have been added (4)
  4797.  
  4798.   const _v4sf*         multipoleV = (const _v4sf*)        multipoleS;
  4799.   const _v4sf*   grpNodeSizeInfoV = (const _v4sf*)  grpNodeSizeInfoS;
  4800.   const _v4sf* grpNodeCenterInfoV = (const _v4sf*)grpNodeCenterInfoS;
  4801.  
  4802.   for(int i=0; i < start; i++) nodeInfoS[i].z = 3;
  4803.  
  4804.   nAcceptedNodes = start;
  4805.   nParticles     = 0;
  4806.  
  4807.   int curLevelCount  = 0;
  4808.   int nextLevelCount = 0;
  4809.  
  4810.   for(int k = start; k < end; k++)
  4811.   {
  4812.     uint2 stackItem;
  4813.     stackItem.x = k;
  4814.     curLevel[curLevelCount++] = stackItem;
  4815.   }
  4816.  
  4817.   bool overRuleBegin = true;
  4818.  
  4819.   while(curLevelCount > 0)
  4820.   {
  4821.     nextLevelCount = 0;
  4822.     for(int idx = 0; idx < curLevelCount; idx++)
  4823.       //for(int idx = curLevelCount-1; idx >= 0; idx--) //std::stack order
  4824.     {
  4825.       const uint2 stackItem  = curLevel[idx];
  4826.       const uint nodeID      = stackItem.x;
  4827.  
  4828.       //Tree-node information
  4829.       const nInfoStruct nodeInfoX = nodeInfoS[nodeID];
  4830.  
  4831.       //Early out if this is an accepted leaf node
  4832.       if(nodeInfoX.z  & 4) continue;
  4833.  
  4834.       //Only mark the first time, saves writes --> Always writing turns out to be faster
  4835.       if(nodeInfoX.z == 0)
  4836.       {
  4837.         nAcceptedNodes++;
  4838.         nodeInfoS[nodeID].z = 1;
  4839.       }
  4840.  
  4841.       //Read the COM and combine it with opening angle criteria from nodeInfoX.x
  4842.       _v4sf nodeCOM = multipoleV[nodeID*3];
  4843.       nodeCOM       = __builtin_ia32_vec_set_v4sf (nodeCOM, nodeInfoX.x, 3);
  4844.  
  4845.       int begin, end;
  4846.  
  4847.       //I need this since I can't guarantee that I can encode the start-grp info
  4848.       //in the available bytes.
  4849.       if(overRuleBegin)
  4850.       {
  4851.         begin = startGrp; end   = endGrp;
  4852.       }
  4853.       else
  4854.       {
  4855.         begin = stackItem.y & 0x0FFFFFFF;
  4856.         end   = begin +  ((stackItem.y & 0xF0000000) >> 28) ;
  4857.       }
  4858.  
  4859.       for(int grpId=begin; grpId <= end; grpId++)
  4860.       {
  4861.         //Group information
  4862.         const _v4sf grpCenter = grpNodeCenterInfoV[grpId];
  4863.         const _v4sf grpSize   = grpNodeSizeInfoV[grpId];
  4864.  
  4865.         const int split = split_node_grav_impbh_sse(nodeCOM, grpCenter, grpSize);
  4866.         //        const int split = 1;
  4867.  
  4868.         if(split)
  4869.         {
  4870.           const bool leaf        = nodeInfoX.x <= 0;
  4871.  
  4872.           if(!leaf)
  4873.           {
  4874.             //nodeInfoS[nodeID].z = nodeInfoS[nodeID].z |  3; //Mark this node as being split, usefull for
  4875.             nodeInfoS[nodeID].z = 3; //Mark this node as being split, useful for
  4876.             //when creating LET tree, we can mark end-points
  4877.             //Sets the split, and visit bits
  4878.  
  4879.             const int child    =    nodeInfoX.y & 0x0FFFFFFF;            //Index to the first child of the node
  4880.             const int nchild   = (((nodeInfoX.y & 0xF0000000) >> 28)) ;  //The number of children this node has
  4881. #if 0
  4882.             int childinfoGrp;
  4883.             if( __builtin_ia32_vec_ext_v4sf(grpCenter, 3) <= 0)
  4884.             { //Its a leaf so we stay with this group
  4885.               //              childinfoGrp = grpId | (1) << 28;
  4886.               childinfoGrp = grpId;
  4887.             }
  4888.             else
  4889.               childinfoGrp    = __builtin_ia32_vec_ext_v4si((_v4si)grpSize,3);
  4890. #else
  4891.             int childinfoGrp = grpId;
  4892.             //If its not a leaf so we continue down the group-tree
  4893.             if( __builtin_ia32_vec_ext_v4sf(grpCenter, 3) > 0)
  4894.               childinfoGrp    = __builtin_ia32_vec_ext_v4si((_v4si)grpSize,3);
  4895. #endif
  4896.  
  4897.             //Go check the child nodes and child grps
  4898.             for(int i=child; i < child+nchild; i++)
  4899.             { //Add the nodes to the stack
  4900.               nextLevel[nextLevelCount++] = make_uint2(i, childinfoGrp);
  4901.             }
  4902.           }//if !leaf
  4903.           else if(nodeInfoS[nodeID].z != 7)
  4904.           {
  4905.             int nchild  = (((nodeInfoX.y & INVBMASK) >> LEAFBIT)+1);
  4906.  
  4907.             //Mark this leaf as completed, no further checks required
  4908.             nodeInfoS[nodeID].z = 7;
  4909.             nParticles        += nchild;
  4910.             break; //We can jump out of these groups
  4911.           }//if !leaf
  4912.         }//if !split
  4913.       }//for grps
  4914.     }// end inner while
  4915.  
  4916.     //Swap stacks
  4917.     uint2 *temp = nextLevel;
  4918.     nextLevel   = curLevel;
  4919.     curLevel    = temp;
  4920.  
  4921.     curLevelCount  = nextLevelCount;
  4922.     nextLevelCount = 0;
  4923.     overRuleBegin = false;
  4924.   } //end inner while
  4925. #endif //if USE_MPI
  4926. } //end function
  4927.  
  4928.  
  4929. //Function that walks over the pre-processed data (processed/generated by the tree-tree walk)
  4930. //and fills the LET buffers with the data from the particles and the nodes
  4931. void octree::stackFill(real4 *LETBuffer, real4 *nodeCenter, real4* nodeSize,
  4932.     real4* bodies, real4 *multipole,
  4933.     nInfoStruct *nodeInfo,
  4934.     int nParticles, int nNodes,
  4935.     int start, int end,
  4936.     uint *curLevelStack, uint* nextLevelStack)
  4937. {
  4938. #ifdef USE_MPI
  4939.  
  4940.   int curLeveCount   = 0;
  4941.   int nextLevelCount = 0;
  4942.  
  4943.   int nStoreIdx = nParticles;
  4944.  
  4945.   nParticles = 0;
  4946.  
  4947.   int multiStoreIdx = nStoreIdx+2*nNodes; //multipole starts after particles and nodeSize, nodeCenter
  4948.  
  4949.   //Copy top nodes, directly after the bodies
  4950.   for(int node=0; node < start; node++)
  4951.   {
  4952.     LETBuffer[nStoreIdx]              = nodeSize[node];
  4953.     LETBuffer[nStoreIdx+nNodes]       = nodeCenter[node];
  4954.     memcpy(&LETBuffer[multiStoreIdx], &multipole[3*node], sizeof(float4)*(3));
  4955.     multiStoreIdx += 3;
  4956.     nStoreIdx++;
  4957.   }
  4958.  
  4959.   int childNodeOffset     = end;
  4960.  
  4961.   for(int node=start; node < end; node++){
  4962.     curLevelStack[curLeveCount++] = node;
  4963.   }
  4964.  
  4965.   while(curLeveCount > 0)
  4966.   {
  4967.     for(int i=0; i < curLeveCount; i++)
  4968.     {
  4969.       const uint node               = curLevelStack[i];
  4970.       const nInfoStruct curNodeInfo = nodeInfo[node];
  4971.       nodeInfo[node].z = 0; //Reset the node for next round/tree
  4972.  
  4973.       const int childinfo = curNodeInfo.y;
  4974.       uint newChildInfo   = 0xFFFFFFFF; //Mark node as not split
  4975.  
  4976.       uint child, nchild;
  4977.  
  4978.       if(curNodeInfo.z & 2) //Split
  4979.       {
  4980.         if(curNodeInfo.z & 4)
  4981.         { //Leaf that is split
  4982.           child   =   childinfo & BODYMASK;
  4983.           nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);
  4984.           newChildInfo = nParticles; //Set the start of the particle buffer
  4985.  
  4986.           memcpy(&LETBuffer[nParticles], &bodies[child], sizeof(float4)*(nchild));
  4987.           nParticles += nchild;
  4988.  
  4989.           nchild  =  nchild-1; //Minus 1 to get it in right format when combining
  4990.           //with newChildInfo
  4991.         }
  4992.         else
  4993.         { //Normal node that is split
  4994.           child    =    childinfo & BODYMASK;           //Index to the first child of the node
  4995.           nchild   = (((childinfo & INVBMASK) >> LEAFBIT)) ; //The number of children this node has
  4996.  
  4997.           newChildInfo     = childNodeOffset;
  4998.           childNodeOffset += nchild;
  4999.  
  5000.           for(int j=child; j < child+nchild; j++)
  5001.           {
  5002.             nextLevelStack[nextLevelCount++] = j;
  5003.           }//for
  5004.         }//if leaf
  5005.       }//if split
  5006.  
  5007.  
  5008.       //Copy this node info
  5009.       LETBuffer[nStoreIdx]            = nodeSize[node];
  5010.       LETBuffer[nStoreIdx].w          = host_int_as_float(newChildInfo | (nchild << LEAFBIT));
  5011.       LETBuffer[nStoreIdx+nNodes]     = nodeCenter[node];
  5012.       memcpy(&LETBuffer[multiStoreIdx], &multipole[3*node], sizeof(float4)*(3));
  5013.       multiStoreIdx += 3;
  5014.       nStoreIdx++;
  5015.       if(procId < 0)
  5016.       {
  5017.         if(node < 200)
  5018.           LOGF(stderr, "Node-normal: %d\tMultipole: %f\n", node, multipole[3*node].x);
  5019.       }
  5020.     }//end for
  5021.  
  5022.     //Swap stacks
  5023.     uint *temp          = curLevelStack;
  5024.     curLevelStack       = nextLevelStack;
  5025.     nextLevelStack      = temp;
  5026.     curLeveCount        = nextLevelCount;
  5027.     nextLevelCount      = 0;
  5028.   }
  5029.  
  5030. #endif //if USE_MPI
  5031. }//stackFill
  5032.  
  5033.  
  5034. //Exchange the LET structure, this is a point to point communication operation
  5035. real4* octree::MP_exchange_bhlist(int ibox, int isource,
  5036.     int bufferSize, real4 *letDataBuffer)
  5037. {
  5038. #ifdef USE_MPI
  5039.   MPI_Status status;
  5040.   int nrecvlist;
  5041.   int nlist = bufferSize;
  5042.  
  5043.   double t0 = get_time();
  5044.   //first send&get the number of particles to send&get
  5045.   MPI_Sendrecv(&nlist,1,MPI_INT,ibox,procId*10, &nrecvlist,
  5046.       1,MPI_INT,isource,isource*10,MPI_COMM_WORLD, &status);
  5047.  
  5048.   double t1= get_time();
  5049.   //Resize the buffer so it has the correct size and then exchange the tree
  5050.   real4 *recvDataBuffer = new real4[nrecvlist];
  5051.   /*
  5052. http://books.google.nl/books?id=x79puJ2YkroC&lpg=PA90&ots=54LRnnXOH4&dq=mpi_irecv%20producer%20consumer&pg=PA83#v=onepage&q=mpi_irecv%20producer%20consumer&f=false
  5053. http://www.mpi-forum.org/docs/mpi-11-html/node47.html
  5054. http://supercomputingblog.com/mpi/mpi-tutorial-5-asynchronous-communication/
  5055. http://cs.ucsb.edu/~hnielsen/cs140/mpi-deadlocks.html
  5056. http://www.mpi-forum.org/docs/mpi-11-html/node50.html
  5057. MPI_test
  5058. MPI_wait*/
  5059.  
  5060.  
  5061.   double t2=get_time();
  5062.   //Particles
  5063.   MPI_Sendrecv(&letDataBuffer[0], nlist*sizeof(real4), MPI_BYTE, ibox, procId*10+1,
  5064.       &recvDataBuffer[0], nrecvlist*sizeof(real4), MPI_BYTE, isource, isource*10+1,
  5065.       MPI_COMM_WORLD, &status);
  5066.  
  5067.   LOG("LET Data Exchange: %d <-> %d  sync-size: %f  alloc: %f  data: %f Total: %lg MB : %f \n",
  5068.       ibox, isource, t1-t0, t2-t1, get_time()-t2, get_time()-t0, (nlist*sizeof(real4)/(double)(1024*1024)));
  5069.  
  5070.   return recvDataBuffer;
  5071. #else
  5072.   return NULL;
  5073. #endif
  5074. }
  5075.  
  5076.  
  5077.  
  5078. void octree::ICSend(int destination, real4 *bodyPositions, real4 *bodyVelocities,  int *bodiesIDs, int toSend)
  5079. {
  5080. #ifdef USE_MPI
  5081.   //First send the number of particles, then the actual sample data
  5082.   MPI_Send(&toSend, 1, MPI_INT, destination, destination*2 , MPI_COMM_WORLD);
  5083.  
  5084.   //Send the positions, velocities and ids
  5085.   MPI_Send( bodyPositions,  toSend*sizeof(real)*4, MPI_BYTE, destination, destination*2+1, MPI_COMM_WORLD);
  5086.   MPI_Send( bodyVelocities, toSend*sizeof(real)*4, MPI_BYTE, destination, destination*2+2, MPI_COMM_WORLD);
  5087.   MPI_Send( bodiesIDs,      toSend*sizeof(int),    MPI_BYTE, destination, destination*2+3, MPI_COMM_WORLD);
  5088.  
  5089.   /*    MPI_Send( (real*)&bodyPositions[0],  toSend*sizeof(real)*4, MPI_BYTE, destination, destination*2+1, MPI_COMM_WORLD);
  5090.         MPI_Send( (real*)&bodyVelocities[0], toSend*sizeof(real)*4, MPI_BYTE, destination, destination*2+2, MPI_COMM_WORLD);
  5091.         MPI_Send( (int *)&bodiesIDs[0],      toSend*sizeof(int),    MPI_BYTE, destination, destination*2+3, MPI_COMM_WORLD);*/
  5092. #endif
  5093. }
  5094.  
  5095. void octree::ICRecv(int recvFrom, vector<real4> &bodyPositions, vector<real4> &bodyVelocities,  vector<int> &bodiesIDs)
  5096. {
  5097. #ifdef USE_MPI
  5098.   MPI_Status status;
  5099.   int nreceive;
  5100.   int procId = mpiGetRank();
  5101.  
  5102.   //First send the number of particles, then the actual sample data
  5103.   MPI_Recv(&nreceive, 1, MPI_INT, recvFrom, procId*2, MPI_COMM_WORLD,&status);
  5104.  
  5105.   bodyPositions.resize(nreceive);
  5106.   bodyVelocities.resize(nreceive);
  5107.   bodiesIDs.resize(nreceive);
  5108.  
  5109.   //Recv the positions, velocities and ids
  5110.   MPI_Recv( (real*)&bodyPositions[0],  nreceive*sizeof(real)*4, MPI_BYTE, recvFrom, procId*2+1, MPI_COMM_WORLD,&status);
  5111.   MPI_Recv( (real*)&bodyVelocities[0], nreceive*sizeof(real)*4, MPI_BYTE, recvFrom, procId*2+2, MPI_COMM_WORLD,&status);
  5112.   MPI_Recv( (int *)&bodiesIDs[0],      nreceive*sizeof(int),    MPI_BYTE, recvFrom, procId*2+3, MPI_COMM_WORLD,&status);
  5113. #endif
  5114. }
  5115.  
  5116. void octree::determine_sample_freq(int numberOfParticles)
  5117. {
  5118.   //Sum the number of particles on all processes
  5119. #ifdef USE_MPI
  5120.   //int tmp;
  5121.   //MPI_Allreduce(&numberOfParticles,&tmp,1, MPI_INT, MPI_SUM,MPI_COMM_WORLD);
  5122.   //nTotalFreq = tmp;
  5123.  
  5124.     unsigned long long tmp;
  5125.     unsigned long long tmp2 = numberOfParticles;
  5126.   MPI_Allreduce(&tmp2,&tmp,1, MPI_UNSIGNED_LONG_LONG, MPI_SUM,MPI_COMM_WORLD);
  5127.   nTotalFreq_ull = tmp;
  5128. #else
  5129.   nTotalFreq = numberOfParticles;
  5130. #endif
  5131.  
  5132.  
  5133. #ifdef PRINT_MPI_DEBUG
  5134.   if(procId == 0)
  5135.     LOG("Total number of particles: %llu\n", nTotalFreq_ull);
  5136. #endif
  5137.  
  5138.   int maxsample = (int)(NMAXSAMPLE*0.8); // 0.8 is safety factor
  5139.   sampleFreq = (nTotalFreq_ull+(unsigned long long)maxsample-1)/ (unsigned long long)maxsample;
  5140.  
  5141.   if(procId == 0)  LOGF(stderr,"Sample Frequency: %d \n", sampleFreq);
  5142.  
  5143.   prevSampFreq = sampleFreq;
  5144.  
  5145. }
  5146.  
  5147. #if 0
  5148. /*************************************************************************
  5149.  *                                                                        *
  5150.  *                          NON-Used  / Old functions                     *
  5151.  *                                                                        *
  5152. /*************************************************************************/
  5153.  
  5154.  
  5155.  
  5156.  
  5157.  
  5158. //Sort function based on Makinos function
  5159. //Sorts (a part) of the coordinate array
  5160. //containing the sample particles
  5161. //Either sorts the x,y or z direction
  5162. //lo is the lower bound of the to sorted part
  5163. //up is the upper bound of the to sorted part
  5164. //cid is the index/axes to sort
  5165. //cid=0=x, cid=1=y and cid=2=z
  5166. void octree::sortCoordinates(real4 *r, int lo, int up, int cid )
  5167. {
  5168.   int i, j;
  5169.   real4 tempr;
  5170.   while ( up>lo ) {
  5171.     i = lo;
  5172.     j = up;
  5173.     tempr = r[lo];
  5174.     /*** Split file in two ***/
  5175.     while ( i<j )
  5176.     {
  5177.       if(cid==0)
  5178.         for ( ; r[j].x > tempr.x; j-- );
  5179.       else if(cid==1)
  5180.         for ( ; r[j].y > tempr.y; j-- );
  5181.       else
  5182.         for ( ; r[j].z > tempr.z; j-- );
  5183.  
  5184.       if(cid==0)
  5185.         for ( r[i]=r[j]; i<j && r[i].x <= tempr.x; i++ );
  5186.       else if(cid==1)
  5187.         for ( r[i]=r[j]; i<j && r[i].y <= tempr.y; i++ );
  5188.       else
  5189.         for ( r[i]=r[j]; i<j && r[i].z <= tempr.z; i++ );
  5190.  
  5191.       r[j] = r[i];
  5192.     }
  5193.     r[i] = tempr;
  5194.     /*** Sort recursively, the smallest first ***/
  5195.     if ( i-lo < up-i )
  5196.     {
  5197.       sortCoordinates(r,lo,i-1,cid);
  5198.       lo = i+1;
  5199.     }
  5200.     else
  5201.     {
  5202.       sortCoordinates(r,i+1,up,cid);
  5203.       up = i-1;
  5204.     }
  5205.   }
  5206. }
  5207.  
  5208. bool sortByX (real4 i,real4 j) { return (i.x<j.x); }
  5209. bool sortByY (real4 i,real4 j) { return (i.y<j.y); }
  5210. bool sortByZ (real4 i,real4 j) { return (i.z<j.z); }
  5211.  
  5212.  
  5213. void octree::sortCoordinates2(real4 *r, int lo, int up, int cid )
  5214. {
  5215.   up += 1;
  5216.   if(cid == 0)
  5217.     std::sort(&r[lo], &r[up], sortByX);
  5218.   else if(cid == 1)
  5219.     std::sort(&r[lo], &r[up], sortByY);
  5220.   else
  5221.     std::sort(&r[lo], &r[up], sortByZ);
  5222.  
  5223. }
  5224.  
  5225.  
  5226. //Copied from Makino code
  5227. void octree::createORB()
  5228. {
  5229.   int n0, n1;
  5230.   n0 = (int)pow(nProcs+0.1,0.33333333333333333333);
  5231.   while(nProcs % n0)
  5232.     n0--;
  5233.  
  5234.   nx = n0;
  5235.   n1 = nProcs/nx;
  5236.   n0 = (int)sqrt(n1+0.1);
  5237.   while(n1 % n0)
  5238.     n0++;
  5239.  
  5240.   ny = n0; nz = n1/n0;
  5241.   int ntmp;
  5242.   if (nz > ny){
  5243.     ntmp = nz; nz = ny; ny = ntmp;
  5244.   }
  5245.   if (ny > nx){
  5246.     ntmp = nx; nx = ny; ny = ntmp;
  5247.   }
  5248.   if (nz > ny){
  5249.     ntmp = nz; nz = ny; ny = ntmp;
  5250.   }
  5251.   if (nx*ny*nz != nProcs){
  5252.     cerr << "create_division: Intenal Error " << nProcs << " " << nx
  5253.       << " " << ny << " " << nz <<endl;
  5254.   }
  5255.  
  5256. #ifdef PRINT_MPI_DEBUG
  5257.   if(procId == 0) LOG("Division: nx: %d ny: %d nz: %d \n", nx, ny, nz);
  5258. #endif
  5259. }
  5260.  
  5261.  
  5262.  
  5263.  
  5264.  
  5265.  
  5266. void octree::sendCurrentRadiusInfoCoarse(real4 *rmin, real4 *rmax, int n_coarseGroups)
  5267. {
  5268. #ifdef USE_MPI
  5269.   int *coarseGrpCountBytes = new int[nProcs];
  5270.   int *receiveOffsetsBytes = new int[nProcs];
  5271.   //Send the number of coarseGroups that belongs to this process, and gather
  5272.   //That information from the other processors
  5273.   MPI_Allgather(&n_coarseGroups,            sizeof(int),  MPI_BYTE,
  5274.       this->globalCoarseGrpCount, sizeof(uint), MPI_BYTE, MPI_COMM_WORLD);
  5275.  
  5276.  
  5277.   //Compute offsets using prefix sum and total number of groups we will receive
  5278.   this->globalCoarseGrpOffsets[0] = 0;
  5279.   coarseGrpCountBytes[0]          = this->globalCoarseGrpCount[0]*sizeof(real4);
  5280.   receiveOffsetsBytes[0]          = 0;
  5281.   for(int i=1; i < nProcs; i++)
  5282.   {
  5283.     this->globalCoarseGrpOffsets[i]  = this->globalCoarseGrpOffsets[i-1] + this->globalCoarseGrpCount[i-1];
  5284.  
  5285.     coarseGrpCountBytes[i] = this->globalCoarseGrpCount[i]  *sizeof(real4);
  5286.     receiveOffsetsBytes[i] = this->globalCoarseGrpOffsets[i]*sizeof(real4);
  5287.  
  5288.     LOGF(stderr,"Proc: %d Received on idx: %d\t%d prefix: %d \n",
  5289.         procId, i, globalCoarseGrpCount[i], globalCoarseGrpOffsets[i]);
  5290.   }
  5291.  
  5292.   int totalNumberOfGroups = this->globalCoarseGrpOffsets[nProcs-1]+this->globalCoarseGrpCount[nProcs-1];
  5293.  
  5294.   //Allocate memory
  5295.   if(coarseGroupBoundMin) delete[]  coarseGroupBoundMin;
  5296.   if(coarseGroupBoundMax) delete[]  coarseGroupBoundMax;
  5297.  
  5298.   if(coarseGroupBoxCenter) delete[] coarseGroupBoxCenter;
  5299.   if(coarseGroupBoxSize)   delete[] coarseGroupBoxSize;
  5300.  
  5301.   coarseGroupBoundMax = new real4[totalNumberOfGroups];
  5302.   coarseGroupBoundMin = new real4[totalNumberOfGroups];
  5303.  
  5304.   coarseGroupBoxCenter = new double4[totalNumberOfGroups];
  5305.   coarseGroupBoxSize   = new double4[totalNumberOfGroups];
  5306.  
  5307.   //Exchange the coarse group boundaries
  5308.   MPI_Allgatherv(rmin, n_coarseGroups*sizeof(real4), MPI_BYTE,
  5309.       coarseGroupBoundMin, coarseGrpCountBytes,
  5310.       receiveOffsetsBytes, MPI_BYTE, MPI_COMM_WORLD);
  5311.   MPI_Allgatherv(rmax, n_coarseGroups*sizeof(real4), MPI_BYTE,
  5312.       coarseGroupBoundMax, coarseGrpCountBytes,
  5313.       receiveOffsetsBytes, MPI_BYTE, MPI_COMM_WORLD);
  5314.  
  5315.   //Compute center and size
  5316.   for(int i= 0; i < totalNumberOfGroups; i++)
  5317.   {
  5318.  
  5319.     double4 boxCenter = {     0.5*(coarseGroupBoundMin[i].x  + coarseGroupBoundMax[i].x),
  5320.       0.5*(coarseGroupBoundMin[i].y  + coarseGroupBoundMax[i].y),
  5321.       0.5*(coarseGroupBoundMin[i].z  + coarseGroupBoundMax[i].z), 0};
  5322.     double4 boxSize   = {fabs(0.5*(coarseGroupBoundMax[i].x - coarseGroupBoundMin[i].x)),
  5323.       fabs(0.5*(coarseGroupBoundMax[i].y - coarseGroupBoundMin[i].y)),
  5324.       fabs(0.5*(coarseGroupBoundMax[i].z - coarseGroupBoundMin[i].z)), 0};
  5325.  
  5326.     coarseGroupBoxCenter[i] = boxCenter;
  5327.     coarseGroupBoxSize[i]   = boxSize;
  5328.   }
  5329.  
  5330.   delete[] coarseGrpCountBytes;
  5331.   delete[] receiveOffsetsBytes;
  5332. #else
  5333.   //TODO check if we need something here
  5334.   //  curSysState[0] = curProcState;
  5335. #endif
  5336. }
  5337.  
  5338.  
  5339.  
  5340. //Uses one communication by storing data in one buffer
  5341. //nsample can be set to zero if this call is only used
  5342. //to get updated domain information
  5343. void octree::sendSampleAndRadiusInfo(int nsample, real4 &rmin, real4 &rmax)
  5344. {
  5345.   sampleRadInfo curProcState;
  5346.  
  5347.   curProcState.nsample      = nsample;
  5348.   curProcState.rmin         = make_double4(rmin.x, rmin.y, rmin.z, rmin.w);
  5349.   curProcState.rmax         = make_double4(rmax.x, rmax.y, rmax.z, rmax.w);
  5350.  
  5351.   globalRmax            = 0;
  5352.   totalNumberOfSamples  = 0;
  5353.  
  5354. #ifdef USE_MPI
  5355.   //Get the number of sample particles and the domain size information
  5356.   MPI_Allgather(&curProcState, sizeof(sampleRadInfo), MPI_BYTE,  curSysState,
  5357.       sizeof(sampleRadInfo), MPI_BYTE, MPI_COMM_WORLD);
  5358. #else
  5359.   curSysState[0] = curProcState;
  5360. #endif
  5361.  
  5362.   rmin.x                 =  (real)curSysState[0].rmin.x;
  5363.   rmin.y                 =  (real)curSysState[0].rmin.y;
  5364.   rmin.z                 =  (real)curSysState[0].rmin.z;
  5365.  
  5366.   rmax.x                 =  (real)curSysState[0].rmax.x;
  5367.   rmax.y                 =  (real)curSysState[0].rmax.y;
  5368.   rmax.z                 =  (real)curSysState[0].rmax.z;
  5369.  
  5370.   totalNumberOfSamples   = curSysState[0].nsample;
  5371.  
  5372.  
  5373.   for(int i=1; i < nProcs; i++)
  5374.   {
  5375.     rmin.x = std::min(rmin.x, (real)curSysState[i].rmin.x);
  5376.     rmin.y = std::min(rmin.y, (real)curSysState[i].rmin.y);
  5377.     rmin.z = std::min(rmin.z, (real)curSysState[i].rmin.z);
  5378.  
  5379.     rmax.x = std::max(rmax.x, (real)curSysState[i].rmax.x);
  5380.     rmax.y = std::max(rmax.y, (real)curSysState[i].rmax.y);
  5381.     rmax.z = std::max(rmax.z, (real)curSysState[i].rmax.z);
  5382.  
  5383.  
  5384.     totalNumberOfSamples   += curSysState[i].nsample;
  5385.   }
  5386.  
  5387.   if(procId == 0)
  5388.   {
  5389.     if(fabs(rmin.x)>globalRmax)  globalRmax=fabs(rmin.x);
  5390.     if(fabs(rmin.y)>globalRmax)  globalRmax=fabs(rmin.y);
  5391.     if(fabs(rmin.z)>globalRmax)  globalRmax=fabs(rmin.z);
  5392.     if(fabs(rmax.x)>globalRmax)  globalRmax=fabs(rmax.x);
  5393.     if(fabs(rmax.y)>globalRmax)  globalRmax=fabs(rmax.y);
  5394.     if(fabs(rmax.z)>globalRmax)  globalRmax=fabs(rmax.z);
  5395.  
  5396.     if(totalNumberOfSamples > sampleArray.size())
  5397.     {
  5398.       sampleArray.resize(totalNumberOfSamples);
  5399.     }
  5400.   }
  5401. }
  5402.  
  5403. void octree::gpu_collect_sample_particles(int nSample, real4 *sampleParticles)
  5404. {
  5405.   int *nReceiveCnts  = new int[nProcs];
  5406.   int *nReceiveDpls  = new int[nProcs];
  5407.   nReceiveCnts[0] = nSample*sizeof(real4);
  5408.   nReceiveDpls[0] = 0;
  5409.  
  5410.   if(procId == 0)
  5411.   {
  5412.     for(int i=1; i < nProcs; i++)
  5413.     {
  5414.       nReceiveCnts[i] = curSysState[i].nsample*sizeof(real4);
  5415.       nReceiveDpls[i] = nReceiveDpls[i-1] + nReceiveCnts[i-1];
  5416.     }
  5417.   }
  5418.  
  5419.   //Collect sample particles
  5420. #ifdef USE_MPI
  5421.   MPI_Gatherv(&sampleParticles[0], nSample*sizeof(real4), MPI_BYTE,
  5422.       &sampleArray[0], nReceiveCnts, nReceiveDpls, MPI_BYTE,
  5423.       0, MPI_COMM_WORLD);
  5424. #else
  5425.   std::copy(sampleParticles, sampleParticles + nSample, sampleArray.begin());
  5426. #endif
  5427.  
  5428.   delete[] nReceiveCnts;
  5429.   delete[] nReceiveDpls;
  5430. }
  5431.  
  5432.  
  5433. void octree::collect_sample_particles(real4 *bodies,
  5434.     int nbody,
  5435.     int sample_freq,
  5436.     vector<real4> &sampleArray,
  5437.     int &nsample,
  5438.     double &rmax)
  5439. {
  5440.   //Select the sample particles
  5441.   int ii, i;
  5442.   for(i = ii= 0;ii<nbody; i++,ii+=sample_freq)
  5443.   {
  5444.     sampleArray.push_back(bodies[ii]);
  5445.   }
  5446.   nsample = i;
  5447.  
  5448.   //Now gather the particles at process 0
  5449.   //NOTE: Im using my own implementation instead of makino's which
  5450.   //can grow out of the memory array (I think...)
  5451.  
  5452.   //Instead of using mpi-reduce but broadcast or something we can receive the
  5453.   //individual values,so we dont haveto send them in the part below, saves
  5454.   //communication time!!!  This function is only used once so no problem
  5455.   int *nSampleValues = new int[nProcs];
  5456.   int *nReceiveCnts  = new int[nProcs];
  5457.   int *nReceiveDpls  = new int[nProcs];
  5458.  
  5459. #ifdef USE_MPI
  5460.   MPI_Gather(&nsample, 1, MPI_INT, nSampleValues, 1, MPI_INT, 0, MPI_COMM_WORLD);
  5461. #else
  5462.   nSampleValues[0] = nsample;
  5463. #endif
  5464.  
  5465.   //Increase the size of the result buffer if needed
  5466.   if(procId == 0)
  5467.   {
  5468.     //Sum the total amount of sample particles
  5469.     unsigned int totalNumberOfSamples = 0;
  5470.  
  5471.     for(int i=0; i < nProcs; i++)
  5472.     {
  5473.       totalNumberOfSamples += nSampleValues[i];
  5474.     }
  5475.  
  5476.     if(totalNumberOfSamples > sampleArray.size())
  5477.     {
  5478.       sampleArray.resize(totalNumberOfSamples);
  5479.     }
  5480.   }
  5481.  
  5482.   //Compute buffer and displacements for MPI_Gatherv
  5483.   nReceiveCnts[0] = nsample*sizeof(real4);
  5484.   nReceiveDpls[0] = 0;
  5485.  
  5486.   if(procId == 0)
  5487.   {
  5488.     for(int i=1; i < nProcs; i++)
  5489.     {
  5490.       nReceiveCnts[i] = nSampleValues[i]*sizeof(real4);
  5491.       nReceiveDpls[i] = nReceiveDpls[i-1] + nReceiveCnts[i-1];
  5492.     }
  5493.   }
  5494.  
  5495.   //Collect sample particles, note the MPI_IN_PLACE to prevent MPI errors
  5496. #ifdef USE_MPI
  5497.   MPI_Gatherv((procId ? &sampleArray[0] : MPI_IN_PLACE), nsample*sizeof(real4), MPI_BYTE,
  5498.       &sampleArray[0], nReceiveCnts, nReceiveDpls, MPI_BYTE,
  5499.       0, MPI_COMM_WORLD);
  5500. #endif
  5501.  
  5502.   nsample = (nReceiveCnts[mpiGetNProcs()-1] +  nReceiveDpls[mpiGetNProcs()-1]) / sizeof(real4);
  5503.  
  5504.   //Find the maximum particle position
  5505.   double tmp = 0;
  5506.   for(i = 0;i<nbody; i++)
  5507.   {
  5508.     real4 r = bodies[i];
  5509.     //check x,y and z
  5510.     if(fabs(r.x)>tmp)  tmp=fabs(r.x);
  5511.     if(fabs(r.y)>tmp)  tmp=fabs(r.y);
  5512.     if(fabs(r.z)>tmp)  tmp=fabs(r.z);
  5513.   }
  5514.  
  5515.   //Find the global maximum
  5516. #ifdef USE_MPI
  5517.   MPI_Allreduce(&tmp, &rmax,1, MPI_DOUBLE, MPI_MAX,MPI_COMM_WORLD);
  5518. #else
  5519.   rmax = tmp;
  5520. #endif
  5521.  
  5522.   delete[] nSampleValues;
  5523.   delete[] nReceiveCnts;
  5524.   delete[] nReceiveDpls;
  5525. }
  5526.  
  5527. void octree::createDistribution(real4 *bodies, int n_bodies)
  5528. {
  5529.   determine_sample_freq(n_bodies);
  5530.  
  5531.   vector<real4> sampleArray;
  5532.   sampleArray.reserve(NMAXSAMPLE);
  5533.  
  5534.   int     nsample;  //Number of samples for this process
  5535.   double  rmax;     //maximum coordinate used to create a box
  5536.  
  5537.   //Get the sample particles from the other processes
  5538.   collect_sample_particles(bodies, n_bodies, sampleFreq, sampleArray, nsample, rmax);
  5539.  
  5540.   //Now that we have a sample from all proces we setup the space division
  5541.   //Processor 0 determines the division
  5542.   if(procId == 0)
  5543.     determine_division(nsample, sampleArray,nx, ny, nz, rmax,domainRLow, domainRHigh);
  5544.  
  5545. #ifdef USE_MPI
  5546.   //Now broadcast the results to all other processes
  5547.   MPI_Bcast(domainRLow,  sizeof(double4)*nProcs,MPI_BYTE,0,MPI_COMM_WORLD);
  5548.   MPI_Bcast(domainRHigh, sizeof(double4)*nProcs,MPI_BYTE,0,MPI_COMM_WORLD);
  5549. #endif
  5550.  
  5551.   return;
  5552. }
  5553.  
  5554.  
  5555. /*
  5556.    Only update the box-sizes, box-boundaries
  5557.    of the different processes, do not do
  5558.    anything related to sample particles
  5559.    */
  5560. void octree::gpu_updateDomainOnly()
  5561. {
  5562.   real4 r_min, r_max;
  5563.   //Get the current system/particle boundaries
  5564.   this->getBoundaries(localTree, r_min, r_max);
  5565.  
  5566.   int nSamples = 0;
  5567.   this->sendSampleAndRadiusInfo(nSamples, r_min, r_max);
  5568.   rMinGlobal = r_min;
  5569.   rMaxGlobal = r_max;
  5570. }
  5571.  
  5572.  
  5573.  
  5574. //Calculates the dimension of the box
  5575. //np number of sample particles
  5576. //pos the sample particle positions
  5577. //cid the coordinate index, 0=x, 1=y, 2=z
  5578. //istart/iend the start and end position of the sorted array
  5579. //rmax the maximum coordinate
  5580. //xlow/xhigh the box coordinates
  5581. void octree::calculate_boxdim(int np, real4 pos[], int cid, int istart, int iend,
  5582.     double rmax, double & xlow, double & xhigh)
  5583. {
  5584.   if(istart == 0)
  5585.   {
  5586.     xlow = -rmax;
  5587.   }
  5588.   else
  5589.   {
  5590.     if(cid==0)
  5591.       xlow = (pos[istart].x + pos[istart-1].x)/2;
  5592.     else if(cid==1)
  5593.       xlow = (pos[istart].y + pos[istart-1].y)/2;
  5594.     else
  5595.       xlow = (pos[istart].z + pos[istart-1].z)/2;
  5596.   }
  5597.  
  5598.   if(iend == np-1)
  5599.   {
  5600.     xhigh = rmax;
  5601.   }
  5602.   else
  5603.   {
  5604.     if(cid==0)
  5605.       xhigh = (pos[iend].x + pos[iend+1].x)/2;
  5606.     else if(cid==1)
  5607.       xhigh = (pos[iend].y + pos[iend+1].y)/2;
  5608.     else
  5609.       xhigh = (pos[iend].z + pos[iend+1].z)/2;
  5610.   }
  5611. }
  5612.  
  5613. inline double computeNewCoordinate(double old, double newc, int prevChange)
  5614. {
  5615.  
  5616.   //return newc;
  5617.  
  5618.   int curChange = (fabs(old) > fabs(newc));
  5619.  
  5620.   double factor1 = 1, factor2 = 2, factor3 = 1;
  5621.  
  5622.   if(prevChange != curChange)
  5623.   {
  5624.     //Different direction take half a step
  5625.     factor1 = 1; factor2 = 2;
  5626.   }
  5627.   else
  5628.   {
  5629.     //Same direction, take some bigger step (3/4th)
  5630.     factor1 = 3; factor2 = 4;
  5631.  
  5632.     //Same direction, take full step
  5633.     //    factor3 = 0; factor1 = 1; factor2 = 1;
  5634.   }
  5635.  
  5636.   double temp = (factor3*old + factor1*newc) / factor2;
  5637.  
  5638.   return temp;
  5639.  
  5640.   //Default
  5641.   //return newc;
  5642.   //avg
  5643.   //  return (old+newc)/2;
  5644.   //3/4:
  5645.   //  return (old + 3*newc) / 4;
  5646.  
  5647. }
  5648.  
  5649. void octree::determine_division(int np,         // number of particles
  5650.     vector<real4> &pos,     // positions of particles
  5651.     int nx,
  5652.     int ny,
  5653.     int nz,
  5654.     double rmax,
  5655.     double4 xlow[],         // left-bottom coordinate of divisions
  5656.     double4 xhigh[])        // size of divisions
  5657. {
  5658.   int numberOfProcs = nProcs;
  5659.   int *istart  = new int[numberOfProcs+1];
  5660.   int *iend    = new int[numberOfProcs+1];
  5661.   int n = nx*ny*nz;
  5662.  
  5663.   //     fprintf(stderr, "TIME4 TEST:  %d  %d \n", np-1, pos.size());
  5664.   //
  5665.   //     double t1 = get_time();
  5666.   sortCoordinates(&pos[0], 0, np-1, 0);
  5667.   //     sortCoordinates2(&pos[0], 0, np-1, 0);
  5668.  
  5669.   //     double t2 = get_time();
  5670.   //     fprintf(stderr, "TIME4 TEST: %g  %d \n", t2-t1, np-1);
  5671.  
  5672.   //Split the array in more or less equal parts
  5673.   for(int i = 0;i<n;i++)
  5674.   {
  5675.     istart[i] = (i*np)/n;
  5676.     //NOTE: It was i>= 0, changed this otherwise it writes before begin array...
  5677.     if(i > 0 )
  5678.       iend[i-1]=istart[i]-1;
  5679.   }
  5680.   iend[n-1] = np-1;
  5681.  
  5682.   //     borderCnt++;
  5683.  
  5684.   //Split the x-axis
  5685.   for(int ix = 0;ix<nx;ix++)
  5686.   {
  5687.     double x0, x1;
  5688.     int ix0 = ix*ny*nz;
  5689.     int ix1 = (ix+1)*ny*nz;
  5690.     calculate_boxdim(np, &pos[0], 0,istart[ix0],iend[ix1-1],rmax,x0,x1);
  5691.     for(int i=ix0; i<ix1; i++)
  5692.     {
  5693.       //Check the domain borders and set a constant
  5694.       if(istart[ix0] == 0)
  5695.       {
  5696.         xlowPrev[i].x = 10e10;
  5697.       }
  5698.       if(iend[ix1-1] == np-1)
  5699.       {
  5700.         xhighPrev[i].x = 10e10;
  5701.       }
  5702.  
  5703.       xlow[i].x   = x0;
  5704.       xhigh[i].x  = x1;
  5705.     }
  5706.   }
  5707.  
  5708.   //For each x split the various y parts
  5709.   for(int ix = 0;ix<nx;ix++)
  5710.   {
  5711.     int ix0 = ix*ny*nz;
  5712.     int ix1 = (ix+1)*ny*nz;
  5713.     int npy = iend[ix1-1] - istart[ix0] + 1;
  5714.     sortCoordinates(&pos[0], istart[ix0],iend[ix1-1], 1);
  5715.     for(int iy = 0;iy<ny;iy++){
  5716.       double y0, y1;
  5717.       int iy0 = ix0+iy*nz;
  5718.       int iy1 = ix0+(iy+1)*nz;
  5719.       calculate_boxdim(npy, &pos[istart[ix0]], 1,istart[iy0]-istart[ix0],
  5720.           iend[iy1-1]-istart[ix0], rmax, y0,y1);
  5721.       for(int i=iy0; i<iy1; i++)
  5722.       {
  5723.         //Check domain borders and set a constant
  5724.         if(istart[iy0]-istart[ix0] == 0)
  5725.         {
  5726.           xlowPrev[i].y = 10e10;
  5727.         }
  5728.         if( iend[iy1-1]-istart[ix0] == npy-1)
  5729.         {
  5730.           xhighPrev[i].y = 10e10;
  5731.         }
  5732.  
  5733.         xlow[i].y  = y0;
  5734.         xhigh[i].y = y1;
  5735.       }
  5736.     }
  5737.   }
  5738.  
  5739.   //For each x and for each y split the z axis
  5740.   for(int ix = 0;ix<nx;ix++){
  5741.     int ix0 = ix*ny*nz;
  5742.     for(int iy = 0;iy<ny;iy++){
  5743.       int iy0 = ix0+iy*nz;
  5744.       int iy1 = ix0+(iy+1)*nz;
  5745.       int npz = iend[iy1-1] - istart[iy0] + 1;
  5746.       sortCoordinates(&pos[0], istart[iy0],iend[iy1-1], 2);
  5747.       for(int iz = 0;iz<nz;iz++){
  5748.         double z0, z1;
  5749.         int iz0 = iy0+iz;
  5750.         calculate_boxdim(npz, &pos[istart[iy0]], 2,istart[iz0]-istart[iy0],
  5751.             iend[iz0]-istart[iy0], rmax, z0,z1);
  5752.  
  5753.         //Check the domain borders
  5754.         if(istart[iz0]-istart[iy0] == 0)
  5755.         {
  5756.           xlowPrev[iz0].z = 10e10;
  5757.         }
  5758.         if(iend[iz0]-istart[iy0] == npz-1)
  5759.         {
  5760.           xhighPrev[iz0].z = 10e10;
  5761.         }
  5762.  
  5763.         xlow[iz0].z   = z0;
  5764.         xhigh[iz0].z  = z1;
  5765.       }
  5766.     }
  5767.   }
  5768.  
  5769.  
  5770.   //Do the magic to get a better load balance by changing the decompositon
  5771.   //slightly
  5772.   static bool isFirstStep  = true;
  5773.  
  5774.   if(!isFirstStep)
  5775.   {
  5776.     double temp;
  5777.     for(int i=0; i < nProcs; i++)
  5778.     {
  5779.       //       fprintf(stderr,"DOMAIN LOW  %d || CUR: %f %f %f \tPREV: %f %f %f\n", i,
  5780.       //               xlow[i].x, xlow[i].y, xlow[i].z,
  5781.       //               xlowPrev[i].x, xlowPrev[i].y, xlowPrev[i].z);
  5782.       //       fprintf(stderr,"DOMAIN HIGH %d || CUR: %f %f %f \tPREV: %f %f %f\n", i,
  5783.       //               xhigh[i].x, xhigh[i].y, xhigh[i].z,
  5784.       //               xhighPrev[i].x, xhighPrev[i].y, xhighPrev[i].z);
  5785.       //
  5786.       //Do magic !
  5787.       if(xlowPrev[i].x != 10e10)
  5788.       {
  5789.         temp               = computeNewCoordinate(xlowPrev[i].x, xlow[i].x, domHistoryLow[i].x);
  5790.         domHistoryLow[i].x = (abs(xlowPrev[i].x) > fabs(xlow[i].x));
  5791.         xlow[i].x          = temp;
  5792.       }
  5793.       if(xhighPrev[i].x != 10e10)
  5794.       {
  5795.         temp                 = computeNewCoordinate(xhighPrev[i].x, xhigh[i].x, domHistoryHigh[i].x);
  5796.         domHistoryHigh[i].x  = (abs(xhighPrev[i].x) > fabs(xhigh[i].x));
  5797.         xhigh[i].x           = temp;
  5798.       }
  5799.  
  5800.       if(xlowPrev[i].y != 10e10)
  5801.       {
  5802.         temp               = computeNewCoordinate(xlowPrev[i].y, xlow[i].y, domHistoryLow[i].y);
  5803.         domHistoryLow[i].y = (abs(xlowPrev[i].y) > fabs(xlow[i].y));
  5804.         xlow[i].y          = temp;
  5805.       }
  5806.       if(xhighPrev[i].y != 10e10)
  5807.       {
  5808.         temp                 = computeNewCoordinate(xhighPrev[i].y, xhigh[i].y, domHistoryHigh[i].y);
  5809.         domHistoryHigh[i].y  = (abs(xhighPrev[i].y) > fabs(xhigh[i].y));
  5810.         xhigh[i].y           = temp;
  5811.       }
  5812.  
  5813.       if(xlowPrev[i].z != 10e10)
  5814.       {
  5815.         temp               = computeNewCoordinate(xlowPrev[i].z, xlow[i].z, domHistoryLow[i].z);
  5816.         domHistoryLow[i].z = (abs(xlowPrev[i].z) > fabs(xlow[i].z));
  5817.         xlow[i].z          = temp;
  5818.       }
  5819.       if(xhighPrev[i].z != 10e10)
  5820.       {
  5821.         temp                 = computeNewCoordinate(xhighPrev[i].z, xhigh[i].z, domHistoryHigh[i].z);
  5822.         domHistoryHigh[i].z  = (abs(xhighPrev[i].z) > fabs(xhigh[i].z));
  5823.         xhigh[i].z           = temp;
  5824.       }
  5825.  
  5826.     }
  5827.   }
  5828.  
  5829.  
  5830.   //Copy the current decomposition to the previous for next step
  5831.   for(int i=0; i < nProcs; i++)
  5832.   {
  5833.     xlowPrev[i]   = xlow[i];
  5834.     xhighPrev[i]  = xhigh[i];
  5835.   }
  5836.  
  5837.   isFirstStep = false;
  5838.  
  5839.   //Free up memory
  5840.   delete[] istart;
  5841.   delete[] iend;
  5842.  
  5843.   return;
  5844. }
  5845.  
  5846.  
  5847.  
  5848. /*
  5849.    Get the domain boundaries
  5850.    Get the sample particles
  5851.    Send them to process 0
  5852.    Process 0 computes the new domain decomposition and broadcasts this
  5853.    */
  5854. void octree::gpu_updateDomainDistribution(double timeLocal)
  5855. {
  5856.   my_dev::dev_stream aSyncStream;
  5857.  
  5858.   real4 r_min, r_max;
  5859.   //    double t1 = get_time();
  5860.   //Get the current system/particle boundaries
  5861.   this->getBoundaries(localTree, r_min, r_max);
  5862.  
  5863.   int finalNRate;
  5864.  
  5865.   //Average the previous and current execution time to make everything smoother
  5866.   //results in much better load-balance
  5867.   prevDurStep = (prevDurStep <= 0) ? timeLocal : prevDurStep;
  5868.   timeLocal   = (timeLocal + prevDurStep) / 2;
  5869.  
  5870.   double nrate = 0;
  5871. #if 1
  5872.   //Only base load balancing on the computation time
  5873.   double timeSum   = 0.0;
  5874.  
  5875.   //Sum the execution times
  5876. #ifdef USE_MPI
  5877.   MPI_Allreduce( &timeLocal, &timeSum, 1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
  5878. #else
  5879.   timeSum = timeLocal;
  5880. #endif
  5881.  
  5882.   nrate = timeLocal / timeSum;
  5883.  
  5884.   if(1)       //Don't fluctuate particles too much
  5885.   {
  5886. #define SAMPLING_LOWER_LIMIT_FACTOR  (1.9)
  5887.  
  5888.     double nrate2 = (double)localTree.n / (double) nTotalFreq;
  5889.     nrate2       /= SAMPLING_LOWER_LIMIT_FACTOR;
  5890.  
  5891.     if(nrate < nrate2)
  5892.     {
  5893.       nrate = nrate2;
  5894.     }
  5895.  
  5896.     double nrate2_sum = 0.0;
  5897. #ifdef USE_MPI
  5898.     MPI_Allreduce( &nrate, &nrate2_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
  5899. #else
  5900.     nrate2_sum = nrate;
  5901. #endif
  5902.  
  5903.     nrate /= nrate2_sum;
  5904.   }
  5905. #else
  5906.   //Equal number of particles
  5907.   nrate = (double)localTree.n / (double)nTotalFreq;
  5908. #endif
  5909.  
  5910.   int    nsamp    = (int)(nTotalFreq *0.001f/4.0) + 1;  //Total number of sample particles, global
  5911.   int nsamp_local = (int)(nsamp*nrate) + 1;
  5912.   int nSamples    = nsamp_local;
  5913.  
  5914.   finalNRate      = localTree.n / nsamp_local;
  5915.  
  5916.   LOGF(stderr, "NSAMP [%d]: sample: %d nrate: %f finalrate: %d localTree.n: %d  \
  5917.      previous: %d timeLocal: %f prevTimeLocal: %f \n",
  5918.       procId, nsamp_local, nrate, finalNRate, localTree.n, prevSampFreq,
  5919.       timeLocal, prevDurStep);
  5920.  
  5921.   prevDurStep  = timeLocal;
  5922.   prevSampFreq = finalNRate;
  5923.  
  5924.  
  5925.   my_dev::dev_mem<real4>  samplePositions(devContext);
  5926.  
  5927.   samplePositions.cmalloc_copy(localTree.generalBuffer1, nSamples, 0);
  5928.  
  5929.  
  5930.   //   double t2 = get_time();
  5931.   //   fprintf(stderr, "TIME1 (boundaries) %g \n", t2 - t1);
  5932.  
  5933.   //Get the sample particles from the device and only copy
  5934.   //the number of particles that is used
  5935.   //Action overlaps with the communication of domain boundary
  5936.   extractSampleParticles.set_arg<int>(0,     &localTree.n);
  5937.   extractSampleParticles.set_arg<int>(1,     &finalNRate);
  5938.   extractSampleParticles.set_arg<cl_mem>(2,  localTree.bodies_Ppos.p());
  5939.   extractSampleParticles.set_arg<cl_mem>(3,  samplePositions.p());
  5940.   extractSampleParticles.setWork(nSamples, 256);
  5941.   extractSampleParticles.execute(aSyncStream.s());
  5942.  
  5943.  
  5944.   //JB since Fermi had problems with pinned memory
  5945.   //we cant do this async
  5946.   if (this->getDevContext()->getComputeCapability() < 350)
  5947.   {
  5948.     aSyncStream.sync();
  5949.     samplePositions.d2h(nSamples);
  5950.   }
  5951.   else
  5952.   {
  5953.     samplePositions.d2h(nSamples, false, aSyncStream.s());
  5954.   }
  5955.  
  5956.  
  5957.   //Get number of sample particles per process and domain size information
  5958.   this->sendSampleAndRadiusInfo(nSamples, r_min, r_max);
  5959.   rMinGlobal = r_min;
  5960.   rMaxGlobal = r_max;
  5961.  
  5962.   //    double t3 = get_time();
  5963.   //   fprintf(stderr, "TIME2 (get and send sample info) %g \t %g \n", t3 - t2, t3-t1);
  5964.   aSyncStream.sync();
  5965.   gpu_collect_sample_particles(nSamples, &samplePositions[0]);
  5966.  
  5967.   //double t4 = get_time();
  5968.   //fprintf(stderr, "TIME3 (get and send sample particles) %g \t %g \n", t4 - t3, t4-t1);
  5969.  
  5970.   //Processor 0 determines the division
  5971.   if(procId == 0)
  5972.     determine_division(totalNumberOfSamples, sampleArray,nx, ny, nz, globalRmax, domainRLow, domainRHigh);
  5973.  
  5974.   //   double t5 = get_time();
  5975.   //   fprintf(stderr, "TIME4 (determ div ) %g \t %g \n", t5 - t4, t5-t1);
  5976.  
  5977.   //Now broadcast the results to all other processes
  5978. #ifdef USE_MPI
  5979.   MPI_Bcast(domainRLow,  sizeof(double4)*nProcs,MPI_BYTE,0,MPI_COMM_WORLD);
  5980.   MPI_Bcast(domainRHigh, sizeof(double4)*nProcs,MPI_BYTE,0,MPI_COMM_WORLD);
  5981. #endif
  5982.  
  5983.   //   double t5 = get_time();
  5984.   //   fprintf(stderr, "TIME4 (determ div and bcast) %g \t %g \n", t5 - t4, t5-t1);
  5985.   //   fprintf(stderr, "TIME4 (Total sample part)  %g \n", t5-t1);
  5986.  
  5987.   //   if(this->nProcs > 1)
  5988.   //   {
  5989.   //     if(this->procId == 0)
  5990.   //       for(int i = 0;i< this->nProcs;i++)
  5991.   //       {
  5992.   //         cerr << "Domain: " << i << " " << this->domainRLow[i].x << " " << this->domainRLow[i].y << " " << this->domainRLow[i].z << " "
  5993.   //                                        << this->domainRHigh[i].x << " " << this->domainRHigh[i].y << " " << this->domainRHigh[i].z <<endl;
  5994.   //       }
  5995.   //   }
  5996.  
  5997.  
  5998.   return;
  5999. }
  6000.  
  6001.  
  6002.  
  6003. //Checks if the position falls within the specified box
  6004. inline int isinbox(real4 pos, double4 xlow, double4 xhigh)
  6005. {
  6006.   if((pos.x < xlow.x)||(pos.x > xhigh.x))
  6007.     return 0;
  6008.   if((pos.y < xlow.y)||(pos.y > xhigh.y))
  6009.     return 0;
  6010.   if((pos.z < xlow.z)||(pos.z > xhigh.z))
  6011.     return 0;
  6012.  
  6013.   return 1;
  6014. }
  6015.  
  6016.  
  6017.  
  6018.  
  6019. //Send particles to the appropriate processors
  6020. int octree::exchange_particles_with_overflow_check(tree_structure &tree)
  6021. {
  6022.   int myid      = procId;
  6023.   int nproc     = nProcs;
  6024.   int iloc      = 0;
  6025.   int totalsent = 0;
  6026.   int nbody     = tree.n;
  6027.  
  6028.  
  6029.   real4  *bodiesPositions = &tree.bodies_pos[0];
  6030.   real4  *velocities      = &tree.bodies_vel[0];
  6031.   real4  *bodiesAcc0      = &tree.bodies_acc0[0];
  6032.   real4  *bodiesAcc1      = &tree.bodies_acc1[0];
  6033.   float2 *bodiesTime      = &tree.bodies_time[0];
  6034.   int    *bodiesIds       = &tree.bodies_ids[0];
  6035.   real4  *predictedBodiesPositions = &tree.bodies_Ppos[0];
  6036.   real4  *predictedVelocities      = &tree.bodies_Pvel[0];
  6037.  
  6038.   real4  tmpp;
  6039.   float2 tmpp2;
  6040.   int    tmpp3;
  6041.   int *firstloc   = new int[nProcs+1];
  6042.   int *nparticles = new int[nProcs+1];
  6043.  
  6044.   // Loop over particles and determine which particle needs to go where
  6045.   // reorder the bodies in such a way that bodies that have to be send
  6046.   // away are stored after each other in the array
  6047.   double t1 = get_time();
  6048.  
  6049.   //Array reserve some memory at forehand , 1%
  6050.   vector<bodyStruct> array2Send;
  6051.   //vector<bodyStruct> array2Send(((int)(tree.n * 0.01)));
  6052.  
  6053.   for(int ib=0;ib<nproc;ib++)
  6054.   {
  6055.     int ibox       = (ib+myid)%nproc;
  6056.     firstloc[ibox] = iloc;      //Index of the first particle send to proc: ibox
  6057.  
  6058.     for(int i=iloc; i<nbody;i++)
  6059.     {
  6060.       //      if(myid == 0){PRC(i); PRC(pb[i].get_pos());}
  6061.       if(isinbox(predictedBodiesPositions[i], domainRLow[ibox], domainRHigh[ibox]))
  6062.       {
  6063.         //Position
  6064.         tmpp                  = bodiesPositions[iloc];
  6065.         bodiesPositions[iloc] = bodiesPositions[i];
  6066.         bodiesPositions[i]    = tmpp;
  6067.         //Velocity
  6068.         tmpp             = velocities[iloc];
  6069.         velocities[iloc] = velocities[i];
  6070.         velocities[i]    = tmpp;
  6071.         //Acc0
  6072.         tmpp             = bodiesAcc0[iloc];
  6073.         bodiesAcc0[iloc] = bodiesAcc0[i];
  6074.         bodiesAcc0[i]    = tmpp;
  6075.         //Acc1
  6076.         tmpp             = bodiesAcc1[iloc];
  6077.         bodiesAcc1[iloc] = bodiesAcc1[i];
  6078.         bodiesAcc1[i]    = tmpp;
  6079.         //Predicted position
  6080.         tmpp                           = predictedBodiesPositions[iloc];
  6081.         predictedBodiesPositions[iloc] = predictedBodiesPositions[i];
  6082.         predictedBodiesPositions[i]    = tmpp;
  6083.         //Predicted velocity
  6084.         tmpp                  = predictedVelocities[iloc];
  6085.         predictedVelocities[iloc] = predictedVelocities[i];
  6086.         predictedVelocities[i]    = tmpp;
  6087.         //Time-step
  6088.         tmpp2            = bodiesTime[iloc];
  6089.         bodiesTime[iloc] = bodiesTime[i];
  6090.         bodiesTime[i]    = tmpp2;
  6091.         //IDs
  6092.         tmpp3            = bodiesIds[iloc];
  6093.         bodiesIds[iloc]  = bodiesIds[i];
  6094.         bodiesIds[i]     = tmpp3;
  6095.  
  6096.         //Put the particle in the array of to send particles
  6097.         if(ibox != myid)
  6098.         {
  6099.           bodyStruct body;
  6100.           body.pos  = bodiesPositions[iloc];
  6101.           body.vel  = velocities[iloc];
  6102.           body.acc0 = bodiesAcc0[iloc];
  6103.           body.acc1 = bodiesAcc1[iloc];
  6104.           body.time = bodiesTime[iloc];
  6105.           body.id   = bodiesIds[iloc];
  6106.           body.Ppos  = predictedBodiesPositions[iloc];
  6107.           body.Pvel  = predictedVelocities[iloc];
  6108.           array2Send.push_back(body);
  6109.         }
  6110.  
  6111.         iloc++;
  6112.       }// end if
  6113.     }//for i=iloc
  6114.     nparticles[ibox] = iloc-firstloc[ibox];//Number of particles that has to be send to proc: ibox
  6115.   } // for(int ib=0;ib<nproc;ib++)
  6116.  
  6117.   LOG("Required search time: %lg ,proc: %d found in our own box: %d n: %d  send to others: %ld \n",
  6118.       get_time()-t1, myid, nparticles[myid], tree.n, array2Send.size());
  6119.  
  6120.   t1 = get_time();
  6121.  
  6122.   totalsent = nbody - nparticles[myid];
  6123.  
  6124.   int tmp;
  6125. #ifdef USE_MPI
  6126.   MPI_Reduce(&totalsent,&tmp,1, MPI_INT, MPI_SUM,0,MPI_COMM_WORLD);
  6127. #else
  6128.   tmp = totalsent;
  6129. #endif
  6130.  
  6131.   if(procId == 0)
  6132.   {
  6133.     totalsent = tmp;
  6134.     LOG("Exchanged particles = %d \n", totalsent);
  6135.   }
  6136.  
  6137.   if(iloc < nbody)
  6138.   {
  6139.     cerr << procId <<" exchange_particle error: particle in no box...iloc: " << iloc
  6140.       << " and nbody: " << nbody << "\n";
  6141.   }
  6142.  
  6143.   vector<bodyStruct> recv_buffer3(nbody- nparticles[myid]);
  6144.  
  6145.   int tempidFirst, tempRecvCount;
  6146.   unsigned int recvCount = 0;
  6147.  
  6148.   //Exchange the data with the other processors
  6149.   int ibend = -1;
  6150.   int nsend = 0;
  6151.   int isource = 0;
  6152.   for(int ib=nproc-1;ib>0;ib--)
  6153.   {
  6154.     int ibox = (ib+myid)%nproc; //index to send...
  6155.  
  6156.     if (ib == nproc-1)
  6157.     {
  6158.       isource= (myid+1)%nproc;
  6159.     }
  6160.     else
  6161.     {
  6162.       isource = (isource+1)%nproc;
  6163.       if (isource == myid)isource = (isource+1)%nproc;
  6164.     }
  6165.  
  6166.     if(MP_exchange_particle_with_overflow_check<bodyStruct>(ibox, &array2Send[0],
  6167.           recv_buffer3, firstloc[ibox] - nparticles[myid],
  6168.           nparticles[ibox], isource,
  6169.           nsend, recvCount))
  6170.     {
  6171.       ibend = ibox; //Here we get if exchange failed
  6172.       ib = 0;
  6173.     }//end if mp exchang
  6174.   }//end for all boxes
  6175.  
  6176.   LOG("Required inter-process communication time: %lg ,proc: %d\n", get_time()-t1, myid);
  6177.   t1 = get_time();
  6178.   double t2= t1;
  6179.  
  6180.   //    ... should do something different for nsend...
  6181.   int idfirst;
  6182.   if(ibend >= 0)
  6183.   {
  6184.     idfirst = firstloc[ibend]+nparticles[ibend]-nsend;
  6185.   }
  6186.   else
  6187.   {
  6188.     idfirst = nparticles[myid];
  6189.   }
  6190.  
  6191.   //Have to resize the bodies vector to keep the numbering correct
  6192.   tree.setN(idfirst+recvCount);
  6193.   tree.bodies_pos.cresize (idfirst+recvCount + 1, false);
  6194.   tree.bodies_acc0.cresize(idfirst+recvCount,     false);
  6195.   tree.bodies_acc1.cresize(idfirst+recvCount,     false);
  6196.   tree.bodies_vel.cresize (idfirst+recvCount,     false);
  6197.   tree.bodies_time.cresize(idfirst+recvCount,     false);
  6198.   tree.bodies_ids.cresize (idfirst+recvCount + 1, false);
  6199.   tree.bodies_Ppos.cresize(idfirst+recvCount + 1, false);
  6200.   tree.bodies_Pvel.cresize(idfirst+recvCount + 1, false);
  6201.  
  6202.   //This one has to be at least the same size as the number of particles inorder to
  6203.   //have enough space to store the other buffers
  6204.   tree.generalBuffer1.cresize(3*(idfirst+recvCount)*4, false);
  6205.  
  6206.   LOG("Benodigde gpu malloc tijd stap 1: %lg \t Size: %d \tRank: %d \t Size: %d \n",
  6207.       get_time()-t1, idfirst+recvCount, mpiGetRank(), tree.bodies_Ppos.get_size());
  6208.   t1 = get_time();
  6209.  
  6210.   tempidFirst = idfirst; tempRecvCount = recvCount;
  6211.  
  6212.   //Copy data from struct into the main arrays
  6213.   for(unsigned int P=0; P < recvCount; P++)
  6214.   {
  6215.     tree.bodies_pos[idfirst+P]  = recv_buffer3[P].pos;        tree.bodies_vel[idfirst+P]      = recv_buffer3[P].vel;
  6216.     tree.bodies_acc0[idfirst+P] = recv_buffer3[P].acc0;       tree.bodies_acc1[idfirst+P]     = recv_buffer3[P].acc1;
  6217.     tree.bodies_time[idfirst+P] = recv_buffer3[P].time;       tree.bodies_ids[idfirst+P]      = recv_buffer3[P].id;
  6218.     tree.bodies_Ppos[idfirst+P] = recv_buffer3[P].Ppos;       tree.bodies_Pvel[idfirst+P]     = recv_buffer3[P].Pvel;
  6219.   }
  6220.  
  6221.   LOG("Required DATA in struct copy time: %lg \n", get_time()-t1); t1 = get_time();
  6222.  
  6223.  
  6224.   if(ibend == -1){
  6225.  
  6226.   }else{
  6227.     //Something went wrong
  6228.     cerr << "ERROR in exchange_particles_with_overflow_check! \n"; exit(0);
  6229.   }
  6230.  
  6231.  
  6232.   //Resize the arrays of the tree
  6233.   reallocateParticleMemory(tree);
  6234.  
  6235.   LOG("Required gpu malloc time step 2: %lg \n", get_time()-t1);
  6236.   LOG("Total GPU interaction time: %lg \n", get_time()-t2);
  6237.  
  6238.   int retValue = 0;
  6239.  
  6240.  
  6241.   delete[] firstloc;
  6242.   delete[] nparticles;
  6243.  
  6244.   return retValue;
  6245. }
  6246.  
  6247.  
  6248.  
  6249.  
  6250. //Function that uses the GPU to get a set of particles that have to be
  6251. //send to other processes
  6252. void octree::gpuRedistributeParticles()
  6253. {
  6254.   //Memory buffers to hold the extracted particle information
  6255.   my_dev::dev_mem<uint>  validList(devContext);
  6256.   my_dev::dev_mem<uint>  compactList(devContext);
  6257.  
  6258.   int memOffset1 = compactList.cmalloc_copy(localTree.generalBuffer1,
  6259.       localTree.n, 0);
  6260.   int memOffset2 = validList.cmalloc_copy(localTree.generalBuffer1,
  6261.       localTree.n, memOffset1);
  6262.  
  6263.   double4 thisXlow  = domainRLow [this->procId];
  6264.   double4 thisXhigh = domainRHigh[this->procId];
  6265.  
  6266.   domainCheck.set_arg<int>(0,     &localTree.n);
  6267.   domainCheck.set_arg<double4>(1, &thisXlow);
  6268.   domainCheck.set_arg<double4>(2, &thisXhigh);
  6269.   domainCheck.set_arg<cl_mem>(3,  localTree.bodies_Ppos.p());
  6270.   domainCheck.set_arg<cl_mem>(4,  validList.p());
  6271.   domainCheck.setWork(localTree.n, 128);
  6272.   domainCheck.execute(execStream->s());
  6273.  
  6274.   //Create a list of valid and invalid particles
  6275.   this->resetCompact();  //Make sure compact has been reset
  6276.   int validCount;
  6277.   gpuSplit(devContext, validList, compactList, localTree.n, &validCount);
  6278.  
  6279.  
  6280.   //Check if the memory size, of the generalBuffer is large enough to store the exported particles
  6281.   int tempSize = localTree.generalBuffer1.get_size() - localTree.n;
  6282.   int needSize = (int)(1.01f*(validCount*(sizeof(bodyStruct)/sizeof(int))));
  6283.  
  6284.   if(tempSize < needSize)
  6285.   {
  6286.     int itemsNeeded = needSize + localTree.n + 4092; //Slightly larger as before for offset space
  6287.  
  6288.     //Copy the compact list to the host we need this list intact
  6289.     compactList.d2h();
  6290.     int *tempBuf = new int[localTree.n];
  6291.     memcpy(tempBuf, &compactList[0], localTree.n*sizeof(int));
  6292.  
  6293.     //Resize the general buffer
  6294.     localTree.generalBuffer1.cresize(itemsNeeded, false);
  6295.     //Reset memory pointers
  6296.     memOffset1 = compactList.cmalloc_copy(localTree.generalBuffer1,
  6297.         localTree.n, 0);
  6298.  
  6299.     //Restore the compactList
  6300.     memcpy(&compactList[0], tempBuf, localTree.n*sizeof(int));
  6301.     compactList.h2d();
  6302.  
  6303.     delete[] tempBuf;
  6304.   }
  6305.  
  6306.   my_dev::dev_mem<bodyStruct>  bodyBuffer(devContext);
  6307.  
  6308.   memOffset1 = bodyBuffer.cmalloc_copy(localTree.generalBuffer1,
  6309.       localTree.n, memOffset1);
  6310.  
  6311.   extractOutOfDomainBody.set_arg<int>(0,    &validCount);
  6312.   extractOutOfDomainBody.set_arg<cl_mem>(1, compactList.p());
  6313.   extractOutOfDomainBody.set_arg<cl_mem>(2, localTree.bodies_Ppos.p());
  6314.   extractOutOfDomainBody.set_arg<cl_mem>(3, localTree.bodies_Pvel.p());
  6315.   extractOutOfDomainBody.set_arg<cl_mem>(4, localTree.bodies_pos.p());
  6316.   extractOutOfDomainBody.set_arg<cl_mem>(5, localTree.bodies_vel.p());
  6317.   extractOutOfDomainBody.set_arg<cl_mem>(6, localTree.bodies_acc0.p());
  6318.   extractOutOfDomainBody.set_arg<cl_mem>(7, localTree.bodies_acc1.p());
  6319.   extractOutOfDomainBody.set_arg<cl_mem>(8, localTree.bodies_time.p());
  6320.   extractOutOfDomainBody.set_arg<cl_mem>(9, localTree.bodies_ids.p());
  6321.   extractOutOfDomainBody.set_arg<cl_mem>(10, bodyBuffer.p());
  6322.   extractOutOfDomainBody.setWork(validCount, 128);
  6323.   extractOutOfDomainBody.execute(execStream->s());
  6324.  
  6325.   bodyBuffer.d2h(validCount);
  6326.  
  6327.   //Now we have to move particles from the back of the array to the invalid spots
  6328.   //this can be done in parallel with exchange operation to hide some time
  6329.  
  6330.   //One integer for counting, true-> initialize to zero so counting starts at 0
  6331.   my_dev::dev_mem<uint>  atomicBuff(devContext, 1, true);
  6332.  
  6333.   //Internal particle movement
  6334.   internalMove.set_arg<int>(0,    &validCount);
  6335.   internalMove.set_arg<int>(1,    &localTree.n);
  6336.   internalMove.set_arg<double4>(2,    &thisXlow);
  6337.   internalMove.set_arg<double4>(3,    &thisXhigh);
  6338.   internalMove.set_arg<cl_mem>(4, compactList.p());
  6339.   internalMove.set_arg<cl_mem>(5, atomicBuff.p());
  6340.   internalMove.set_arg<cl_mem>(6, localTree.bodies_Ppos.p());
  6341.   internalMove.set_arg<cl_mem>(7, localTree.bodies_Pvel.p());
  6342.   internalMove.set_arg<cl_mem>(8, localTree.bodies_pos.p());
  6343.   internalMove.set_arg<cl_mem>(9, localTree.bodies_vel.p());
  6344.   internalMove.set_arg<cl_mem>(10, localTree.bodies_acc0.p());
  6345.   internalMove.set_arg<cl_mem>(11, localTree.bodies_acc1.p());
  6346.   internalMove.set_arg<cl_mem>(12, localTree.bodies_time.p());
  6347.   internalMove.set_arg<cl_mem>(13, localTree.bodies_ids.p());
  6348.   internalMove.setWork(validCount, 128);
  6349.   internalMove.execute(execStream->s());
  6350.  
  6351.   this->gpu_exchange_particles_with_overflow_check(localTree, &bodyBuffer[0], compactList, validCount);
  6352.  
  6353. } //End gpuRedistributeParticles
  6354.  
  6355.  
  6356.  
  6357.  
  6358. void octree::essential_tree_exchange(vector<real4> &treeStructure, tree_structure &tree, tree_structure &remote)
  6359. {
  6360.   int myid    = procId;
  6361.   int nproc   = nProcs;
  6362.   int isource = 0;
  6363.  
  6364.   double t0 = get_time();
  6365.  
  6366.   bool mergeOwntree = false;          //Default do not include our own tree-structre, thats mainly used for testing
  6367.   int step          = nProcs - 1;     //Default merge all remote trees into one structure
  6368.   //   step              = 1;
  6369.   int level_start   = tree.startLevelMin; //Depth of where to start the tree-walk
  6370.   int procTrees     = 0;              //Number of trees that we've received and processed
  6371.  
  6372.   real4  *bodies              = &tree.bodies_Ppos[0];
  6373.   real4  *velocities          = &tree.bodies_Pvel[0];
  6374.   real4  *multipole           = &tree.multipole[0];
  6375.   real4  *nodeSizeInfo        = &tree.boxSizeInfo[0];
  6376.   real4  *nodeCenterInfo      = &tree.boxCenterInfo[0];
  6377.  
  6378.   vector<real4> recv_particles;
  6379.   vector<real4> recv_multipoleData;
  6380.   vector<real4> recv_nodeSizeData;
  6381.   vector<real4> recv_nodeCenterData;
  6382.  
  6383.  
  6384.  
  6385.  
  6386.  
  6387.  
  6388.   if(procId == -1)
  6389.   {
  6390.     uint2 node_begend;
  6391.     node_begend.x   = tree.level_list[level_start].x;
  6392.     node_begend.y   = tree.level_list[level_start].y;
  6393.  
  6394.     int remoteId = 1;
  6395.  
  6396.     char buffFilename[256];
  6397.     sprintf(buffFilename, "grpAndTreeDump_%d_%d.bin", procId, remoteId);
  6398.  
  6399.     ofstream outFile(buffFilename, ios::out|ios::binary);
  6400.     if(outFile.is_open())
  6401.     {
  6402.       //Write the properties
  6403.       outFile.write((char*)&globalCoarseGrpCount[remoteId], sizeof(int));
  6404.       outFile.write((char*)&node_begend.x, sizeof(int));
  6405.       outFile.write((char*)&node_begend.y, sizeof(int));
  6406.       outFile.write((char*)&tree.n_nodes, sizeof(int));
  6407.       outFile.write((char*)&tree.n, sizeof(int));
  6408.  
  6409.       //Write the groups
  6410.       for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  6411.       {
  6412.         int idx = globalCoarseGrpOffsets[remoteId] + i;
  6413.         double4 boxCenter = coarseGroupBoxCenter[idx];
  6414.         double4 boxSize   = coarseGroupBoxSize  [idx];
  6415.         outFile.write((char*)&boxCenter, sizeof(double4));
  6416.         outFile.write((char*)&boxSize, sizeof(double4));
  6417.       }
  6418.  
  6419.       //Write the particles
  6420.       for(int i=0; i < tree.n; i++)
  6421.       {
  6422.         outFile.write((char*)&bodies[i], sizeof(real4));
  6423.       }
  6424.  
  6425.       //Write the multipole
  6426.       for(int i=0; i < tree.n_nodes; i++)
  6427.       {
  6428.         outFile.write((char*)&multipole[i*3 + 0], sizeof(real4));
  6429.         outFile.write((char*)&multipole[i*3 + 1], sizeof(real4));
  6430.         outFile.write((char*)&multipole[i*3 + 2], sizeof(real4));
  6431.       }
  6432.  
  6433.       //Write the nodeSizeInfo
  6434.       for(int i=0; i < tree.n_nodes; i++)
  6435.       {
  6436.         outFile.write((char*)&nodeSizeInfo[i], sizeof(real4));
  6437.       }
  6438.  
  6439.       //Write the nodeCenterInfo
  6440.       for(int i=0; i < tree.n_nodes; i++)
  6441.       {
  6442.         outFile.write((char*)&nodeCenterInfo[i], sizeof(real4));
  6443.       }
  6444.  
  6445.       outFile.close();
  6446.  
  6447.     }
  6448.  
  6449.   }
  6450.  
  6451.  
  6452.  
  6453.  
  6454.  
  6455.   real4 **treeBuffers;
  6456.  
  6457.   //creates a new array of pointers to int objects, with space for the local tree
  6458.   treeBuffers  = new real4*[mpiGetNProcs()];
  6459.  
  6460.   //Timers for the LET Exchange
  6461.   static double totalLETExTime    = 0;
  6462.   //   double thisPartLETExTime = 0;
  6463.   thisPartLETExTime = 0;
  6464.   double tStart = 0;
  6465.  
  6466.   //   for(int z=nproc-1; z > 0; z-=step)
  6467.   for(int z=nproc-1; z > 0; )
  6468.   {
  6469.     tStart = get_time();
  6470.  
  6471.     step = min(step, z);
  6472.  
  6473.     int recvTree = 0;
  6474.     //For each process
  6475.     for(int ib = z; recvTree < step; recvTree++, ib--)
  6476.     {
  6477.       int ibox = (ib+myid)%nproc; //index to send...
  6478.       if (ib == nproc-1){
  6479.         isource= (myid+1)%nproc;
  6480.       }else{
  6481.         isource = (isource+1)%nproc;
  6482.         if (isource == myid)isource = (isource+1)%nproc;
  6483.       }
  6484.  
  6485.       /*
  6486.          cerr << "\nibox: " << ibox << endl;
  6487.          cerr << "Other proc has box: low: " << let_xlow[ibox].x << "\t" <<  let_xlow[ibox].y  << "\t" <<  let_xlow[ibox].z
  6488.          << "\thigh: "  << let_xhigh[ibox].x << "\t" <<  let_xhigh[ibox].y  << "\t" <<  let_xhigh[ibox].z << endl;*/
  6489.  
  6490.       double4 boxCenter = {     0.5*(currentRLow[ibox].x  + currentRHigh[ibox].x),
  6491.         0.5*(currentRLow[ibox].y  + currentRHigh[ibox].y),
  6492.         0.5*(currentRLow[ibox].z  + currentRHigh[ibox].z), 0};
  6493.       double4 boxSize   = {fabs(0.5*(currentRHigh[ibox].x - currentRLow[ibox].x)),
  6494.         fabs(0.5*(currentRHigh[ibox].y - currentRLow[ibox].y)),
  6495.         fabs(0.5*(currentRHigh[ibox].z - currentRLow[ibox].z)), 0};
  6496.  
  6497.  
  6498.       //       printf("Other proc min and max: [%f %f %f] \t [%f %f %f] \n", currentRLow[ibox].x, currentRLow[ibox].y, currentRLow[ibox].z,
  6499.       //               currentRHigh[ibox].x, currentRHigh[ibox].y, currentRHigh[ibox].z);
  6500.  
  6501.       //   printf("Other proc center and size: [%f %f %f] \t [%f %f %f] \n", boxCenter.x, boxCenter.y, boxCenter.z,
  6502.       //          boxSize.x, boxSize.y, boxSize.z);
  6503.  
  6504.       uint2 node_begend;
  6505.       node_begend.x   = tree.level_list[level_start].x;
  6506.       node_begend.y   = tree.level_list[level_start].y;
  6507.  
  6508.       int particleCount, nodeCount;
  6509.  
  6510.       double t1 = get_time();
  6511.       //      create_local_essential_tree_count(bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  6512.       //                                  boxCenter, boxSize, (float)currentRLow[ibox].w, node_begend.x, node_begend.y,
  6513.       //                                  particleCount, nodeCount);
  6514.       create_local_essential_tree_count(bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  6515.           ibox, (float)currentRLow[ibox].w, node_begend.x, node_begend.y,
  6516.           particleCount, nodeCount);
  6517.  
  6518.       LOG("LET count (ibox: %d): %lg \t Coarse groups %d Since start: %lg\n", ibox, get_time()-t1,  globalCoarseGrpCount[ibox],get_time()-t0);
  6519.       LOG("LET count:  Particle count %d Node count: %d\n", particleCount, nodeCount);
  6520.       //Buffer that will contain all the data:
  6521.       //|real4| 2*particleCount*real4| nodes*real4 | nodes*real4 | nodes*3*real4 |
  6522.       //1 + 2*particleCount + nodeCount + nodeCount + 3*nodeCount
  6523.  
  6524.       //Increase the number of particles and the number of nodes by the texture-offset such that these are correctly
  6525.       //aligned in memory
  6526.       particleCount += getTextureAllignmentOffset(particleCount, sizeof(real4));
  6527.       nodeCount     += getTextureAllignmentOffset(nodeCount    , sizeof(real4));
  6528.  
  6529.       //0-1 )                               Info about #particles, #nodes, start and end of tree-walk
  6530.       //1- Npart)                           The particle positions
  6531.       //1+Npart-Npart )                     The particle velocities
  6532.       //1+2*Npart-Nnode )                   The nodeSizeData
  6533.       //1+*2Npart+Nnode - Npart+2*Nnode )   The nodeCenterData
  6534.       //1+2*Npart+2*Nnode - Npart+5*Nnode ) The multipole data, is 3x number of nodes (mono and quadrupole data)
  6535.       int bufferSize = 1 + 2*particleCount + 5*nodeCount;
  6536.       real4 *letDataBuffer = new real4[bufferSize];
  6537.  
  6538.       //      create_local_essential_tree_fill(bodies, velocities, multipole, nodeSizeInfo, nodeCenterInfo,
  6539.       //                                  boxCenter, boxSize, (float)currentRLow[ibox].w, node_begend.x, node_begend.y,
  6540.       //                                  particleCount, nodeCount, letDataBuffer);
  6541.       create_local_essential_tree_fill(bodies, velocities, multipole, nodeSizeInfo, nodeCenterInfo,
  6542.           ibox, (float)currentRLow[ibox].w, node_begend.x, node_begend.y,
  6543.           particleCount, nodeCount, letDataBuffer);
  6544.       LOG("LET count&fill: %lg  since start: %lg \n", get_time()-t1, get_time()-t0);
  6545.  
  6546.  
  6547.       /*
  6548.          printf("LET count&fill: %lg\n", get_time()-t1);
  6549.          t1 = get_time();
  6550.          printf("Speciaal: %lg\n", get_time()-t1);
  6551.          t1 = get_time();
  6552.          create_local_essential_tree(bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  6553.          boxCenter, boxSize, node_begend.x, node_begend.y,
  6554.          particles, multipoleData, nodeSizeData, nodeCenterData);
  6555.          printf("Gewoon: %lg\n", get_time()-t1); */
  6556.  
  6557.       //Set the tree properties, before we exchange the data
  6558.       letDataBuffer[0].x = (float)particleCount;         //Number of particles in the LET
  6559.       letDataBuffer[0].y = (float)nodeCount;             //Number of nodes     in the LET
  6560.       letDataBuffer[0].z = (float)node_begend.x;         //First node on the level that indicates the start of the tree walk
  6561.       letDataBuffer[0].w = (float)node_begend.y;         //last node on the level that indicates the start of the tree walk
  6562.  
  6563.       double t9 = get_time();
  6564.       //Exchange the data of the tree structures  between the processes
  6565.       treeBuffers[recvTree] = MP_exchange_bhlist(ibox, isource, bufferSize, letDataBuffer);
  6566.       LOG("LET exchange trees: %d <-> %d  took: %lg  since start: %lg \n", ibox, isource,get_time()-t9, get_time()-t0);
  6567.  
  6568.       delete[] letDataBuffer;
  6569.  
  6570.       //This determines if we interrupt the exchange by starting a gravity kernel on the GPU
  6571.       if(gravStream->isFinished())
  6572.       {
  6573.         LOGF(stderr,"GRAVFINISHED %d recvTree: %d  Time: %lg Since start: %lg\n",
  6574.             procId, recvTree, get_time()-t1, get_time()-t0);
  6575.         recvTree++;
  6576.         break;
  6577.       }
  6578.     }//end for each process
  6579.  
  6580.  
  6581.  
  6582.     z-=recvTree;
  6583.  
  6584.     //Now we have to merge the seperate tree-structures into one process
  6585.  
  6586.     //     double t1 = get_time();
  6587.  
  6588.     int PROCS = recvTree;
  6589.  
  6590.     procTrees += recvTree;
  6591.  
  6592.     if(mergeOwntree)
  6593.     {
  6594.       //Add the processors own tree to the LET tree
  6595.       int particleCount   = tree.n;
  6596.       int nodeCount       = tree.n_nodes;
  6597.  
  6598.       int realParticleCount = tree.n;
  6599.       int realNodeCount     = tree.n_nodes;
  6600.  
  6601.       particleCount += getTextureAllignmentOffset(particleCount, sizeof(real4));
  6602.       nodeCount     += getTextureAllignmentOffset(nodeCount    , sizeof(real4));
  6603.  
  6604.       int bufferSizeLocal = 1 + 2*particleCount + 5*nodeCount;
  6605.  
  6606.       treeBuffers[PROCS]  = new real4[bufferSizeLocal];
  6607.  
  6608.       //Note that we use the real*Counts otherwise we read out of the array boundaries!!
  6609.       int idx = 1;
  6610.       memcpy(&treeBuffers[PROCS][idx], &bodies[0],         sizeof(real4)*realParticleCount);
  6611.       idx += particleCount;
  6612.       memcpy(&treeBuffers[PROCS][idx], &velocities[0],     sizeof(real4)*realParticleCount);
  6613.       idx += particleCount;
  6614.       memcpy(&treeBuffers[PROCS][idx], &nodeSizeInfo[0],   sizeof(real4)*realNodeCount);
  6615.       idx += nodeCount;
  6616.       memcpy(&treeBuffers[PROCS][idx], &nodeCenterInfo[0], sizeof(real4)*realNodeCount);
  6617.       idx += nodeCount;
  6618.       memcpy(&treeBuffers[PROCS][idx], &multipole[0],      sizeof(real4)*realNodeCount*3);
  6619.  
  6620.       treeBuffers[PROCS][0].x = (float)particleCount;
  6621.       treeBuffers[PROCS][0].y = (float)nodeCount;
  6622.       treeBuffers[PROCS][0].z = (float)tree.level_list[level_start].x;
  6623.       treeBuffers[PROCS][0].w = (float)tree.level_list[level_start].y;
  6624.       PROCS                   = PROCS + 1; //Signal that we added one more tree-structure
  6625.       mergeOwntree            = false;     //Set it to false incase we do not merge all trees at once, we only inlcude our own once
  6626.     }
  6627.  
  6628.     //Arrays to store and compute the offsets
  6629.     int *particleSumOffsets  = new int[mpiGetNProcs()+1];
  6630.     int *nodeSumOffsets      = new int[mpiGetNProcs()+1];
  6631.     int *startNodeSumOffsets = new int[mpiGetNProcs()+1];
  6632.     uint2 *nodesBegEnd       = new uint2[mpiGetNProcs()+1];
  6633.  
  6634.     //Offsets start at 0 and then are increased by the number of nodes of each LET tree
  6635.     particleSumOffsets[0]           = 0;
  6636.     nodeSumOffsets[0]               = 0;
  6637.     startNodeSumOffsets[0]          = 0;
  6638.     nodesBegEnd[mpiGetNProcs()].x   = nodesBegEnd[mpiGetNProcs()].y = 0; //Make valgrind happy
  6639.     int totalTopNodes               = 0;
  6640.  
  6641.  
  6642.     //Calculate the offsets
  6643.     for(int i=0; i < PROCS ; i++)
  6644.     {
  6645.       int particles = (int)treeBuffers[i][0].x;
  6646.       int nodes     = (int)treeBuffers[i][0].y;
  6647.  
  6648.       nodesBegEnd[i].x = (int)treeBuffers[i][0].z;
  6649.       nodesBegEnd[i].y = (int)treeBuffers[i][0].w;
  6650.  
  6651.       totalTopNodes += nodesBegEnd[i].y-nodesBegEnd[i].x;
  6652.  
  6653.       particleSumOffsets[i+1]     = particleSumOffsets[i]  + particles;
  6654.       nodeSumOffsets[i+1]         = nodeSumOffsets[i]      + nodes - nodesBegEnd[i].y;    //Without the top-nodes
  6655.       startNodeSumOffsets[i+1]    = startNodeSumOffsets[i] + nodesBegEnd[i].y-nodesBegEnd[i].x;
  6656.     }
  6657.  
  6658.     //Compute total particles and total nodes, totalNodes is WITHOUT topNodes
  6659.     int totalParticles    = particleSumOffsets[PROCS];
  6660.     int totalNodes        = nodeSumOffsets[PROCS];
  6661.  
  6662.     //To bind parts of the memory to different textures, the memory start address
  6663.     //has to be aligned with XXX bytes, so nodeInformation*sizeof(real4) has to be
  6664.     //increased by an offset, so that the node data starts at a XXX byte boundary
  6665.     //this is already done on the sending process, but since we modify the structure
  6666.     //it has to be done again
  6667.     int nodeTextOffset = getTextureAllignmentOffset(totalNodes+totalTopNodes, sizeof(real4));
  6668.  
  6669.     //Compute the total size of the buffer
  6670.     int bufferSize     = 2*(totalParticles) + 5*(totalNodes+totalTopNodes + nodeTextOffset);
  6671.  
  6672.     thisPartLETExTime += get_time() - tStart;
  6673.     //Allocate memory on host and device to store the merged tree-structure
  6674.     if(bufferSize > remote.fullRemoteTree.get_size())
  6675.     {
  6676.       //Can only resize if we are sure the LET is not running
  6677.       if(letRunning)
  6678.       {
  6679.         gravStream->sync();     //Wait till the LET run is finished
  6680.       }
  6681.       remote.fullRemoteTree.cresize(bufferSize, false);  //Change the size but ONLY if we need more memory
  6682.     }
  6683.     tStart = get_time();
  6684.  
  6685.     real4 *combinedRemoteTree = &remote.fullRemoteTree[0];
  6686.  
  6687.     //Copy all the pieces of the different trees at the correct memory offsets
  6688.     for(int i=0; i < PROCS; i++)
  6689.     {
  6690.       //Get the properties of the LET
  6691.       int remoteP = (int) treeBuffers[i][0].x;    //Number of particles
  6692.       int remoteN = (int) treeBuffers[i][0].y;    //Number of nodes
  6693.       int remoteB = (int) treeBuffers[i][0].z;    //Begin id of top nodes
  6694.       int remoteE = (int) treeBuffers[i][0].w;    //End   id of top nodes
  6695.       int remoteNstart = remoteE-remoteB;
  6696.  
  6697.       //Particles
  6698.       memcpy(&combinedRemoteTree[particleSumOffsets[i]],   &treeBuffers[i][1], sizeof(real4)*remoteP);
  6699.  
  6700.       //Velocities
  6701.       memcpy(&combinedRemoteTree[(totalParticles) + particleSumOffsets[i]],
  6702.           &treeBuffers[i][1+remoteP], sizeof(real4)*remoteP);
  6703.  
  6704.       //The start nodes, nodeSizeInfo
  6705.       memcpy(&combinedRemoteTree[2*(totalParticles) + startNodeSumOffsets[i]],
  6706.           &treeBuffers[i][1+2*remoteP+remoteB], //From the start node onwards
  6707.           sizeof(real4)*remoteNstart);
  6708.  
  6709.       //Non start nodes, nodeSizeInfo
  6710.       memcpy(&combinedRemoteTree[2*(totalParticles) +  totalTopNodes + nodeSumOffsets[i]],
  6711.           &treeBuffers[i][1+2*remoteP+remoteE], //From the last start node onwards
  6712.           sizeof(real4)*(remoteN-remoteE));
  6713.  
  6714.       //The start nodes, nodeCenterInfo
  6715.       memcpy(&combinedRemoteTree[2*(totalParticles) + startNodeSumOffsets[i]
  6716.           + (totalNodes + totalTopNodes + nodeTextOffset)],
  6717.           &treeBuffers[i][1+2*remoteP+remoteB + remoteN], //From the start node onwards
  6718.           sizeof(real4)*remoteNstart);
  6719.  
  6720.       //Non start nodes, nodeCenterInfo
  6721.       memcpy(&combinedRemoteTree[2*(totalParticles) +  totalTopNodes
  6722.           + nodeSumOffsets[i] + (totalNodes + totalTopNodes + nodeTextOffset)],
  6723.           &treeBuffers[i][1+2*remoteP+remoteE + remoteN], //From the last start node onwards
  6724.           sizeof(real4)*(remoteN-remoteE));
  6725.  
  6726.       //The start nodes, multipole
  6727.       memcpy(&combinedRemoteTree[2*(totalParticles) + 3*startNodeSumOffsets[i] +
  6728.           2*(totalNodes+totalTopNodes + nodeTextOffset)],
  6729.           &treeBuffers[i][1+2*remoteP+2*remoteN + 3*remoteB], //From the start node onwards
  6730.           sizeof(real4)*remoteNstart*3);
  6731.  
  6732.       //Non start nodes, multipole
  6733.       memcpy(&combinedRemoteTree[2*(totalParticles) +  3*totalTopNodes +
  6734.           3*nodeSumOffsets[i] + 2*(totalNodes+totalTopNodes+nodeTextOffset)],
  6735.           &treeBuffers[i][1+2*remoteP+remoteE*3 + 2*remoteN], //From the last start node onwards
  6736.           sizeof(real4)*(remoteN-remoteE)*3);
  6737.       /*
  6738.          |real4| 2*particleCount*real4| nodes*real4 | nodes*real4 | nodes*3*real4 |
  6739.          1 + 2*particleCount + nodeCount + nodeCount + 3*nodeCount
  6740.  
  6741.          Info about #particles, #nodes, start and end of tree-walk
  6742.          The particle positions
  6743.          velocities
  6744.          The nodeSizeData
  6745.          The nodeCenterData
  6746.          The multipole data, is 3x number of nodes (mono and quadrupole data)
  6747.  
  6748.          Now that the data is copied, modify the offsets of the tree so that everything works
  6749.          with the new correct locations and references. This takes place in two steps:
  6750.          First  the top nodes
  6751.          Second the normal nodes
  6752.          Has to be done in two steps since they are not continous in memory if NPROCS > 2
  6753.          */
  6754.  
  6755.       //Modify the top nodes
  6756.       int modStart = 2*(totalParticles) + startNodeSumOffsets[i];
  6757.       int modEnd   = modStart           + remoteNstart;
  6758.  
  6759.       for(int j=modStart; j < modEnd; j++)
  6760.       {
  6761.         real4 nodeCenter = combinedRemoteTree[j+totalTopNodes+totalNodes+nodeTextOffset];
  6762.         real4 nodeSize   = combinedRemoteTree[j];
  6763.         bool leaf        = nodeCenter.w <= 0;
  6764.  
  6765.         int childinfo = host_float_as_int(nodeSize.w);
  6766.         int child, nchild;
  6767.  
  6768.         if(!leaf)
  6769.         {
  6770.           //Node
  6771.           child    =    childinfo & 0x0FFFFFFF;                  //Index to the first child of the node
  6772.           nchild   = (((childinfo & 0xF0000000) >> 28)) ;        //The number of children this node has
  6773.  
  6774.           child = child - nodesBegEnd[i].y + totalTopNodes + nodeSumOffsets[i]; //Calculate the new start (non-leaf)
  6775.           child = child | (nchild << 28);                                       //Merging back in one int
  6776.  
  6777.           if(nchild == 0) child = 0;                             //To prevent incorrect negative values
  6778.         }else{ //Leaf
  6779.           child   =   childinfo & BODYMASK;                      //the first body in the leaf
  6780.           nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  6781.  
  6782.           child   =  child + particleSumOffsets[i];               //Increasing offset
  6783.           child   = child | ((nchild-1) << LEAFBIT);              //Merging back to one int
  6784.         }//end !leaf
  6785.         combinedRemoteTree[j].w =  host_int_as_float(child);      //store the modified offset
  6786.       }
  6787.  
  6788.       //Now the non-top nodes for this process
  6789.       modStart =  totalTopNodes + nodeSumOffsets[i] + 2*(totalParticles);
  6790.       modEnd   =  modStart      + remoteN-remoteE;
  6791.       for(int j=modStart; j < modEnd; j++)
  6792.       {
  6793.         real4 nodeCenter = combinedRemoteTree[j+totalTopNodes+totalNodes+nodeTextOffset];
  6794.         real4 nodeSize   = combinedRemoteTree[j];
  6795.         bool leaf        = nodeCenter.w <= 0;
  6796.  
  6797.         int childinfo = host_float_as_int(nodeSize.w);
  6798.         int child, nchild;
  6799.  
  6800.         if(!leaf) {  //Node
  6801.           child    =    childinfo & 0x0FFFFFFF;                   //Index to the first child of the node
  6802.           nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  6803.  
  6804.           //Calculate the new start (non-leaf)
  6805.           child = child - nodesBegEnd[i].y + totalTopNodes + nodeSumOffsets[i];  ;
  6806.  
  6807.           //Combine and store
  6808.           child = child | (nchild << 28);
  6809.  
  6810.           if(nchild == 0) child = 0;                              //To prevent incorrect negative values
  6811.         }else{ //Leaf
  6812.           child   =   childinfo & BODYMASK;                       //the first body in the leaf
  6813.           nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);      //number of bodies in the leaf masked with the flag
  6814.  
  6815.           child =  child + particleSumOffsets[i];                 //Modify the particle offsets
  6816.           child = child | ((nchild-1) << LEAFBIT);                //Merging the data back into one int
  6817.         }//end !leaf
  6818.         combinedRemoteTree[j].w =  host_int_as_float(child);      //Store the modified value
  6819.       }
  6820.  
  6821.       delete[] treeBuffers[i];    //Free the memory of this part of the LET
  6822.     }
  6823.  
  6824.     /*
  6825.        The final tree structure looks as follows:
  6826.        particlesT1, partcilesT2,...mparticlesTn |,
  6827.        topNodeSizeT1, topNodeSizeT2,..., topNodeSizeT2 | nodeSizeT1, nodeSizeT2, ...nodeSizeT3 |,
  6828.        topNodeCentT1, topNodeCentT2,..., topNodeCentT2 | nodeCentT1, nodeCentT2, ...nodeCentT3 |,
  6829.        topNodeMultT1, topNodeMultT2,..., topNodeMultT2 | nodeMultT1, nodeMultT2, ...nodeMultT3
  6830.  
  6831.        NOTE that the Multipole data consists of 3 float4 values per node
  6832.  
  6833. */
  6834.  
  6835.     //Store the tree properties (number of particles, number of nodes, start and end topnode)
  6836.     remote.remoteTreeStruct.x = totalParticles;
  6837.     remote.remoteTreeStruct.y = totalNodes+totalTopNodes;
  6838.     remote.remoteTreeStruct.z = nodeTextOffset;
  6839.     totalTopNodes             = (0 << 16) | (totalTopNodes);  //If its a merged tree we start at 0
  6840.     remote.remoteTreeStruct.w = totalTopNodes;
  6841.  
  6842.     //     fprintf(stderr,"Modifying the LET took: %g \n", get_time()-t1);
  6843.     LOGF(stderr,"Number of local bodies: %d number LET bodies: %d number LET nodes: %d top nodes: %d Processed trees: %d (%d) \n",
  6844.         tree.n, totalParticles, totalNodes, remote.remoteTreeStruct.y-totalNodes, PROCS, procTrees);
  6845.  
  6846.     delete[] particleSumOffsets;
  6847.     delete[] nodeSumOffsets;
  6848.     delete[] startNodeSumOffsets;
  6849.     delete[] nodesBegEnd;
  6850.  
  6851.  
  6852.     thisPartLETExTime += get_time() - tStart;
  6853.  
  6854.  
  6855.     //Check if we need to summarize which particles are active,
  6856.     //only done during the last approximate_gravity_let call
  6857.     bool doActivePart = (procTrees == mpiGetNProcs() -1);
  6858.  
  6859.     approximate_gravity_let(this->localTree, this->remoteTree, bufferSize, doActivePart);
  6860.  
  6861.   } //end z
  6862.   delete[] treeBuffers;
  6863.  
  6864.  
  6865.   totalLETExTime += thisPartLETExTime;
  6866.  
  6867.   LOGF(stderr,"LETEX [%d] curStep: %g\t   Total: %g \n", procId, thisPartLETExTime, totalLETExTime);
  6868. }
  6869.  
  6870.  
  6871.  
  6872. inline double cust_fabs2(double a)
  6873. {
  6874.   return (a > 0) ? a : -a;
  6875. }
  6876.  
  6877.  
  6878. int globalCHECKCount;
  6879. //Improved Barnes Hut criterium
  6880. #ifdef INDSOFT
  6881. bool split_node_grav_impbh(float4 nodeCOM, double4 boxCenter, double4 boxSize,
  6882.     float group_eps, float node_eps)
  6883. #else
  6884. bool split_node_grav_impbh(float4 nodeCOM, double4 boxCenter, double4 boxSize)
  6885. #endif
  6886. {
  6887.   globalCHECKCount++;
  6888. #if 1
  6889.   //Compute the distance between the group and the cell
  6890.   float3 dr = make_float3(fabs((float)boxCenter.x - nodeCOM.x) - (float)boxSize.x,
  6891.       fabs((float)boxCenter.y - nodeCOM.y) - (float)boxSize.y,
  6892.       fabs((float)boxCenter.z - nodeCOM.z) - (float)boxSize.z);
  6893.  
  6894.   dr.x += fabs(dr.x); dr.x *= 0.5f;
  6895.   dr.y += fabs(dr.y); dr.y *= 0.5f;
  6896.   dr.z += fabs(dr.z); dr.z *= 0.5f;
  6897.  
  6898.  
  6899.   //Distance squared, no need to do sqrt since opening criteria has been squared
  6900.   float ds2    = dr.x*dr.x + dr.y*dr.y + dr.z*dr.z;
  6901.  
  6902. #ifdef INDSOFT
  6903.   if(ds2      <= ((group_eps + node_eps ) * (group_eps + node_eps) ))           return true;
  6904.   //Limited precision can result in round of errors. Use this as extra safe guard
  6905.   if(fabs(ds2 -  ((group_eps + node_eps ) * (group_eps + node_eps) )) < 10e-04) return true;
  6906. #endif
  6907.  
  6908.   if (ds2     <= fabs(nodeCOM.w))           return true;
  6909.   if (fabs(ds2 - fabs(nodeCOM.w)) < 10e-04) return true; //Limited precision can result in round of errors. Use this as extra safe guard
  6910.  
  6911.   //   return true;
  6912.   return false;
  6913. #else
  6914.  
  6915.   //Compute the distance between the group and the cell
  6916.   float3 dr = make_float3(cust_fabs2((float)boxCenter.x - nodeCOM.x) - (float)boxSize.x,
  6917.       cust_fabs2((float)boxCenter.y - nodeCOM.y) - (float)boxSize.y,
  6918.       cust_fabs2((float)boxCenter.z - nodeCOM.z) - (float)boxSize.z);
  6919.  
  6920.   dr.x += cust_fabs2(dr.x); dr.x *= 0.5f;
  6921.   dr.y += cust_fabs2(dr.y); dr.y *= 0.5f;
  6922.   dr.z += cust_fabs2(dr.z); dr.z *= 0.5f;
  6923.  
  6924.   //Distance squared, no need to do sqrt since opening criteria has been squared
  6925.   float ds2    = dr.x*dr.x + dr.y*dr.y + dr.z*dr.z;
  6926.  
  6927. #ifdef INDSOFT
  6928.   if(ds2      <= ((group_eps + node_eps ) * (group_eps + node_eps) ))           return true;
  6929.   //Limited precision can result in round of errors. Use this as extra safe guard
  6930.   if(cust_fabs2(ds2 -  ((group_eps + node_eps ) * (group_eps + node_eps) )) < 10e-04) return true;
  6931. #endif
  6932.  
  6933.   if (ds2     <= cust_fabs2(nodeCOM.w))           return true;
  6934.   if (cust_fabs2(ds2 - cust_fabs2(nodeCOM.w)) < 10e-04) return true; //Limited precision can result in round of errors. Use this as extra safe guard
  6935.  
  6936.   //   return true;
  6937.   return false;
  6938. #endif
  6939. }
  6940.  
  6941.  
  6942.  
  6943.  
  6944.  
  6945. //Minimal Distance version
  6946.  
  6947. //Minimum distance opening criteria
  6948. #ifdef INDSOFT
  6949. bool split_node(real4 nodeCenter, real4 nodeSize, double4 boxCenter, double4 boxSize,
  6950.     float group_eps, float node_eps)
  6951. #else
  6952. bool split_node(real4 nodeCenter, real4 nodeSize, double4 boxCenter, double4 boxSize)
  6953. #endif
  6954. {
  6955.   //Compute the distance between the group and the cell
  6956.   float3 dr = make_float3(fabs((float)boxCenter.x - nodeCenter.x) - (float)(boxSize.x + nodeSize.x),
  6957.       fabs((float)boxCenter.y - nodeCenter.y) - (float)(boxSize.y + nodeSize.y),
  6958.       fabs((float)boxCenter.z - nodeCenter.z) - (float)(boxSize.z + nodeSize.z));
  6959.  
  6960.   dr.x += fabs(dr.x); dr.x *= 0.5f;
  6961.   dr.y += fabs(dr.y); dr.y *= 0.5f;
  6962.   dr.z += fabs(dr.z); dr.z *= 0.5f;
  6963.  
  6964.   float ds2    = dr.x*dr.x + dr.y*dr.y + dr.z*dr.z;
  6965.  
  6966. #ifdef INDSOFT
  6967.   if(ds2 <=      ((group_eps + node_eps ) * (group_eps + node_eps) ))           return true;
  6968.   if(fabs(ds2 -  ((group_eps + node_eps ) * (group_eps + node_eps) )) < 10e-04) return true;
  6969. #endif
  6970.  
  6971.   if (ds2     <= fabs(nodeCenter.w))           return true;
  6972.   if (fabs(ds2 - fabs(nodeCenter.w)) < 10e-04) return true; //Limited precision can result in round of errors. Use this as extra safe guard
  6973.  
  6974.   return false;
  6975.  
  6976. }
  6977.  
  6978.  
  6979.  
  6980. void octree::create_local_essential_tree(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  6981.     double4 boxCenter, double4 boxSize, float group_eps, int start, int end,
  6982.     vector<real4> &particles, vector<real4> &multipoleData,
  6983.     vector<real4> &nodeSizeData, vector<real4> &nodeCenterData)
  6984. {
  6985.   //Walk the tree as is done on device, level by level
  6986.   vector<int> curLevel;
  6987.   vector<int> nextLevel;
  6988.  
  6989.  
  6990.   double t1 = get_time();
  6991.  
  6992.   double massSum = 0;
  6993.  
  6994.   int nodeCount       = 0;
  6995.  
  6996.   //Add the initial nodes to the curLevel list
  6997.   for(int i=start; i < end; i++)
  6998.   {
  6999.     curLevel.push_back(i);
  7000.   }
  7001.  
  7002.   //Add the nodes before the start and end to the node list
  7003.   for(int i=0; i < start; i++)
  7004.   {
  7005.     nodeSizeData.push_back(nodeSizeInfo[i]);
  7006.     nodeCenterData.push_back(nodeCenterInfo[i]);
  7007.  
  7008.     multipoleData.push_back(multipole[i*3 + 0]);
  7009.     multipoleData.push_back(multipole[i*3 + 1]);
  7010.     multipoleData.push_back(multipole[i*3 + 2]);
  7011.     nodeCount++;
  7012.   }
  7013.  
  7014.   //Start the tree-walk
  7015.   LOG("Start: %d end: %d \n", start, end);
  7016.   LOG("Sarting walk on: %d items! \n", (int)curLevel.size());
  7017.  
  7018.  
  7019.   int childNodeOffset         = end;
  7020.   int childParticleOffset     = 0;
  7021.  
  7022.   while(curLevel.size() > 0)
  7023.   {
  7024.     for(unsigned int i=0; i < curLevel.size(); i++)
  7025.     {
  7026.       //Read node data
  7027.       int node         = curLevel[i];
  7028.       real4 nodeCenter = nodeCenterInfo[node];
  7029.       real4 nodeSize   = nodeSizeInfo[node];
  7030.       bool leaf        = nodeCenter.w <= 0;
  7031.  
  7032.       union{float f; int i;} u; //__float_as_int
  7033.       u.f           = nodeSize.w;
  7034.       int childinfo = u.i;
  7035.  
  7036.       int child, nchild;
  7037.       if(!leaf)
  7038.       {
  7039.         //Node
  7040.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  7041.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  7042.       }
  7043.       else
  7044.       {
  7045.         //Leaf
  7046.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  7047.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  7048.       }
  7049.  
  7050. #ifdef INDSOFT
  7051.       //Very inefficient this but for testing I have to live with it...
  7052.       float node_eps_val = multipole[node*3 + 1].w;
  7053. #endif
  7054.  
  7055. #ifdef IMPBH
  7056.       //Improved barnes hut version
  7057.       float4 nodeCOM     = multipole[node*3 + 0];
  7058.       nodeCOM.w = nodeCenter.w;
  7059.  
  7060. #ifdef INDSOFT
  7061.       bool split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  7062. #else
  7063.       bool split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  7064. #endif
  7065.  
  7066. #else
  7067.       //Minimal distance version
  7068.  
  7069. #ifdef INDSOFT
  7070.       bool split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  7071. #else
  7072.       bool split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  7073. #endif
  7074.  
  7075. #endif
  7076.       //       printf("Node %d is a leaf: %d  en childinfo: %d  \t\t-> %d en %d \t split: %d\n", node, leaf, childinfo, child, nchild, split);
  7077.       //          split = false;
  7078.       uint temp =0;
  7079.       //if split & node add children to next lvl stack
  7080.       if(split && !leaf)
  7081.       {
  7082.         for(int i=child; i < child+nchild; i++)
  7083.         {
  7084.           nextLevel.push_back(i);
  7085.         }
  7086.  
  7087.         temp = childNodeOffset | (nchild << 28);
  7088.         //Update reference to children
  7089.         childNodeOffset += nchild;
  7090.       }
  7091.  
  7092.       //if split & leaf add particles to particle list
  7093.       if(split && leaf)
  7094.       {
  7095.         for(int i=child; i < child+nchild; i++)
  7096.         {
  7097.           particles.push_back(bodies[i]);
  7098.           massSum += bodies[i].w;
  7099.         }
  7100.  
  7101.         temp = childParticleOffset | ((nchild-1) << LEAFBIT);
  7102.         childParticleOffset += nchild;
  7103.       }
  7104.  
  7105.  
  7106.       //Add the node data to the appropriate arrays
  7107.       //and modify the node reference
  7108.       //start ofset for its children, should be nodeCount at start of this level +numberofnodes on this level
  7109.       //plus a counter that counts the number of childs of the nodes we have tested
  7110.  
  7111.       //New childoffset:
  7112.       union{int i; float f;} itof; //__int_as_float
  7113.       itof.i           = temp;
  7114.       float tempConv = itof.f;
  7115.  
  7116.       //Add node properties and update references
  7117.       real4 nodeSizeInfoTemp  = nodeSizeInfo[node];
  7118.       nodeSizeInfoTemp.w      = tempConv;             //Replace child reference
  7119.       nodeSizeData.push_back(nodeSizeInfoTemp);
  7120.  
  7121.  
  7122.       multipoleData.push_back(multipole[node*3 + 0]);
  7123.       multipoleData.push_back(multipole[node*3 + 1]);
  7124.       multipoleData.push_back(multipole[node*3 + 2]);
  7125.  
  7126.       if(!split)
  7127.       {
  7128.         massSum += multipole[node*3 + 0].w;
  7129.       }
  7130.  
  7131.  
  7132.     } //end for curLevel.size
  7133.  
  7134.  
  7135.     //Put next level stack into current level and continue
  7136.     curLevel.clear();
  7137.  
  7138.     //       cout << "Next level: " << nextLevel.size() << endl;
  7139.     curLevel.assign(nextLevel.begin(), nextLevel.end());
  7140.     nextLevel.clear();
  7141.  
  7142.  
  7143.   }//end while
  7144.  
  7145.   cout << "New tree structure: bodies: " << particles.size() << "\tnodes: " << nodeSizeData.size() << "\t took: " << get_time() -t1 << endl;
  7146.   cout << "Mass sum: " << massSum << endl;
  7147.   cout << "Mass sumtest: " << multipole[0*0 + 0].w << endl;
  7148.  
  7149. }
  7150.  
  7151. #if 1
  7152.  
  7153. typedef struct{
  7154.   int nodeID;
  7155.   vector<int> coarseIDs;
  7156. } combNodeCheck;
  7157.  
  7158.  
  7159. //void octree::create_local_essential_tree_fill(real4* bodies, real4* velocities, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  7160. //                                         double4 boxCenter, double4 boxSize, float group_eps, int start, int end,
  7161. //                                         int particleCount, int nodeCount, real4 *dataBuffer)
  7162. void octree::create_local_essential_tree_fill(real4* bodies, real4* velocities, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  7163.     int remoteId, float group_eps, int start, int end,
  7164.     int particleCount, int nodeCount, real4 *dataBuffer)
  7165. {
  7166.  
  7167. #if 1
  7168.   create_local_essential_tree_fill_novector_startend4(bodies, velocities, multipole, nodeSizeInfo, nodeCenterInfo,
  7169.       remoteId, group_eps, start, end,
  7170.       particleCount, nodeCount, dataBuffer);
  7171.  
  7172.   return;
  7173.  
  7174.  
  7175. #endif
  7176.  
  7177.   //Walk the tree as is done on device, level by level
  7178.   vector<combNodeCheck> curLevel;
  7179.   vector<combNodeCheck> nextLevel;
  7180.  
  7181.   curLevel.reserve(1024*128);
  7182.   nextLevel.reserve(1024*128);
  7183.  
  7184.   vector<int> coarseIDs;
  7185.   //     double t1 = get_time();
  7186.  
  7187.   double massSum = 0;
  7188.  
  7189.   int particleOffset     = 1;
  7190.   int velParticleOffset  = particleOffset      + particleCount;
  7191.   int nodeSizeOffset     = velParticleOffset   + particleCount;
  7192.   int nodeCenterOffset   = nodeSizeOffset      + nodeCount;
  7193.   int multiPoleOffset    = nodeCenterOffset    + nodeCount;
  7194.  
  7195.   //|real4| 2*particleCount*real4| nodes*real4 | nodes*real4 | nodes*3*real4 |
  7196.   //Info about #particles, #nodes, start and end of tree-walk
  7197.   //The particle positions and velocities
  7198.   //The nodeSizeData
  7199.   //The nodeCenterData
  7200.   //The multipole data
  7201.  
  7202.   //Add the initial coarse boxes to this level
  7203.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  7204.   {
  7205.     coarseIDs.push_back(globalCoarseGrpOffsets[remoteId] + i);
  7206.   }
  7207.  
  7208.   //Add the initial nodes to the curLevel list
  7209.   for(int i=start; i < end; i++)
  7210.   {
  7211.     combNodeCheck check;
  7212.     check.nodeID    = i;
  7213.     check.coarseIDs = coarseIDs;
  7214.     curLevel.push_back(check);
  7215.   }
  7216.  
  7217.   //Add the nodes before the start and end to the node list
  7218.   for(int i=0; i < start; i++)
  7219.   {
  7220.     dataBuffer[nodeSizeOffset++]   = nodeSizeInfo[i];
  7221.     dataBuffer[nodeCenterOffset++] = nodeCenterInfo[i];
  7222.  
  7223.     dataBuffer[multiPoleOffset++]  = multipole[i*3 + 0];
  7224.     dataBuffer[multiPoleOffset++]  = multipole[i*3 + 1];
  7225.     dataBuffer[multiPoleOffset++]  = multipole[i*3 + 2];
  7226.   }
  7227.  
  7228.   //Start the tree-walk
  7229.   //Variables to rewrite the tree-structure indices
  7230.   int childNodeOffset         = end;
  7231.   int childParticleOffset     = 0;
  7232.  
  7233.  
  7234.   while(curLevel.size() > 0)
  7235.   {
  7236.     for(unsigned int i=0; i < curLevel.size(); i++)
  7237.     {
  7238.       //Read node data
  7239.       //Read node data
  7240.       combNodeCheck check = curLevel[i];
  7241.       int node           = check.nodeID;
  7242.  
  7243.       real4 nodeCenter = nodeCenterInfo[node];
  7244.       real4 nodeSize   = nodeSizeInfo[node];
  7245.       bool leaf        = nodeCenter.w <= 0;
  7246.  
  7247.       union{float f; int i;} u; //__float_as_int
  7248.       u.f           = nodeSize.w;
  7249.       int childinfo = u.i;
  7250.  
  7251.       int child, nchild;
  7252.       if(!leaf)
  7253.       {
  7254.         //Node
  7255.         child    =    childinfo & 0x0FFFFFFF;                   //Index to the first child of the node
  7256.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  7257.       }
  7258.       else
  7259.       {
  7260.         //Leaf
  7261.         child   =    childinfo & BODYMASK;                     //the first body in the leaf
  7262.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  7263.       }
  7264.  
  7265.       bool split = false;
  7266.  
  7267. #ifdef INDSOFT
  7268.       //Very inefficient this but for testing I have to live with it...
  7269.       float node_eps_val = multipole[node*3 + 1].w;
  7270. #endif
  7271.  
  7272. #if 0
  7273.       double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  7274.         0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  7275.         0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  7276.       double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  7277.         fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  7278.         fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  7279.  
  7280. #ifdef IMPBH
  7281.       //Improved barnes hut version
  7282.       float4 nodeCOM     = multipole[node*3 + 0];
  7283.       nodeCOM.w = nodeCenter.w;
  7284.  
  7285. #ifdef INDSOFT
  7286.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  7287. #else
  7288.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  7289. #endif
  7290. #else
  7291.       //Minimal distance version
  7292. #ifdef INDSOFT
  7293.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  7294. #else
  7295.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  7296. #endif
  7297. #endif //if IMPBH
  7298.  
  7299. #else
  7300.  
  7301.       vector<int> checkIDs;
  7302.       bool curSplit = false;
  7303.  
  7304.       for(int k=0; k < check.coarseIDs.size(); k++)
  7305.       {
  7306.         //Read box info
  7307.         int coarseGrpId = check.coarseIDs[k];
  7308.  
  7309.         double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  7310.         double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  7311.  
  7312. #ifdef IMPBH
  7313.         //Improved barnes hut version
  7314.         float4 nodeCOM     = multipole[node*3 + 0];
  7315.         nodeCOM.w = nodeCenter.w;
  7316.  
  7317. #ifdef INDSOFT
  7318.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  7319. #else
  7320.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  7321. #endif
  7322.  
  7323. #else
  7324.         //Minimal distance version
  7325.  
  7326. #ifdef INDSOFT
  7327.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  7328. #else
  7329.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  7330. #endif
  7331. #endif //if IMPBH
  7332.  
  7333.         //Early out if at least one box requires this info
  7334.         if(curSplit){
  7335.           split = true;
  7336.           checkIDs.push_back(coarseGrpId);
  7337.           //              splitIdxToUse = k;
  7338.           //              LOGF(stderr, "LET count On level: %d\tNode: %d\tStart: %d\tEnd: %d\tChecks: %d \n",
  7339.           //                  level,node, startCoarseBox, splitIdxToUse, splitIdxToUse-startCoarseBox+1);
  7340.  
  7341.           //              extraChecks += splitIdxToUse-startCoarseBox;
  7342.           //              break;
  7343.         }
  7344.       } //For globalCoarseGrpCount[remoteId]
  7345. #endif
  7346.  
  7347.  
  7348.       uint temp = 0;  //A node that is not split and is not a leaf will get childinfo 0
  7349.       //if split & node add children to next lvl stack
  7350.       if(split && !leaf)
  7351.       {
  7352.         for(int i=child; i < child+nchild; i++)
  7353.         {
  7354.           combNodeCheck check;
  7355.           check.nodeID    = i;
  7356.           check.coarseIDs = checkIDs;
  7357.           nextLevel.push_back(check);
  7358.         }
  7359.  
  7360.         temp = childNodeOffset | (nchild << 28);
  7361.         //Update reference to children
  7362.         childNodeOffset += nchild;
  7363.       }
  7364.  
  7365.       //if split & leaf add particles to particle list
  7366.       if(split && leaf)
  7367.       {
  7368.         for(int i=child; i < child+nchild; i++)
  7369.         {
  7370.           dataBuffer[particleOffset++] = bodies[i];
  7371.           dataBuffer[velParticleOffset++] = velocities[i];
  7372.           massSum += bodies[i].w;
  7373.         }
  7374.  
  7375.         temp = childParticleOffset | ((nchild-1) << LEAFBIT);
  7376.         childParticleOffset += nchild;
  7377.       }
  7378.  
  7379.  
  7380.  
  7381.       //Add the node data to the appropriate arrays and modify the node reference
  7382.       //start ofset for its children, should be nodeCount at start of this level +numberofnodes on this level
  7383.       //plus a counter that counts the number of childs of the nodes we have tested
  7384.  
  7385.       //New childoffset:
  7386.       union{int i; float f;} itof; //__int_as_float
  7387.       itof.i         = temp;
  7388.       float tempConv = itof.f;
  7389.  
  7390.       //Add node properties and update references
  7391.       real4 nodeSizeInfoTemp  = nodeSizeInfo[node];
  7392.       nodeSizeInfoTemp.w      = tempConv;             //Replace child reference
  7393.  
  7394.       dataBuffer[nodeSizeOffset++]   = nodeSizeInfoTemp;
  7395.       dataBuffer[nodeCenterOffset++] = nodeCenterInfo[node];
  7396.       dataBuffer[multiPoleOffset++]  = multipole[node*3 + 0];
  7397.       dataBuffer[multiPoleOffset++]  = multipole[node*3 + 1];
  7398.       dataBuffer[multiPoleOffset++]  = multipole[node*3 + 2];
  7399.  
  7400.       if(!split)
  7401.       {
  7402.         massSum += multipole[node*3 + 0].w;
  7403.       }
  7404.     } //end for curLevel.size
  7405.  
  7406.     //Put next level stack into current level and continue
  7407.     curLevel.clear();
  7408.  
  7409.     //       cout << "Next level: " << nextLevel.size() << endl;
  7410.     curLevel.assign(nextLevel.begin(), nextLevel.end());
  7411.     nextLevel.clear();
  7412.  
  7413.   }//end while
  7414.  
  7415.   //   cout << "New offsets: "  << particleOffset << " \t" << nodeSizeOffset << " \t" << nodeCenterOffset << endl;
  7416.   //    cout << "Mass sum: " << massSum  << endl;
  7417.   //   cout << "Mass sumtest: " << multipole[0*0 + 0].w << endl;
  7418. }
  7419.  
  7420. #else
  7421.  
  7422. //void octree::create_local_essential_tree_fill(real4* bodies, real4* velocities, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  7423. //                                         double4 boxCenter, double4 boxSize, float group_eps, int start, int end,
  7424. //                                         int particleCount, int nodeCount, real4 *dataBuffer)
  7425. void octree::create_local_essential_tree_fill(real4* bodies, real4* velocities, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  7426.     int remoteId, float group_eps, int start, int end,
  7427.     int particleCount, int nodeCount, real4 *dataBuffer)
  7428. {
  7429.   //Walk the tree as is done on device, level by level
  7430.   vector<int> curLevel;
  7431.   vector<int> nextLevel;
  7432.  
  7433.  
  7434.   //     double t1 = get_time();
  7435.  
  7436.   double massSum = 0;
  7437.  
  7438.   int particleOffset     = 1;
  7439.   int velParticleOffset  = particleOffset      + particleCount;
  7440.   int nodeSizeOffset     = velParticleOffset   + particleCount;
  7441.   int nodeCenterOffset   = nodeSizeOffset      + nodeCount;
  7442.   int multiPoleOffset    = nodeCenterOffset    + nodeCount;
  7443.  
  7444.   //|real4| 2*particleCount*real4| nodes*real4 | nodes*real4 | nodes*3*real4 |
  7445.   //Info about #particles, #nodes, start and end of tree-walk
  7446.   //The particle positions and velocities
  7447.   //The nodeSizeData
  7448.   //The nodeCenterData
  7449.   //The multipole data
  7450.  
  7451.   //Add the initial nodes to the curLevel list
  7452.   for(int i=start; i < end; i++)
  7453.   {
  7454.     curLevel.push_back(i);
  7455.   }
  7456.  
  7457.   //Add the nodes before the start and end to the node list
  7458.   for(int i=0; i < start; i++)
  7459.   {
  7460.     dataBuffer[nodeSizeOffset++]   = nodeSizeInfo[i];
  7461.     dataBuffer[nodeCenterOffset++] = nodeCenterInfo[i];
  7462.  
  7463.     dataBuffer[multiPoleOffset++]  = multipole[i*3 + 0];
  7464.     dataBuffer[multiPoleOffset++]  = multipole[i*3 + 1];
  7465.     dataBuffer[multiPoleOffset++]  = multipole[i*3 + 2];
  7466.   }
  7467.  
  7468.   //Start the tree-walk
  7469.   //Variables to rewrite the tree-structure indices
  7470.   int childNodeOffset         = end;
  7471.   int childParticleOffset     = 0;
  7472.  
  7473.  
  7474.   while(curLevel.size() > 0)
  7475.   {
  7476.     for(unsigned int i=0; i < curLevel.size(); i++)
  7477.     {
  7478.       //Read node data
  7479.       int node         = curLevel[i];
  7480.       real4 nodeCenter = nodeCenterInfo[node];
  7481.       real4 nodeSize   = nodeSizeInfo[node];
  7482.       bool leaf        = nodeCenter.w <= 0;
  7483.  
  7484.       union{float f; int i;} u; //__float_as_int
  7485.       u.f           = nodeSize.w;
  7486.       int childinfo = u.i;
  7487.  
  7488.       int child, nchild;
  7489.       if(!leaf)
  7490.       {
  7491.         //Node
  7492.         child    =    childinfo & 0x0FFFFFFF;                   //Index to the first child of the node
  7493.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  7494.       }
  7495.       else
  7496.       {
  7497.         //Leaf
  7498.         child   =    childinfo & BODYMASK;                     //the first body in the leaf
  7499.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  7500.       }
  7501.  
  7502. #ifdef INDSOFT
  7503.       //Very inefficient this but for testing I have to live with it...
  7504.       float node_eps_val = multipole[node*3 + 1].w;
  7505. #endif
  7506. #if 0
  7507. #ifdef IMPBH
  7508.       //Improved barnes hut version
  7509.       float4 nodeCOM     = multipole[node*3 + 0];
  7510.       nodeCOM.w = nodeCenter.w;
  7511.  
  7512. #ifdef INDSOFT
  7513.       bool split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  7514. #else
  7515.       bool split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  7516. #endif
  7517.  
  7518. #else
  7519.       //Minimal distance version
  7520. #ifdef INDSOFT
  7521.       bool split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  7522. #else
  7523.       bool split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  7524. #endif
  7525.  
  7526. #endif
  7527.  
  7528. #endif //if0
  7529.  
  7530.       bool split = false;
  7531. #if 0
  7532.       double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  7533.         0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  7534.         0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  7535.       double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  7536.         fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  7537.         fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  7538.  
  7539. #ifdef IMPBH
  7540.       //Improved barnes hut version
  7541.       float4 nodeCOM     = multipole[node*3 + 0];
  7542.       nodeCOM.w = nodeCenter.w;
  7543.  
  7544. #ifdef INDSOFT
  7545.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  7546. #else
  7547.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  7548. #endif
  7549. #else
  7550.       //Minimal distance version
  7551. #ifdef INDSOFT
  7552.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  7553. #else
  7554.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  7555. #endif
  7556. #endif //if IMPBH
  7557.  
  7558. #else
  7559.       for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  7560.       {
  7561.         //Compute this specific box...kinda expensive should just
  7562.         //make this list when receiving it and look it up.
  7563.         //For now just using for testing method
  7564.         //TODO NOTE BUG ERROR
  7565.         int coarseGrpId = globalCoarseGrpOffsets[remoteId] + i;
  7566.  
  7567.         double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  7568.         double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  7569.  
  7570. #ifdef IMPBH
  7571.         //Improved barnes hut version
  7572.         float4 nodeCOM     = multipole[node*3 + 0];
  7573.         nodeCOM.w = nodeCenter.w;
  7574.  
  7575. #ifdef INDSOFT
  7576.         split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  7577. #else
  7578.         split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  7579. #endif
  7580.  
  7581. #else
  7582.         //Minimal distance version
  7583.  
  7584. #ifdef INDSOFT
  7585.         split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  7586. #else
  7587.         split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  7588. #endif
  7589. #endif //if IMPBH
  7590.  
  7591.         //Early out if at least one box requires this info
  7592.         if(split) break;
  7593.       } //For globalCoarseGrpCount[remoteId]
  7594. #endif
  7595.  
  7596.  
  7597.       uint temp = 0;  //A node that is not split and is not a leaf will get childinfo 0
  7598.       //if split & node add children to next lvl stack
  7599.       if(split && !leaf)
  7600.       {
  7601.         for(int i=child; i < child+nchild; i++)
  7602.         {
  7603.           nextLevel.push_back(i);
  7604.         }
  7605.  
  7606.         temp = childNodeOffset | (nchild << 28);
  7607.         //Update reference to children
  7608.         childNodeOffset += nchild;
  7609.       }
  7610.  
  7611.       //if split & leaf add particles to particle list
  7612.       if(split && leaf)
  7613.       {
  7614.         for(int i=child; i < child+nchild; i++)
  7615.         {
  7616.           dataBuffer[particleOffset++] = bodies[i];
  7617.           dataBuffer[velParticleOffset++] = velocities[i];
  7618.           massSum += bodies[i].w;
  7619.         }
  7620.  
  7621.         temp = childParticleOffset | ((nchild-1) << LEAFBIT);
  7622.         childParticleOffset += nchild;
  7623.       }
  7624.  
  7625.  
  7626.  
  7627.       //Add the node data to the appropriate arrays and modify the node reference
  7628.       //start ofset for its children, should be nodeCount at start of this level +numberofnodes on this level
  7629.       //plus a counter that counts the number of childs of the nodes we have tested
  7630.  
  7631.       //New childoffset:
  7632.       union{int i; float f;} itof; //__int_as_float
  7633.       itof.i         = temp;
  7634.       float tempConv = itof.f;
  7635.  
  7636.       //Add node properties and update references
  7637.       real4 nodeSizeInfoTemp  = nodeSizeInfo[node];
  7638.       nodeSizeInfoTemp.w      = tempConv;             //Replace child reference
  7639.  
  7640.       dataBuffer[nodeSizeOffset++]   = nodeSizeInfoTemp;
  7641.       dataBuffer[nodeCenterOffset++] = nodeCenterInfo[node];
  7642.       dataBuffer[multiPoleOffset++]  = multipole[node*3 + 0];
  7643.       dataBuffer[multiPoleOffset++]  = multipole[node*3 + 1];
  7644.       dataBuffer[multiPoleOffset++]  = multipole[node*3 + 2];
  7645.  
  7646.       if(!split)
  7647.       {
  7648.         massSum += multipole[node*3 + 0].w;
  7649.       }
  7650.     } //end for curLevel.size
  7651.  
  7652.     //Put next level stack into current level and continue
  7653.     curLevel.clear();
  7654.  
  7655.     //       cout << "Next level: " << nextLevel.size() << endl;
  7656.     curLevel.assign(nextLevel.begin(), nextLevel.end());
  7657.     nextLevel.clear();
  7658.  
  7659.   }//end while
  7660.  
  7661.   //   cout << "New offsets: "  << particleOffset << " \t" << nodeSizeOffset << " \t" << nodeCenterOffset << endl;
  7662.   //    cout << "Mass sum: " << massSum  << endl;
  7663.   //   cout << "Mass sumtest: " << multipole[0*0 + 0].w << endl;
  7664. }
  7665. #endif
  7666.  
  7667. #if 0
  7668. //Does not work,this one tries to order the boxes so the one needed is up front
  7669.  
  7670. //void octree::create_local_essential_tree_count(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  7671. //                                         double4 boxCenter, double4 boxSize, float group_eps, int start, int end,
  7672. //                                         int &particles, int &nodes)
  7673. void octree::create_local_essential_tree_count(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  7674.     int remoteId, float group_eps, int start, int end,
  7675.     int &particles, int &nodes)
  7676. {
  7677.  
  7678.   //Walk the tree as is done on device, level by level
  7679.   vector<combNodeCheck> curLevel;
  7680.   vector<combNodeCheck> nextLevel;
  7681.  
  7682.   curLevel.reserve(1024*128);
  7683.   nextLevel.reserve(1024*128);
  7684.  
  7685.   vector<int> coarseIDs;
  7686.  
  7687.   int particleCount   = 0;
  7688.   int nodeCount       = 0;
  7689.  
  7690.   int level           = 0;
  7691.  
  7692.   int extraChecks = 0;
  7693.   int uselessChecks = 0;
  7694.   int splitChecks = 0;
  7695.  
  7696.   LOGF(stderr,"Test loop value: %d", this->globalCoarseGrpCount[remoteId]);
  7697.  
  7698.  
  7699.  
  7700.   //Add the initial coarse boxes to this level
  7701.   for(int i=0; i < this->globalCoarseGrpCount[remoteId]; i++)
  7702.   {
  7703.     coarseIDs.push_back(this->globalCoarseGrpOffsets[remoteId] + i);
  7704.   }
  7705.  
  7706.   //Add the initial nodes to the curLevel list
  7707.   for(int i=start; i < end; i++)
  7708.   {
  7709.     combNodeCheck check;
  7710.     check.nodeID    = i;
  7711.     check.coarseIDs = coarseIDs;
  7712.     curLevel.push_back(check);
  7713.   }
  7714.  
  7715.   //Add the nodes before the start and end to the node list
  7716.   for(int i=0; i < start; i++)
  7717.   {
  7718.     nodeCount++;
  7719.   }
  7720.  
  7721.   //Start the tree-walk
  7722.   while(curLevel.size() > 0)
  7723.   {
  7724.     for(unsigned int i=0; i < curLevel.size(); i++)
  7725.     {
  7726.       //Read node data
  7727.       combNodeCheck check = curLevel[i];
  7728.       int node           = check.nodeID;
  7729.  
  7730.       //        LOGF(stderr, "LET count On level: %d\tNode: %d\tGoing to check: %d\n",
  7731.       //                          level,node, check.coarseIDs.size());
  7732.  
  7733.       real4 nodeCenter = nodeCenterInfo[node];
  7734.       real4 nodeSize   = nodeSizeInfo[node];
  7735.       bool leaf        = nodeCenter.w <= 0;
  7736.  
  7737.       union{float f; int i;} u; //__float_as_int
  7738.       u.f           = nodeSize.w;
  7739.       int childinfo = u.i;
  7740.  
  7741.       int child, nchild;
  7742.       if(!leaf)
  7743.       {
  7744.         //Node
  7745.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  7746.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  7747.       }
  7748.       else
  7749.       {
  7750.         //Leaf
  7751.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  7752.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  7753.       }
  7754.  
  7755.       bool split = false;
  7756.  
  7757.       int splitIdxToUse = 0;
  7758.  
  7759.       splitChecks++;
  7760.  
  7761.       vector<int> checkIDs;
  7762.       bool curSplit = false;
  7763.  
  7764.       //        for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  7765.       float ds2;
  7766.       float ds2min = 10e10f;
  7767.       int   ds2min_idx = -1;
  7768.  
  7769.       for(int k=0; k < check.coarseIDs.size(); k++)
  7770.       {
  7771.         extraChecks++;
  7772.         //  particleCount++;
  7773.         //Test this specific box
  7774.         int coarseGrpId = check.coarseIDs[k];
  7775.  
  7776.         if(coarseGrpId < 0) LOGF(stderr,"FAIIIIIIIIIIIIIIIIIIL %d \n", coarseGrpId);
  7777.  
  7778.         double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  7779.         double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  7780.  
  7781.  
  7782. #ifdef IMPBH
  7783.         //Improved barnes hut version
  7784.         float4 nodeCOM     = multipole[node*3 + 0];
  7785.         nodeCOM.w = nodeCenter.w;
  7786.  
  7787. #ifdef INDSOFT
  7788.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  7789. #else
  7790.         curSplit = split_node_grav_impbh_SFCtest(nodeCOM, boxCenter, boxSize, ds2);
  7791.         //              curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  7792. #endif
  7793.  
  7794. #else
  7795.         //Minimal distance version
  7796.  
  7797. #ifdef INDSOFT
  7798.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  7799. #else
  7800.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  7801. #endif
  7802. #endif //if IMPBH
  7803.  
  7804.         //Early out if at least one box requires this info
  7805.         if(curSplit){
  7806.           split = true;
  7807.  
  7808.           //            if(0)
  7809.           if(level < 2)
  7810.           {
  7811.             //Stop right away
  7812.             checkIDs.insert(checkIDs.begin(), &check.coarseIDs[k], &check.coarseIDs[0]+check.coarseIDs.size());
  7813.             break;
  7814.  
  7815.           }
  7816.           else
  7817.           {
  7818.             //Now order checkIDs
  7819.             if(ds2 < ds2min)
  7820.             {
  7821.               checkIDs.insert(checkIDs.begin(),coarseGrpId);
  7822.               //                LOGF(stderr,"TestSmaller: %f %f \t %d", ds2min, ds2, ds2min_idx);
  7823.               ds2min = ds2;
  7824.               //                ds2min_idx = coarseGrpId;
  7825.  
  7826.             }
  7827.             else
  7828.             {
  7829.               //                LOGF(stderr,"FAILED: %f %f \t %d", ds2min, ds2, ds2min_idx);
  7830.             }
  7831.           }//level > 30
  7832.           //              splitIdxToUse = k;
  7833.           //              LOGF(stderr, "LET count On level: %d\tNode: %d\tStart: %d\tEnd: %d\tChecks: %d \n",
  7834.           //                  level,node, startCoarseBox, splitIdxToUse, splitIdxToUse-startCoarseBox+1);
  7835.  
  7836.           //              extraChecks += splitIdxToUse-startCoarseBox;
  7837.           //              break;
  7838.         }//if curSplit
  7839.       } //For globalCoarseGrpCount[remoteId]
  7840.  
  7841.       //        if(ds2min_idx >= 0)
  7842.       //        checkIDs.push_back(ds2min_idx);
  7843.       //        if(ds2min_idx < 0)
  7844.       //        {
  7845.       //          LOGF(stderr, "ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRROR %f %d split: %d\n", ds2min, ds2min_idx, split);
  7846.       //        }
  7847.  
  7848.       if(split == false)
  7849.       {
  7850.         //          uselessChecks +=  boxIndicesToUse.size()-startCoarseBox;
  7851.       }
  7852.  
  7853.       //if split & node add children to next lvl stack
  7854.       if(split && !leaf)
  7855.       {
  7856.         for(int i=child; i < child+nchild; i++)
  7857.         {
  7858.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  7859.           combNodeCheck check;
  7860.           check.nodeID    = i;
  7861.           check.coarseIDs = checkIDs;
  7862.           nextLevel.push_back(check);
  7863.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  7864.         }
  7865.       }
  7866.  
  7867.       //if split & leaf add particles to particle list
  7868.       if(split && leaf)
  7869.       {
  7870.         for(int i=child; i < child+nchild; i++)
  7871.         {
  7872.           particleCount++;
  7873.         }
  7874.       }
  7875.  
  7876.       //Increase the nodeCount, since this node will be part of the tree-structure
  7877.       nodeCount++;
  7878.     } //end for curLevel.size
  7879.  
  7880.  
  7881.     //Put next level stack into current level and continue
  7882.     curLevel.clear();
  7883.  
  7884.     //       cout << "Next level: " << nextLevel.size() << endl;
  7885.     curLevel.assign(nextLevel.begin(), nextLevel.end());
  7886.     nextLevel.clear();
  7887.     level++;
  7888.   }//end while
  7889.  
  7890.   particles = particleCount;
  7891.   nodes     = nodeCount;
  7892.  
  7893.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  7894.  
  7895.   /*    fprintf(stderr, "Count found: %d particles and %d nodes. Boxsize: (%f %f %f ) BoxCenter: (%f %f %f)\n",
  7896.         particles, nodes, boxSize.x ,boxSize.y, boxSize.z, boxCenter.x, boxCenter.y, boxCenter.z );  */
  7897. }
  7898.  
  7899. #endif
  7900.  
  7901. #if 1
  7902. //This one goes over all coarse grps and removes the ones where the split
  7903. //fails. Does test them all
  7904.  
  7905. //void octree::create_local_essential_tree_count(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  7906. //                                         double4 boxCenter, double4 boxSize, float group_eps, int start, int end,
  7907. //                                         int &particles, int &nodes)
  7908. void octree::create_local_essential_tree_count(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  7909.     int remoteId, float group_eps, int start, int end,
  7910.     int &particles, int &nodes)
  7911. {
  7912.   globalCHECKCount = 0;
  7913. #if 0
  7914.   create_local_essential_tree_count_recursive(
  7915.       bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  7916.       remoteId, group_eps, start, end, particles, nodes);
  7917.  
  7918.   LOGF(stderr,"LET Number of total CHECKS: %d \n", globalCHECKCount);
  7919.   return;
  7920.  
  7921. #elif 0
  7922.  
  7923.   //Fastest so far, but recursive
  7924.   create_local_essential_tree_count_recursive_try2(
  7925.       bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  7926.       remoteId, group_eps, start, end, particles, nodes);
  7927.  
  7928.   LOGF(stderr,"LET Number of total CHECKS: %d \n", globalCHECKCount);
  7929.   return;
  7930.  
  7931. #elif 0
  7932.   create_local_essential_tree_count_novector(bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  7933.       remoteId, group_eps, start, end, particles, nodes);
  7934.   LOGF(stderr,"LET Number of total CHECKS: %d \n", globalCHECKCount);
  7935.   return;
  7936.  
  7937. #elif 0
  7938.   create_local_essential_tree_count_vector_filter(bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  7939.       remoteId, group_eps, start, end, particles, nodes);
  7940.   LOGF(stderr,"LET Number of total CHECKS: %d \n", globalCHECKCount);
  7941.   return;
  7942.  
  7943.  
  7944. #elif 0
  7945.  
  7946.   //Was the Fastest non-recursive version untill create_local_essential_tree_count_novector_startend4
  7947.   create_local_essential_tree_count_novector_startend(bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  7948.       remoteId, group_eps, start, end, particles, nodes);
  7949.   LOGF(stderr,"LET Number of total CHECKS: %d \n", globalCHECKCount);
  7950.  
  7951.   return;
  7952.  
  7953. #elif 0
  7954.  
  7955.   //SLOW
  7956.   create_local_essential_tree_count_novector_startend2(bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  7957.       remoteId, group_eps, start, end, particles, nodes);
  7958.   LOGF(stderr,"LET Number of total CHECKS: %d \n", globalCHECKCount);
  7959.  
  7960.   return;
  7961.  
  7962. #elif 0
  7963.  
  7964.   //Second best
  7965.   create_local_essential_tree_count_novector_startend3(bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  7966.       remoteId, group_eps, start, end, particles, nodes);
  7967.   LOGF(stderr,"LET Number of total CHECKS: %d \n", globalCHECKCount);
  7968.  
  7969.   return;
  7970.  
  7971. #elif 1
  7972.  
  7973.   //Fastest so far, it sorts the boxes by putting most used ones in the back
  7974.   //Which reduces opening checks. Since there should be less unneeded checks
  7975.   //on the deeper levels of the tree
  7976.   create_local_essential_tree_count_novector_startend4(bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  7977.       remoteId, group_eps, start, end, particles, nodes);
  7978.   LOGF(stderr,"LET Number of total CHECKS: %d \n", globalCHECKCount);
  7979.  
  7980.   return;
  7981.  
  7982. #elif 0
  7983.  
  7984.   //Creates seperate box lists for differnt top nodes. Some sort of initial filter, does not help compared
  7985.   //to number startend4
  7986.   create_local_essential_tree_count_novector_startend5(bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  7987.       remoteId, group_eps, start, end, particles, nodes);
  7988.   LOGF(stderr,"LET Number of total CHECKS: %d \n", globalCHECKCount);
  7989.  
  7990.   return;
  7991.  
  7992. #endif
  7993.  
  7994.   //Walk the tree as is done on device, level by level
  7995.   vector<combNodeCheck> curLevel;
  7996.   vector<combNodeCheck> nextLevel;
  7997.  
  7998.   curLevel.reserve(1024*64);
  7999.   nextLevel.reserve(1024*64);
  8000.  
  8001.  
  8002.  
  8003.   int particleCount   = 0;
  8004.   int nodeCount       = 0;
  8005.  
  8006.   int level           = 0;
  8007.  
  8008.   int extraChecks = 0;
  8009.   int uselessChecks = 0;
  8010.   int splitChecks = 0;
  8011.  
  8012.   vector<int> coarseIDs;
  8013.   //Add the initial coarse boxes to this level
  8014.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8015.   {
  8016.     coarseIDs.push_back(globalCoarseGrpOffsets[remoteId] + i);
  8017.   }
  8018.  
  8019.   //Add the initial nodes to the curLevel list
  8020.   for(int i=start; i < end; i++)
  8021.   {
  8022.     combNodeCheck check;
  8023.     check.nodeID    = i;
  8024.     check.coarseIDs = coarseIDs;
  8025.     curLevel.push_back(check);
  8026.   }
  8027.  
  8028.   //Add the nodes before the start and end to the node list
  8029.   for(int i=0; i < start; i++)
  8030.   {
  8031.     nodeCount++;
  8032.   }
  8033.  
  8034.   //Start the tree-walk
  8035.   while(curLevel.size() > 0)
  8036.   {
  8037.     for(unsigned int i=0; i < curLevel.size(); i++)
  8038.     {
  8039.       //Read node data
  8040.       combNodeCheck check = curLevel[i];
  8041.       int node           = check.nodeID;
  8042.  
  8043.       //        LOGF(stderr, "LET count On level: %d\tNode: %d\tGoing to check: %d\n",
  8044.       //                          level,node, check.coarseIDs.size());
  8045.  
  8046.       real4 nodeCenter = nodeCenterInfo[node];
  8047.       real4 nodeSize   = nodeSizeInfo[node];
  8048.       bool leaf        = nodeCenter.w <= 0;
  8049.  
  8050.       union{float f; int i;} u; //__float_as_int
  8051.       u.f           = nodeSize.w;
  8052.       int childinfo = u.i;
  8053.  
  8054.       int child, nchild;
  8055.       if(!leaf)
  8056.       {
  8057.         //Node
  8058.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  8059.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  8060.       }
  8061.       else
  8062.       {
  8063.         //Leaf
  8064.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  8065.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  8066.       }
  8067.  
  8068. #ifdef INDSOFT
  8069.       //Very inefficient this but for testing I have to live with it...
  8070.       float node_eps_val = multipole[node*3 + 1].w;
  8071. #endif
  8072.  
  8073.  
  8074.       bool split = false;
  8075.  
  8076.       int splitIdxToUse = 0;
  8077.       vector<int> checkIDs;
  8078. #if 0
  8079.       splitChecks++;
  8080.       double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  8081.         0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  8082.         0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  8083.       double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  8084.         fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  8085.         fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  8086.  
  8087. #ifdef IMPBH
  8088.       //Improved barnes hut version
  8089.       float4 nodeCOM     = multipole[node*3 + 0];
  8090.       nodeCOM.w = nodeCenter.w;
  8091.  
  8092. #ifdef INDSOFT
  8093.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  8094. #else
  8095.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  8096. #endif
  8097. #else
  8098.       //Minimal distance version
  8099. #ifdef INDSOFT
  8100.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  8101. #else
  8102.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  8103. #endif
  8104. #endif //if IMPBH
  8105.  
  8106. #else
  8107.       splitChecks++;
  8108.  
  8109.  
  8110.       bool curSplit = false;
  8111.  
  8112.       //        for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8113.       for(int k=0; k < check.coarseIDs.size(); k++)
  8114.       {
  8115.         extraChecks++;
  8116.         //  particleCount++;
  8117.         //Test this specific box
  8118.         int coarseGrpId = check.coarseIDs[k];
  8119.  
  8120.         double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  8121.         double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  8122.  
  8123.  
  8124. #ifdef IMPBH
  8125.         //Improved barnes hut version
  8126.         float4 nodeCOM     = multipole[node*3 + 0];
  8127.         nodeCOM.w = nodeCenter.w;
  8128.  
  8129. #ifdef INDSOFT
  8130.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  8131. #else
  8132.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  8133. #endif
  8134.  
  8135. #else
  8136.         //Minimal distance version
  8137.  
  8138. #ifdef INDSOFT
  8139.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  8140. #else
  8141.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  8142. #endif
  8143. #endif //if IMPBH
  8144.  
  8145.         //Early out if at least one box requires this info
  8146.         if(curSplit){
  8147.           split = true;
  8148.  
  8149.           if(leaf) break;
  8150.  
  8151.           checkIDs.push_back(coarseGrpId);
  8152.           //              splitIdxToUse = k;
  8153.           //              LOGF(stderr, "LET count On level: %d\tNode: %d\tStart: %d\tEnd: %d\tChecks: %d \n",
  8154.           //                  level,node, startCoarseBox, splitIdxToUse, splitIdxToUse-startCoarseBox+1);
  8155.  
  8156.           //              extraChecks += splitIdxToUse-startCoarseBox;
  8157.           //              break;
  8158.         }
  8159.       } //For globalCoarseGrpCount[remoteId]
  8160.  
  8161.       if(split == false)
  8162.       {
  8163.         //          uselessChecks +=  boxIndicesToUse.size()-startCoarseBox;
  8164.       }
  8165.  
  8166. #endif
  8167.       //if split & node add children to next lvl stack
  8168.       if(split && !leaf)
  8169.       {
  8170.         for(int i=child; i < child+nchild; i++)
  8171.         {
  8172.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  8173.           combNodeCheck check;
  8174.           check.nodeID    = i;
  8175.           check.coarseIDs = checkIDs;
  8176.           nextLevel.push_back(check);
  8177.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  8178.         }
  8179.       }
  8180.  
  8181.       //if split & leaf add particles to particle list
  8182.       if(split && leaf)
  8183.       {
  8184.         for(int i=child; i < child+nchild; i++)
  8185.         {
  8186.           particleCount++;
  8187.         }
  8188.       }
  8189.  
  8190.       //Increase the nodeCount, since this node will be part of the tree-structure
  8191.       nodeCount++;
  8192.     } //end for curLevel.size
  8193.  
  8194.  
  8195.     //Put next level stack into current level and continue
  8196.     curLevel.clear();
  8197.  
  8198.     //       cout << "Next level: " << nextLevel.size() << endl;
  8199.     curLevel.assign(nextLevel.begin(), nextLevel.end());
  8200.     nextLevel.clear();
  8201.     level++;
  8202.   }//end while
  8203.  
  8204.   particles = particleCount;
  8205.   nodes     = nodeCount;
  8206.  
  8207.   LOGF(stderr,"LET Number of total CHECKS: %d \n", globalCHECKCount);
  8208.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  8209.  
  8210.   /*    fprintf(stderr, "Count found: %d particles and %d nodes. Boxsize: (%f %f %f ) BoxCenter: (%f %f %f)\n",
  8211.         particles, nodes, boxSize.x ,boxSize.y, boxSize.z, boxCenter.x, boxCenter.y, boxCenter.z );  */
  8212. }
  8213.  
  8214. typedef struct{
  8215.   int nodeID;
  8216.   int coarseIDOffset;
  8217. } combNodeCheck2;
  8218.  
  8219. void octree::create_local_essential_tree_count_novector(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  8220.     int remoteId, float group_eps, int start, int end,
  8221.     int &particles, int &nodes)
  8222. {
  8223.   //Walk the tree as is done on device, level by level
  8224.   //    vector<combNodeCheck> curLevel;
  8225.   //    vector<combNodeCheck> nextLevel;
  8226.  
  8227.   combNodeCheck2 *curLevel = new combNodeCheck2[1024*64];
  8228.   combNodeCheck2 *nextLevel = new combNodeCheck2[1024*64];
  8229.  
  8230.   int curLevelCount = 0;
  8231.   int nextLevelCount = 0;
  8232.  
  8233.  
  8234.   int particleCount   = 0;
  8235.   int nodeCount       = 0;
  8236.  
  8237.   int level           = 0;
  8238.  
  8239.   int extraChecks = 0;
  8240.   int uselessChecks = 0;
  8241.   int splitChecks = 0;
  8242.  
  8243.  
  8244.   double4 bigBoxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  8245.     0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  8246.     0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  8247.   double4 bigBoxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  8248.     fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  8249.     fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  8250.  
  8251.   //    vector<int> coarseIDs;
  8252.   //    //Add the initial coarse boxes to this level
  8253.   //    for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8254.   //    {
  8255.   //      coarseIDs.push_back(globalCoarseGrpOffsets[remoteId] + i);
  8256.   //    }
  8257.  
  8258.   int *coarseIDs = new int[globalCoarseGrpCount[remoteId]];
  8259.   //Add the initial coarse boxes to this level
  8260.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8261.   {
  8262.     coarseIDs[i] = globalCoarseGrpOffsets[remoteId] + i;
  8263.   }
  8264.  
  8265.   //Add the initial nodes to the curLevel list
  8266.   for(int i=start; i < end; i++)
  8267.   {
  8268.     combNodeCheck2 check;
  8269.     check.nodeID    = i;
  8270.     check.coarseIDOffset = 0;
  8271.     //      check.coarseIDs.insert(check.coarseIDs.begin(), coarseIDs, coarseIDs+globalCoarseGrpCount[remoteId]);
  8272.     curLevel[curLevelCount++] = check;
  8273.   }
  8274.  
  8275.   /*    //Filter out the initial boxes that will fail anyway
  8276.         for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8277.         {
  8278.   // coarseIDs[i] = globalCoarseGrpOffsets[remoteId] + i;
  8279.   bool split;
  8280.   for(int j=start; j < end; j++)
  8281.   {
  8282.   real4 nodeCenter  = nodeCenterInfo[j];
  8283.   real4 nodeSize    = nodeSizeInfo[j];
  8284.   double4 boxCenter = coarseGroupBoxCenter[coarseIDs[i]];
  8285.   double4 boxSize   = coarseGroupBoxSize  [coarseIDs[i]];
  8286.   float4 nodeCOM    = multipole[j*3 + 0];
  8287.   nodeCOM.w         = nodeCenter.w;
  8288.  
  8289.   split |= split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  8290.  
  8291.   if(!split_node_grav_impbh(nodeCOM, boxCenter, boxSize))
  8292.   {
  8293.   //          LOGF(stderr,"LET INITIAL Failed on box %d node: %d\n", i, j);
  8294.   }
  8295.   }
  8296.   if(split == false)
  8297.   {
  8298.   LOGF(stderr,"LET INITIAL Failed on %d \n", i);
  8299.   }
  8300.   }
  8301.   */
  8302.   curLevelCount = 0;
  8303.   //Add the initial nodes to the curLevel list
  8304.   for(int i=start; i < end; i++)
  8305.   {
  8306.     combNodeCheck2 check;
  8307.     check.nodeID    = i;
  8308.     check.coarseIDOffset = globalCoarseGrpCount[remoteId]+1; //Out of range default
  8309.  
  8310.     for(int j=0; j < globalCoarseGrpCount[remoteId]; j++)
  8311.     {
  8312.       real4 nodeCenter  = nodeCenterInfo[i];
  8313.       real4 nodeSize    = nodeSizeInfo[i];
  8314.       double4 boxCenter = coarseGroupBoxCenter[coarseIDs[j]];
  8315.       double4 boxSize   = coarseGroupBoxSize  [coarseIDs[j]];
  8316.       float4 nodeCOM    = multipole[j*3 + 0];
  8317.       nodeCOM.w         = nodeCenter.w;
  8318.  
  8319.       //Skip all previous not needed checks
  8320.       if(split_node_grav_impbh(nodeCOM, boxCenter, boxSize))
  8321.       {
  8322.         check.coarseIDOffset = j;
  8323.         //          LOGF(stderr,"LET INITIAL Start node: %d at grp %d \n", i, j);
  8324.         break;
  8325.       }
  8326.     }
  8327.     curLevel[curLevelCount++] = check;
  8328.   }
  8329.  
  8330.  
  8331.  
  8332.  
  8333.   //Add the nodes before the start and end to the node list
  8334.   for(int i=0; i < start; i++)
  8335.   {
  8336.     nodeCount++;
  8337.   }
  8338.  
  8339.   //Start the tree-walk
  8340.   while(curLevelCount > 0)
  8341.   {
  8342.     for(unsigned int i=0; i < curLevelCount; i++)
  8343.     {
  8344.       //Read node data
  8345.       combNodeCheck2 check = curLevel[i];
  8346.       int node           = check.nodeID;
  8347.  
  8348.       //        LOGF(stderr, "LET count On level: %d\tNode: %d\tGoing to check: %d\n",
  8349.       //                          level,node, check.coarseIDs.size());
  8350.  
  8351.       real4 nodeCenter = nodeCenterInfo[node];
  8352.       real4 nodeSize   = nodeSizeInfo[node];
  8353.       bool leaf        = nodeCenter.w <= 0;
  8354.  
  8355.       union{float f; int i;} u; //__float_as_int
  8356.       u.f           = nodeSize.w;
  8357.       int childinfo = u.i;
  8358.  
  8359.       int child, nchild;
  8360.       if(!leaf)
  8361.       {
  8362.         //Node
  8363.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  8364.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  8365.       }
  8366.       else
  8367.       {
  8368.         //Leaf
  8369.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  8370.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  8371.       }
  8372.  
  8373. #ifdef INDSOFT
  8374.       //Very inefficient this but for testing I have to live with it...
  8375.       float node_eps_val = multipole[node*3 + 1].w;
  8376. #endif
  8377.  
  8378.  
  8379.       bool split = false;
  8380.  
  8381.       int splitIdxToUse = 0;
  8382.       //        vector<int> checkIDs;
  8383. #if 0
  8384.       splitChecks++;
  8385.       double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  8386.         0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  8387.         0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  8388.       double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  8389.         fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  8390.         fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  8391.  
  8392. #ifdef IMPBH
  8393.       //Improved barnes hut version
  8394.       float4 nodeCOM     = multipole[node*3 + 0];
  8395.       nodeCOM.w = nodeCenter.w;
  8396.  
  8397. #ifdef INDSOFT
  8398.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  8399. #else
  8400.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  8401. #endif
  8402. #else
  8403.       //Minimal distance version
  8404. #ifdef INDSOFT
  8405.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  8406. #else
  8407.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  8408. #endif
  8409. #endif //if IMPBH
  8410.  
  8411. #else
  8412.       splitChecks++;
  8413.  
  8414.  
  8415.       bool curSplit = false;
  8416.  
  8417.       int newOffset = 0;
  8418.  
  8419.       //        for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8420.       for(int k=check.coarseIDOffset; k < globalCoarseGrpCount[remoteId]; k++)
  8421.       {
  8422.         extraChecks++;
  8423.         //  particleCount++;
  8424.         //Test this specific box
  8425.         int coarseGrpId = coarseIDs[k];
  8426.  
  8427.         double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  8428.         double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  8429.  
  8430.  
  8431. #ifdef IMPBH
  8432.         //Improved barnes hut version
  8433.         float4 nodeCOM     = multipole[node*3 + 0];
  8434.         nodeCOM.w = nodeCenter.w;
  8435.  
  8436. #ifdef INDSOFT
  8437.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  8438. #else
  8439.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  8440. #endif
  8441.  
  8442. #else
  8443.         //Minimal distance version
  8444.  
  8445. #ifdef INDSOFT
  8446.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  8447. #else
  8448.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  8449. #endif
  8450. #endif //if IMPBH
  8451.  
  8452.         //Early out if at least one box requires this info
  8453.         if(curSplit){
  8454.           split = true;
  8455.           newOffset = k;
  8456.           break;
  8457.           //              splitIdxToUse = k;
  8458.           //              LOGF(stderr, "LET count On level: %d\tNode: %d\tStart: %d\tEnd: %d\tChecks: %d \n",
  8459.           //                  level,node, startCoarseBox, splitIdxToUse, splitIdxToUse-startCoarseBox+1);
  8460.  
  8461.           //              extraChecks += splitIdxToUse-startCoarseBox;
  8462.           //              break;
  8463.         }
  8464.         else
  8465.         {
  8466.           //Check the big box
  8467.           //            curSplit = split_node(nodeCenter, nodeSize, bigBoxCenter, bigBoxSize);
  8468.           //            if(curSplit == false) break;
  8469.         }
  8470.       } //For globalCoarseGrpCount[remoteId]
  8471.  
  8472.       if(split == false)
  8473.       {
  8474.         //          uselessChecks +=  boxIndicesToUse.size()-startCoarseBox;
  8475.       }
  8476.  
  8477. #endif
  8478.       //if split & node add children to next lvl stack
  8479.       if(split && !leaf)
  8480.       {
  8481.         for(int i=child; i < child+nchild; i++)
  8482.         {
  8483.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  8484.           combNodeCheck2 check;
  8485.           check.nodeID    = i;
  8486.           check.coarseIDOffset = newOffset;
  8487.           nextLevel[nextLevelCount++] = check;
  8488.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  8489.         }
  8490.       }
  8491.  
  8492.       //if split & leaf add particles to particle list
  8493.       if(split && leaf)
  8494.       {
  8495.         for(int i=child; i < child+nchild; i++)
  8496.         {
  8497.           particleCount++;
  8498.         }
  8499.       }
  8500.  
  8501.       //Increase the nodeCount, since this node will be part of the tree-structure
  8502.       nodeCount++;
  8503.     } //end for curLevel.size
  8504.  
  8505.  
  8506.     //Put next level stack into current level and continue
  8507.     //      curLevel.clear();
  8508.     ////       cout << "Next level: " << nextLevel.size() << endl;
  8509.     //      curLevel.assign(nextLevel.begin(), nextLevel.end());
  8510.     //      nextLevel.clear();
  8511.  
  8512.     curLevelCount = nextLevelCount;
  8513.     combNodeCheck2 *temp = curLevel;
  8514.     curLevel = nextLevel;
  8515.     nextLevel = temp;
  8516.     nextLevelCount = 0;
  8517.  
  8518.     level++;
  8519.   }//end while
  8520.  
  8521.   particles = particleCount;
  8522.   nodes     = nodeCount;
  8523.  
  8524.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  8525.  
  8526.   /*    fprintf(stderr, "Count found: %d particles and %d nodes. Boxsize: (%f %f %f ) BoxCenter: (%f %f %f)\n",
  8527.         particles, nodes, boxSize.x ,boxSize.y, boxSize.z, boxCenter.x, boxCenter.y, boxCenter.z );  */
  8528. }
  8529.  
  8530.  
  8531. typedef struct{
  8532.   int nodeID;
  8533.   int coarseIDOffset;
  8534.   int coarseIDEnd;
  8535. } combNodeCheck3;
  8536.  
  8537. void octree::create_local_essential_tree_count_novector_startend(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  8538.     int remoteId, float group_eps, int start, int end,
  8539.     int &particles, int &nodes)
  8540. {
  8541.   //Walk the tree as is done on device, level by level
  8542.   //    vector<combNodeCheck> curLevel;
  8543.   //    vector<combNodeCheck> nextLevel;
  8544.  
  8545.   combNodeCheck3 *curLevel = new combNodeCheck3[1024*64];
  8546.   combNodeCheck3 *nextLevel = new combNodeCheck3[1024*64];
  8547.  
  8548.   int curLevelCount = 0;
  8549.   int nextLevelCount = 0;
  8550.  
  8551.  
  8552.   int particleCount   = 0;
  8553.   int nodeCount       = 0;
  8554.  
  8555.   int level           = 0;
  8556.  
  8557.   int extraChecks = 0;
  8558.   int uselessChecks = 0;
  8559.   int splitChecks = 0;
  8560.  
  8561.  
  8562.   double4 bigBoxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  8563.     0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  8564.     0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  8565.   double4 bigBoxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  8566.     fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  8567.     fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  8568.  
  8569.   //    vector<int> coarseIDs;
  8570.   //    //Add the initial coarse boxes to this level
  8571.   //    for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8572.   //    {
  8573.   //      coarseIDs.push_back(globalCoarseGrpOffsets[remoteId] + i);
  8574.   //    }
  8575.  
  8576.   int *coarseIDs = new int[globalCoarseGrpCount[remoteId]];
  8577.   //Add the initial coarse boxes to this level
  8578.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8579.   {
  8580.     coarseIDs[i] = globalCoarseGrpOffsets[remoteId] + i;
  8581.   }
  8582.  
  8583.   //Add the initial nodes to the curLevel list
  8584.   for(int i=start; i < end; i++)
  8585.   {
  8586.     combNodeCheck3 check;
  8587.     check.nodeID    = i;
  8588.     check.coarseIDOffset = 0;
  8589.     check.coarseIDEnd = globalCoarseGrpCount[remoteId];
  8590.     //      check.coarseIDs.insert(check.coarseIDs.begin(), coarseIDs, coarseIDs+globalCoarseGrpCount[remoteId]);
  8591.     curLevel[curLevelCount++] = check;
  8592.   }
  8593.  
  8594.   //Filter out the initial boxes that will fail anyway
  8595.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8596.   {
  8597.     // coarseIDs[i] = globalCoarseGrpOffsets[remoteId] + i;
  8598.     bool split;
  8599.     for(int j=start; j < end; j++)
  8600.     {
  8601.       real4 nodeCenter  = nodeCenterInfo[j];
  8602.       real4 nodeSize    = nodeSizeInfo[j];
  8603.       double4 boxCenter = coarseGroupBoxCenter[coarseIDs[i]];
  8604.       double4 boxSize   = coarseGroupBoxSize  [coarseIDs[i]];
  8605.       float4 nodeCOM    = multipole[j*3 + 0];
  8606.       nodeCOM.w         = nodeCenter.w;
  8607.  
  8608.       split |= split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  8609.  
  8610.       if(!split_node_grav_impbh(nodeCOM, boxCenter, boxSize))
  8611.       {
  8612.         //          LOGF(stderr,"LET INITIAL Failed on box %d node: %d\n", i, j);
  8613.       }
  8614.     }
  8615.     if(split == false)
  8616.     {
  8617.       LOGF(stderr,"LET INITIAL Failed on %d \n", i);
  8618.     }
  8619.   }
  8620.  
  8621.   //    curLevelCount = 0;
  8622.   //    //Add the initial nodes to the curLevel list
  8623.   //    for(int i=start; i < end; i++)
  8624.   //    {
  8625.   //      combNodeCheck3 check;
  8626.   //      check.nodeID    = i;
  8627.   //      check.coarseIDOffset = 0; //Out of range default
  8628.   //      check.coarseIDEnd    = globalCoarseGrpCount[remoteId]; //Out of range default
  8629.   //
  8630.   ////      for(int j=0; j < globalCoarseGrpCount[remoteId]; j++)
  8631.   ////      {
  8632.   ////        real4 nodeCenter  = nodeCenterInfo[i];
  8633.   ////        real4 nodeSize    = nodeSizeInfo[i];
  8634.   ////        double4 boxCenter = coarseGroupBoxCenter[coarseIDs[j]];
  8635.   ////        double4 boxSize   = coarseGroupBoxSize  [coarseIDs[j]];
  8636.   ////        float4 nodeCOM    = multipole[j*3 + 0];
  8637.   ////        nodeCOM.w         = nodeCenter.w;
  8638.   ////
  8639.   ////        //Skip all previous not needed checks
  8640.   ////        if(split_node_grav_impbh(nodeCOM, boxCenter, boxSize))
  8641.   ////        {
  8642.   ////          check.coarseIDOffset = j;
  8643.   //////          LOGF(stderr,"LET INITIAL Start node: %d at grp %d \n", i, j);
  8644.   ////          break;
  8645.   ////        }
  8646.   ////      }
  8647.   //      curLevel[curLevelCount++] = check;
  8648.   //    }
  8649.  
  8650.  
  8651.  
  8652.  
  8653.   //Add the nodes before the start and end to the node list
  8654.   for(int i=0; i < start; i++)
  8655.   {
  8656.     nodeCount++;
  8657.   }
  8658.  
  8659.   //Start the tree-walk
  8660.   while(curLevelCount > 0)
  8661.   {
  8662.     for(unsigned int i=0; i < curLevelCount; i++)
  8663.     {
  8664.       //Read node data
  8665.       combNodeCheck3 check = curLevel[i];
  8666.       int node           = check.nodeID;
  8667.  
  8668.       //        LOGF(stderr, "LET count On level: %d\tNode: %d\tGoing to check: %d\n",
  8669.       //                          level,node, check.coarseIDs.size());
  8670.  
  8671.       real4 nodeCenter = nodeCenterInfo[node];
  8672.       real4 nodeSize   = nodeSizeInfo[node];
  8673.       bool leaf        = nodeCenter.w <= 0;
  8674.  
  8675.       union{float f; int i;} u; //__float_as_int
  8676.       u.f           = nodeSize.w;
  8677.       int childinfo = u.i;
  8678.  
  8679.       int child, nchild;
  8680.       if(!leaf)
  8681.       {
  8682.         //Node
  8683.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  8684.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  8685.       }
  8686.       else
  8687.       {
  8688.         //Leaf
  8689.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  8690.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  8691.       }
  8692.  
  8693. #ifdef INDSOFT
  8694.       //Very inefficient this but for testing I have to live with it...
  8695.       float node_eps_val = multipole[node*3 + 1].w;
  8696. #endif
  8697.  
  8698.  
  8699.       bool split = false;
  8700.  
  8701.       int splitIdxToUse = 0;
  8702.       //        vector<int> checkIDs;
  8703. #if 0
  8704.       splitChecks++;
  8705.       double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  8706.         0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  8707.         0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  8708.       double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  8709.         fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  8710.         fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  8711.  
  8712. #ifdef IMPBH
  8713.       //Improved barnes hut version
  8714.       float4 nodeCOM     = multipole[node*3 + 0];
  8715.       nodeCOM.w = nodeCenter.w;
  8716.  
  8717. #ifdef INDSOFT
  8718.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  8719. #else
  8720.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  8721. #endif
  8722. #else
  8723.       //Minimal distance version
  8724. #ifdef INDSOFT
  8725.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  8726. #else
  8727.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  8728. #endif
  8729. #endif //if IMPBH
  8730.  
  8731. #else
  8732.       splitChecks++;
  8733.  
  8734.  
  8735.       bool curSplit = false;
  8736.  
  8737.       int newOffset = -1;
  8738.       int newEnd  = 0;
  8739.       bool didBigCheck = false;
  8740.  
  8741.       //        for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8742.       for(int k=check.coarseIDOffset; k < check.coarseIDEnd; k++)
  8743.       {
  8744.         extraChecks++;
  8745.         //  particleCount++;
  8746.         //Test this specific box
  8747.         int coarseGrpId = coarseIDs[k];
  8748.  
  8749.         double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  8750.         double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  8751.  
  8752.  
  8753. #ifdef IMPBH
  8754.         //Improved barnes hut version
  8755.         float4 nodeCOM     = multipole[node*3 + 0];
  8756.         nodeCOM.w = nodeCenter.w;
  8757.  
  8758. #ifdef INDSOFT
  8759.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  8760. #else
  8761.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  8762. #endif
  8763.  
  8764. #else
  8765.         //Minimal distance version
  8766.  
  8767. #ifdef INDSOFT
  8768.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  8769. #else
  8770.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  8771. #endif
  8772. #endif //if IMPBH
  8773.  
  8774.         //Early out if at least one box requires this info
  8775.         if(curSplit){
  8776.           split = true;
  8777.  
  8778.           if(leaf)  break;  //Early out if this is a leaf, since we wont have to check any further
  8779.  
  8780.           if(newOffset < 0)
  8781.             newOffset = k;
  8782.           newEnd = k+1;
  8783.  
  8784.  
  8785.           //            break;
  8786.           //              splitIdxToUse = k;
  8787.           //              LOGF(stderr, "LET count On level: %d\tNode: %d\tStart: %d\tEnd: %d\tChecks: %d \n",
  8788.           //                  level,node, startCoarseBox, splitIdxToUse, splitIdxToUse-startCoarseBox+1);
  8789.  
  8790.           //              extraChecks += splitIdxToUse-startCoarseBox;
  8791.           //              break;
  8792.         }
  8793.         else
  8794.         {
  8795.           //Instead of checking all boxes we can just go over the tree-structure again
  8796.           //if we fail to check if there is any more grp that is required
  8797.  
  8798.  
  8799.           //Check the big box
  8800.           //            if(!didBigCheck)
  8801.           //            {
  8802.           //              curSplit = split_node(nodeCenter, nodeSize, bigBoxCenter, bigBoxSize);
  8803.           //              if(curSplit == false) break;
  8804.           //              didBigCheck = true;
  8805.           //            }
  8806.         }
  8807.       } //For globalCoarseGrpCount[remoteId]
  8808.  
  8809.       if(split == false)
  8810.       {
  8811.         //          uselessChecks +=  boxIndicesToUse.size()-startCoarseBox;
  8812.       }
  8813.  
  8814. #endif
  8815.       //if split & node add children to next lvl stack
  8816.       if(split && !leaf)
  8817.       {
  8818.         for(int i=child; i < child+nchild; i++)
  8819.         {
  8820.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  8821.           combNodeCheck3 check;
  8822.           check.nodeID    = i;
  8823.           check.coarseIDOffset = newOffset;
  8824.           check.coarseIDEnd    = newEnd;
  8825.           nextLevel[nextLevelCount++] = check;
  8826.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  8827.         }
  8828.       }
  8829.  
  8830.       //if split & leaf add particles to particle list
  8831.       if(split && leaf)
  8832.       {
  8833.         for(int i=child; i < child+nchild; i++)
  8834.         {
  8835.           particleCount++;
  8836.         }
  8837.       }
  8838.  
  8839.       //Increase the nodeCount, since this node will be part of the tree-structure
  8840.       nodeCount++;
  8841.     } //end for curLevel.size
  8842.  
  8843.  
  8844.     //Put next level stack into current level and continue
  8845.     //      curLevel.clear();
  8846.     ////       cout << "Next level: " << nextLevel.size() << endl;
  8847.     //      curLevel.assign(nextLevel.begin(), nextLevel.end());
  8848.     //      nextLevel.clear();
  8849.  
  8850.     curLevelCount = nextLevelCount;
  8851.     combNodeCheck3 *temp = curLevel;
  8852.     curLevel = nextLevel;
  8853.     nextLevel = temp;
  8854.     nextLevelCount = 0;
  8855.  
  8856.     level++;
  8857.   }//end while
  8858.  
  8859.   particles = particleCount;
  8860.   nodes     = nodeCount;
  8861.  
  8862.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  8863.  
  8864.   /*    fprintf(stderr, "Count found: %d particles and %d nodes. Boxsize: (%f %f %f ) BoxCenter: (%f %f %f)\n",
  8865.         particles, nodes, boxSize.x ,boxSize.y, boxSize.z, boxCenter.x, boxCenter.y, boxCenter.z );  */
  8866. }
  8867.  
  8868. void octree::create_local_essential_tree_count_novector_startend2(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  8869.     int remoteId, float group_eps, int start, int end,
  8870.     int &particles, int &nodes)
  8871. {
  8872.   //Walk the tree as is done on device, level by level
  8873.  
  8874.   combNodeCheck3 *curLevel = new combNodeCheck3[1024*64];
  8875.   combNodeCheck3 *nextLevel = new combNodeCheck3[1024*64];
  8876.  
  8877.   int curLevelCount = 0;
  8878.   int nextLevelCount = 0;
  8879.  
  8880.  
  8881.   int particleCount   = 0;
  8882.   int nodeCount       = 0;
  8883.  
  8884.   int level           = 0;
  8885.  
  8886.   int extraChecks = 0;
  8887.   int uselessChecks = 0;
  8888.   int splitChecks = 0;
  8889.  
  8890.  
  8891.   double4 bigBoxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  8892.     0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  8893.     0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  8894.   double4 bigBoxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  8895.     fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  8896.     fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  8897.  
  8898.  
  8899.   int *coarseIDs = new int[globalCoarseGrpCount[remoteId]];
  8900.   //Add the initial coarse boxes to this level
  8901.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  8902.   {
  8903.     coarseIDs[i] = globalCoarseGrpOffsets[remoteId] + i;
  8904.   }
  8905.  
  8906.   //Add the initial nodes to the curLevel list
  8907.   for(int i=start; i < end; i++)
  8908.   {
  8909.     combNodeCheck3 check;
  8910.     check.nodeID    = i;
  8911.     check.coarseIDOffset = 0;
  8912.     check.coarseIDEnd = globalCoarseGrpCount[remoteId];
  8913.     curLevel[curLevelCount++] = check;
  8914.   }
  8915.  
  8916.   //Add the nodes before the start and end to the node list
  8917.   for(int i=0; i < start; i++)
  8918.   {
  8919.     nodeCount++;
  8920.   }
  8921.  
  8922.   //Start the tree-walk
  8923.   while(curLevelCount > 0)
  8924.   {
  8925.     for(unsigned int i=0; i < curLevelCount; i++)
  8926.     {
  8927.       //Read node data
  8928.       combNodeCheck3 check = curLevel[i];
  8929.       int node           = check.nodeID;
  8930.  
  8931.  
  8932.       real4 nodeCenter = nodeCenterInfo[node];
  8933.       real4 nodeSize   = nodeSizeInfo[node];
  8934.       bool leaf        = nodeCenter.w <= 0;
  8935.  
  8936.       union{float f; int i;} u; //__float_as_int
  8937.       u.f           = nodeSize.w;
  8938.       int childinfo = u.i;
  8939.  
  8940.       int child, nchild;
  8941.       if(!leaf)
  8942.       {
  8943.         //Node
  8944.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  8945.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  8946.       }
  8947.       else
  8948.       {
  8949.         //Leaf
  8950.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  8951.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  8952.       }
  8953.  
  8954. #ifdef INDSOFT
  8955.       //Very inefficient this but for testing I have to live with it...
  8956.       float node_eps_val = multipole[node*3 + 1].w;
  8957. #endif
  8958.  
  8959.  
  8960.       bool split = false;
  8961.  
  8962.       int splitIdxToUse = 0;
  8963.       //        vector<int> checkIDs;
  8964. #if 0
  8965.  
  8966.  
  8967. #else
  8968.       splitChecks++;
  8969.  
  8970.  
  8971.       bool curSplit = false;
  8972.  
  8973.       int newOffset = -1;
  8974.       int newEnd  = 0;
  8975.       bool didBigCheck = false;
  8976.  
  8977.       int coarseGrpId = coarseIDs[check.coarseIDOffset];
  8978.  
  8979.       double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  8980.       double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  8981.  
  8982. #ifdef IMPBH
  8983.       //Improved barnes hut version
  8984.       float4 nodeCOM     = multipole[node*3 + 0];
  8985.       nodeCOM.w = nodeCenter.w;
  8986.  
  8987. #ifdef INDSOFT
  8988.       curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  8989. #else
  8990.       curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  8991. #endif
  8992.  
  8993. #else
  8994.       //Minimal distance version
  8995.  
  8996. #ifdef INDSOFT
  8997.       curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  8998. #else
  8999.       curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  9000. #endif
  9001. #endif //if IMPBH
  9002.  
  9003.       if(curSplit)
  9004.       {
  9005.         //Continue like this
  9006.         newOffset = check.coarseIDOffset;
  9007.         newEnd    = check.coarseIDEnd;
  9008.         split = true;
  9009.       }
  9010.       else
  9011.       {
  9012.         //Check others
  9013.         for(int k=check.coarseIDOffset+1; k < check.coarseIDEnd; k++)
  9014.         {
  9015.           //Test this specific box
  9016.           int coarseGrpId = coarseIDs[k];
  9017.  
  9018.           double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  9019.           double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  9020.  
  9021.           //Improved barnes hut version
  9022.           float4 nodeCOM     = multipole[node*3 + 0];
  9023.           nodeCOM.w = nodeCenter.w;
  9024.           curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  9025.  
  9026.           //Early out if at least one box requires this info
  9027.           if(curSplit)
  9028.           {
  9029.             split = true;
  9030.  
  9031.             if(leaf)  break;  //Early out if this is a leaf, since we wont have to check any further
  9032.  
  9033.             newOffset = k;
  9034.             newEnd    = check.coarseIDEnd;
  9035.             break;
  9036.           }//if cursplit
  9037.         }//end for loop
  9038.       }//end else
  9039.  
  9040.  
  9041.  
  9042. #endif //if old method
  9043.  
  9044.       //if split & node add children to next lvl stack
  9045.       if(split && !leaf)
  9046.       {
  9047.         for(int i=child; i < child+nchild; i++)
  9048.         {
  9049.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  9050.           combNodeCheck3 check;
  9051.           check.nodeID    = i;
  9052.           check.coarseIDOffset = newOffset;
  9053.           check.coarseIDEnd    = newEnd;
  9054.           nextLevel[nextLevelCount++] = check;
  9055.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  9056.         }
  9057.       }
  9058.  
  9059.       //if split & leaf add particles to particle list
  9060.       if(split && leaf)
  9061.       {
  9062.         for(int i=child; i < child+nchild; i++)
  9063.         {
  9064.           particleCount++;
  9065.         }
  9066.       }
  9067.  
  9068.       //Increase the nodeCount, since this node will be part of the tree-structure
  9069.       nodeCount++;
  9070.     } //end for curLevel.size
  9071.  
  9072.  
  9073.     curLevelCount = nextLevelCount;
  9074.     combNodeCheck3 *temp = curLevel;
  9075.     curLevel = nextLevel;
  9076.     nextLevel = temp;
  9077.     nextLevelCount = 0;
  9078.  
  9079.     level++;
  9080.   }//end while
  9081.  
  9082.   particles = particleCount;
  9083.   nodes     = nodeCount;
  9084.  
  9085.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  9086.  
  9087. }
  9088.  
  9089.  
  9090. typedef struct{
  9091.   int nodeID;
  9092.   int coarseIDs[64];
  9093.   int coarseIDCount;
  9094. } combNodeCheck4;
  9095.  
  9096.  
  9097. void octree::create_local_essential_tree_count_novector_startend3(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  9098.     int remoteId, float group_eps, int start, int end,
  9099.     int &particles, int &nodes)
  9100. {
  9101.   //Walk the tree as is done on device, level by level
  9102.  
  9103.   combNodeCheck4 *curLevel = new combNodeCheck4[1024*64];
  9104.   combNodeCheck4 *nextLevel = new combNodeCheck4[1024*64];
  9105.  
  9106.   int curLevelCount = 0;
  9107.   int nextLevelCount = 0;
  9108.  
  9109.  
  9110.   int particleCount   = 0;
  9111.   int nodeCount       = 0;
  9112.  
  9113.   int level           = 0;
  9114.  
  9115.   int extraChecks = 0;
  9116.   int uselessChecks = 0;
  9117.   int splitChecks = 0;
  9118.  
  9119.  
  9120.   double4 bigBoxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  9121.     0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  9122.     0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  9123.   double4 bigBoxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  9124.     fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  9125.     fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  9126.  
  9127.  
  9128.   int *coarseIDs = new int[globalCoarseGrpCount[remoteId]];
  9129.   //Add the initial coarse boxes to this level
  9130.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  9131.   {
  9132.     coarseIDs[i] = globalCoarseGrpOffsets[remoteId] + i;
  9133.   }
  9134.  
  9135.   //Add the initial nodes to the curLevel list
  9136.   for(int i=start; i < end; i++)
  9137.   {
  9138.     combNodeCheck4 check;
  9139.     check.nodeID    = i;
  9140.     for(int j=0; j < globalCoarseGrpCount[remoteId]; j++)
  9141.     {
  9142.       check.coarseIDs[j] = globalCoarseGrpOffsets[remoteId] + j;
  9143.     }
  9144.     check.coarseIDCount =  globalCoarseGrpCount[remoteId];
  9145.     curLevel[curLevelCount++] = check;
  9146.   }
  9147.  
  9148.   //Add the nodes before the start and end to the node list
  9149.   for(int i=0; i < start; i++)
  9150.   {
  9151.     nodeCount++;
  9152.   }
  9153.  
  9154.   //Start the tree-walk
  9155.   while(curLevelCount > 0)
  9156.   {
  9157.     for(unsigned int i=0; i < curLevelCount; i++)
  9158.     {
  9159.       //Read node data
  9160.       combNodeCheck4 check = curLevel[i];
  9161.       int node           = check.nodeID;
  9162.  
  9163.  
  9164.       real4 nodeCenter = nodeCenterInfo[node];
  9165.       real4 nodeSize   = nodeSizeInfo[node];
  9166.       bool leaf        = nodeCenter.w <= 0;
  9167.  
  9168.       union{float f; int i;} u; //__float_as_int
  9169.       u.f           = nodeSize.w;
  9170.       int childinfo = u.i;
  9171.  
  9172.       int child, nchild;
  9173.       if(!leaf)
  9174.       {
  9175.         //Node
  9176.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  9177.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  9178.       }
  9179.       else
  9180.       {
  9181.         //Leaf
  9182.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  9183.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  9184.       }
  9185.  
  9186. #ifdef INDSOFT
  9187.       //Very inefficient this but for testing I have to live with it...
  9188.       float node_eps_val = multipole[node*3 + 1].w;
  9189. #endif
  9190.  
  9191.  
  9192.       bool split = false;
  9193.  
  9194.       int splitIdxToUse = 0;
  9195.  
  9196. #if 0
  9197.  
  9198. #else
  9199.       splitChecks++;
  9200.  
  9201.  
  9202.       bool curSplit = false;
  9203.  
  9204.       int newOffset = 0;
  9205.       bool didBigCheck = false;
  9206.  
  9207.       int tempList[128];
  9208.  
  9209.       //        for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  9210.       for(int k=0; k < check.coarseIDCount; k++)
  9211.       {
  9212.         extraChecks++;
  9213.  
  9214.         //Test this specific box
  9215.         int coarseGrpId = check.coarseIDs[k];
  9216.  
  9217.         double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  9218.         double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  9219.  
  9220.  
  9221. #ifdef IMPBH
  9222.         //Improved barnes hut version
  9223.         float4 nodeCOM     = multipole[node*3 + 0];
  9224.         nodeCOM.w = nodeCenter.w;
  9225.  
  9226. #ifdef INDSOFT
  9227.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  9228. #else
  9229.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  9230. #endif
  9231.  
  9232. #else
  9233.         //Minimal distance version
  9234.  
  9235. #ifdef INDSOFT
  9236.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  9237. #else
  9238.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  9239. #endif
  9240. #endif //if IMPBH
  9241.  
  9242.         //Early out if at least one box requires this info
  9243.         if(curSplit){
  9244.           split = true;
  9245.  
  9246.           if(leaf)  break;  //Early out if this is a leaf, since we wont have to check any further
  9247.  
  9248.           tempList[newOffset++] = check.coarseIDs[k];
  9249.         }
  9250.       } //For globalCoarseGrpCount[remoteId]
  9251.  
  9252.  
  9253. #endif //if old method
  9254.  
  9255.       //if split & node add children to next lvl stack
  9256.       if(split && !leaf)
  9257.       {
  9258.         for(int i=child; i < child+nchild; i++)
  9259.         {
  9260.           combNodeCheck4 check;
  9261.           check.nodeID    = i;
  9262.           check.coarseIDCount = newOffset;
  9263.  
  9264.           memcpy(check.coarseIDs, tempList, sizeof(int)*newOffset);
  9265.  
  9266.           nextLevel[nextLevelCount++] = check;
  9267.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  9268.         }
  9269.       }
  9270.  
  9271.       //if split & leaf add particles to particle list
  9272.       if(split && leaf)
  9273.       {
  9274.         for(int i=child; i < child+nchild; i++)
  9275.         {
  9276.           particleCount++;
  9277.         }
  9278.       }
  9279.  
  9280.       //Increase the nodeCount, since this node will be part of the tree-structure
  9281.       nodeCount++;
  9282.     } //end for curLevel.size
  9283.  
  9284.  
  9285.     curLevelCount = nextLevelCount;
  9286.     combNodeCheck4 *temp = curLevel;
  9287.     curLevel = nextLevel;
  9288.     nextLevel = temp;
  9289.     nextLevelCount = 0;
  9290.  
  9291.     level++;
  9292.   }//end while
  9293.  
  9294.   particles = particleCount;
  9295.   nodes     = nodeCount;
  9296.  
  9297.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  9298.  
  9299. }
  9300.  
  9301.  
  9302.  
  9303. struct cmp_key_value{
  9304.   bool operator () (const int2 &a, const int2 &b){
  9305.     return ( a.y < b.y);
  9306.   }
  9307. };
  9308.  
  9309. //This one sorts the groups by the most strict one as last
  9310. //and the least hit ones in the beginning, to quickly
  9311. //filter out things the deeper we go
  9312. void octree::create_local_essential_tree_count_novector_startend4(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  9313.     int remoteId, float group_eps, int start, int end,
  9314.     int &particles, int &nodes)
  9315. {
  9316.   //Walk the tree as is done on device, level by level
  9317.   const int stackSize = 512;
  9318.   combNodeCheck3 *curLevel  = new combNodeCheck3[1024*stackSize];
  9319.   combNodeCheck3 *nextLevel = new combNodeCheck3[1024*stackSize];
  9320.  
  9321.  
  9322.   int curLevelCount  = 0;
  9323.   int nextLevelCount = 0;
  9324.  
  9325.  
  9326.   int particleCount   = 0;
  9327.   int nodeCount       = 0;
  9328.  
  9329.   int level           = 0;
  9330.  
  9331.   double4 bigBoxCenter = {  0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  9332.     0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  9333.     0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  9334.   double4 bigBoxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  9335.     fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  9336.     fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  9337.  
  9338.   int2 *coarseIDsTest = new int2[globalCoarseGrpCount[remoteId]];
  9339.   int  *coarseIDs     = new int[globalCoarseGrpCount[remoteId]];
  9340.   //Add the initial coarse boxes to this level
  9341.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  9342.   {
  9343.     coarseIDs[i] = globalCoarseGrpOffsets[remoteId] + i;
  9344.  
  9345.     coarseIDsTest[i].x = globalCoarseGrpOffsets[remoteId] + i;
  9346.     coarseIDsTest[i].y = 0;
  9347.   }
  9348.  
  9349.   //Add the initial nodes to the curLevel list
  9350.   for(int i=start; i < end; i++)
  9351.   {
  9352.     combNodeCheck3 check;
  9353.     check.nodeID    = i;
  9354.     check.coarseIDOffset = 0;
  9355.     check.coarseIDEnd = globalCoarseGrpCount[remoteId];
  9356.     curLevel[curLevelCount++] = check;
  9357.   }
  9358.  
  9359.   //Compute which boxes are most likely to be used and then sort
  9360.   //them. Saves another few percent
  9361.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  9362.   {
  9363.     double4 boxCenter = coarseGroupBoxCenter[coarseIDs[i]];
  9364.     double4 boxSize   = coarseGroupBoxSize  [coarseIDs[i]];
  9365.  
  9366.     for(int j=start; j < end; j++)
  9367.     {
  9368.       real4 nodeCenter  = nodeCenterInfo[j];
  9369.       real4 nodeSize    = nodeSizeInfo[j];
  9370.       float4 nodeCOM    = multipole[j*3 + 0];
  9371.       nodeCOM.w         = nodeCenter.w;
  9372.  
  9373.       if(split_node_grav_impbh(nodeCOM, boxCenter, boxSize))
  9374.       {
  9375.         coarseIDsTest[i].y++;
  9376.       }
  9377.     } //for j
  9378.   } // for i
  9379.  
  9380.   std::sort(coarseIDsTest, coarseIDsTest+globalCoarseGrpCount[remoteId], cmp_key_value());
  9381.  
  9382.  
  9383.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  9384.   {
  9385.     //       LOGF(stderr, "Box histo2 : %d \t %d \t %d \n", i, coarseIDsTest[i].x, coarseIDsTest[i].y);
  9386.     coarseIDs[i] = coarseIDsTest[i].x;
  9387.   }
  9388.   //Pre-processing done
  9389.  
  9390.  
  9391.   //Add the nodes before the start and end to the node list
  9392.   for(int i=0; i < start; i++)
  9393.   {
  9394.     nodeCount++;
  9395.   }
  9396.  
  9397.   int maxSizeTemp = -1;
  9398.  
  9399.   //Start the tree-walk
  9400.   while(curLevelCount > 0)
  9401.   {
  9402.     maxSizeTemp = max(maxSizeTemp, curLevelCount);
  9403.  
  9404.     for(unsigned int i=0; i < curLevelCount; i++)
  9405.     {
  9406.       //Read node data
  9407.       combNodeCheck3 check = curLevel[i];
  9408.       int node             = check.nodeID;
  9409.  
  9410.       real4 nodeCenter = nodeCenterInfo[node];
  9411.       real4 nodeSize   = nodeSizeInfo[node];
  9412.       bool leaf        = nodeCenter.w <= 0;
  9413.  
  9414.       union{float f; int i;} u; //__float_as_int
  9415.       u.f           = nodeSize.w;
  9416.       int childinfo = u.i;
  9417.  
  9418.       int child, nchild;
  9419.       if(!leaf)
  9420.       {
  9421.         //Node
  9422.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  9423.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  9424.       }
  9425.       else
  9426.       {
  9427.         //Leaf
  9428.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  9429.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  9430.       }
  9431.  
  9432. #ifdef INDSOFT
  9433.       //Very inefficient this but for testing I have to live with it...
  9434.       float node_eps_val = multipole[node*3 + 1].w;
  9435. #endif
  9436.  
  9437.  
  9438.       bool split = false;
  9439.  
  9440.       int splitIdxToUse = 0;
  9441.  
  9442.       int newOffset = -1;
  9443.       int newEnd  = 0;
  9444.  
  9445. #if 0
  9446.       double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  9447.         0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  9448.         0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  9449.       double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  9450.         fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  9451.         fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  9452.  
  9453. #ifdef IMPBH
  9454.       //Improved barnes hut version
  9455.       float4 nodeCOM     = multipole[node*3 + 0];
  9456.       nodeCOM.w = nodeCenter.w;
  9457.  
  9458. #ifdef INDSOFT
  9459.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  9460. #else
  9461.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  9462. #endif
  9463. #else
  9464.       //Minimal distance version
  9465. #ifdef INDSOFT
  9466.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  9467. #else
  9468.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  9469. #endif
  9470. #endif //if IMPBH
  9471.  
  9472. #else
  9473.       bool curSplit = false;
  9474.       bool didBigCheck = false;
  9475.  
  9476.       //          if(split_node(nodeCenter, nodeSize, bigBoxCenter, bigBoxSize))
  9477.       {
  9478.         for(int k=check.coarseIDOffset; k < check.coarseIDEnd; k++)
  9479.         {
  9480.           //Test this specific box
  9481.           int coarseGrpId = coarseIDs[k];
  9482.  
  9483.           double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  9484.           double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  9485.  
  9486.  
  9487. #ifdef IMPBH
  9488.           //Improved Barnes Hut version
  9489.           float4 nodeCOM     = multipole[node*3 + 0];
  9490.           nodeCOM.w = nodeCenter.w;
  9491.  
  9492. #ifdef INDSOFT
  9493.           curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  9494. #else
  9495.           curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  9496. #endif
  9497.  
  9498. #else
  9499.           //Minimal distance version
  9500.  
  9501. #ifdef INDSOFT
  9502.           curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  9503. #else
  9504.           curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  9505. #endif
  9506. #endif //if IMPBH
  9507.  
  9508.           //Check if this box needs to go along for the ride further
  9509.           //down the tree
  9510.           if(curSplit)
  9511.           {
  9512.             split = true;
  9513.  
  9514.             if(leaf)  break;  //Early out if this is a leaf, since we wont have to check any further
  9515.  
  9516.             if(newOffset < 0)
  9517.               newOffset = k;
  9518.             newEnd = k+1;
  9519.           } //if curSplit
  9520.         } //For globalCoarseGrpCount[remoteId]
  9521.       }//Big-check
  9522. #endif
  9523.       //if split & node add children to next lvl stack
  9524.       if(split && !leaf)
  9525.       {
  9526.         for(int i=child; i < child+nchild; i++)
  9527.         {
  9528.           combNodeCheck3 check;
  9529.           check.nodeID                = i;
  9530.           check.coarseIDOffset        = newOffset;
  9531.           check.coarseIDEnd           = newEnd;
  9532.           nextLevel[nextLevelCount++] = check;
  9533.         }
  9534.       }
  9535.  
  9536.       //if split & leaf add particles to particle list
  9537.       if(split && leaf)
  9538.       {
  9539.         for(int i=child; i < child+nchild; i++)
  9540.         {
  9541.           particleCount++;
  9542.         }
  9543.       }
  9544.  
  9545.       //Increase the nodeCount, since this node will be part of the tree-structure
  9546.       nodeCount++;
  9547.     } //end for curLevel.size
  9548.  
  9549.  
  9550.     //Put next level stack into current level and continue
  9551.     curLevelCount         = nextLevelCount;
  9552.     combNodeCheck3 *temp  = curLevel;
  9553.     curLevel              = nextLevel;
  9554.     nextLevel             = temp;
  9555.     nextLevelCount        = 0;
  9556.  
  9557.     level++;
  9558.   }//end while
  9559.  
  9560.   particles = particleCount;
  9561.   nodes     = nodeCount;
  9562.  
  9563.   delete[] curLevel;
  9564.   delete[] nextLevel;
  9565.   delete[] coarseIDsTest;
  9566.   delete[] coarseIDs;
  9567.  
  9568.  
  9569.   //    LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d maxStack: %d\n", extraChecks, splitChecks, uselessChecks, maxSizeTemp);
  9570.  
  9571. }
  9572.  
  9573. void octree::create_local_essential_tree_fill_novector_startend4(real4* bodies, real4* velocities, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  9574.     int remoteId, float group_eps, int start, int end,
  9575.     int particleCount, int nodeCount, real4 *dataBuffer)
  9576. {
  9577.   //Walk the tree as is done on device, level by level
  9578.   const int stackSize = 512;
  9579.   combNodeCheck3 *curLevel  = new combNodeCheck3[1024*stackSize];
  9580.   combNodeCheck3 *nextLevel = new combNodeCheck3[1024*stackSize];
  9581.  
  9582.   int curLevelCount  = 0;
  9583.   int nextLevelCount = 0;
  9584.  
  9585.  
  9586.   int level           = 0;
  9587.  
  9588.   double4 bigBoxCenter = {  0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  9589.     0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  9590.     0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  9591.   double4 bigBoxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  9592.     fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  9593.     fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  9594.  
  9595.   int2 *coarseIDsTest = new int2[globalCoarseGrpCount[remoteId]];
  9596.   int *coarseIDs      = new int [globalCoarseGrpCount[remoteId]];
  9597.   //Add the initial coarse boxes to this level
  9598.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  9599.   {
  9600.     coarseIDs[i] = globalCoarseGrpOffsets[remoteId] + i;
  9601.  
  9602.     coarseIDsTest[i].x = globalCoarseGrpOffsets[remoteId] + i;
  9603.     coarseIDsTest[i].y = 0;
  9604.   }
  9605.  
  9606.   //Add the initial nodes to the curLevel list
  9607.   for(int i=start; i < end; i++)
  9608.   {
  9609.     combNodeCheck3 check;
  9610.     check.nodeID    = i;
  9611.     check.coarseIDOffset = 0;
  9612.     check.coarseIDEnd = globalCoarseGrpCount[remoteId];
  9613.     curLevel[curLevelCount++] = check;
  9614.   }
  9615.  
  9616.   //Compute which boxes are most likely to be used and then sort
  9617.   //them. Saves another few percent
  9618.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  9619.   {
  9620.     for(int j=start; j < end; j++)
  9621.     {
  9622.       real4 nodeCenter  = nodeCenterInfo[j];
  9623.       real4 nodeSize    = nodeSizeInfo[j];
  9624.       double4 boxCenter = coarseGroupBoxCenter[coarseIDs[i]];
  9625.       double4 boxSize   = coarseGroupBoxSize  [coarseIDs[i]];
  9626.       float4 nodeCOM    = multipole[j*3 + 0];
  9627.       nodeCOM.w         = nodeCenter.w;
  9628.  
  9629.       if(split_node_grav_impbh(nodeCOM, boxCenter, boxSize))
  9630.       {
  9631.         coarseIDsTest[i].y++;
  9632.       }
  9633.     } //for j
  9634.   } // for i
  9635.  
  9636.   std::sort(coarseIDsTest, coarseIDsTest+globalCoarseGrpCount[remoteId], cmp_key_value());
  9637.  
  9638.  
  9639.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  9640.   {
  9641.     //       LOGF(stderr, "Box histo2 : %d \t %d \t %d \n", i, coarseIDsTest[i].x, coarseIDsTest[i].y);
  9642.     coarseIDs[i] = coarseIDsTest[i].x;
  9643.   }
  9644.   //Pre-processing done
  9645.  
  9646.  
  9647.  
  9648.   double massSum = 0;
  9649.  
  9650.   int particleOffset     = 1;
  9651.   int velParticleOffset  = particleOffset      + particleCount;
  9652.   int nodeSizeOffset     = velParticleOffset   + particleCount;
  9653.   int nodeCenterOffset   = nodeSizeOffset      + nodeCount;
  9654.   int multiPoleOffset    = nodeCenterOffset    + nodeCount;
  9655.  
  9656.   //|real4| 2*particleCount*real4| nodes*real4 | nodes*real4 | nodes*3*real4 |
  9657.   //Info about #particles, #nodes, start and end of tree-walk
  9658.   //The particle positions and velocities
  9659.   //The nodeSizeData
  9660.   //The nodeCenterData
  9661.   //The multipole data
  9662.  
  9663.   //Add the nodes before the start and end to the node list
  9664.   for(int i=0; i < start; i++)
  9665.   {
  9666.     dataBuffer[nodeSizeOffset++]   = nodeSizeInfo[i];
  9667.     dataBuffer[nodeCenterOffset++] = nodeCenterInfo[i];
  9668.  
  9669.     dataBuffer[multiPoleOffset++]  = multipole[i*3 + 0];
  9670.     dataBuffer[multiPoleOffset++]  = multipole[i*3 + 1];
  9671.     dataBuffer[multiPoleOffset++]  = multipole[i*3 + 2];
  9672.   }
  9673.  
  9674.   //Start the tree-walk
  9675.   //Variables to rewrite the tree-structure indices
  9676.   int childNodeOffset         = end;
  9677.   int childParticleOffset     = 0;
  9678.  
  9679.   //Start the tree-walk
  9680.   while(curLevelCount > 0)
  9681.   {
  9682.     for(unsigned int i=0; i < curLevelCount; i++)
  9683.     {
  9684.       //Read node data
  9685.       combNodeCheck3 check = curLevel[i];
  9686.       int node             = check.nodeID;
  9687.  
  9688.       real4 nodeCenter = nodeCenterInfo[node];
  9689.       real4 nodeSize   = nodeSizeInfo[node];
  9690.       bool leaf        = nodeCenter.w <= 0;
  9691.  
  9692.       union{float f; int i;} u; //__float_as_int
  9693.       u.f           = nodeSize.w;
  9694.       int childinfo = u.i;
  9695.  
  9696.       int child, nchild;
  9697.       if(!leaf)
  9698.       {
  9699.         //Node
  9700.         child    =    childinfo & 0x0FFFFFFF;                   //Index to the first child of the node
  9701.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  9702.       }
  9703.       else
  9704.       {
  9705.         //Leaf
  9706.         child   =    childinfo & BODYMASK;                     //the first body in the leaf
  9707.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  9708.       }
  9709.  
  9710.  
  9711. #ifdef INDSOFT
  9712.       //Very inefficient this but for testing I have to live with it...
  9713.       float node_eps_val = multipole[node*3 + 1].w;
  9714. #endif
  9715.  
  9716.       bool split = false;
  9717.  
  9718.       int splitIdxToUse = 0;
  9719.  
  9720.       int newOffset = -1;
  9721.       int newEnd  = 0;
  9722.  
  9723.  
  9724. #if 0
  9725.       double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  9726.         0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  9727.         0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  9728.       double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  9729.         fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  9730.         fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  9731.  
  9732. #ifdef IMPBH
  9733.       //Improved barnes hut version
  9734.       float4 nodeCOM     = multipole[node*3 + 0];
  9735.       nodeCOM.w = nodeCenter.w;
  9736.  
  9737. #ifdef INDSOFT
  9738.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  9739. #else
  9740.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  9741. #endif
  9742. #else
  9743.       //Minimal distance version
  9744. #ifdef INDSOFT
  9745.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  9746. #else
  9747.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  9748. #endif
  9749. #endif //if IMPBH
  9750.  
  9751. #else
  9752.  
  9753.       bool curSplit = false;
  9754.       bool didBigCheck = false;
  9755.  
  9756.       //          if(split_node(nodeCenter, nodeSize, bigBoxCenter, bigBoxSize))
  9757.       {
  9758.         for(int k=check.coarseIDOffset; k < check.coarseIDEnd; k++)
  9759.         {
  9760.           //Test this specific box
  9761.           int coarseGrpId = coarseIDs[k];
  9762.  
  9763.  
  9764.           double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  9765.           double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  9766.  
  9767. #ifdef IMPBH
  9768.           //Improved barnes hut version
  9769.           float4 nodeCOM     = multipole[node*3 + 0];
  9770.           nodeCOM.w = nodeCenter.w;
  9771.  
  9772. #ifdef INDSOFT
  9773.           curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  9774. #else
  9775.           curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  9776. #endif
  9777.  
  9778. #else
  9779.           //Minimal distance version
  9780.  
  9781. #ifdef INDSOFT
  9782.           curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  9783. #else
  9784.           curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  9785. #endif
  9786. #endif //if IMPBH
  9787.  
  9788.           //Check if this box needs to go along for the ride further
  9789.           //down the tree
  9790.           if(curSplit)
  9791.           {
  9792.             split = true;
  9793.  
  9794.             if(leaf)  break;  //Early out if this is a leaf, since we wont have to check any further
  9795.  
  9796.             if(newOffset < 0)
  9797.               newOffset = k;
  9798.             newEnd = k+1;
  9799.           } //if curSplit
  9800.         } //For globalCoarseGrpCount[remoteId]
  9801.       }//Big-check
  9802. #endif
  9803.  
  9804.       uint temp = 0;  //A node that is not split and is not a leaf will get childinfo 0
  9805.       //if split & node add children to next lvl stack
  9806.       if(split && !leaf)
  9807.       {
  9808.         for(int i=child; i < child+nchild; i++)
  9809.         {
  9810.           combNodeCheck3 check;
  9811.           check.nodeID                = i;
  9812.           check.coarseIDOffset        = newOffset;
  9813.           check.coarseIDEnd           = newEnd;
  9814.           nextLevel[nextLevelCount++] = check;
  9815.         }
  9816.  
  9817.         temp = childNodeOffset | (nchild << 28);
  9818.         //Update reference to children
  9819.         childNodeOffset += nchild;
  9820.       }
  9821.  
  9822.       //if split & leaf add particles to particle list
  9823.       if(split && leaf)
  9824.       {
  9825.         for(int i=child; i < child+nchild; i++)
  9826.         {
  9827.           dataBuffer[particleOffset++] = bodies[i];
  9828.           dataBuffer[velParticleOffset++] = velocities[i];
  9829.           massSum += bodies[i].w;
  9830.         }
  9831.  
  9832.         temp = childParticleOffset | ((nchild-1) << LEAFBIT);
  9833.         childParticleOffset += nchild;
  9834.       }
  9835.  
  9836.  
  9837.  
  9838.       //Add the node data to the appropriate arrays and modify the node reference
  9839.       //start ofset for its children, should be nodeCount at start of this level +numberofnodes on this level
  9840.       //plus a counter that counts the number of childs of the nodes we have tested
  9841.  
  9842.       //New childoffset:
  9843.       union{int i; float f;} itof; //__int_as_float
  9844.       itof.i         = temp;
  9845.       float tempConv = itof.f;
  9846.  
  9847.       //Add node properties and update references
  9848.       real4 nodeSizeInfoTemp  = nodeSizeInfo[node];
  9849.       nodeSizeInfoTemp.w      = tempConv;             //Replace child reference
  9850.  
  9851.       dataBuffer[nodeSizeOffset++]   = nodeSizeInfoTemp;
  9852.       dataBuffer[nodeCenterOffset++] = nodeCenterInfo[node];
  9853.       dataBuffer[multiPoleOffset++]  = multipole[node*3 + 0];
  9854.       dataBuffer[multiPoleOffset++]  = multipole[node*3 + 1];
  9855.       dataBuffer[multiPoleOffset++]  = multipole[node*3 + 2];
  9856.  
  9857.       if(!split)
  9858.       {
  9859.         massSum += multipole[node*3 + 0].w;
  9860.       }
  9861.     } //end for curLevel.size
  9862.  
  9863.  
  9864.     //Put next level stack into current level and continue
  9865.     curLevelCount         = nextLevelCount;
  9866.     combNodeCheck3 *temp  = curLevel;
  9867.     curLevel              = nextLevel;
  9868.     nextLevel             = temp;
  9869.     nextLevelCount        = 0;
  9870.  
  9871.     level++;
  9872.   }//end while
  9873.  
  9874.   delete[] curLevel;
  9875.   delete[] nextLevel;
  9876.   delete[] coarseIDsTest;
  9877.   delete[] coarseIDs;
  9878.  
  9879.   //   cout << "New offsets: "  << particleOffset << " \t" << nodeSizeOffset << " \t" << nodeCenterOffset << endl;
  9880.   //    cout << "Mass sum: " << massSum  << endl;
  9881.   //   cout << "Mass sumtest: " << multipole[0*0 + 0].w << endl;
  9882. }
  9883.  
  9884.  
  9885.  
  9886. typedef struct{
  9887.   int nodeID;
  9888.   int coarseIDList;
  9889.   int coarseIDOffset;
  9890.   int coarseIDEnd;
  9891. } combNodeCheck5;
  9892.  
  9893. //This one makes a seperate list for each top node
  9894. void octree::create_local_essential_tree_count_novector_startend5(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  9895.     int remoteId, float group_eps, int start, int end,
  9896.     int &particles, int &nodes)
  9897. {
  9898.   //Walk the tree as is done on device, level by level
  9899.   const int stackSize = 128;
  9900.   combNodeCheck5 *curLevel  = new combNodeCheck5[1024*stackSize];
  9901.   combNodeCheck5 *nextLevel = new combNodeCheck5[1024*stackSize];
  9902.  
  9903.   int curLevelCount  = 0;
  9904.   int nextLevelCount = 0;
  9905.  
  9906.  
  9907.   int particleCount   = 0;
  9908.   int nodeCount       = 0;
  9909.  
  9910.   int level           = 0;
  9911.  
  9912.   int extraChecks = 0;
  9913.   int uselessChecks = 0;
  9914.   int splitChecks = 0;
  9915.  
  9916.  
  9917.   double4 bigBoxCenter = {  0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  9918.     0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  9919.     0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  9920.   double4 bigBoxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  9921.     fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  9922.     fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  9923.  
  9924.  
  9925.   int **coarseIDLists = new int*[end-start];
  9926.  
  9927.   int *coarseIDs = new int[globalCoarseGrpCount[remoteId]];
  9928.   //Add the initial coarse boxes to this level
  9929.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  9930.   {
  9931.     coarseIDs[i] = globalCoarseGrpOffsets[remoteId] + i;
  9932.   }
  9933.  
  9934.   //Add the initial nodes to the curLevel list
  9935.   for(int i=start; i < end; i++)
  9936.   {
  9937.  
  9938.   }
  9939.  
  9940.   //Filters out the boxes for the topnodes. Idea is that there will be
  9941.   //less boxes to be checked further down the tree
  9942.   int coarseListIdx = 0;
  9943.   for(int j=start; j < end; j++)
  9944.   {
  9945.     coarseIDLists[coarseListIdx] = new int[globalCoarseGrpCount[remoteId]];
  9946.     int foundBoxes = 0;
  9947.     for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  9948.     {
  9949.       real4 nodeCenter  = nodeCenterInfo[j];
  9950.       real4 nodeSize    = nodeSizeInfo[j];
  9951.       double4 boxCenter = coarseGroupBoxCenter[coarseIDs[i]];
  9952.       double4 boxSize   = coarseGroupBoxSize  [coarseIDs[i]];
  9953.       float4 nodeCOM    = multipole[j*3 + 0];
  9954.       nodeCOM.w         = nodeCenter.w;
  9955.  
  9956.       if(split_node_grav_impbh(nodeCOM, boxCenter, boxSize))
  9957.       {
  9958.         coarseIDLists[coarseListIdx][foundBoxes++] = coarseIDs[i];
  9959.       }
  9960.     } //for i
  9961.  
  9962.  
  9963.     combNodeCheck5 check;
  9964.     check.nodeID          = j;
  9965.     check.coarseIDOffset  = 0;
  9966.     check.coarseIDList    = coarseListIdx;
  9967.     check.coarseIDEnd     = foundBoxes;
  9968.     curLevel[curLevelCount++] = check;
  9969.  
  9970.     coarseListIdx++;
  9971.  
  9972.   } // for j
  9973.  
  9974.   //    for(int j=0; j < end-start; j++)
  9975.   //    {
  9976.   //      combNodeCheck5 check = curLevel[j];
  9977.   //      LOGF(stderr ,"Top node info; %d %d %d\n", check.nodeID, check.coarseIDList, check.coarseIDEnd);
  9978.   //    }
  9979.  
  9980.   //Preprocessing done
  9981.  
  9982.  
  9983.   //Add the nodes before the start and end to the node list
  9984.   for(int i=0; i < start; i++)
  9985.   {
  9986.     nodeCount++;
  9987.   }
  9988.  
  9989.   int maxSizeTemp = -1;
  9990.  
  9991.   //Start the tree-walk
  9992.   while(curLevelCount > 0)
  9993.   {
  9994.     maxSizeTemp = max(maxSizeTemp, curLevelCount);
  9995.  
  9996.     for(unsigned int i=0; i < curLevelCount; i++)
  9997.     {
  9998.       //Read node data
  9999.       combNodeCheck5 check = curLevel[i];
  10000.       int node           = check.nodeID;
  10001.  
  10002.       //        LOGF(stderr, "LET count On level: %d\tNode: %d\tGoing to check: %d\n",
  10003.       //                          level,node, check.coarseIDs.size());
  10004.  
  10005.       real4 nodeCenter = nodeCenterInfo[node];
  10006.       real4 nodeSize   = nodeSizeInfo[node];
  10007.       bool leaf        = nodeCenter.w <= 0;
  10008.  
  10009.       union{float f; int i;} u; //__float_as_int
  10010.       u.f           = nodeSize.w;
  10011.       int childinfo = u.i;
  10012.  
  10013.       int child, nchild;
  10014.       if(!leaf)
  10015.       {
  10016.         //Node
  10017.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  10018.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  10019.       }
  10020.       else
  10021.       {
  10022.         //Leaf
  10023.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  10024.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  10025.       }
  10026.  
  10027. #ifdef INDSOFT
  10028.       //Very inefficient this but for testing I have to live with it...
  10029.       float node_eps_val = multipole[node*3 + 1].w;
  10030. #endif
  10031.  
  10032.  
  10033.       bool split = false;
  10034.  
  10035.       int splitIdxToUse = 0;
  10036.  
  10037.       int newOffset = -1;
  10038.       int newEnd  = 0;
  10039.  
  10040. #if 0 //Old big LET method
  10041.       splitChecks++;
  10042.       double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  10043.         0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  10044.         0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  10045.       double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  10046.         fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  10047.         fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  10048.  
  10049. #ifdef IMPBH
  10050.       //Improved barnes hut version
  10051.       float4 nodeCOM     = multipole[node*3 + 0];
  10052.       nodeCOM.w = nodeCenter.w;
  10053.  
  10054. #ifdef INDSOFT
  10055.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  10056. #else
  10057.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  10058. #endif
  10059. #else
  10060.       //Minimal distance version
  10061. #ifdef INDSOFT
  10062.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  10063. #else
  10064.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  10065. #endif
  10066. #endif //if IMPBH
  10067.  
  10068. #else
  10069.       splitChecks++;
  10070.  
  10071.  
  10072.       bool curSplit = false;
  10073.  
  10074.  
  10075.       bool didBigCheck = false;
  10076.  
  10077.       //          if(split_node(nodeCenter, nodeSize, bigBoxCenter, bigBoxSize))
  10078.       {
  10079.         for(int k=check.coarseIDOffset; k < check.coarseIDEnd; k++)
  10080.         {
  10081.           extraChecks++;
  10082.           //Test this specific box
  10083.  
  10084.           //            int coarseGrpId = coarseIDs[k];
  10085.           int coarseGrpId = coarseIDLists[check.coarseIDList][k];
  10086.  
  10087.           double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  10088.           double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  10089.  
  10090.  
  10091. #ifdef IMPBH
  10092.           //Improved barnes hut version
  10093.           float4 nodeCOM     = multipole[node*3 + 0];
  10094.           nodeCOM.w = nodeCenter.w;
  10095.  
  10096. #ifdef INDSOFT
  10097.           curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  10098. #else
  10099.           curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  10100. #endif
  10101.  
  10102. #else
  10103.           //Minimal distance version
  10104.  
  10105. #ifdef INDSOFT
  10106.           curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  10107. #else
  10108.           curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  10109. #endif
  10110. #endif //if IMPBH
  10111.  
  10112.           //Check if this box needs to go along for the ride further
  10113.           //down the tree
  10114.           if(curSplit){
  10115.             split = true;
  10116.  
  10117.             if(leaf)  break;  //Early out if this is a leaf, since we wont have to check any further
  10118.  
  10119.             if(newOffset < 0)
  10120.               newOffset = k;
  10121.             newEnd = k+1;
  10122.           }
  10123.         } //For globalCoarseGrpCount[remoteId]
  10124.       }//Bigcheck
  10125.  
  10126.  
  10127. #endif
  10128.       //if split & node add children to next lvl stack
  10129.       if(split && !leaf)
  10130.       {
  10131.         for(int i=child; i < child+nchild; i++)
  10132.         {
  10133.           combNodeCheck5 check2;
  10134.           check2.nodeID    = i;
  10135.           check2.coarseIDOffset = newOffset;
  10136.           check2.coarseIDEnd    = newEnd;
  10137.           check2.coarseIDList = check.coarseIDList;
  10138.           nextLevel[nextLevelCount++] = check2;
  10139.         }
  10140.       }
  10141.  
  10142.       //if split & leaf add particles to particle list
  10143.       if(split && leaf)
  10144.       {
  10145.         for(int i=child; i < child+nchild; i++)
  10146.         {
  10147.           particleCount++;
  10148.         }
  10149.       }
  10150.  
  10151.       //Increase the nodeCount, since this node will be part of the tree-structure
  10152.       nodeCount++;
  10153.     } //end for curLevel.size
  10154.  
  10155.  
  10156.     //Put next level stack into current level and continue
  10157.     curLevelCount = nextLevelCount;
  10158.     combNodeCheck5 *temp = curLevel;
  10159.     curLevel = nextLevel;
  10160.     nextLevel = temp;
  10161.     nextLevelCount = 0;
  10162.  
  10163.     level++;
  10164.   }//end while
  10165.  
  10166.   particles = particleCount;
  10167.   nodes     = nodeCount;
  10168.  
  10169.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d maxStack: %d\n", extraChecks, splitChecks, uselessChecks, maxSizeTemp);
  10170.  
  10171.   /*    fprintf(stderr, "Count found: %d particles and %d nodes. Boxsize: (%f %f %f ) BoxCenter: (%f %f %f)\n",
  10172.         particles, nodes, boxSize.x ,boxSize.y, boxSize.z, boxCenter.x, boxCenter.y, boxCenter.z );  */
  10173. }
  10174.  
  10175. //This one does an initial filter but note that its not helping
  10176. //at all since we filter anyway on level further down....
  10177. void octree::create_local_essential_tree_count_vector_filter(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  10178.     int remoteId, float group_eps, int start, int end,
  10179.     int &particles, int &nodes)
  10180. {
  10181.  
  10182.   //Walk the tree as is done on device, level by level
  10183.   vector<combNodeCheck> curLevel;
  10184.   vector<combNodeCheck> nextLevel;
  10185.  
  10186.   curLevel.reserve(1024*64);
  10187.   nextLevel.reserve(1024*64);
  10188.  
  10189.  
  10190.  
  10191.   int particleCount   = 0;
  10192.   int nodeCount       = 0;
  10193.  
  10194.   int level           = 0;
  10195.  
  10196.   int extraChecks = 0;
  10197.   int uselessChecks = 0;
  10198.   int splitChecks = 0;
  10199.  
  10200.   vector<int> coarseIDs;
  10201.   //Add the initial coarse boxes to this level
  10202.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  10203.   {
  10204.     coarseIDs.push_back(globalCoarseGrpOffsets[remoteId] + i);
  10205.   }
  10206.  
  10207.   //Add the initial nodes to the curLevel list
  10208.   for(int i=start; i < end; i++)
  10209.   {
  10210.     combNodeCheck check;
  10211.     check.nodeID    = i;
  10212.  
  10213.     for(int j=0; j < globalCoarseGrpCount[remoteId]; j++)
  10214.     {
  10215.       real4 nodeCenter  = nodeCenterInfo[i];
  10216.       real4 nodeSize    = nodeSizeInfo[i];
  10217.       double4 boxCenter = coarseGroupBoxCenter[coarseIDs[j]];
  10218.       double4 boxSize   = coarseGroupBoxSize  [coarseIDs[j]];
  10219.       float4 nodeCOM    = multipole[j*3 + 0];
  10220.       nodeCOM.w         = nodeCenter.w;
  10221.  
  10222.       //Skip all previous not needed checks
  10223.       if(split_node_grav_impbh(nodeCOM, boxCenter, boxSize))
  10224.       {
  10225.         check.coarseIDs.push_back(coarseIDs[j]);
  10226.       }
  10227.     }
  10228.  
  10229.     //      check.coarseIDs = coarseIDs;
  10230.     curLevel.push_back(check);
  10231.   }
  10232.  
  10233.   //Add the nodes before the start and end to the node list
  10234.   for(int i=0; i < start; i++)
  10235.   {
  10236.     nodeCount++;
  10237.   }
  10238.  
  10239.   //Start the tree-walk
  10240.   while(curLevel.size() > 0)
  10241.   {
  10242.     for(unsigned int i=0; i < curLevel.size(); i++)
  10243.     {
  10244.       //Read node data
  10245.       combNodeCheck check = curLevel[i];
  10246.       int node           = check.nodeID;
  10247.  
  10248.       //        LOGF(stderr, "LET count On level: %d\tNode: %d\tGoing to check: %d\n",
  10249.       //                          level,node, check.coarseIDs.size());
  10250.  
  10251.       real4 nodeCenter = nodeCenterInfo[node];
  10252.       real4 nodeSize   = nodeSizeInfo[node];
  10253.       bool leaf        = nodeCenter.w <= 0;
  10254.  
  10255.       union{float f; int i;} u; //__float_as_int
  10256.       u.f           = nodeSize.w;
  10257.       int childinfo = u.i;
  10258.  
  10259.       int child, nchild;
  10260.       if(!leaf)
  10261.       {
  10262.         //Node
  10263.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  10264.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  10265.       }
  10266.       else
  10267.       {
  10268.         //Leaf
  10269.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  10270.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  10271.       }
  10272.  
  10273. #ifdef INDSOFT
  10274.       //Very inefficient this but for testing I have to live with it...
  10275.       float node_eps_val = multipole[node*3 + 1].w;
  10276. #endif
  10277.  
  10278.  
  10279.       bool split = false;
  10280.  
  10281.       int splitIdxToUse = 0;
  10282.       vector<int> checkIDs;
  10283. #if 0
  10284.       splitChecks++;
  10285.       double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  10286.         0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  10287.         0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  10288.       double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  10289.         fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  10290.         fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  10291.  
  10292. #ifdef IMPBH
  10293.       //Improved barnes hut version
  10294.       float4 nodeCOM     = multipole[node*3 + 0];
  10295.       nodeCOM.w = nodeCenter.w;
  10296.  
  10297. #ifdef INDSOFT
  10298.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  10299. #else
  10300.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  10301. #endif
  10302. #else
  10303.       //Minimal distance version
  10304. #ifdef INDSOFT
  10305.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  10306. #else
  10307.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  10308. #endif
  10309. #endif //if IMPBH
  10310.  
  10311. #else
  10312.       splitChecks++;
  10313.  
  10314.  
  10315.       bool curSplit = false;
  10316.  
  10317.       //        for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  10318.       for(int k=0; k < check.coarseIDs.size(); k++)
  10319.       {
  10320.         extraChecks++;
  10321.         //  particleCount++;
  10322.         //Test this specific box
  10323.         int coarseGrpId = check.coarseIDs[k];
  10324.  
  10325.         double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  10326.         double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  10327.  
  10328.  
  10329. #ifdef IMPBH
  10330.         //Improved barnes hut version
  10331.         float4 nodeCOM     = multipole[node*3 + 0];
  10332.         nodeCOM.w = nodeCenter.w;
  10333.  
  10334. #ifdef INDSOFT
  10335.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  10336. #else
  10337.         curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  10338. #endif
  10339.  
  10340. #else
  10341.         //Minimal distance version
  10342.  
  10343. #ifdef INDSOFT
  10344.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  10345. #else
  10346.         curSplit = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  10347. #endif
  10348. #endif //if IMPBH
  10349.  
  10350.         //Early out if at least one box requires this info
  10351.         if(curSplit){
  10352.           split = true;
  10353.           checkIDs.push_back(coarseGrpId);
  10354.           //              splitIdxToUse = k;
  10355.           //              LOGF(stderr, "LET count On level: %d\tNode: %d\tStart: %d\tEnd: %d\tChecks: %d \n",
  10356.           //                  level,node, startCoarseBox, splitIdxToUse, splitIdxToUse-startCoarseBox+1);
  10357.  
  10358.           //              extraChecks += splitIdxToUse-startCoarseBox;
  10359.           //              break;
  10360.         }
  10361.       } //For globalCoarseGrpCount[remoteId]
  10362.  
  10363.       if(split == false)
  10364.       {
  10365.         //          uselessChecks +=  boxIndicesToUse.size()-startCoarseBox;
  10366.       }
  10367.  
  10368. #endif
  10369.       //if split & node add children to next lvl stack
  10370.       if(split && !leaf)
  10371.       {
  10372.         for(int i=child; i < child+nchild; i++)
  10373.         {
  10374.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  10375.           combNodeCheck check;
  10376.           check.nodeID    = i;
  10377.           check.coarseIDs = checkIDs;
  10378.           nextLevel.push_back(check);
  10379.           //            nextLevel.push_back(make_int2(i, splitIdxToUse));
  10380.         }
  10381.       }
  10382.  
  10383.       //if split & leaf add particles to particle list
  10384.       if(split && leaf)
  10385.       {
  10386.         for(int i=child; i < child+nchild; i++)
  10387.         {
  10388.           particleCount++;
  10389.         }
  10390.       }
  10391.  
  10392.       //Increase the nodeCount, since this node will be part of the tree-structure
  10393.       nodeCount++;
  10394.     } //end for curLevel.size
  10395.  
  10396.  
  10397.     //Put next level stack into current level and continue
  10398.     curLevel.clear();
  10399.  
  10400.     //       cout << "Next level: " << nextLevel.size() << endl;
  10401.     curLevel.assign(nextLevel.begin(), nextLevel.end());
  10402.     nextLevel.clear();
  10403.     level++;
  10404.   }//end while
  10405.  
  10406.   particles = particleCount;
  10407.   nodes     = nodeCount;
  10408.  
  10409.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  10410.  
  10411.   /*    fprintf(stderr, "Count found: %d particles and %d nodes. Boxsize: (%f %f %f ) BoxCenter: (%f %f %f)\n",
  10412.         particles, nodes, boxSize.x ,boxSize.y, boxSize.z, boxCenter.x, boxCenter.y, boxCenter.z );  */
  10413. }
  10414.  
  10415.  
  10416. void octree::create_local_essential_tree_count_recursive_part2(
  10417.     real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  10418.     int nodeID,
  10419.     vector<int> &remoteGrps, uint remoteGrpStart,
  10420.     int &particles, int &nodes)
  10421. {
  10422.   //Read node data
  10423.  
  10424.   int node = nodeID;
  10425.  
  10426.   real4 nodeCenter = nodeCenterInfo[node];
  10427.   real4 nodeSize   = nodeSizeInfo[node];
  10428.   bool leaf        = nodeCenter.w <= 0;
  10429.  
  10430.   union{float f; int i;} u; //__float_as_int
  10431.   u.f           = nodeSize.w;
  10432.   int childinfo = u.i;
  10433.  
  10434.   int child, nchild;
  10435.   if(!leaf)
  10436.   {
  10437.     //Node
  10438.     child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  10439.     nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  10440.   }
  10441.   else
  10442.   {
  10443.     //Leaf
  10444.     child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  10445.     nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  10446.   }
  10447.  
  10448.   bool split = false;
  10449.  
  10450.   int splitIdxToUse = 0;
  10451.  
  10452.   bool curSplit = false;
  10453.  
  10454.   int coarseGrpStart;
  10455.  
  10456.   //        for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  10457.   for(int k=remoteGrpStart; k < remoteGrps.size(); k++)
  10458.   {
  10459.     //Test this specific box
  10460.     coarseGrpStart  = k;
  10461.     int coarseGrpId = remoteGrps[k];
  10462.  
  10463.     double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  10464.     double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  10465.  
  10466.     //Improved barnes hut version
  10467.     float4 nodeCOM     = multipole[node*3 + 0];
  10468.     nodeCOM.w = nodeCenter.w;
  10469.  
  10470.     curSplit = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  10471.  
  10472.     //Early out if at least one box requires this info
  10473.     if(curSplit){
  10474.       split = true;
  10475.       break;
  10476.     }
  10477.   } //For globalCoarseGrpCount[remoteId]
  10478.  
  10479.  
  10480.   //if split & node add children to next lvl stack
  10481.   if(split && !leaf)
  10482.   {
  10483.     for(int i=child; i < child+nchild; i++)
  10484.     {
  10485.       nodes++;
  10486.       create_local_essential_tree_count_recursive_part2(
  10487.           bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  10488.           i, remoteGrps, coarseGrpStart ,particles, nodes);
  10489.     }
  10490.   }
  10491.  
  10492.   //if split & leaf add particles to particle list
  10493.   if(split && leaf)
  10494.   {
  10495.     for(int i=child; i < child+nchild; i++)
  10496.     {
  10497.       particles++;
  10498.     }
  10499.   }
  10500. }
  10501.  
  10502.  
  10503. void octree::create_local_essential_tree_count_recursive(
  10504.     real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  10505.     int remoteId, float group_eps, int start, int end,
  10506.     int &particles, int &nodes)
  10507. {
  10508.   vector<int> coarseIDs;
  10509.  
  10510.   int particleCount   = 0;
  10511.   int nodeCount       = 0;
  10512.  
  10513.   int level           = 0;
  10514.  
  10515.   int extraChecks = 0;
  10516.   int uselessChecks = 0;
  10517.   int splitChecks = 0;
  10518.  
  10519.   //Add the initial coarse boxes to this level
  10520.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  10521.   {
  10522.     coarseIDs.push_back(globalCoarseGrpOffsets[remoteId] + i);
  10523.   }
  10524.  
  10525.   nodeCount += start;
  10526.   //Add the initial nodes to the curLevel list
  10527.   for(int i=start; i < end; i++)
  10528.   {
  10529.     nodeCount++;
  10530.     create_local_essential_tree_count_recursive_part2(
  10531.         bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  10532.         i, coarseIDs, 0,particleCount, nodeCount);
  10533.  
  10534.   }
  10535.  
  10536.  
  10537.   particles = particleCount;
  10538.   nodes     = nodeCount;
  10539.  
  10540.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  10541.  
  10542.   /*    fprintf(stderr, "Count found: %d particles and %d nodes. Boxsize: (%f %f %f ) BoxCenter: (%f %f %f)\n",
  10543.         particles, nodes, boxSize.x ,boxSize.y, boxSize.z, boxCenter.x, boxCenter.y, boxCenter.z );  */
  10544. }
  10545.  
  10546.  
  10547. void octree::create_local_essential_tree_count_recursive_try2(
  10548.     real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  10549.     int remoteId, float group_eps, int start, int end,
  10550.     int &particles, int &nodes)
  10551. {
  10552.   int particleCount   = 0;
  10553.   int nodeCount       = 0;
  10554.  
  10555.   int level           = 0;
  10556.  
  10557.   int extraChecks = 0;
  10558.   int uselessChecks = 0;
  10559.   int splitChecks = 0;
  10560.  
  10561.   uint2 node_begend;
  10562.   node_begend.x   = this->localTree.level_list[2].x;
  10563.   node_begend.y   = this->localTree.level_list[2].y;
  10564.  
  10565.   //Add the initial coarse boxes to this level
  10566.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  10567.   {
  10568.     //      if(procId == 1)   LOGF(stderr,"Going to check : %d \n", globalCoarseGrpOffsets[remoteId] + i);
  10569.     bool allDone = false;
  10570.     for(int k = node_begend.x; k < node_begend.y; k++)
  10571.     {
  10572.       create_local_essential_tree_count_recursive_part2_try2(
  10573.           bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  10574.           k, globalCoarseGrpOffsets[remoteId] + i,particleCount, nodeCount, allDone);
  10575.     }
  10576.  
  10577.   }
  10578.  
  10579.   nodeCount += start;
  10580.   //Add the initial nodes to the curLevel list
  10581.   for(int i=start; i < end; i++)
  10582.   {
  10583.     nodeCount++;
  10584.   }
  10585.  
  10586.  
  10587.   particles = particleCount;
  10588.   nodes     = nodeCount;
  10589.  
  10590.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  10591.  
  10592.   /*    fprintf(stderr, "Count found: %d particles and %d nodes. Boxsize: (%f %f %f ) BoxCenter: (%f %f %f)\n",
  10593.         particles, nodes, boxSize.x ,boxSize.y, boxSize.z, boxCenter.x, boxCenter.y, boxCenter.z );  */
  10594. }
  10595.  
  10596.  
  10597. //This one checks only one box
  10598. void octree::create_local_essential_tree_count_recursive_part2_try2(
  10599.     real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  10600.     int nodeID, uint remoteGrpID, int &particles, int &nodes, bool &allDone)
  10601. {
  10602.   //Read node data
  10603.  
  10604.   int node = nodeID;
  10605.  
  10606.   real4 nodeCenter = nodeCenterInfo[node];
  10607.   real4 nodeSize   = nodeSizeInfo[node];
  10608.   bool leaf        = nodeCenter.w <= 0;
  10609.  
  10610.   union{float f; int i;} u; //__float_as_int
  10611.   u.f           = nodeSize.w;
  10612.   int childinfo = u.i;
  10613.  
  10614.   int child, nchild;
  10615.   if(!leaf)
  10616.   {
  10617.     //Node
  10618.     child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  10619.     nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  10620.  
  10621.     //Early out if this node has been processed before
  10622.     if(childinfo == 0xFFFFFFFF) return;
  10623.   }
  10624.   else
  10625.   {
  10626.     //Leaf
  10627.     child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  10628.     nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  10629.  
  10630.     //Early out if this leaf has been processed before
  10631.     if(childinfo == 0xFFFFFFFF) return;
  10632.   }
  10633.  
  10634.   bool split = false;
  10635.  
  10636.   //Test this specific box
  10637.   double4 boxCenter = coarseGroupBoxCenter[remoteGrpID];
  10638.   double4 boxSize   = coarseGroupBoxSize  [remoteGrpID];
  10639.  
  10640.   //Improved barnes hut version
  10641.   float4 nodeCOM     = multipole[node*3 + 0];
  10642.   nodeCOM.w = nodeCenter.w;
  10643.  
  10644.   split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  10645.  
  10646.   //if split & node add children to next lvl stack
  10647.   if(split && !leaf)
  10648.   {
  10649.     int nNodesDone = 0;
  10650.     for(int i=child; i < child+nchild; i++)
  10651.     {
  10652.       bool thisOneDone = false;
  10653.       nodes++;
  10654.       create_local_essential_tree_count_recursive_part2_try2(
  10655.           bodies, multipole, nodeSizeInfo, nodeCenterInfo,
  10656.           i, remoteGrpID ,particles, nodes, thisOneDone);
  10657.       if(thisOneDone) nNodesDone++;
  10658.     }
  10659.     if(nNodesDone == nchild)
  10660.     {
  10661.       //        LOGF(stderr, "Processed a full node! [%d - %d ] %d DONE? : %d\n",child, child+nchild, nNodesDone, nNodesDone == nchild);
  10662.       nodeSizeInfo[node].w = host_int_as_float(0xFFFFFFFF);
  10663.     }
  10664.     //      if(nNodesDone >= nchild/2)
  10665.     //      {
  10666.     ////        LOGF(stderr, "ALMOST a full node! [%d - %d ] %d DONE? : %d\n",
  10667.     ////            child, child+nchild, nNodesDone, nNodesDone == nchild);
  10668.     //        nodeSizeInfo[node].w = host_int_as_float(0xFFFFFFFF);
  10669.     //      }
  10670.   }
  10671.  
  10672.   //if split & leaf add particles to particle list
  10673.   if(split && leaf)
  10674.   {
  10675.     for(int i=child; i < child+nchild; i++)
  10676.     {
  10677.       particles++;
  10678.     }
  10679.     //Modify this leaf, so we do not process it anymore
  10680.     nodeSizeInfo[node].w = host_int_as_float(0xFFFFFFFF);
  10681.     allDone = true;
  10682.     //      LOGF(stderr, "Processed a leaf %d\n", node);
  10683.   }
  10684. }
  10685.  
  10686.  
  10687.  
  10688.  
  10689.  
  10690. #endif
  10691. #if 0
  10692. //This one remembers the index of where the split happend and uses this as start next time
  10693. //all before are ignored
  10694.  
  10695. //void octree::create_local_essential_tree_count(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  10696. //                                         double4 boxCenter, double4 boxSize, float group_eps, int start, int end,
  10697. //                                         int &particles, int &nodes)
  10698. void octree::create_local_essential_tree_count(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  10699.     int remoteId, float group_eps, int start, int end,
  10700.     int &particles, int &nodes)
  10701. {
  10702.   //Walk the tree as is done on device, level by level
  10703.   vector<int2> curLevel;
  10704.   vector<int2> nextLevel;
  10705.  
  10706.   int particleCount   = 0;
  10707.   int nodeCount       = 0;
  10708.  
  10709.   int level           = 0;
  10710.  
  10711.   int extraChecks = 0;
  10712.   int uselessChecks = 0;
  10713.   int splitChecks = 0;
  10714.  
  10715.   vector<int> boxIndicesToUse;
  10716.  
  10717.   //Add the initial nodes to the curLevel list
  10718.   for(int i=start; i < end; i++)
  10719.   {
  10720.     curLevel.push_back(make_int2(i,0));
  10721.   }
  10722.  
  10723.   //Add the initial coarse boxes to this level
  10724.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  10725.   {
  10726.     boxIndicesToUse.push_back(globalCoarseGrpOffsets[remoteId] + i);
  10727.   }
  10728.  
  10729.   //Add the nodes before the start and end to the node list
  10730.   for(int i=0; i < start; i++)
  10731.   {
  10732.     nodeCount++;
  10733.   }
  10734.  
  10735.   //Start the tree-walk
  10736.   while(curLevel.size() > 0)
  10737.   {
  10738.     for(unsigned int i=0; i < curLevel.size(); i++)
  10739.     {
  10740.       //Read node data
  10741.       int node           = curLevel[i].x;
  10742.       int startCoarseBox = curLevel[i].y;
  10743.       real4 nodeCenter = nodeCenterInfo[node];
  10744.       real4 nodeSize   = nodeSizeInfo[node];
  10745.       bool leaf        = nodeCenter.w <= 0;
  10746.  
  10747.       union{float f; int i;} u; //__float_as_int
  10748.       u.f           = nodeSize.w;
  10749.       int childinfo = u.i;
  10750.  
  10751.       int child, nchild;
  10752.       if(!leaf)
  10753.       {
  10754.         //Node
  10755.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  10756.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  10757.       }
  10758.       else
  10759.       {
  10760.         //Leaf
  10761.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  10762.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  10763.       }
  10764.  
  10765. #ifdef INDSOFT
  10766.       //Very inefficient this but for testing I have to live with it...
  10767.       float node_eps_val = multipole[node*3 + 1].w;
  10768. #endif
  10769.  
  10770.  
  10771.       bool split = false;
  10772.  
  10773.       int splitIdxToUse = 0;
  10774. #if 0
  10775.       splitChecks++;
  10776.       double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  10777.         0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  10778.         0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  10779.       double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  10780.         fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  10781.         fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  10782.  
  10783. #ifdef IMPBH
  10784.       //Improved barnes hut version
  10785.       float4 nodeCOM     = multipole[node*3 + 0];
  10786.       nodeCOM.w = nodeCenter.w;
  10787.  
  10788. #ifdef INDSOFT
  10789.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  10790. #else
  10791.       split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  10792. #endif
  10793. #else
  10794.       //Minimal distance version
  10795. #ifdef INDSOFT
  10796.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  10797. #else
  10798.       split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  10799. #endif
  10800. #endif //if IMPBH
  10801.  
  10802. #else
  10803.       splitChecks++;
  10804.  
  10805.       //        for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  10806.       for(int k=startCoarseBox; k < boxIndicesToUse.size(); k++)
  10807.       {
  10808.         //  particleCount++;
  10809.         //Test this specific box
  10810.         int coarseGrpId = boxIndicesToUse[k];
  10811.  
  10812.         double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  10813.         double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  10814.  
  10815.  
  10816. #ifdef IMPBH
  10817.         //Improved barnes hut version
  10818.         float4 nodeCOM     = multipole[node*3 + 0];
  10819.         nodeCOM.w = nodeCenter.w;
  10820.  
  10821. #ifdef INDSOFT
  10822.         split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  10823. #else
  10824.         split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  10825. #endif
  10826.  
  10827. #else
  10828.         //Minimal distance version
  10829.  
  10830. #ifdef INDSOFT
  10831.         split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  10832. #else
  10833.         split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  10834. #endif
  10835. #endif //if IMPBH
  10836.  
  10837.         //Early out if at least one box requires this info
  10838.         if(split){
  10839.           splitIdxToUse = k;
  10840.           //              LOGF(stderr, "LET count On level: %d\tNode: %d\tStart: %d\tEnd: %d\tChecks: %d \n",
  10841.           //                  level,node, startCoarseBox, splitIdxToUse, splitIdxToUse-startCoarseBox+1);
  10842.  
  10843.           extraChecks += splitIdxToUse-startCoarseBox;
  10844.           break;
  10845.         }
  10846.       } //For globalCoarseGrpCount[remoteId]
  10847.  
  10848.       if(split == false)
  10849.       {
  10850.         uselessChecks +=  boxIndicesToUse.size()-startCoarseBox;
  10851.       }
  10852.  
  10853. #endif
  10854.       //if split & node add children to next lvl stack
  10855.       if(split && !leaf)
  10856.       {
  10857.         for(int i=child; i < child+nchild; i++)
  10858.         {
  10859.           nextLevel.push_back(make_int2(i, splitIdxToUse));
  10860.         }
  10861.       }
  10862.  
  10863.       //if split & leaf add particles to particle list
  10864.       if(split && leaf)
  10865.       {
  10866.         for(int i=child; i < child+nchild; i++)
  10867.         {
  10868.           particleCount++;
  10869.         }
  10870.       }
  10871.  
  10872.       //Increase the nodeCount, since this node will be part of the tree-structure
  10873.       nodeCount++;
  10874.     } //end for curLevel.size
  10875.  
  10876.  
  10877.  
  10878.     //      Hier gebleven dit werkt niet. Er is altijd wel 1 group die het heeft
  10879.     //      Oplossing, per node bijgaan houden waar we zitten in de lijst
  10880.     //      Dit kan door curLevel en nextLevel niet als int op te slaan maar als int2
  10881.     //      en dan in x het nodeID en in y de i waar we gebleven waren met de split
  10882.  
  10883.  
  10884.     //End reduce the boxes to use
  10885.  
  10886.     //Put next level stack into current level and continue
  10887.     curLevel.clear();
  10888.  
  10889.     //       cout << "Next level: " << nextLevel.size() << endl;
  10890.     curLevel.assign(nextLevel.begin(), nextLevel.end());
  10891.     nextLevel.clear();
  10892.     level++;
  10893.   }//end while
  10894.  
  10895.   particles = particleCount;
  10896.   nodes     = nodeCount;
  10897.  
  10898.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  10899.  
  10900.   /*    fprintf(stderr, "Count found: %d particles and %d nodes. Boxsize: (%f %f %f ) BoxCenter: (%f %f %f)\n",
  10901.         particles, nodes, boxSize.x ,boxSize.y, boxSize.z, boxCenter.x, boxCenter.y, boxCenter.z );  */
  10902. }
  10903. #endif
  10904.  
  10905.  
  10906. #if 0
  10907. //This is the one that goes over the full box-grp
  10908.  
  10909. //void octree::create_local_essential_tree_count(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  10910. //                                         double4 boxCenter, double4 boxSize, float group_eps, int start, int end,
  10911. //                                         int &particles, int &nodes)
  10912. void octree::create_local_essential_tree_count(real4* bodies, real4* multipole, real4* nodeSizeInfo, real4* nodeCenterInfo,
  10913.     int remoteId, float group_eps, int start, int end,
  10914.     int &particles, int &nodes)
  10915. {
  10916.   //Walk the tree as is done on device, level by level
  10917.   vector<int2> curLevel;
  10918.   vector<int2> nextLevel;
  10919.  
  10920.   int particleCount   = 0;
  10921.   int nodeCount       = 0;
  10922.  
  10923.   int level           = 0;
  10924.  
  10925.   int extraChecks = 0;
  10926.   int uselessChecks = 0;
  10927.   int splitChecks = 0;
  10928.  
  10929.   vector<int> boxIndicesToUse;
  10930.  
  10931.   //Add the initial nodes to the curLevel list
  10932.   for(int i=start; i < end; i++)
  10933.   {
  10934.     curLevel.push_back(make_int2(i,0));
  10935.   }
  10936.  
  10937.   //Add the initial coarse boxes to this level
  10938.   for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  10939.   {
  10940.     boxIndicesToUse.push_back(globalCoarseGrpOffsets[remoteId] + i);
  10941.   }
  10942.  
  10943.   //Add the nodes before the start and end to the node list
  10944.   for(int i=0; i < start; i++)
  10945.   {
  10946.     nodeCount++;
  10947.   }
  10948.  
  10949.   double4 boxCenter = {     0.5*(currentRLow[remoteId].x  + currentRHigh[remoteId].x),
  10950.     0.5*(currentRLow[remoteId].y  + currentRHigh[remoteId].y),
  10951.     0.5*(currentRLow[remoteId].z  + currentRHigh[remoteId].z), 0};
  10952.   double4 boxSize   = {fabs(0.5*(currentRHigh[remoteId].x - currentRLow[remoteId].x)),
  10953.     fabs(0.5*(currentRHigh[remoteId].y - currentRLow[remoteId].y)),
  10954.     fabs(0.5*(currentRHigh[remoteId].z - currentRLow[remoteId].z)), 0};
  10955.  
  10956.   LOGF(stderr,"TEST: %f %f %f || %f %f %f \n", boxCenter.x, boxCenter.y, boxCenter.z,
  10957.       boxSize.x, boxSize.y, boxSize.z);
  10958.  
  10959.   //Start the tree-walk
  10960.   while(curLevel.size() > 0)
  10961.   {
  10962.     for(unsigned int i=0; i < curLevel.size(); i++)
  10963.     {
  10964.       //Read node data
  10965.       int node           = curLevel[i].x;
  10966.       int startCoarseBox = curLevel[i].y;
  10967.       real4 nodeCenter = nodeCenterInfo[node];
  10968.       real4 nodeSize   = nodeSizeInfo[node];
  10969.       bool leaf        = nodeCenter.w <= 0;
  10970.  
  10971.       union{float f; int i;} u; //__float_as_int
  10972.       u.f           = nodeSize.w;
  10973.       int childinfo = u.i;
  10974.  
  10975.       int child, nchild;
  10976.       if(!leaf)
  10977.       {
  10978.         //Node
  10979.         child    =    childinfo & 0x0FFFFFFF;                         //Index to the first child of the node
  10980.         nchild   = (((childinfo & 0xF0000000) >> 28)) ;         //The number of children this node has
  10981.       }
  10982.       else
  10983.       {
  10984.         //Leaf
  10985.         child   =   childinfo & BODYMASK;                                     //thre first body in the leaf
  10986.         nchild  = (((childinfo & INVBMASK) >> LEAFBIT)+1);     //number of bodies in the leaf masked with the flag
  10987.       }
  10988.  
  10989. #ifdef INDSOFT
  10990.       //Very inefficient this but for testing I have to live with it...
  10991.       float node_eps_val = multipole[node*3 + 1].w;
  10992. #endif
  10993.  
  10994.  
  10995.       bool split = false;
  10996.  
  10997.       int splitIdxToUse = 0;
  10998.  
  10999.       splitChecks++;
  11000.  
  11001.       //        for(int i=0; i < globalCoarseGrpCount[remoteId]; i++)
  11002.       //        for(int k=startCoarseBox; k < boxIndicesToUse.size(); k++)
  11003.       {
  11004.         //  particleCount++;
  11005.         //Test this specific box
  11006.         //          int coarseGrpId = boxIndicesToUse[k];
  11007.         //
  11008.         //          double4 boxCenter = coarseGroupBoxCenter[coarseGrpId];
  11009.         //          double4 boxSize   = coarseGroupBoxSize  [coarseGrpId];
  11010.  
  11011.  
  11012. #ifdef IMPBH
  11013.         //Improved barnes hut version
  11014.         float4 nodeCOM     = multipole[node*3 + 0];
  11015.         nodeCOM.w = nodeCenter.w;
  11016.  
  11017. #ifdef INDSOFT
  11018.         split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize, group_eps, node_eps_val);
  11019. #else
  11020.         split = split_node_grav_impbh(nodeCOM, boxCenter, boxSize);
  11021. #endif
  11022.  
  11023. #else
  11024.         //Minimal distance version
  11025.  
  11026. #ifdef INDSOFT
  11027.         split = split_node(nodeCenter, nodeSize, boxCenter, boxSize, group_eps, node_eps_val);  //Check if node should be split
  11028. #else
  11029.         split = split_node(nodeCenter, nodeSize, boxCenter, boxSize);
  11030. #endif
  11031. #endif //if IMPBH
  11032.  
  11033.         //Early out if at least one box requires this info
  11034.         if(split){
  11035.           //              splitIdxToUse = k;
  11036.           //              LOGF(stderr, "LET count On level: %d\tNode: %d\tStart: %d\tEnd: %d\tChecks: %d \n",
  11037.           //                  level,node, startCoarseBox, splitIdxToUse, splitIdxToUse-startCoarseBox+1);
  11038.  
  11039.           //              extraChecks += splitIdxToUse-startCoarseBox;
  11040.           //              break;
  11041.         }
  11042.       } //For globalCoarseGrpCount[remoteId]
  11043.  
  11044.       if(split == false)
  11045.       {
  11046.         uselessChecks +=  boxIndicesToUse.size()-startCoarseBox;
  11047.       }
  11048.  
  11049.       //if split & node add children to next lvl stack
  11050.       if(split && !leaf)
  11051.       {
  11052.         for(int i=child; i < child+nchild; i++)
  11053.         {
  11054.           nextLevel.push_back(make_int2(i, splitIdxToUse));
  11055.         }
  11056.       }
  11057.  
  11058.       //if split & leaf add particles to particle list
  11059.       if(split && leaf)
  11060.       {
  11061.         for(int i=child; i < child+nchild; i++)
  11062.         {
  11063.           particleCount++;
  11064.         }
  11065.       }
  11066.  
  11067.       //Increase the nodeCount, since this node will be part of the tree-structure
  11068.       nodeCount++;
  11069.     } //end for curLevel.size
  11070.  
  11071.  
  11072.  
  11073.     //      Hier gebleven dit werkt niet. Er is altijd wel 1 group die het heeft
  11074.     //      Oplossing, per node bijgaan houden waar we zitten in de lijst
  11075.     //      Dit kan door curLevel en nextLevel niet als int op te slaan maar als int2
  11076.     //      en dan in x het nodeID en in y de i waar we gebleven waren met de split
  11077.  
  11078.  
  11079.     //End reduce the boxes to use
  11080.  
  11081.     //Put next level stack into current level and continue
  11082.     curLevel.clear();
  11083.  
  11084.     //       cout << "Next level: " << nextLevel.size() << endl;
  11085.     curLevel.assign(nextLevel.begin(), nextLevel.end());
  11086.     nextLevel.clear();
  11087.     level++;
  11088.   }//end while
  11089.  
  11090.   particles = particleCount;
  11091.   nodes     = nodeCount;
  11092.  
  11093.   LOGF(stderr, "LET Extra checks: %d SplitChecks: %d UselessChecks: %d\n", extraChecks, splitChecks, uselessChecks);
  11094.  
  11095.   /*    fprintf(stderr, "Count found: %d particles and %d nodes. Boxsize: (%f %f %f ) BoxCenter: (%f %f %f)\n",
  11096.         particles, nodes, boxSize.x ,boxSize.y, boxSize.z, boxCenter.x, boxCenter.y, boxCenter.z );  */
  11097. }
  11098. #endif
  11099.  
  11100.  
  11101. #if 0
  11102. //Exchange particles with other processes
  11103. int octree::gpu_exchange_particles_with_overflow_check(tree_structure &tree,
  11104.     bodyStruct *particlesToSend,
  11105.     my_dev::dev_mem<uint> &extractList,
  11106.     int nToSend)
  11107. {
  11108.   int myid      = procId;
  11109.   int nproc     = nProcs;
  11110.   int iloc      = 0;
  11111.   int nbody     = nToSend;
  11112.  
  11113.  
  11114.   bodyStruct  tmpp;
  11115.  
  11116.   int *firstloc   = new int[nProcs+1];
  11117.   int *nparticles = new int[nProcs+1];
  11118.  
  11119.   // Loop over particles and determine which particle needs to go where
  11120.   // reorder the bodies in such a way that bodies that have to be send
  11121.   // away are stored after each other in the array
  11122.   double t1 = get_time();
  11123.  
  11124.   //Array reserve some memory at forehand , 1%
  11125.   vector<bodyStruct> array2Send;
  11126.   array2Send.reserve((int)(nToSend*1.5));
  11127.  
  11128.   for(int ib=0;ib<nproc;ib++)
  11129.   {
  11130.     int ibox       = (ib+myid)%nproc;
  11131.     firstloc[ibox] = iloc;      //Index of the first particle send to proc: ibox
  11132.  
  11133.     for(int i=iloc; i<nbody;i++)
  11134.     {
  11135.       if(isinbox(particlesToSend[i].Ppos, domainRLow[ibox], domainRHigh[ibox]))
  11136.       {
  11137.         //Reorder the particle information
  11138.         tmpp                  = particlesToSend[iloc];
  11139.         particlesToSend[iloc] = particlesToSend[i];
  11140.         particlesToSend[i]    = tmpp;
  11141.  
  11142.         //Put the particle in the array of to send particles
  11143.         array2Send.push_back(particlesToSend[iloc]);
  11144.  
  11145.         iloc++;
  11146.       }// end if
  11147.     }//for i=iloc
  11148.     nparticles[ibox] = iloc-firstloc[ibox];//Number of particles that has to be send to proc: ibox
  11149.   } // for(int ib=0;ib<nproc;ib++)
  11150.  
  11151.  
  11152.   //   printf("Required search time: %lg ,proc: %d found in our own box: %d n: %d  to others: %ld \n",
  11153.   //          get_time()-t1, myid, nparticles[myid], tree.n, array2Send.size());
  11154.  
  11155.  
  11156.   if(iloc < nbody)
  11157.   {
  11158.     cerr << procId <<" exchange_particle error: particle in no box...iloc: " << iloc
  11159.       << " and nbody: " << nbody << "\n";
  11160.     exit(0);
  11161.   }
  11162.  
  11163.  
  11164.   /*totalsent = nbody - nparticles[myid];
  11165.  
  11166.     int tmp;
  11167.     MPI_Reduce(&totalsent,&tmp,1, MPI_INT, MPI_SUM,0,MPI_COMM_WORLD);
  11168.     if(procId == 0)
  11169.     {
  11170.     totalsent = tmp;
  11171.     cout << "Exchanged particles = " << totalsent << endl;
  11172.     }*/
  11173.  
  11174.   t1 = get_time();
  11175.  
  11176.   //Allocate two times the amount of memory of that which we send
  11177.   vector<bodyStruct> recv_buffer3(nbody*2);
  11178.   unsigned int recvCount = 0;
  11179.  
  11180.   //Exchange the data with the other processors
  11181.   int ibend = -1;
  11182.   int nsend;
  11183.   int isource = 0;
  11184.   for(int ib=nproc-1;ib>0;ib--)
  11185.   {
  11186.     int ibox = (ib+myid)%nproc; //index to send...
  11187.  
  11188.     if (ib == nproc-1)
  11189.     {
  11190.       isource= (myid+1)%nproc;
  11191.     }
  11192.     else
  11193.     {
  11194.       isource = (isource+1)%nproc;
  11195.       if (isource == myid)isource = (isource+1)%nproc;
  11196.     }
  11197.  
  11198.     if(MP_exchange_particle_with_overflow_check<bodyStruct>(ibox, &array2Send[0],
  11199.           recv_buffer3, firstloc[ibox] - nparticles[myid],
  11200.           nparticles[ibox], isource,
  11201.           nsend, recvCount))
  11202.     {
  11203.       ibend = ibox; //Here we get if exchange failed
  11204.       ib = 0;
  11205.     }//end if mp exchang
  11206.   }//end for all boxes
  11207.  
  11208.  
  11209.   if(ibend == -1){
  11210.  
  11211.   }else{
  11212.     //Something went wrong
  11213.     cerr << "ERROR in exchange_particles_with_overflow_check! \n"; exit(0);
  11214.   }
  11215.  
  11216.  
  11217.   LOG("Required inter-process communication time: %lg ,proc: %d\n",
  11218.       get_time()-t1, myid);
  11219.  
  11220.   //Compute the new number of particles:
  11221.   int newN = tree.n + recvCount - nToSend;
  11222.  
  11223.   execStream->sync();   //make certain that the particle movement on the device
  11224.   //is complete before we resize
  11225.  
  11226.   //Have to resize the bodies vector to keep the numbering correct
  11227.   //but do not reduce the size since we need to preserve the particles
  11228.   //in the oversized memory
  11229.   int memSize = newN*1.05; //5% extra
  11230.   tree.bodies_pos.cresize (memSize + 1, false);
  11231.   tree.bodies_acc0.cresize(memSize,     false);
  11232.   tree.bodies_acc1.cresize(memSize,     false);
  11233.   tree.bodies_vel.cresize (memSize,     false);
  11234.   tree.bodies_time.cresize(memSize,     false);
  11235.   tree.bodies_ids.cresize (memSize + 1, false);
  11236.   tree.bodies_Ppos.cresize(memSize + 1, false);
  11237.   tree.bodies_Pvel.cresize(memSize + 1, false);
  11238.  
  11239.   //This one has to be at least the same size as the number of particles inorder to
  11240.   //have enough space to store the other buffers
  11241.   //Can only be resized after we are done since we still have
  11242.   //parts of memory pointing to that buffer (extractList)
  11243.   //Note that we allocate some extra memory to make everything texture/memory alligned
  11244.   tree.generalBuffer1.cresize(3*(memSize)*4 + 4096, false);
  11245.  
  11246.   //Now we have to copy the data in batches incase the generalBuffer1 is not large enough
  11247.   //Amount we can store:
  11248.   int spaceInIntSize    = 3*(newN)*4;
  11249.   int newParticleSpace  = spaceInIntSize / (sizeof(bodyStruct) / sizeof(int));
  11250.   int stepSize = newParticleSpace;
  11251.  
  11252.   my_dev::dev_mem<bodyStruct>  bodyBuffer(devContext);
  11253.  
  11254.   int memOffset1 = bodyBuffer.cmalloc_copy(localTree.generalBuffer1,
  11255.       stepSize, 0);
  11256.  
  11257.  
  11258.   LOGF(stderr, "Exchange, received particles: (%d): %d \tnewN: %d\tItems that can be insert in one step: %d\n",
  11259.       procId, recvCount, newN, stepSize);
  11260.  
  11261.   int insertOffset = 0;
  11262.   for(unsigned int i=0; i < recvCount; i+= stepSize)
  11263.   {
  11264.     int items = min(stepSize, (int)(recvCount-i));
  11265.  
  11266.     if(items > 0)
  11267.     {
  11268.       //Copy the data from the MPI receive buffers into the GPU-send buffer
  11269.       memcpy(&bodyBuffer[0], &recv_buffer3[insertOffset], sizeof(bodyStruct)*items);
  11270.  
  11271.       bodyBuffer.h2d(items);
  11272.  
  11273.       //       int threads = max(nToSend, (int)recvCount);
  11274.  
  11275.       //Start the kernel that puts everything in place
  11276.       insertNewParticles.set_arg<int>(0,    &nToSend);
  11277.       insertNewParticles.set_arg<int>(1,    &items);
  11278.       insertNewParticles.set_arg<int>(2,    &tree.n);
  11279.       insertNewParticles.set_arg<int>(3,    &insertOffset);
  11280.       insertNewParticles.set_arg<cl_mem>(4, localTree.bodies_Ppos.p());
  11281.       insertNewParticles.set_arg<cl_mem>(5, localTree.bodies_Pvel.p());
  11282.       insertNewParticles.set_arg<cl_mem>(6, localTree.bodies_pos.p());
  11283.       insertNewParticles.set_arg<cl_mem>(7, localTree.bodies_vel.p());
  11284.       insertNewParticles.set_arg<cl_mem>(8, localTree.bodies_acc0.p());
  11285.       insertNewParticles.set_arg<cl_mem>(9, localTree.bodies_acc1.p());
  11286.       insertNewParticles.set_arg<cl_mem>(10, localTree.bodies_time.p());
  11287.       insertNewParticles.set_arg<cl_mem>(11, localTree.bodies_ids.p());
  11288.       insertNewParticles.set_arg<cl_mem>(12, bodyBuffer.p());
  11289.       insertNewParticles.setWork(items, 128);
  11290.       insertNewParticles.execute(execStream->s());
  11291.     }
  11292.  
  11293.     insertOffset += items;
  11294.   }
  11295.  
  11296.   //   printf("Required gpu malloc time step1: %lg \t Size: %d \tRank: %d \t Size: %d \n",
  11297.   //          get_time()-t1, newN, mpiGetRank(), tree.bodies_Ppos.get_size());
  11298.   //   t1 = get_time();
  11299.  
  11300.  
  11301.   tree.setN(newN);
  11302.  
  11303.   //Resize the arrays of the tree
  11304.   reallocateParticleMemory(tree);
  11305.  
  11306.   //   printf("Required gpu malloc tijd step 2: %lg \n", get_time()-t1);
  11307.   //   printf("Total GPU interaction time: %lg \n", get_time()-t2);
  11308.  
  11309.   int retValue = 0;
  11310.  
  11311.   delete[] firstloc;
  11312.   delete[] nparticles;
  11313.  
  11314.   return retValue;
  11315. }
  11316.  
  11317. #endif
  11318. //Exchange particles with other processes
  11319. int octree::gpu_exchange_particles_with_overflow_check(tree_structure &tree,
  11320.     bodyStruct *particlesToSend,
  11321.     my_dev::dev_mem<uint> &extractList,
  11322.     int nToSend)
  11323. {
  11324.   int myid      = procId;
  11325.   int nproc     = nProcs;
  11326.   int iloc      = 0;
  11327.   int nbody     = nToSend;
  11328.  
  11329.  
  11330.   bodyStruct  tmpp;
  11331.  
  11332.   int *firstloc   = new int[nProcs+1];
  11333.   int *nparticles = new int[nProcs+1];
  11334.  
  11335.   // Loop over particles and determine which particle needs to go where
  11336.   // reorder the bodies in such a way that bodies that have to be send
  11337.   // away are stored after each other in the array
  11338.   double t1 = get_time();
  11339.  
  11340.   //Array reserve some memory at forehand , 1%
  11341.   vector<bodyStruct> array2Send;
  11342.   array2Send.reserve((int)(nToSend*1.5));
  11343.  
  11344.   for(int ib=0;ib<nproc;ib++)
  11345.   {
  11346.     int ibox       = (ib+myid)%nproc;
  11347.     firstloc[ibox] = iloc;      //Index of the first particle send to proc: ibox
  11348.  
  11349.     for(int i=iloc; i<nbody;i++)
  11350.     {
  11351.       if(isinbox(particlesToSend[i].Ppos, domainRLow[ibox], domainRHigh[ibox]))
  11352.       {
  11353.         //Reorder the particle information
  11354.         tmpp                  = particlesToSend[iloc];
  11355.         particlesToSend[iloc] = particlesToSend[i];
  11356.         particlesToSend[i]    = tmpp;
  11357.  
  11358.         //Put the particle in the array of to send particles
  11359.         array2Send.push_back(particlesToSend[iloc]);
  11360.  
  11361.         iloc++;
  11362.       }// end if
  11363.     }//for i=iloc
  11364.     nparticles[ibox] = iloc-firstloc[ibox];//Number of particles that has to be send to proc: ibox
  11365.   } // for(int ib=0;ib<nproc;ib++)
  11366.  
  11367.  
  11368.   //   printf("Required search time: %lg ,proc: %d found in our own box: %d n: %d  to others: %ld \n",
  11369.   //          get_time()-t1, myid, nparticles[myid], tree.n, array2Send.size());
  11370.  
  11371.  
  11372.   if(iloc < nbody)
  11373.   {
  11374.     cerr << procId <<" exchange_particle error: particle in no box...iloc: " << iloc
  11375.       << " and nbody: " << nbody << "\n";
  11376.     exit(0);
  11377.   }
  11378.  
  11379.  
  11380.   /*totalsent = nbody - nparticles[myid];
  11381.  
  11382.     int tmp;
  11383.     MPI_Reduce(&totalsent,&tmp,1, MPI_INT, MPI_SUM,0,MPI_COMM_WORLD);
  11384.     if(procId == 0)
  11385.     {
  11386.     totalsent = tmp;
  11387.     cout << "Exchanged particles = " << totalsent << endl;
  11388.     }*/
  11389.  
  11390.   t1 = get_time();
  11391.  
  11392.   //Allocate two times the amount of memory of that which we send
  11393.   vector<bodyStruct> recv_buffer3(nbody*2);
  11394.   unsigned int recvCount = 0;
  11395.  
  11396.   //Exchange the data with the other processors
  11397.   int ibend = -1;
  11398.   int nsend;
  11399.   int isource = 0;
  11400.   for(int ib=nproc-1;ib>0;ib--)
  11401.   {
  11402.     int ibox = (ib+myid)%nproc; //index to send...
  11403.  
  11404.     if (ib == nproc-1)
  11405.     {
  11406.       isource= (myid+1)%nproc;
  11407.     }
  11408.     else
  11409.     {
  11410.       isource = (isource+1)%nproc;
  11411.       if (isource == myid)isource = (isource+1)%nproc;
  11412.     }
  11413.  
  11414.     if(MP_exchange_particle_with_overflow_check<bodyStruct>(ibox, &array2Send[0],
  11415.           recv_buffer3, firstloc[ibox] - nparticles[myid],
  11416.           nparticles[ibox], isource,
  11417.           nsend, recvCount))
  11418.     {
  11419.       ibend = ibox; //Here we get if exchange failed
  11420.       ib = 0;
  11421.     }//end if mp exchang
  11422.   }//end for all boxes
  11423.  
  11424.  
  11425.   if(ibend == -1){
  11426.  
  11427.   }else{
  11428.     //Something went wrong
  11429.     cerr << "ERROR in exchange_particles_with_overflow_check! \n"; exit(0);
  11430.   }
  11431.  
  11432.  
  11433.   LOG("Required inter-process communication time: %lg ,proc: %d\n",
  11434.       get_time()-t1, myid);
  11435.  
  11436.   //Compute the new number of particles:
  11437.   int newN = tree.n + recvCount - nToSend;
  11438.  
  11439.   execStream->sync();   //make certain that the particle movement on the device
  11440.   //is complete before we resize
  11441.  
  11442.   //Have to resize the bodies vector to keep the numbering correct
  11443.   //but do not reduce the size since we need to preserve the particles
  11444.   //in the oversized memory
  11445.   int memSize = newN*1.05; //5% extra
  11446.   tree.bodies_pos.cresize (memSize + 1, false);
  11447.   tree.bodies_acc0.cresize(memSize,     false);
  11448.   tree.bodies_acc1.cresize(memSize,     false);
  11449.   tree.bodies_vel.cresize (memSize,     false);
  11450.   tree.bodies_time.cresize(memSize,     false);
  11451.   tree.bodies_ids.cresize (memSize + 1, false);
  11452.   tree.bodies_Ppos.cresize(memSize + 1, false);
  11453.   tree.bodies_Pvel.cresize(memSize + 1, false);
  11454.  
  11455.   //This one has to be at least the same size as the number of particles inorder to
  11456.   //have enough space to store the other buffers
  11457.   //Can only be resized after we are done since we still have
  11458.   //parts of memory pointing to that buffer (extractList)
  11459.   //Note that we allocate some extra memory to make everything texture/memory alligned
  11460.   tree.generalBuffer1.cresize(3*(memSize)*4 + 4096, false);
  11461.  
  11462.   //Now we have to copy the data in batches incase the generalBuffer1 is not large enough
  11463.   //Amount we can store:
  11464.   int spaceInIntSize    = 3*(newN)*4;
  11465.   int newParticleSpace  = spaceInIntSize / (sizeof(bodyStruct) / sizeof(int));
  11466.   int stepSize = newParticleSpace;
  11467.  
  11468.   my_dev::dev_mem<bodyStruct>  bodyBuffer(devContext);
  11469.  
  11470.   int memOffset1 = bodyBuffer.cmalloc_copy(localTree.generalBuffer1,
  11471.       stepSize, 0);
  11472.  
  11473.  
  11474.   LOGF(stderr, "Exchange, received particles: (%d): %d \tnewN: %d\tItems that can be insert in one step: %d\n",
  11475.       procId, recvCount, newN, stepSize);
  11476.  
  11477.   int insertOffset = 0;
  11478.   for(unsigned int i=0; i < recvCount; i+= stepSize)
  11479.   {
  11480.     int items = min(stepSize, (int)(recvCount-i));
  11481.  
  11482.     if(items > 0)
  11483.     {
  11484.       //Copy the data from the MPI receive buffers into the GPU-send buffer
  11485.       memcpy(&bodyBuffer[0], &recv_buffer3[insertOffset], sizeof(bodyStruct)*items);
  11486.  
  11487.       bodyBuffer.h2d(items);
  11488.  
  11489.       //       int threads = max(nToSend, (int)recvCount);
  11490.  
  11491.       //Start the kernel that puts everything in place
  11492.       insertNewParticles.set_arg<int>(0,    &nToSend);
  11493.       insertNewParticles.set_arg<int>(1,    &items);
  11494.       insertNewParticles.set_arg<int>(2,    &tree.n);
  11495.       insertNewParticles.set_arg<int>(3,    &insertOffset);
  11496.       insertNewParticles.set_arg<cl_mem>(4, localTree.bodies_Ppos.p());
  11497.       insertNewParticles.set_arg<cl_mem>(5, localTree.bodies_Pvel.p());
  11498.       insertNewParticles.set_arg<cl_mem>(6, localTree.bodies_pos.p());
  11499.       insertNewParticles.set_arg<cl_mem>(7, localTree.bodies_vel.p());
  11500.       insertNewParticles.set_arg<cl_mem>(8, localTree.bodies_acc0.p());
  11501.       insertNewParticles.set_arg<cl_mem>(9, localTree.bodies_acc1.p());
  11502.       insertNewParticles.set_arg<cl_mem>(10, localTree.bodies_time.p());
  11503.       insertNewParticles.set_arg<cl_mem>(11, localTree.bodies_ids.p());
  11504.       insertNewParticles.set_arg<cl_mem>(12, bodyBuffer.p());
  11505.       insertNewParticles.setWork(items, 128);
  11506.       insertNewParticles.execute(execStream->s());
  11507.     }
  11508.  
  11509.     insertOffset += items;
  11510.   }
  11511.  
  11512.   //   printf("Required gpu malloc time step1: %lg \t Size: %d \tRank: %d \t Size: %d \n",
  11513.   //          get_time()-t1, newN, mpiGetRank(), tree.bodies_Ppos.get_size());
  11514.   //   t1 = get_time();
  11515.  
  11516.  
  11517.   tree.setN(newN);
  11518.  
  11519.   //Resize the arrays of the tree
  11520.   reallocateParticleMemory(tree);
  11521.  
  11522.   //   printf("Required gpu malloc tijd step 2: %lg \n", get_time()-t1);
  11523.   //   printf("Total GPU interaction time: %lg \n", get_time()-t2);
  11524.  
  11525.   int retValue = 0;
  11526.  
  11527.   delete[] firstloc;
  11528.   delete[] nparticles;
  11529.  
  11530.   return retValue;
  11531. }
  11532.  
  11533.  
  11534.  
  11535. //Improved Barnes Hut criterium
  11536. bool split_node_grav_impbh_SFCtest(float4 nodeCOM, double4 boxCenter, double4 boxSize, float &ds2)
  11537.  
  11538. {
  11539.   //Compute the distance between the group and the cell
  11540.   float3 dr = make_float3(fabs((float)boxCenter.x - nodeCOM.x) - (float)boxSize.x,
  11541.       fabs((float)boxCenter.y - nodeCOM.y) - (float)boxSize.y,
  11542.       fabs((float)boxCenter.z - nodeCOM.z) - (float)boxSize.z);
  11543.  
  11544.   dr.x += fabs(dr.x); dr.x *= 0.5f;
  11545.   dr.y += fabs(dr.y); dr.y *= 0.5f;
  11546.   dr.z += fabs(dr.z); dr.z *= 0.5f;
  11547.  
  11548.   //Distance squared, no need to do sqrt since opening criteria has been squared
  11549.   //  float ds2    = dr.x*dr.x + dr.y*dr.y + dr.z*dr.z;
  11550.   ds2    = dr.x*dr.x + dr.y*dr.y + dr.z*dr.z;
  11551.  
  11552.  
  11553. #ifdef INDSOFT
  11554.   if(ds2      <= ((group_eps + node_eps ) * (group_eps + node_eps) ))           return true;
  11555.   //Limited precision can result in round of errors. Use this as extra safe guard
  11556.   if(fabs(ds2 -  ((group_eps + node_eps ) * (group_eps + node_eps) )) < 10e-04) return true;
  11557. #endif
  11558.  
  11559.   if (ds2     <= fabs(nodeCOM.w))           return true;
  11560.   if (fabs(ds2 - fabs(nodeCOM.w)) < 10e-04) return true; //Limited precision can result in round of errors. Use this as extra safe guard
  11561.  
  11562.   return false;
  11563. }
  11564.  
  11565.  
  11566.  
  11567.  
  11568. #if 0
  11569.  
  11570.  
  11571. //Sort using our custom merge sort, this requires that the subranges are sorted
  11572. //already!
  11573.  
  11574. #if 0
  11575. //Merge the received results with the already available data, this works
  11576. //for two processes only
  11577. uint4 *result = new uint4[totalNumberOfHashes];
  11578. merge_sort(result, &allHashes[0],nReceiveCnts[0] / sizeof(uint4),
  11579.     &allHashes[nReceiveDpls[1] / sizeof(uint4) ], nReceiveCnts[1] / sizeof(uint4));
  11580. memcpy(allHashes, result, sizeof(uint4)*totalNumberOfHashes);
  11581. #endif
  11582.  
  11583. #if 0
  11584.  
  11585. //Multiple merges to merge the different items
  11586. uint4 *result = new uint4[totalNumberOfHashes];
  11587. bool ping = true;
  11588. for(int i=0; i < nProcs-1; i++)
  11589. {
  11590.   if(ping)
  11591.   {
  11592.     merge_sort(result, &allHashes[0],nReceiveDpls[i+1] / sizeof(uint4),
  11593.         &allHashes[nReceiveDpls[i+1] / sizeof(uint4) ], //start
  11594.         nReceiveCnts[i+1] / sizeof(uint4)); //items
  11595.     ping = false;
  11596.     fprintf(stderr,"StartA at: %d  count: %d \n",nReceiveDpls[i+1] / sizeof(uint4), nReceiveCnts[i+1] / sizeof(uint4));
  11597.   }
  11598.   else
  11599.   {
  11600.     merge_sort(allHashes, &result[0],nReceiveDpls[i+1] / sizeof(uint4),
  11601.         &allHashes[nReceiveDpls[i+1] / sizeof(uint4) ], //start
  11602.         nReceiveCnts[i+1] / sizeof(uint4));             //items
  11603.     ping = true;
  11604.     fprintf(stderr,"StartB at: %d  count: %d \n",nReceiveDpls[i+1] / sizeof(uint4), nReceiveCnts[i+1] / sizeof(uint4));
  11605.   }
  11606. }
  11607.  
  11608. if(!ping)
  11609. {
  11610.   memcpy(allHashes, result, sizeof(uint4)*totalNumberOfHashes);
  11611. }
  11612.  
  11613. #endif
  11614.  
  11615.  
  11616. //Test ex
  11617. #if 0
  11618. //Multi-merge
  11619. uint4 *result = new uint4[totalNumberOfHashes]; //TEST
  11620. int *sizes  = new int[nProcs];
  11621. int *starts = new int[nProcs];
  11622.  
  11623. for(int z = 0 ; z < nProcs; z++)
  11624. {
  11625.   sizes[z] = nReceiveCnts[z] / sizeof(uint4);
  11626.   starts[z] = nReceiveDpls[z] / sizeof(uint4);
  11627. }
  11628.  
  11629. merge_sort2(result, allHashes,sizes, starts, nProcs);
  11630. //end test ex
  11631. memcpy(allHashes, result, sizeof(uint4)*totalNumberOfHashes);
  11632. #endif
  11633.  
  11634. #if 0
  11635. //Multi-merge using priority queue
  11636. uint4 *result = new uint4[totalNumberOfHashes]; //TEST
  11637. int *sizes  = new int[nProcs];
  11638. int *starts = new int[nProcs];
  11639.  
  11640. for(int z = 0 ; z < nProcs; z++)
  11641. {
  11642.   sizes[z] = nReceiveCnts[z] / sizeof(uint4);
  11643.   starts[z] = nReceiveDpls[z] / sizeof(uint4);
  11644. }
  11645.  
  11646. merge_sort3(result, allHashes,sizes, starts, nProcs);
  11647. //end test ex
  11648. memcpy(allHashes, result, sizeof(uint4)*totalNumberOfHashes);
  11649. #endif
  11650.  
  11651.  
  11652.  
  11653. LOGF(stderr, "Domain hash sort: %f on number of particles: %d\n",
  11654.     get_time()-t1, totalNumberOfHashes);
  11655.  
  11656. sumTime += get_time()-t1;
  11657.  
  11658.  
  11659. int sum = 0;
  11660. for(int i=0; i < totalNumberOfHashes-1; i++)
  11661. {
  11662.   int comp = cmp_uint4_host(allHashes[i], allHashes[i+1]);
  11663.  
  11664.   if(comp > 0)
  11665.   {
  11666.     LOGF(stderr, "Sorting FAILED to get the correct order :(  %d \n", comp);
  11667.     LOGF(stderr,"%d \t Key: %d %d %d \tsize->\t %d\n", i,
  11668.         allHashes[i].x, allHashes[i].y, allHashes[i].z, allHashes[i].w);
  11669.  
  11670.     LOGF(stderr,"%d \t Key: %d %d %d \tsize->\t %d\n", i+1,
  11671.         allHashes[i+1].x, allHashes[i+1].y, allHashes[i+1].z, allHashes[i+1].w);
  11672.   }
  11673.  
  11674.  
  11675.   // LOGF(stderr,"%d \t Key: %d %d %d \tsize->\t %d\n", i,
  11676.   //      allHashes[i].x, allHashes[i].y, allHashes[i].z, allHashes[i].w);
  11677.   sum += allHashes[i].w;
  11678. }
  11679.  
  11680. //   LOGF(stderr,"%d \t Key: %d %d %d \tsize->\t %d\n", totalNumberOfHashes-1,        allHashes[totalNumberOfHashes-1].x, allHashes[totalNumberOfHashes-1].y, allHashes[totalNumberOfHashes-1].z, allHashes[totalNumberOfHashes-1].w);
  11681.  
  11682.  
  11683. sum += allHashes[totalNumberOfHashes-1].w;
  11684. LOGF(stderr,"Total particlesA: %d \n", sum);
  11685.  
  11686.  
  11687.  
  11688.  
  11689.  
  11690. Old sorting codes
  11691.  
  11692. void merge_sort(uint4 *result, uint4 *left, int sizeLeft, uint4 *right, int sizeRight)
  11693. {
  11694.   uint iLeft = 0;
  11695.   uint iRight = 0;
  11696.   uint res = 0;
  11697.  
  11698.   while(iLeft < sizeLeft && iRight < sizeRight)
  11699.   {
  11700.     //      uint4 valLeft  = left[iLeft];
  11701.     //      uint4 valRight = right[iRight];
  11702.  
  11703.     int comp = cmp_uint4_host(left[iLeft], right[iRight]);
  11704.  
  11705.     if (comp <= 0)
  11706.     {
  11707.       result[res++] = left[iLeft];
  11708.       ++iLeft;
  11709.     }
  11710.     if (comp >= 0)
  11711.     {
  11712.       result[res++] = right[iRight];
  11713.       ++iRight;
  11714.     }
  11715.   }
  11716.  
  11717.   if(iLeft!=sizeLeft)
  11718.     memcpy(&result[res], &left[iLeft],   sizeof(uint4)*(sizeLeft-iLeft));
  11719.   else
  11720.     memcpy(&result[res], &right[iRight], sizeof(uint4)*(sizeRight-iRight));
  11721. }
  11722.  
  11723. void merge_sort2(uint4 *result, uint4 *data, int *sizes, int *starts, int nLists)
  11724. {
  11725.   uint iLeft = 0;
  11726.   uint iRight = 0;
  11727.   uint res = 0;
  11728.  
  11729.   fprintf(stderr, "Merge sorting, total lists: %d \n", nLists);
  11730.  
  11731.   uint4 *queue  = new uint4[nLists];
  11732.   int4 *readIdx = new int4[nLists];
  11733.  
  11734.   for(int i=0; i < nLists; i++)
  11735.   {
  11736.     queue[i]   = data[starts[i]];
  11737.  
  11738.     int4 read;
  11739.     read.x = i; //Source file
  11740.     read.y = starts[i]; //read Index in Data
  11741.     read.z = sizes[i]-1; //items left to process
  11742.  
  11743.     fprintf(stderr, "List: %d  Start: %d  Items: %d \n", i, starts[i], sizes[i]);
  11744.  
  11745.     readIdx[i] = read;
  11746.     //TODO should check on length !!! when adding first item
  11747.     //in case length is 0
  11748.   }
  11749.  
  11750.   int itemsInQueue = nLists;
  11751.  
  11752.   while(1)
  11753.   {
  11754.     int idxSmallest = 0;
  11755.     //Find the smallest item in the queue
  11756.     for(int j=1; j < itemsInQueue; j++)
  11757.     {
  11758.       //      fprintf(stderr, "Comparing; %d and %d  \t %d ",
  11759.       //          queue[idxSmallest].x, queue[j].x, cmp_uint4_host(queue[idxSmallest], queue[j]));
  11760.  
  11761.       if(cmp_uint4_host(queue[idxSmallest], queue[j]) >= 0)
  11762.         idxSmallest = j;
  11763.     }
  11764.  
  11765.     //Add items j to the list and refill queue
  11766.     result[res++] = queue[idxSmallest];
  11767.  
  11768.     if(readIdx[idxSmallest].z > 0)
  11769.     {
  11770.       readIdx[idxSmallest].z--; //decrease items left
  11771.       readIdx[idxSmallest].y++; //increase read location
  11772.       queue[idxSmallest] = data[readIdx[idxSmallest].y];
  11773.     }
  11774.     else
  11775.     {
  11776.       queue[idxSmallest] = queue[itemsInQueue-1];
  11777.       readIdx[idxSmallest] = readIdx[itemsInQueue-1];
  11778.       itemsInQueue -= 1; //decrease items in queue
  11779.     }
  11780.  
  11781.     if(itemsInQueue == 0) break;
  11782.  
  11783.   }//end while
  11784.  
  11785.   //  if(iLeft!=sizeLeft)
  11786.   //    memcpy(&result[res], &left[iLeft],   sizeof(uint4)*(sizeLeft-iLeft));
  11787.   //  else
  11788.   //    memcpy(&result[res], &right[iRight], sizeof(uint4)*(sizeRight-iRight));
  11789. }
  11790.  
  11791. typedef struct queueObject
  11792. {
  11793.   uint4 key;
  11794.   int4 val;
  11795. } queueObject;
  11796.  
  11797. struct cmp_ph_key_test{
  11798.   bool operator () (const queueObject &a, const queueObject &b){
  11799.     return ( cmp_uint4_host( b.key, a.key) < 1); //note reverse
  11800.   }
  11801. };
  11802. #include <queue>
  11803. void merge_sort3(uint4 *result, uint4 *data, int *sizes, int *starts, int nLists)
  11804. {
  11805.   std::priority_queue<queueObject, vector<queueObject>, cmp_ph_key_test> queue;
  11806.  
  11807.   uint iLeft = 0;
  11808.   uint iRight = 0;
  11809.   uint res = 0;
  11810.  
  11811.   fprintf(stderr, "Merge3 sorting, total lists: %d \n", nLists);
  11812.  
  11813.   //  uint4 *queue  = new uint4[nLists];
  11814.   //  int4 *readIdx = new int4[nLists];
  11815.  
  11816.   for(int i=0; i < nLists; i++)
  11817.   {
  11818.     queueObject obj;
  11819.     obj.key = data[starts[i]];
  11820.  
  11821.     int4 read;
  11822.     read.x = i; //Source file
  11823.     read.y = starts[i]; //read Index in Data
  11824.     read.z = sizes[i]-1; //items left to process
  11825.  
  11826.     obj.val = read;
  11827.  
  11828.     queue.push(obj);
  11829.     //TODO should check on length !!! when adding first item
  11830.     //in case length is 0
  11831.   }
  11832.  
  11833.   int itemsInQueue = nLists;
  11834.  
  11835.   while(1)
  11836.   {
  11837.     int idxSmallest = 0;
  11838.     //Find the smallest item in the queue
  11839.  
  11840.     queueObject obj = queue.top();
  11841.  
  11842.     //    fprintf(stderr, "Item 0: %d ", obj.key.x);
  11843.     //    queue.pop();
  11844.     //    obj = queue.top();
  11845.     //    fprintf(stderr, "Item 1: %d ", obj.key.x);
  11846.     //
  11847.     //    exit(0);
  11848.  
  11849.  
  11850.     //Add items j to the list and refill queue
  11851.     result[res++] = obj.key;
  11852.  
  11853.     queue.pop();
  11854.  
  11855.     if(obj.val.z > 0)
  11856.     {
  11857.       obj.val.z--; //decrease items left
  11858.       obj.val.y++; //increase read location
  11859.       obj.key = data[obj.val.y];
  11860.       queue.push(obj);
  11861.       //      fprintf(stderr, "Adding items from list: %d  from loc: %d  left: %d \n",
  11862.       //          readIdx[idxSmallest].x, readIdx[idxSmallest].y, readIdx[idxSmallest].z);
  11863.     }
  11864.  
  11865.     if(queue.empty()) break;
  11866.  
  11867.   }//end while
  11868.  
  11869. }
  11870. #endif
  11871.  
  11872.  
  11873. int octree::stackBasedTopLEvelsCheck(tree_structure &tree,
  11874.     real4 *treeBuffer,
  11875.     int proc,
  11876.     int nTopLevelTrees,
  11877.     uint2 *curLevelStack,
  11878.     uint2 *nextLevelStack,
  11879.     int &DistanceCheck)
  11880. {
  11881.   int DistanceCheckPP = 0;
  11882.  
  11883.   int ib       = (nProcs-1)-proc;
  11884.   int ibox = (ib+procId)%nProcs; //index to send...)
  11885.  
  11886.   //    LOGF(stderr,"Process %d Checking %d \t [%d %d %d ] \n", procId, ibox,i,ib,nProcs);
  11887.  
  11888.   int doFullGrp = fullGrpAndLETRequest[ibox];
  11889.  
  11890.   //Group info for this process
  11891.   int idx          =   globalGrpTreeOffsets[ibox];
  11892.   real4 *grpCenter =  &globalGrpTreeCntSize[idx];
  11893.   idx             += this->globalGrpTreeCount[ibox] / 2; //Divide by two to get halfway
  11894.   real4 *grpSize   =  &globalGrpTreeCntSize[idx];
  11895.  
  11896.   //Retrieve required for the tree-walk from the top node
  11897.   union{int i; float f;} itof; //float as int
  11898.  
  11899.   itof.f       = grpCenter[0].x;
  11900.   int startGrp = itof.i;
  11901.   itof.f       = grpCenter[0].y;
  11902.   int endGrp   = itof.i;
  11903.  
  11904.   if(!doFullGrp)
  11905.   {
  11906.     //This is a topNode only
  11907.     startGrp = 0;
  11908.     endGrp   = this->globalGrpTreeCount[ibox] / 2;
  11909.   }
  11910.  
  11911.   //Tree info
  11912.   const int nParticles = host_float_as_int(treeBuffer[0].x);
  11913.   const int nNodes     = host_float_as_int(treeBuffer[0].y);
  11914.  
  11915.   //    LOGF(stderr,"Working with %d and %d || %d %d\n", nParticles, nNodes, 1+nParticles+nNodes,nTopLevelTrees );
  11916.  
  11917.   real4* treeBoxSizes   = &treeBuffer[1+nParticles];
  11918.   real4* treeBoxCenters = &treeBuffer[1+nParticles+nNodes];
  11919.   real4* treeBoxMoments = &treeBuffer[1+nParticles+2*nNodes];
  11920.  
  11921.   int maxLevel = 0;
  11922.  
  11923.   //Walk these groups along our tree
  11924.   //Add the topNode to the stack
  11925.   int nexLevelCount = 0;
  11926.   int curLevelCount = 1;
  11927.   curLevelStack[0]  = make_uint2(0, startGrp); //Add top node
  11928.  
  11929.   while(curLevelCount > 0)
  11930.   {
  11931.     //        LOGF(stderr,"Processing level: %d  with %d %d  and %d Source: %d\n", maxLevel, curLevelCount, startGrp,endGrp, ibox);
  11932.     for(int idx = 0; idx < curLevelCount; idx++)
  11933.     {
  11934.       int nodeID = curLevelStack[idx].x;
  11935.       int grpID  = curLevelStack[idx].y;
  11936.       //Check this node against the groups
  11937.       real4 nodeCOM  = treeBoxMoments[nodeID*3];
  11938.       real4 nodeSize = treeBoxSizes  [nodeID];
  11939.       real4 nodeCntr = treeBoxCenters[nodeID];
  11940.  
  11941.       nodeCOM.w = nodeCntr.w;
  11942.       for(int grp=grpID; grp < endGrp; grp++)
  11943.       {
  11944.         real4 grpcntr = grpCenter[grp];
  11945.         real4 grpsize = grpSize[grp];
  11946.  
  11947.         bool split = false;
  11948.         {
  11949.           DistanceCheck++;
  11950.           DistanceCheckPP++;
  11951.           //Compute the distance between the group and the cell
  11952.           float3 dr = make_float3(fabs((float)grpcntr.x - nodeCOM.x) - (float)grpsize.x,
  11953.               fabs((float)grpcntr.y - nodeCOM.y) - (float)grpsize.y,
  11954.               fabs((float)grpcntr.z - nodeCOM.z) - (float)grpsize.z);
  11955.  
  11956.           dr.x += fabs(dr.x); dr.x *= 0.5f;
  11957.           dr.y += fabs(dr.y); dr.y *= 0.5f;
  11958.           dr.z += fabs(dr.z); dr.z *= 0.5f;
  11959.  
  11960.           //Distance squared, no need to do sqrt since opening criteria has been squared
  11961.           float ds2    = dr.x*dr.x + dr.y*dr.y + dr.z*dr.z;
  11962.  
  11963.           if (ds2     <= fabs(nodeCOM.w))           split = true;
  11964.           if (fabs(ds2 - fabs(nodeCOM.w)) < 10e-04) split = true; //Limited precision can result in round of errors. Use this as extra safe guard
  11965.  
  11966.           //          LOGF(stderr,"Node: %d grp: %d  split: %d || %f %f\n", curLevelStack[idx], grp, split, ds2, nodeCOM.w);
  11967.         }
  11968.  
  11969.  
  11970.         if(split)
  11971.         {
  11972.           if(host_float_as_int(nodeSize.w) == 0xFFFFFFFF)
  11973.           {
  11974.             //We want to split, but then we go to deep. So we need a full tree-walk
  11975.             return -1;
  11976.           }
  11977.  
  11978.           int child, nchild;
  11979.           int childinfo = host_float_as_int(nodeSize.w);
  11980.           bool leaf = nodeCntr.w <= 0;
  11981.  
  11982.           if(!leaf)
  11983.           {
  11984.             //Node
  11985.             child    =    childinfo & 0x0FFFFFFF;           //Index to the first child of the node
  11986.             nchild   = (((childinfo & 0xF0000000) >> 28)) ; //The number of children this node has
  11987.             //Add the child-nodes to the next stack
  11988.             for(int y=child; y < child+nchild; y++)
  11989.               nextLevelStack[nexLevelCount++] = make_uint2(y,grpID);
  11990.           }//!leaf
  11991.           //Skip rest of the groups
  11992.           grp = endGrp;
  11993.         }//if split
  11994.         if(maxLevel < 0) break;
  11995.       }//for groups
  11996.  
  11997.       if(maxLevel < 0) break;
  11998.     }//for curLevelCount
  11999.     if(maxLevel < 0) break;
  12000.  
  12001.     if(nexLevelCount == 0)
  12002.       return maxLevel;
  12003.  
  12004.     //Check if we continue
  12005.     if(nexLevelCount > 0)
  12006.     {
  12007.       curLevelCount   = nexLevelCount; nexLevelCount = 0;
  12008.       uint2 *temp     = nextLevelStack;
  12009.       nextLevelStack  = curLevelStack;
  12010.       curLevelStack   = temp;
  12011.       maxLevel++;
  12012.       //          LOGF(stderr, "Max level found: %d \n", maxLevel)
  12013.     }
  12014.   }//while curLevelCount > 0
  12015.  
  12016.   //  LOGF(stderr, "Finally Max level found: %d Process : %d \n", maxLevel, ibox)
  12017.   return maxLevel;
  12018. }
  12019.  
  12020. #endif
Advertisement
Add Comment
Please, Sign In to add comment