Advertisement
Guest User

Untitled

a guest
Oct 19th, 2019
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.81 KB | None | 0 0
  1. #[derive(Default)]
  2. struct Body {
  3. position: [f64; 3],
  4. velocity: [f64; 3],
  5. mass: f64
  6. }
  7.  
  8. const SOLAR_MASS: f64 = (4*std::f64::consts::PI*std::f64::consts::PI);
  9. const DAYS_PER_YEAR: f64 = 365.24;
  10. const BODIES_COUNT: usize = 5;
  11.  
  12. const solar_Bodies: [Body; 9]={
  13. Body { // Sun
  14. mass: SOLAR_MASS,
  15. ..Body::default()
  16. },
  17. Body { // Jupiter
  18. position: [
  19. 4.84143144246472090e+00,
  20. -1.16032004402742839e+00,
  21. -1.03622044471123109e-01
  22. ],
  23. velocity: [
  24. 1.66007664274403694e-03 * DAYS_PER_YEAR,
  25. 7.69901118419740425e-03 * DAYS_PER_YEAR,
  26. -6.90460016972063023e-05 * DAYS_PER_YEAR
  27. ],
  28. mass: 9.54791938424326609e-04 * SOLAR_MASS
  29. },
  30. { // Saturn
  31. {
  32. 8.34336671824457987e+00,
  33. 4.12479856412430479e+00,
  34. -4.03523417114321381e-01
  35. },
  36. {
  37. -2.76742510726862411e-03 * DAYS_PER_YEAR,
  38. 4.99852801234917238e-03 * DAYS_PER_YEAR,
  39. 2.30417297573763929e-05 * DAYS_PER_YEAR
  40. },
  41. 2.85885980666130812e-04 * SOLAR_MASS
  42. },
  43. { // Uranus
  44. {
  45. 1.28943695621391310e+01,
  46. -1.51111514016986312e+01,
  47. -2.23307578892655734e-01
  48. },
  49. {
  50. 2.96460137564761618e-03 * DAYS_PER_YEAR,
  51. 2.37847173959480950e-03 * DAYS_PER_YEAR,
  52. -2.96589568540237556e-05 * DAYS_PER_YEAR
  53. },
  54. 4.36624404335156298e-05 * SOLAR_MASS
  55. },
  56. { // Neptune
  57. {
  58. 1.53796971148509165e+01,
  59. -2.59193146099879641e+01,
  60. 1.79258772950371181e-01
  61. },
  62. {
  63. 2.68067772490389322e-03 * DAYS_PER_YEAR,
  64. 1.62824170038242295e-03 * DAYS_PER_YEAR,
  65. -9.51592254519715870e-05 * DAYS_PER_YEAR
  66. },
  67. 5.15138902046611451e-05 * SOLAR_MASS
  68. }
  69. };
  70.  
  71.  
  72. // Advance all the bodies in the system by one timestep. Calculate the
  73. // interactions between all the bodies, update each body's velocity based on
  74. // those interactions, and update each body's position by the distance it
  75. // travels in a timestep at it's updated velocity.
  76. fn advance(bodies: &[Body; BODIES_COUNT]) {
  77.  
  78. // Figure out how many total different interactions there are between each
  79. // body and every other body. Some of the calculations for these
  80. // interactions will be calculated two at a time by using x86 SSE
  81. // instructions and because of that it will also be useful to have a
  82. // ROUNDED_INTERACTIONS_COUNT that is equal to the next highest even number
  83. // which is equal to or greater than INTERACTIONS_COUNT.
  84. const INTERACTIONS_COUNT: usize = (BODIES_COUNT*(BODIES_COUNT-1)/2);
  85. const ROUNDED_INTERACTIONS_COUNT: usize = (INTERACTIONS_COUNT+INTERACTIONS_COUNT%2);
  86.  
  87. // It's useful to have two arrays to keep track of the position_Deltas
  88. // and magnitudes of force between the bodies for each interaction. For the
  89. // position_Deltas array, instead of using a one dimensional array of
  90. // structures that each contain the X, Y, and Z components for a position
  91. // delta, a two dimensional array is used instead which consists of three
  92. // arrays that each contain all of the X, Y, and Z components for all of the
  93. // position_Deltas. This allows for more efficient loading of this data into
  94. // SSE registers. Both of these arrays are also set to contain
  95. // ROUNDED_INTERACTIONS_COUNT elements to simplify one of the following
  96. // loops and to also keep the second and third arrays in position_Deltas
  97. // aligned properly.
  98. static alignas(__m128d) double
  99. position_Deltas[3][ROUNDED_INTERACTIONS_COUNT],
  100. magnitudes[ROUNDED_INTERACTIONS_COUNT];
  101.  
  102. // Calculate the position_Deltas between the bodies for each interaction.
  103. for(intnative_t i=0, k=0; i<BODIES_COUNT-1; ++i)
  104. for(intnative_t j=i+1; j<BODIES_COUNT; ++j, ++k)
  105. for(intnative_t m=0; m<3; ++m)
  106. position_Deltas[m][k]=
  107. bodies[i].position[m]-bodies[j].position[m];
  108.  
  109. // Calculate the magnitudes of force between the bodies for each
  110. // interaction. This loop processes two interactions at a time which is why
  111. // ROUNDED_INTERACTIONS_COUNT/2 iterations are done.
  112. for(intnative_t i=0; i<ROUNDED_INTERACTIONS_COUNT/2; ++i){
  113.  
  114. // Load position_Deltas of two bodies into position_Delta.
  115. __m128d position_Delta[3];
  116. for(intnative_t m=0; m<3; ++m)
  117. position_Delta[m]=((__m128d *)position_Deltas[m])[i];
  118.  
  119. const __m128d distance_Squared=
  120. position_Delta[0]*position_Delta[0]+
  121. position_Delta[1]*position_Delta[1]+
  122. position_Delta[2]*position_Delta[2];
  123.  
  124. // Doing square roots normally using double precision floating point
  125. // math can be quite time consuming so SSE's much faster single
  126. // precision reciprocal square root approximation instruction is used as
  127. // a starting point instead. The precision isn't quite sufficient to get
  128. // acceptable results so two iterations of the Newton–Raphson method are
  129. // done to improve precision further.
  130. __m128d distance_Reciprocal=
  131. _mm_cvtps_pd(_mm_rsqrt_ps(_mm_cvtpd_ps(distance_Squared)));
  132. for(intnative_t j=0; j<2; ++j)
  133. // Normally the last four multiplications in this equation would
  134. // have to be done sequentially but by placing the last
  135. // multiplication in parentheses, a compiler can then schedule that
  136. // multiplication earlier.
  137. distance_Reciprocal=distance_Reciprocal*1.5-
  138. 0.5*distance_Squared*distance_Reciprocal*
  139. (distance_Reciprocal*distance_Reciprocal);
  140.  
  141. // Calculate the magnitudes of force between the bodies. Typically this
  142. // calculation would probably be done by using a division by the cube of
  143. // the distance (or similarly a multiplication by the cube of its
  144. // reciprocal) but for better performance on modern computers it often
  145. // will make sense to do part of the calculation using a division by the
  146. // distance_Squared which was already calculated earlier. Additionally
  147. // this method is probably a little more accurate due to less rounding
  148. // as well.
  149. ((__m128d *)magnitudes)[i]=0.01/distance_Squared*distance_Reciprocal;
  150. }
  151.  
  152. // Use the calculated magnitudes of force to update the velocities for all
  153. // of the bodies.
  154. for(intnative_t i=0, k=0; i<BODIES_COUNT-1; ++i)
  155. for(intnative_t j=i+1; j<BODIES_COUNT; ++j, ++k){
  156. // Precompute the products of the mass and magnitude since it can be
  157. // reused a couple times.
  158. const double
  159. i_mass_magnitude=bodies[i].mass*magnitudes[k],
  160. j_mass_magnitude=bodies[j].mass*magnitudes[k];
  161. for(intnative_t m=0; m<3; ++m){
  162. bodies[i].velocity[m]-=position_Deltas[m][k]*j_mass_magnitude;
  163. bodies[j].velocity[m]+=position_Deltas[m][k]*i_mass_magnitude;
  164. }
  165. }
  166.  
  167. // Use the updated velocities to update the positions for all of the bodies.
  168. for(intnative_t i=0; i<BODIES_COUNT; ++i)
  169. for(intnative_t m=0; m<3; ++m)
  170. bodies[i].position[m]+=0.01*bodies[i].velocity[m];
  171. }
  172.  
  173.  
  174. // Calculate the momentum of each body and conserve momentum of the system by
  175. // adding to the Sun's velocity the appropriate opposite velocity needed in
  176. // order to offset that body's momentum.
  177. static void offset_Momentum(body bodies[]){
  178. for(intnative_t i=0; i<BODIES_COUNT; ++i)
  179. for(intnative_t m=0; m<3; ++m)
  180. bodies[0].velocity[m]-=
  181. bodies[i].velocity[m]*bodies[i].mass/SOLAR_MASS;
  182. }
  183.  
  184.  
  185. // Output the total energy of the system.
  186. static void output_Energy(body bodies[]){
  187. double energy=0;
  188. for(intnative_t i=0; i<BODIES_COUNT; ++i){
  189.  
  190. // Add the kinetic energy for each body.
  191. energy+=0.5*bodies[i].mass*(
  192. bodies[i].velocity[0]*bodies[i].velocity[0]+
  193. bodies[i].velocity[1]*bodies[i].velocity[1]+
  194. bodies[i].velocity[2]*bodies[i].velocity[2]);
  195.  
  196. // Add the potential energy between this body and every other body.
  197. for(intnative_t j=i+1; j<BODIES_COUNT; ++j){
  198. double position_Delta[3];
  199. for(intnative_t m=0; m<3; ++m)
  200. position_Delta[m]=bodies[i].position[m]-bodies[j].position[m];
  201.  
  202. energy-=bodies[i].mass*bodies[j].mass/sqrt(
  203. position_Delta[0]*position_Delta[0]+
  204. position_Delta[1]*position_Delta[1]+
  205. position_Delta[2]*position_Delta[2]);
  206. }
  207. }
  208.  
  209. // Output the total energy of the system.
  210. printf("%.9f\n", energy);
  211. }
  212.  
  213.  
  214. int main(int argc, char *argv[]){
  215. offset_Momentum(solar_Bodies);
  216. output_Energy(solar_Bodies);
  217. for(intnative_t n=atoi(argv[1]); n--; advance(solar_Bodies));
  218. output_Energy(solar_Bodies);
  219. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement