Advertisement
Guest User

Untitled

a guest
Mar 5th, 2021
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.78 KB | None | 0 0
  1.  
  2. import os
  3. import math
  4. import std/strutils
  5.  
  6. type Dual* = tuple[val: float, dot: float]
  7.  
  8. func d_dual*(x: float): Dual =
  9. (x, 0.0)
  10.  
  11. func d_var*(x: float): Dual =
  12. (x, 1.0)
  13.  
  14. func `+`*(x, y: Dual): Dual =
  15. (x.val + y.val, x.dot + y.dot)
  16.  
  17. func `+`*(x: Dual, y: float): Dual =
  18. (x.val + y, x.dot)
  19.  
  20. func `+`*(x: float, y: Dual): Dual =
  21. (x + y.val, y.dot)
  22.  
  23. func `-`*(x, y: Dual): Dual =
  24. (x.val - y.val, x.dot - y.dot)
  25.  
  26. func `-`*(x: Dual, y: float): Dual =
  27. (x.val - y, x.dot)
  28.  
  29. func `-`*(x: float, y: Dual): Dual =
  30. (x - y.val, - y.dot)
  31.  
  32. func `*`*(x, y: Dual): Dual =
  33. (x.val * y.val, y.val * y.dot + x.dot * y.val)
  34.  
  35. func `*`*(x: Dual, y: float): Dual =
  36. (x.val * y, x.dot * y)
  37.  
  38. func `*`*(x: float, y: Dual): Dual =
  39. (x * y.val, x * y.dot)
  40.  
  41. func `/`*(x, y: Dual): Dual =
  42. (x.val / y.val, (x.dot * y.val - x.val * y.dot) / (y.val * y.val))
  43.  
  44. func `/`*(x: Dual, y: float): Dual =
  45. (x.val / y, x.dot / y)
  46.  
  47. func `/`*(x: float, y: Dual): Dual =
  48. (x / y.val, - y.dot * x / (y.val * y.val))
  49.  
  50. func sin*(x: Dual): Dual =
  51. (sin(x.val), x.dot * cos(x.val))
  52.  
  53. func cos*(x: Dual): Dual =
  54. (cos(x.val), x.dot * - sin(x.val))
  55.  
  56. type Parameters = tuple[m: float, gm: float, q_r: float, p_r: float, q_phi: float, p_phi: float, h0: float]
  57.  
  58. func h(p: Parameters, qr: Dual, pr: Dual, pth: Dual): Dual = # the Hamiltonian
  59. (pr * pr + pth * pth / (qr * qr)) / (2.0 * p.m) - p.gm / qr
  60.  
  61. proc update_q(p: var Parameters, c: float) = # coordinate updates, dq/dt = dH / dp
  62. let qr = c * h(p, d_dual(p.q_r), d_var(p.p_r), d_dual(p.p_phi)).dot
  63. let qphi = c * h(p, d_dual(p.q_r), d_dual(p.p_r), d_var(p.p_phi)).dot
  64. p.q_r = p.qr + qr
  65. p.q_phi = p.qphi + qphi
  66.  
  67. proc update_p(p: var Parameters, d: float) = # momentum updates, dp/dt = - dH / dq
  68. p.pr = p.pr - d * h(p, d_var(p.q_r), d_dual(p.p_r), d_dual(p.p_phi)).dot
  69.  
  70. proc plot(p: Parameters, t: float) =
  71. let x = p.q_r * sin(p.q_phi)
  72. let y = p.q_r * cos(p.q_phi)
  73. var diff = h(p, d_dual(p.q_r), d_dual(p.p_r), d_dual(p.p_phi)).val - p.h0
  74. var e = if diff > 0.0 : diff else: - diff
  75. var error = 10.0 * log10(if e >= 1e-36 : e else: 1e-36)
  76. echo x, " ", y, " ", 0.0, " ", t, " ", error
  77.  
  78. type
  79. Coefficients = seq[float]
  80.  
  81. proc euler_cromer*(p: var Parameters, cd: Coefficients,
  82. uq: proc(p: var Parameters, h: float),
  83. up: proc(p: var Parameters, h: float)) =
  84. uq(p, cd[0])
  85. up(p, cd[1])
  86.  
  87. proc symplectic*(p: var Parameters, cd: Coefficients,
  88. uq: proc(p: var Parameters, h: float),
  89. up: proc(p: var Parameters, h: float)) =
  90. for i in countup(0, cd.len - 1):
  91. if (i mod 2) == 0: uq(p, cd[i]) else: up(p, cd[i])
  92. for i in countdown(cd.len - 2, 0):
  93. if (i mod 2) == 0: uq(p, cd[i]) else: up(p, cd[i])
  94.  
  95. type
  96. ArgumentError = object of ValueError
  97.  
  98. proc solve*(args: seq[string], p: var Parameters,
  99. uq: proc(p: var Parameters, c: float),
  100. up: proc(p: var Parameters, d: float),
  101. output: proc(p: Parameters, t: float)) =
  102. let
  103. order: int64 = parseInt(args[1])
  104. h: float = parseFloat(args[2])
  105. steps: int64 = parseInt(args[3])
  106. z1: float = 1.0 / (4.0 - pow(4.0, (1.0 / 3.0)))
  107. y1: float = 1.0 / (4.0 - pow(4.0, (1.0 / 5.0)))
  108. x1: float = 1.0 / (4.0 - pow(4.0, (1.0 / 7.0)))
  109. z0: float = 1.0 - 4.0 * z1
  110. y0: float = 1.0 - 4.0 * y1
  111. x0: float = 1.0 - 4.0 * y1
  112. var
  113. cd: Coefficients
  114. integrator: proc(p: var Parameters, cd: Coefficients,
  115. uq: proc(p: var Parameters, h: float),
  116. up: proc(p: var Parameters, h: float))
  117. case order
  118. of 1:
  119. cd = @[h, h]
  120. integrator = euler_cromer
  121. of 2: # Stormer-Verlet
  122. cd = @[0.5 * h, h]
  123. integrator = symplectic
  124. of -4: # Forest-Ruth
  125. let z1: float = 1.0 / (2.0 - pow(2.0, (1.0 / 3.0)))
  126. let z0: float = 1.0 - 2.0 * z1
  127. cd = @[0.5 * h * z1, h * z1, 0.5 * h * (z1 + z0), h * z0]
  128. integrator = symplectic
  129. of 4: # m4r35n357_4
  130. cd = @[0.5 * h * z1, h * z1, h * z1, h * z1, 0.5 * h * (z1 + z0), h * z0]
  131. integrator = symplectic
  132. of 6: # m4r35n357_6
  133. cd = @[0.5 * h * z1 * y1, h * z1 * y1, h * z1 * y1, h * z1 * y1, 0.5 * h * (z1 + z0) * y1, h * z0 * y1, 0.5 * h * (z0 + z1) * y1, h * z1 * y1, h * z1 * y1, h * z1 * y1, h * z1 * y1, h * z1 * y1, h * z1 * y1, h * z1 * y1, 0.5 * h * (z1 + z0) * y1, h * z0 * y1, 0.5 * h * (z0 + z1) * y1, h * z1 * y1, h * z1 * y1, h * z1 * y1, 0.5 * h * z1 * (y1 + y0), h * z1 * y0, h * z1 * y0, h * z1 * y0, 0.5 * h * (z1 + z0) * y0, h * z0 * y0]
  134. integrator = symplectic
  135. of 8: # m4r35n357_8
  136. cd = @[0.5 * h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * (z1 + z0) * y1 * x1, h * z0 * y1 * x1, 0.5 * h * (z0 + z1) * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * (z1 + z0) * y1 * x1, h * z0 * y1 * x1, 0.5 * h * (z0 + z1) * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * z1 * (y1 + y0) * x1, h * z1 * y0 * x1, h * z1 * y0 * x1, h * z1 * y0 * x1, 0.5 * h * (z1 + z0) * y0 * x1, h * z0 * y0 * x1, 0.5 * h * (z0 + z1) * y0 * x1, h * z1 * y0 * x1, h * z1 * y0 * x1, h * z1 * y0 * x1, 0.5 * h * z1 * (y1 + y0) * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * (z1 + z0) * y1 * x1, h * z0 * y1 * x1, 0.5 * h * (z0 + z1) * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * (z1 + z0) * y1 * x1, h * z0 * y1 * x1, 0.5 * h * (z0 + z1) * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * (z1 + z0) * y1 * x1, h * z0 * y1 * x1, 0.5 * h * (z0 + z1) * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * (z1 + z0) * y1 * x1, h * z0 * y1 * x1, 0.5 * h * (z0 + z1) * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * z1 * (y1 + y0) * x1, h * z1 * y0 * x1, h * z1 * y0 * x1, h * z1 * y0 * x1, 0.5 * h * (z1 + z0) * y0 * x1, h * z0 * y0 * x1, 0.5 * h * (z0 + z1) * y0 * x1, h * z1 * y0 * x1, h * z1 * y0 * x1, h * z1 * y0 * x1, 0.5 * h * z1 * (y1 + y0) * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * (z1 + z0) * y1 * x1, h * z0 * y1 * x1, 0.5 * h * (z0 + z1) * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * (z1 + z0) * y1 * x1, h * z0 * y1 * x1, 0.5 * h * (z0 + z1) * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, h * z1 * y1 * x1, 0.5 * h * z1 * y1 * (x1 + x0), h * z1 * y1 * x0, h * z1 * y1 * x0, h * z1 * y1 * x0, 0.5 * h * (z1 + z0) * y1 * x0, h * z0 * y1 * x0, 0.5 * h * (z0 + z1) * y1 * x0, h * z1 * y1 * x0, h * z1 * y1 * x0, h * z1 * y1 * x0, h * z1 * y1 * x0, h * z1 * y1 * x0, h * z1 * y1 * x0, h * z1 * y1 * x0, 0.5 * h * (z1 + z0) * y1 * x0, h * z0 * y1 * x0, 0.5 * h * (z0 + z1) * y1 * x0, h * z1 * y1 * x0, h * z1 * y1 * x0, h * z1 * y1 * x0, 0.5 * h * z1 * (y1 + y0) * x0, h * z1 * y0 * x0, h * z1 * y0 * x0, h * z1 * y0 * x0, 0.5 * h * (z1 + z0) * y0 * x0, h * z0 * y0 * x0]
  137. integrator = symplectic
  138. else:
  139. echo "invalid integrator ", order, ", should be 1, 2, 4, 6, 8 or -4"
  140. raise newException(ArgumentError, "invalid integrator")
  141. p.h0 = h(p, d_dual(p.q_r), d_dual(p.p_r), d_dual(p.p_phi)).val
  142. for step in 1..steps:
  143. integrator(p, cd, uq, up)
  144. output(p, step.float * h)
  145.  
  146. # ./h_newton 6 2 1 10000 1 12 .6
  147. let
  148. args: seq[string] = commandLineParams()
  149. mass = parseFloat(args[4])
  150. r0 = parseFloat(args[5])
  151. lfac = parseFloat(args[6])
  152. var p: Parameters = (mass, mass, r0, 0.0, 0.0, lfac * sqrt(r0), 0.0)
  153. solve(args, p, update_q, update_p, plot)
  154.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement