Guest User

nbody.pyx

a guest
Jun 20th, 2016
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.13 KB | None | 0 0
  1. # The Computer Language Benchmarks Game
  2. # http://benchmarksgame.alioth.debian.org/
  3. #
  4. # originally by Kevin Carson
  5. # modified by Tupteq, Fredrik Johansson, and Daniel Nanz
  6. # modified by Maciej Fijalkowski
  7. # 2to3
  8.  
  9. from libc.math cimport pow, sqrt
  10. import sys
  11.  
  12. PI = 3.14159265358979323
  13. SOLAR_MASS = 4 * PI * PI
  14. DAYS_PER_YEAR = 365.24
  15.  
  16. cdef struct body_t:
  17. double x[3]
  18. double v[3]
  19. double m
  20.  
  21. DEF NBODIES = 5
  22.  
  23. BODIES = {
  24. 'sun': ([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], SOLAR_MASS),
  25.  
  26. 'jupiter': ([4.84143144246472090e+00,
  27. -1.16032004402742839e+00,
  28. -1.03622044471123109e-01],
  29. [1.66007664274403694e-03 * DAYS_PER_YEAR,
  30. 7.69901118419740425e-03 * DAYS_PER_YEAR,
  31. -6.90460016972063023e-05 * DAYS_PER_YEAR],
  32. 9.54791938424326609e-04 * SOLAR_MASS),
  33.  
  34. 'saturn': ([8.34336671824457987e+00,
  35. 4.12479856412430479e+00,
  36. -4.03523417114321381e-01],
  37. [-2.76742510726862411e-03 * DAYS_PER_YEAR,
  38. 4.99852801234917238e-03 * DAYS_PER_YEAR,
  39. 2.30417297573763929e-05 * DAYS_PER_YEAR],
  40. 2.85885980666130812e-04 * SOLAR_MASS),
  41.  
  42. 'uranus': ([1.28943695621391310e+01,
  43. -1.51111514016986312e+01,
  44. -2.23307578892655734e-01],
  45. [2.96460137564761618e-03 * DAYS_PER_YEAR,
  46. 2.37847173959480950e-03 * DAYS_PER_YEAR,
  47. -2.96589568540237556e-05 * DAYS_PER_YEAR],
  48. 4.36624404335156298e-05 * SOLAR_MASS),
  49.  
  50. 'neptune': ([1.53796971148509165e+01,
  51. -2.59193146099879641e+01,
  52. 1.79258772950371181e-01],
  53. [2.68067772490389322e-03 * DAYS_PER_YEAR,
  54. 1.62824170038242295e-03 * DAYS_PER_YEAR,
  55. -9.51592254519715870e-05 * DAYS_PER_YEAR],
  56. 5.15138902046611451e-05 * SOLAR_MASS)
  57. }
  58.  
  59. def combinations(l):
  60. result = []
  61. for x in range(len(l) - 1):
  62. ls = l[x+1:]
  63. for y in ls:
  64. result.append((l[x],y))
  65. return result
  66.  
  67. cdef void make_cbodies(list bodies, body_t *cbodies, int num_cbodies):
  68. cdef body_t *cbody
  69. for i, body in enumerate(bodies):
  70. if i >= num_cbodies:
  71. break
  72. (x, v, m) = body
  73. cbody = &cbodies[i]
  74. cbody.x[0], cbody.x[1], cbody.x[2] = x
  75. cbody.v[0], cbody.v[1], cbody.v[2] = v
  76. cbodies[i].m = m
  77.  
  78. cdef list make_pybodies(body_t *cbodies, int num_cbodies):
  79. pybodies = []
  80. for i in range(num_cbodies):
  81. x = [cbodies[i].x[0], cbodies[i].x[1], cbodies[i].x[2]]
  82. v = [cbodies[i].v[0], cbodies[i].v[1], cbodies[i].v[2]]
  83. pybodies.append((x, v, cbodies[i].m))
  84. return pybodies
  85.  
  86.  
  87. def advance(double dt, int n, bodies):
  88. # Note that this does not take a `pairs` argument, and *returns* a new
  89. # `bodies` list. This is slightly different from the original pure-Python
  90. # version of `advance`.
  91.  
  92. cdef:
  93. int i, ii, jj
  94. double dx, dy, dz, mag, b1m, b2m, ds
  95. body_t *body1
  96. body_t *body2
  97. body_t cbodies[NBODIES]
  98.  
  99. make_cbodies(bodies, cbodies, NBODIES)
  100.  
  101. for i in range(n):
  102. for ii in range(NBODIES-1):
  103. body1 = &cbodies[ii]
  104. for jj in range(ii+1, NBODIES):
  105. body2 = &cbodies[jj]
  106. dx = body1.x[0] - body2.x[0]
  107. dy = body1.x[1] - body2.x[1]
  108. dz = body1.x[2] - body2.x[2]
  109. ds = dx * dx + dy * dy + dz * dz
  110. mag = dt / (ds * sqrt(ds))
  111. b1m = body1.m * mag
  112. b2m = body2.m * mag
  113. body1.v[0] -= dx * b2m
  114. body1.v[1] -= dy * b2m
  115. body1.v[2] -= dz * b2m
  116. body2.v[0] += dx * b1m
  117. body2.v[1] += dy * b1m
  118. body2.v[2] += dz * b1m
  119. for ii in range(NBODIES):
  120. body2 = &cbodies[ii]
  121. body2.x[0] += dt * body2.v[0]
  122. body2.x[1] += dt * body2.v[1]
  123. body2.x[2] += dt * body2.v[2]
  124.  
  125. return make_pybodies(cbodies, NBODIES)
  126.  
  127.  
  128. def report_energy(bodies):
  129. # Note that this takes just a `bodies` list, and computes `pairs`
  130. # internally, which is a slight modification from the original pure-Python
  131. # version of `report_energy`.
  132.  
  133. e = 0.0
  134.  
  135. pairs = combinations(bodies)
  136.  
  137. for (((x1, y1, z1), v1, m1),
  138. ((x2, y2, z2), v2, m2)) in pairs:
  139. dx = x1 - x2
  140. dy = y1 - y2
  141. dz = z1 - z2
  142. e -= (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5)
  143. for (r, [vx, vy, vz], m) in bodies:
  144. e += m * (vx * vx + vy * vy + vz * vz) / 2.
  145. print("%.9f" % e)
  146.  
  147.  
  148. def offset_momentum(ref, bodies):
  149.  
  150. px = py = pz = 0.0
  151.  
  152. for (r, [vx, vy, vz], m) in bodies:
  153. px -= vx * m
  154. py -= vy * m
  155. pz -= vz * m
  156. (r, v, m) = ref
  157. v[0] = px / m
  158. v[1] = py / m
  159. v[2] = pz / m
  160.  
  161.  
  162. def main(n, bodies=BODIES, ref='sun'):
  163. system = list(bodies.values())
  164. offset_momentum(bodies[ref], system)
  165. report_energy(system)
  166. system = advance(0.01, n, system)
  167. report_energy(system)
Add Comment
Please, Sign In to add comment