acclib.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #include <vector>
  2. #include <iostream>
  3. #include <math.h>
  4. #include <chrono>
  5. using namespace std;
  6. using namespace std::chrono;
  7. #include "Node.h"
  8. /*
  9. Calculates the self gravitational acceleration for a set of particles located
  10. at r_vec (n, 3) with masses m_vec (n,) using a Barnes-Hut tree with theta = 0.7
  11. Parameters:
  12. r_vec: the position of the particles.
  13. m_vec: the masses of the particles.
  14. n: the number of particles. This cannot be infered by C++ and must be
  15. passed directly.
  16. size: size of the top node in the octtree.
  17. px, py, pz: coordinates of the lowest corner of the top node.
  18. size: characteristic softening scale.
  19. Returns:
  20. The accelerations computed for each mass (n, 3).
  21. */
  22. extern "C" double* barnesHutCPP(double** r_vec, double* m_vec, int n,
  23. double size, double px, double py, double pz, double soft){
  24. // Create nodes
  25. std::vector<Node*> nodes;
  26. for (int i = 0; i < n; i++){
  27. nodes.push_back(new Node(r_vec[i], m_vec[i]));
  28. }
  29. // Create the tree
  30. Node* tree = new Node(nodes, size, px, py, pz);
  31. // Calculate the accelerations for each node. We want to return the
  32. // result as an array and use a 1D array for simplicity since this will
  33. // be allocated continously in the heap and can be reshaped in Numpy.
  34. double* accel = new double[3*n];
  35. for (int i = 0; i < nodes.size(); i++){
  36. nodes[i]->treeWalk(*tree, 0.7, soft); // thetamax = 0.7
  37. accel[3*i+0] = nodes[i]->g[0];
  38. accel[3*i+1] = nodes[i]->g[1];
  39. accel[3*i+2] = nodes[i]->g[2];
  40. }
  41. // Return as an (n,) array
  42. return accel;
  43. }
  44. /*
  45. Calculates the self gravitational acceleration for a set of particles located
  46. at r_vec (n, 3) with masses m_vec (n,) using Brute Force pairwise summation.
  47. Massive particles must appear first.
  48. Parameters:
  49. r_vec: the position of the particles.
  50. m_vec: the masses of the particles.
  51. n: the number of particles. This cannot be infered by C++ and must be
  52. passed directly.
  53. size: characteristic softening scale.
  54. Returns:
  55. The accelerations computed for each mass (n, 3).
  56. */
  57. extern "C" double* bruteForceCPP(double** r_vec, double* m_vec,
  58. int n, double soft){
  59. // Initialize result and fill with 0s
  60. // Use a 1D array so as not to have to convert back in Numpy
  61. double* accel = new double[3*n];
  62. for (int i=0; i<3*n; i++){
  63. accel[i] = 0;
  64. }
  65. // Compute the acceleration
  66. for (int i=0; i<n; i++){
  67. // Only consider pairs with at least one massive particle i
  68. if (m_vec[i] == 0.) break;
  69. for (int j=i+1; j<n; j++){
  70. // Distance between particles
  71. double delta[3];
  72. for (int k = 0; k < 3; k++) delta[k] = r_vec[j][k] - r_vec[i][k];
  73. double r = sqrt(delta[0]*delta[0]
  74. + delta[1]*delta[1]
  75. + delta[2]*delta[2]);
  76. double tripler = (r+soft) * (r+soft) * r;
  77. // Compute acceleration on first particle
  78. double mr3inv = m_vec[i]/tripler;
  79. for (int k = 0; k < 3; k++) accel[3*j+k] -= mr3inv * delta[k];
  80. // Compute acceleration on second particle
  81. // For pairs with one massless particle, no reaction force
  82. if (m_vec[j] == 0.) break;
  83. // Otherwise, opposite direction (+)
  84. mr3inv = m_vec[j]/tripler;
  85. for (int k = 0; k < 3; k++) accel[3*i+k] += mr3inv * delta[k];
  86. }
  87. }
  88. // Return as an (n,) array
  89. return accel;
  90. }